diff --git a/modules/trading/install.py b/modules/trading/install.py index 2427538..c68af75 100644 --- a/modules/trading/install.py +++ b/modules/trading/install.py @@ -3190,6 +3190,44 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se return val return None + def _ensure_strategy_monitors(conn, mode: str) -> int: + """策略页加载前:恢复误关监控并同步柜台,与持仓页逻辑一致。""" + if not _cached_ctp_status(mode).get("connected"): + return 0 + capital = _capital(conn) + synced = 0 + seen: set[tuple[str, str]] = set() + positions = list(trading_state.get_positions() or []) + if not positions: + positions = list(_ctp_positions(mode, refresh_if_empty=False) or []) + for p in positions: + lots = int(p.get("lots") or 0) + if lots <= 0: + continue + ths = _ctp_pos_to_ths_code(p) or (p.get("symbol") or "") + direction = (p.get("direction") or "long").strip().lower() + key = (ths.lower(), direction) + if key in seen: + continue + seen.add(key) + mon = _find_or_revive_monitor(conn, ths, direction) + if not mon: + continue + mon = _restore_monitor_sl_tp_if_missing(conn, mon, ths, direction) or mon + _sync_monitor_from_ctp( + conn, + int(mon["id"]), + mon.get("symbol") or ths, + mon.get("direction") or direction, + mode, + ctp=p, + capital=capital, + ) + synced += 1 + if synced: + commit_retry(conn) + return synced + @app.route("/strategy") @login_required @_nav("strategy") @@ -3199,13 +3237,14 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se init_strategy_tables(conn) ensure_monitor_order_columns(conn) capital = _capital(conn) + mode = get_trading_mode(get_setting) + _ensure_strategy_monitors(conn, mode) active_trend = conn.execute( "SELECT * FROM trend_pullback_plans WHERE status='active' ORDER BY id DESC LIMIT 1" ).fetchone() monitors_raw = conn.execute( "SELECT * FROM trade_order_monitors WHERE status='active' ORDER BY id DESC" ).fetchall() - mode = get_trading_mode(get_setting) roll_ctx = _build_roll_context(conn) roll_groups = conn.execute( """SELECT g.*, m.symbol_name, m.lots AS mon_lots, m.entry_price AS mon_entry, diff --git a/modules/web/static/js/strategy.js b/modules/web/static/js/strategy.js index 5b82237..9fa5a9a 100644 --- a/modules/web/static/js/strategy.js +++ b/modules/web/static/js/strategy.js @@ -221,6 +221,19 @@ if (btnRollE) btnRollE.hidden = true; return; } + if (rollMonitorSel) { + var opt = rollMonitorSel.options[rollMonitorSel.selectedIndex]; + if (opt && opt.getAttribute('data-eligible') === '0') { + showPreview( + rollPrev, + opt.getAttribute('data-block') || '当前监控不可滚仓', + false, + false + ); + if (btnRollE) btnRollE.hidden = true; + return; + } + } btnRollP.disabled = true; jsonPost('/api/strategy/roll/preview', rollPayload).then(function (d) { if (!d.ok) { diff --git a/modules/web/templates/strategy.html b/modules/web/templates/strategy.html index bc885a4..476b9d5 100644 --- a/modules/web/templates/strategy.html +++ b/modules/web/templates/strategy.html @@ -106,6 +106,10 @@
当前为「{{ sizing_mode_label }}」模式,滚仓不可用。请在系统设置切换为固定金额。
{% endif %} {% if monitors %} + {% set roll_eligible_count = monitors|selectattr('roll_eligible')|list|length %} + {% if roll_eligible_count == 0 %} +检测到 {{ monitors|length }} 条持仓监控,但当前均不可滚仓(见下拉项说明)。
+ {% endif %}风险预算(固定金额):{{ '%.0f'|format(fixed_amount) }} 元