feat: 账户方向与币种白名单 env 开关(三所)
Per-instance TRADE_DIRECTION / TRADE_SYMBOL_WHITELIST restricts UI and API for manual orders, key monitors, and strategies; includes sync script for deployment profiles. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -158,6 +158,14 @@ from lib.trade.position_sizing_lib import (
|
||||
mode_label_zh,
|
||||
risk_percent_for_storage,
|
||||
)
|
||||
from lib.trade.trade_policy_lib import load_trade_policy
|
||||
from lib.trade.trade_policy_app_lib import (
|
||||
check_direction_policy,
|
||||
check_open_policy,
|
||||
check_symbol_policy,
|
||||
default_symbol_for_policy,
|
||||
trade_policy_template_context,
|
||||
)
|
||||
from lib.key_monitor.key_monitor_full_margin_lib import (
|
||||
monitor_type_disallowed_in_full_margin,
|
||||
purge_disallowed_key_monitors,
|
||||
@@ -332,6 +340,7 @@ FORCE_CLOSE_BJ_HOUR = int(os.getenv("FORCE_CLOSE_BJ_HOUR", "0"))
|
||||
# 自动划转:仅在北京时间该整点「小时」内尝试;transfer_logs.transfer_day 存 UTC 自然日便于对账
|
||||
AUTO_TRANSFER_BJ_HOUR = int(os.getenv("AUTO_TRANSFER_BJ_HOUR", "8"))
|
||||
POSITION_SIZING_MODE = load_position_sizing_mode()
|
||||
TRADE_POLICY = load_trade_policy()
|
||||
WECHAT_TIMEOUT_SECONDS = int(os.getenv("WECHAT_TIMEOUT_SECONDS", "10"))
|
||||
AI_TIMEOUT_SECONDS = int(os.getenv("AI_TIMEOUT_SECONDS", "120"))
|
||||
MONITOR_POLL_SECONDS = int(os.getenv("MONITOR_POLL_SECONDS", "3"))
|
||||
@@ -1989,6 +1998,12 @@ def normalize_symbol_input(symbol):
|
||||
return f"{sym}/USDT"
|
||||
|
||||
|
||||
def validate_trade_policy_open(symbol, direction):
|
||||
return check_open_policy(
|
||||
TRADE_POLICY, symbol, direction, normalize_symbol_input
|
||||
)
|
||||
|
||||
|
||||
def normalize_kline_limit(limit_raw, default=200):
|
||||
try:
|
||||
n = int(limit_raw)
|
||||
@@ -7054,6 +7069,7 @@ def render_main_page(page="trade", embed_mode=None):
|
||||
risk_percent=RISK_PERCENT,
|
||||
position_sizing_mode=POSITION_SIZING_MODE,
|
||||
position_sizing_mode_label=mode_label_zh(POSITION_SIZING_MODE),
|
||||
trade_policy=trade_policy_template_context(TRADE_POLICY),
|
||||
open_position_button_label=(
|
||||
"开仓(全仓杠杆)" if is_full_margin_mode(POSITION_SIZING_MODE) else "开仓(以损定仓)"
|
||||
),
|
||||
@@ -7790,7 +7806,10 @@ def key_focus():
|
||||
selected_key = next((k for k in key_list if (k.get("symbol") or "").upper() == symbol_query), None)
|
||||
if selected_key is None and key_list:
|
||||
selected_key = key_list[0]
|
||||
default_symbol = symbol_query or ((selected_key or {}).get("symbol")) or "BTC/USDT"
|
||||
default_symbol = default_symbol_for_policy(
|
||||
TRADE_POLICY,
|
||||
symbol_query or ((selected_key or {}).get("symbol")) or "BTC/USDT",
|
||||
)
|
||||
return render_template(
|
||||
"key_focus_v2.html",
|
||||
key_list=key_list,
|
||||
@@ -7800,6 +7819,7 @@ def key_focus():
|
||||
default_kline_limit=200,
|
||||
price_refresh_seconds=PRICE_REFRESH_SECONDS,
|
||||
exchange_display=EXCHANGE_DISPLAY_NAME,
|
||||
trade_policy=trade_policy_template_context(TRADE_POLICY),
|
||||
)
|
||||
|
||||
|
||||
@@ -7912,6 +7932,12 @@ def add_key():
|
||||
if not symbol:
|
||||
flash("symbol 不能为空")
|
||||
return redirect("/key_monitor")
|
||||
ok_sym, sym_msg = check_symbol_policy(
|
||||
TRADE_POLICY, symbol, normalize_symbol_input
|
||||
)
|
||||
if not ok_sym:
|
||||
flash(sym_msg)
|
||||
return redirect("/key_monitor")
|
||||
mt = (d.get("type") or "").strip()
|
||||
direction_pre = (d.get("direction") or "").strip().lower()
|
||||
dup_msg = check_duplicate_submit(
|
||||
@@ -7927,6 +7953,10 @@ def add_key():
|
||||
elif direction_sel not in ("long", "short"):
|
||||
flash("箱体/收敛突破请选择做多或做空")
|
||||
return redirect("/key_monitor")
|
||||
ok_dir, dir_msg = check_direction_policy(TRADE_POLICY, direction_sel)
|
||||
if not ok_dir:
|
||||
flash(dir_msg)
|
||||
return redirect("/key_monitor")
|
||||
allowed_types = (
|
||||
tuple(KEY_MONITOR_AUTO_TYPES)
|
||||
+ tuple(KEY_MONITOR_ALERT_ONLY_TYPES)
|
||||
@@ -8209,6 +8239,11 @@ def add_order():
|
||||
conn.close()
|
||||
flash("symbol 不能为空")
|
||||
return redirect("/")
|
||||
ok_pol, pol_msg = validate_trade_policy_open(symbol, direction)
|
||||
if not ok_pol:
|
||||
conn.close()
|
||||
flash(f"账户限制:{pol_msg}")
|
||||
return redirect("/trade")
|
||||
dup_msg = check_duplicate_submit(session, submit_scope_add_order(symbol, direction))
|
||||
if dup_msg:
|
||||
conn.close()
|
||||
@@ -9552,6 +9587,7 @@ def _hub_meta_bundle():
|
||||
"max_active_positions": MAX_ACTIVE_POSITIONS,
|
||||
"btc_leverage": BTC_LEVERAGE,
|
||||
"alt_leverage": ALT_LEVERAGE,
|
||||
"trade_policy": trade_policy_template_context(TRADE_POLICY),
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user