diff --git a/crypto_monitor_gate_bot/app.py b/crypto_monitor_gate_bot/app.py index b5a713c..7d34b73 100644 --- a/crypto_monitor_gate_bot/app.py +++ b/crypto_monitor_gate_bot/app.py @@ -5270,11 +5270,27 @@ def background_task(): check_roll_monitors(_roll_cfg) check_order_monitors() - except: - pass + except Exception as e: + print(f"[background_task] error: {e}", flush=True) time.sleep(MONITOR_POLL_SECONDS) +_BG_MONITORS_LOCK = threading.Lock() +_BG_MONITORS_STARTED = False + + +def _ensure_background_monitors_started(): + global _BG_MONITORS_STARTED + with _BG_MONITORS_LOCK: + if _BG_MONITORS_STARTED: + return + _BG_MONITORS_STARTED = True + threading.Thread( + target=background_task, daemon=True, name="gate-bot-monitors" + ).start() + print("[startup] background monitor thread started", flush=True) + + # ====================== 登录路由 ====================== @app.route("/login", methods=["GET", "POST"]) def login(): @@ -5400,12 +5416,26 @@ def render_main_page(page="trade"): "SELECT * FROM trend_pullback_plans WHERE status='active' ORDER BY id DESC" ).fetchall() trend_plans = [] + trend_dca_probes = [] + _trend_cfg = app.extensions.get("strategy_trend_cfg") for r in trend_plans_raw: try: - trend_plans.append(enrich_active_trend_plan_row(r)) + enriched = enrich_active_trend_plan_row(r) + trend_plans.append(enriched) except Exception as e: print(f"[render_main_page] enrich trend plan: {e}") - trend_plans.append(row_to_dict(r)) + enriched = row_to_dict(r) + trend_plans.append(enriched) + if _trend_cfg and page in ("strategy", "strategy_trend", "strategy_roll"): + try: + from strategy_trend_register import summarize_trend_dca_probe + + probe = summarize_trend_dca_probe(_trend_cfg, r) + trend_dca_probes.append(probe) + if isinstance(enriched, dict): + enriched["dca_probe"] = probe + except Exception as e: + print(f"[render_main_page] trend dca probe: {e}") preview_snapshots = [] if page == "records": try: @@ -5511,6 +5541,8 @@ def render_main_page(page="trade"): manual_min_planned_rr=MANUAL_MIN_PLANNED_RR, can_trade=can_trade, trend_plans=trend_plans, + trend_dca_probes=trend_dca_probes, + live_trading_enabled=LIVE_TRADING_ENABLED, preview_snapshots=preview_snapshots, exchange_sync_from_label=(EXCHANGE_POSITION_SYNC_FROM_BJ or "最近90天"), trend_pullback_dca_legs=TREND_PULLBACK_DCA_LEGS, @@ -8017,6 +8049,35 @@ def strategy_trend_page(): return redirect(f"/strategy?{qs}" if qs else "/strategy") +@app.route("/api/trend_poll_status") +@login_required +def api_trend_poll_status(): + from strategy_trend_register import ( + build_trend_config, + get_trend_poll_state, + summarize_trend_dca_probe, + ) + + cfg = app.extensions.get("strategy_trend_cfg") or build_trend_config( + sys.modules[__name__] + ) + conn = get_db() + probes = [] + for r in conn.execute( + "SELECT * FROM trend_pullback_plans WHERE status='active' ORDER BY id DESC" + ).fetchall(): + probes.append(summarize_trend_dca_probe(cfg, r)) + conn.close() + return jsonify( + { + "poll": get_trend_poll_state(), + "probes": probes, + "live_trading_enabled": LIVE_TRADING_ENABLED, + "monitor_poll_seconds": MONITOR_POLL_SECONDS, + } + ) + + @app.route("/strategy/roll") @login_required def strategy_roll_page(): @@ -8035,9 +8096,9 @@ install_strategy_trading( app.extensions["strategy_trend_cfg"] = build_trend_config(sys.modules[__name__]) _purge_key_monitors_if_full_margin() +_ensure_background_monitors_started() # 启动 if __name__ == "__main__": - threading.Thread(target=background_task, daemon=True).start() app.run(host=HOST, port=PORT, debug=DEBUG) diff --git a/strategy_templates/strategy_trend_panel.html b/strategy_templates/strategy_trend_panel.html index 9964036..6c54c8f 100644 --- a/strategy_templates/strategy_trend_panel.html +++ b/strategy_templates/strategy_trend_panel.html @@ -7,6 +7,19 @@ ② 确认执行:市价首仓 50% + 挂交易所止损;首仓后可手动保本(默认均价+{{ trend_manual_breakeven_offset_pct }}%);剩余 50% 在止损与补仓区间之间共 {{ trend_pullback_dca_legs }} 档(做多为上沿、做空为下沿;程序可能因最小张数自动减档)市价补仓;止盈由程序监控
确认执行时若当前可用余额与预览快照相对偏差 > {{ trend_preview_max_drift_pct }}% 会拒绝并要求重新预览。 + {% if trend_dca_probes %} + {% for p in trend_dca_probes %} + {% if p.trigger_reached and p.block_reason %} +
+ 计划 #{{ p.plan_id }} 标记价 {{ p.mark_price }} 已触达补仓触发价 {{ p.next_trigger }},但未自动补仓: + {{ p.block_reason }}。 + {% if not live_trading_enabled %} + 请在 crypto_monitor_gate_bot/.env 设置 LIVE_TRADING_ENABLED=true 后重启 PM2 进程 crypto_gate_bot(不是 manual-agent-gate-bot)。 + {% endif %} +
+ {% endif %} + {% endfor %} + {% endif %}