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:
@@ -159,6 +159,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,
|
||||
@@ -342,6 +350,7 @@ FORCE_CLOSE_BJ_HOUR = int(os.getenv("FORCE_CLOSE_BJ_HOUR", "0"))
|
||||
AUTO_TRANSFER_BJ_HOUR = int(os.getenv("AUTO_TRANSFER_BJ_HOUR", "8"))
|
||||
# 计仓模式:risk=以损定仓(默认);full_margin=合约可用保证金×比例全仓杠杆(仅 env 切换,须无仓)
|
||||
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"))
|
||||
@@ -2035,6 +2044,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)
|
||||
@@ -7277,6 +7292,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 "开仓(以损定仓)"
|
||||
),
|
||||
@@ -7996,7 +8012,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,
|
||||
@@ -8006,6 +8025,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),
|
||||
)
|
||||
|
||||
|
||||
@@ -8116,6 +8136,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_sel = (d.get("direction") or "").strip().lower()
|
||||
dup_msg = check_duplicate_submit(
|
||||
@@ -8130,6 +8156,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)
|
||||
@@ -8375,6 +8405,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()
|
||||
@@ -9703,6 +9738,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