From fc8f9b70da7452566393106ca48e52119643cf59 Mon Sep 17 00:00:00 2001 From: dekun Date: Sat, 23 May 2026 11:20:45 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9ui?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crypto_monitor_binance/app.py | 20 +++++ crypto_monitor_binance/templates/index.html | 7 +- crypto_monitor_gate/app.py | 20 +++++ crypto_monitor_gate/templates/index.html | 7 +- crypto_monitor_gate_bot/app.py | 19 +++- crypto_monitor_gate_bot/templates/index.html | 6 +- crypto_monitor_okx/app.py | 20 +++++ crypto_monitor_okx/templates/index.html | 7 +- strategy_register.py | 64 +------------- strategy_templates/strategy_roll_panel.html | 75 ++++++++++++++++ strategy_templates/strategy_subnav.html | 4 + .../strategy_trend_disabled_panel.html | 13 +++ strategy_ui.py | 88 +++++++++++++++++++ 策略交易说明.md | 23 +++-- 14 files changed, 294 insertions(+), 79 deletions(-) create mode 100644 strategy_templates/strategy_roll_panel.html create mode 100644 strategy_templates/strategy_subnav.html create mode 100644 strategy_templates/strategy_trend_disabled_panel.html create mode 100644 strategy_ui.py diff --git a/crypto_monitor_binance/app.py b/crypto_monitor_binance/app.py index b358187..bdbe065 100644 --- a/crypto_monitor_binance/app.py +++ b/crypto_monitor_binance/app.py @@ -5682,6 +5682,13 @@ def render_main_page(page="trade"): f"箱体/收敛可选 SL/TP 方案(标准 / 箱体1R·止盈1.5H / 趋势单+自填止盈)|移动保本默认关|" f"斐波:限价 @ E(SL/TP 为 H/L),可选移动保本|趋势止损外侧 {KEY_TREND_STOP_OUTSIDE_PCT}%" ) + strategy_extra = {} + if page in ("strategy_trend", "strategy_roll"): + from strategy_ui import strategy_page_template_vars + + strategy_extra = strategy_page_template_vars( + conn, page, default_risk_percent=float(RISK_PERCENT) + ) conn.close() return render_template( "index.html", @@ -5737,6 +5744,7 @@ def render_main_page(page="trade"): key_auto_min_planned_rr=KEY_AUTO_MIN_PLANNED_RR, key_gate_rule_text=key_gate_rule_text, kline_timeframe=KLINE_TIMEFRAME, + **strategy_extra, ) @@ -7674,6 +7682,18 @@ except Exception as _hub_err: print(f"[hub_bridge] binance: {_hub_err}") +@app.route("/strategy/trend") +@login_required +def strategy_trend_page(): + return render_main_page("strategy_trend") + + +@app.route("/strategy/roll") +@login_required +def strategy_roll_page(): + return render_main_page("strategy_roll") + + from strategy_register import install_strategy_trading install_strategy_trading(app, _REPO_ROOT, app_module=sys.modules[__name__]) diff --git a/crypto_monitor_binance/templates/index.html b/crypto_monitor_binance/templates/index.html index 2c0805c..bfbe886 100644 --- a/crypto_monitor_binance/templates/index.html +++ b/crypto_monitor_binance/templates/index.html @@ -218,8 +218,7 @@
关键位监控 实盘下单 - 策略·趋势回调 - 策略·顺势加仓 + 策略交易 交易记录与复盘 统计分析
@@ -540,6 +539,10 @@ + {% elif page == 'strategy_trend' %} + {% include 'strategy_trend_disabled_panel.html' %} + {% elif page == 'strategy_roll' %} + {% include 'strategy_roll_panel.html' %} {% endif %} diff --git a/crypto_monitor_gate/app.py b/crypto_monitor_gate/app.py index c60224f..aa173e5 100644 --- a/crypto_monitor_gate/app.py +++ b/crypto_monitor_gate/app.py @@ -5661,6 +5661,13 @@ def render_main_page(page="trade"): f"箱体/收敛可选 SL/TP 方案(标准 / 箱体1R·止盈1.5H / 趋势单+自填止盈)|移动保本默认关|" f"斐波:限价 @ E(SL/TP 为 H/L),可选移动保本|趋势止损外侧 {KEY_TREND_STOP_OUTSIDE_PCT}%" ) + strategy_extra = {} + if page in ("strategy_trend", "strategy_roll"): + from strategy_ui import strategy_page_template_vars + + strategy_extra = strategy_page_template_vars( + conn, page, default_risk_percent=float(RISK_PERCENT) + ) conn.close() return render_template( "index.html", @@ -5718,6 +5725,7 @@ def render_main_page(page="trade"): key_gate_rule_text=key_gate_rule_text, kline_timeframe=KLINE_TIMEFRAME, exchange_pnl_sync=exchange_pnl_sync, + **strategy_extra, ) @@ -7735,6 +7743,18 @@ except Exception as _hub_err: print(f"[hub_bridge] gate: {_hub_err}") +@app.route("/strategy/trend") +@login_required +def strategy_trend_page(): + return render_main_page("strategy_trend") + + +@app.route("/strategy/roll") +@login_required +def strategy_roll_page(): + return render_main_page("strategy_roll") + + from strategy_register import install_strategy_trading install_strategy_trading(app, _REPO_ROOT, app_module=sys.modules[__name__]) diff --git a/crypto_monitor_gate/templates/index.html b/crypto_monitor_gate/templates/index.html index 553d7fe..156d5b0 100644 --- a/crypto_monitor_gate/templates/index.html +++ b/crypto_monitor_gate/templates/index.html @@ -218,8 +218,7 @@
关键位监控 实盘下单 - 策略·趋势回调 - 策略·顺势加仓 + 策略交易 交易记录与复盘 统计分析
@@ -540,6 +539,10 @@ + {% elif page == 'strategy_trend' %} + {% include 'strategy_trend_disabled_panel.html' %} + {% elif page == 'strategy_roll' %} + {% include 'strategy_roll_panel.html' %} {% endif %} diff --git a/crypto_monitor_gate_bot/app.py b/crypto_monitor_gate_bot/app.py index 8fa7ef2..455c392 100644 --- a/crypto_monitor_gate_bot/app.py +++ b/crypto_monitor_gate_bot/app.py @@ -5312,6 +5312,15 @@ def render_main_page(page="trade"): trend_preview_levels.append({"i": i, "price": pair[0], "contracts": pair[1]}) elif pr: trend_preview_expired = True + strategy_extra = {} + if page == "strategy_roll": + from strategy_ui import fetch_roll_page_data + + strategy_extra = fetch_roll_page_data( + conn, + default_risk_percent=float(RISK_PERCENT), + count_active_trends=lambda c, ta=trend_active: int(ta or 0), + ) conn.close() return render_template( "index.html", @@ -5376,6 +5385,7 @@ def render_main_page(page="trade"): entry_reason_options=list(ENTRY_REASON_OPTIONS), entry_reason_other_value=ENTRY_REASON_OTHER, exchange_display=EXCHANGE_DISPLAY_NAME, + **strategy_extra, ) @@ -7371,10 +7381,18 @@ except Exception as _hub_err: print(f"[hub_bridge] gate_bot: {_hub_err}") +@app.route("/strategy/trend") +@login_required def strategy_trend_page(): return render_main_page("strategy_trend") +@app.route("/strategy/roll") +@login_required +def strategy_roll_page(): + return render_main_page("strategy_roll") + + from strategy_register import install_strategy_trading install_strategy_trading( @@ -7382,7 +7400,6 @@ install_strategy_trading( _REPO_ROOT, app_module=sys.modules[__name__], trend_enabled=True, - render_trend_page=login_required(strategy_trend_page), ) diff --git a/crypto_monitor_gate_bot/templates/index.html b/crypto_monitor_gate_bot/templates/index.html index cbb0a79..f031a06 100644 --- a/crypto_monitor_gate_bot/templates/index.html +++ b/crypto_monitor_gate_bot/templates/index.html @@ -205,8 +205,7 @@
交易执行 - 策略·趋势回调 - 策略·顺势加仓 + 策略交易 交易记录与复盘 统计分析
@@ -372,6 +371,7 @@ {% elif page == 'strategy_trend' %} + {% include 'strategy_subnav.html' %}

趋势回调策略

@@ -553,6 +553,8 @@
+ {% elif page == 'strategy_roll' %} + {% include 'strategy_roll_panel.html' %} {% endif %} {% if page == 'records' %} diff --git a/crypto_monitor_okx/app.py b/crypto_monitor_okx/app.py index 6d6ed20..dbcf3d4 100644 --- a/crypto_monitor_okx/app.py +++ b/crypto_monitor_okx/app.py @@ -4192,6 +4192,13 @@ def render_main_page(page="trade"): f"自动开仓盈亏比 > {KEY_AUTO_MIN_PLANNED_RR}:1|日成交量排名前 {KEY_DAILY_VOLUME_RANK_MAX}|" f"斐波:添加后立即挂限价 @ E,失效按标记价触达 H/L(未成交撤单)" ) + strategy_extra = {} + if page in ("strategy_trend", "strategy_roll"): + from strategy_ui import strategy_page_template_vars + + strategy_extra = strategy_page_template_vars( + conn, page, default_risk_percent=float(RISK_PERCENT) + ) conn.close() return render_template( "index.html", @@ -4242,6 +4249,7 @@ def render_main_page(page="trade"): entry_reason_other_value=ENTRY_REASON_OTHER, key_gate_rule_text=key_gate_rule_text, key_auto_min_planned_rr=KEY_AUTO_MIN_PLANNED_RR, + **strategy_extra, ) @@ -5950,6 +5958,18 @@ except Exception as _hub_err: print(f"[hub_bridge] okx: {_hub_err}") +@app.route("/strategy/trend") +@login_required +def strategy_trend_page(): + return render_main_page("strategy_trend") + + +@app.route("/strategy/roll") +@login_required +def strategy_roll_page(): + return render_main_page("strategy_roll") + + from strategy_register import install_strategy_trading install_strategy_trading(app, _REPO_ROOT, app_module=sys.modules[__name__]) diff --git a/crypto_monitor_okx/templates/index.html b/crypto_monitor_okx/templates/index.html index 23cd7da..343eeaf 100644 --- a/crypto_monitor_okx/templates/index.html +++ b/crypto_monitor_okx/templates/index.html @@ -154,8 +154,7 @@

加密货币|交易监控 + AI复盘一体化

交易执行 - 策略·趋势回调 - 策略·顺势加仓 + 策略交易 交易记录与复盘 统计分析
@@ -353,6 +352,10 @@ {% endfor %} + {% elif page == 'strategy_trend' %} + {% include 'strategy_trend_disabled_panel.html' %} + {% elif page == 'strategy_roll' %} + {% include 'strategy_roll_panel.html' %} {% endif %} {% if page == 'records' %} diff --git a/strategy_register.py b/strategy_register.py index 417af4c..957ffef 100644 --- a/strategy_register.py +++ b/strategy_register.py @@ -5,7 +5,7 @@ import os from functools import wraps from typing import Any, Callable, Optional -from flask import Flask, flash, jsonify, redirect, render_template, request, url_for +from flask import Flask, flash, jsonify, redirect, request, url_for from jinja2 import ChoiceLoader, FileSystemLoader from strategy_db import init_strategy_tables @@ -13,14 +13,12 @@ from strategy_roll_lib import preview_roll def install_strategy_trading(app: Flask, repo_root: str, app_module: Any = None, **build_kw) -> None: - """在 app.py 末尾调用(login_required 已定义后)。build_kw 传给 build_strategy_config。""" + """在 app.py 末尾调用(login_required 已定义后)。仅注册 POST API;页面由各 app 的 render_main_page 渲染。""" from strategy_config import build_strategy_config - render_trend_page = build_kw.pop("render_trend_page", None) + build_kw.pop("render_trend_page", None) attach_strategy_templates(app, repo_root) cfg = build_strategy_config(app_module, **build_kw) - if render_trend_page is not None: - cfg["render_trend_page"] = render_trend_page register_strategy_trading(app, cfg) @@ -43,66 +41,10 @@ def register_strategy_trading(app: Flask, cfg: dict[str, Any]) -> None: login_required = cfg["login_required"] get_db = cfg["get_db"] - trend_enabled = bool(cfg.get("trend_enabled")) - render_trend_page = cfg.get("render_trend_page") def _lr(f): return login_required(f) - if trend_enabled and callable(render_trend_page): - app.add_url_rule( - "/strategy/trend", - endpoint="strategy_trend_page", - view_func=_lr(render_trend_page), - ) - else: - - @_lr - @app.route("/strategy/trend") - def strategy_trend_disabled_page(): - return render_template( - "strategy_trend_disabled.html", - exchange_display=cfg.get("exchange_display", ""), - trend_note=cfg.get( - "trend_disabled_note", - "趋势回调(自动补仓)当前仅在 Gate 趋势机器人实例中启用。", - ), - ) - - @_lr - @app.route("/strategy/roll") - def strategy_roll_page(): - conn = get_db() - init_strategy_tables(conn) - monitors = [] - for row in conn.execute( - "SELECT * FROM order_monitors WHERE status='active' ORDER BY id DESC" - ).fetchall(): - monitors.append(_row_to_dict(row)) - roll_groups = [] - for row in conn.execute( - "SELECT * FROM roll_groups WHERE status='active' ORDER BY id DESC" - ).fetchall(): - roll_groups.append(_row_to_dict(row)) - legs = [] - for row in conn.execute( - "SELECT * FROM roll_legs ORDER BY id DESC LIMIT 50" - ).fetchall(): - legs.append(_row_to_dict(row)) - trend_n = _count_active_trends(conn, cfg) - conn.close() - return render_template( - "strategy_roll.html", - page="strategy_roll", - exchange_display=cfg.get("exchange_display", ""), - monitors=monitors, - roll_groups=roll_groups, - roll_legs=legs, - trend_active=trend_n, - default_risk_percent=cfg.get("default_risk_percent", 2), - price_fmt=cfg.get("price_fmt"), - ) - @_lr @app.route("/strategy/roll/preview", methods=["POST"]) def strategy_roll_preview(): diff --git a/strategy_templates/strategy_roll_panel.html b/strategy_templates/strategy_roll_panel.html new file mode 100644 index 0000000..0ee3fee --- /dev/null +++ b/strategy_templates/strategy_roll_panel.html @@ -0,0 +1,75 @@ +{% include 'strategy_subnav.html' %} +
+

顺势加仓(滚仓)

+
+ 仅人工加仓,程序不会自动触发。须先在「实盘下单」有同向持仓。
+ 做多最多滚仓 3 次;止盈锁定首仓不变;每次填写新统一止损,总风险%按「合并持仓打到新止损≈账户风险」反推张数。
+ 斐波限价:上沿 H、下沿 L 仅用于算 0.618/0.786 加仓价(多:下沿=止损侧;空:上沿=止损侧)。
+ {% if roll_trend_active %}当前有运行中的趋势回调计划,请先结束后再滚仓。{% endif %} +
+
+ + + + + + + + +
+

执行前可用开发者工具 POST /strategy/roll/preview 查看 JSON 预览。

+
+ +
+

活跃滚仓组

+
+ + + {% for g in roll_groups %} + + + + + + + + + {% else %} + + {% endfor %} +
ID币种方向腿数首仓TP当前SL
{{ g.id }}{{ g.symbol }}{{ g.direction }}{{ g.leg_count }}{% if price_fmt %}{{ price_fmt(g.symbol, g.initial_take_profit) }}{% else %}{{ g.initial_take_profit }}{% endif %}{% if price_fmt %}{{ price_fmt(g.symbol, g.current_stop_loss) }}{% else %}{{ g.current_stop_loss }}{% endif %}
暂无
+
+
+ +
+

最近滚仓腿

+
+ + + {% for leg in roll_legs %} + + + + + + + + + {% else %} + + {% endfor %} +
#方式张数新SL状态
{{ leg.leg_index }}{{ leg.roll_group_id }}{{ leg.add_mode }}{{ leg.amount }}{{ leg.new_stop_loss }}{{ leg.status }}
暂无
+
+
diff --git a/strategy_templates/strategy_subnav.html b/strategy_templates/strategy_subnav.html new file mode 100644 index 0000000..f53393d --- /dev/null +++ b/strategy_templates/strategy_subnav.html @@ -0,0 +1,4 @@ +
+ 趋势回调 + 顺势加仓 +
diff --git a/strategy_templates/strategy_trend_disabled_panel.html b/strategy_templates/strategy_trend_disabled_panel.html new file mode 100644 index 0000000..5bc5013 --- /dev/null +++ b/strategy_templates/strategy_trend_disabled_panel.html @@ -0,0 +1,13 @@ +{% include 'strategy_subnav.html' %} +
+

趋势回调

+
{{ trend_disabled_note }}
+
+ 趋势回调含自动补仓档位与预览执行,仅在 Gate 趋势机器人crypto_monitor_gate_bot)实例中运行。 + 请访问该实例同一菜单「策略交易 → 趋势回调」,或常用地址 :5002/strategy/trend。 +
+

+ 返回实盘下单 + | 顺势加仓(本实例可用) +

+
diff --git a/strategy_ui.py b/strategy_ui.py new file mode 100644 index 0000000..96d817a --- /dev/null +++ b/strategy_ui.py @@ -0,0 +1,88 @@ +"""策略交易页:主站 index.html 所需数据(顺势加仓等)。""" +from __future__ import annotations + +from typing import Any, Callable, Optional + +from strategy_db import init_strategy_tables + + +def _row_to_dict(row) -> dict: + if row is None: + return {} + try: + return dict(row) + except Exception: + return {} + + +def count_active_trend_plans(conn, count_fn: Optional[Callable] = None) -> int: + if callable(count_fn): + return int(count_fn(conn) or 0) + try: + return int( + conn.execute( + "SELECT COUNT(*) FROM trend_pullback_plans WHERE status='active'" + ).fetchone()[0] + ) + except Exception: + return 0 + + +def fetch_roll_page_data( + conn, + *, + default_risk_percent: float = 2.0, + count_active_trends: Optional[Callable] = None, +) -> dict[str, Any]: + init_strategy_tables(conn) + monitors = [] + for row in conn.execute( + "SELECT * FROM order_monitors WHERE status='active' ORDER BY id DESC" + ).fetchall(): + monitors.append(_row_to_dict(row)) + roll_groups = [] + for row in conn.execute( + "SELECT * FROM roll_groups WHERE status='active' ORDER BY id DESC" + ).fetchall(): + roll_groups.append(_row_to_dict(row)) + roll_legs = [] + for row in conn.execute( + "SELECT * FROM roll_legs ORDER BY id DESC LIMIT 50" + ).fetchall(): + roll_legs.append(_row_to_dict(row)) + return { + "roll_monitors": monitors, + "roll_groups": roll_groups, + "roll_legs": roll_legs, + "roll_trend_active": count_active_trend_plans(conn, count_active_trends), + "default_risk_percent": default_risk_percent, + } + + +DEFAULT_TREND_DISABLED_NOTE = ( + "趋势回调(预览、自动补仓、程序止盈)仅在 Gate 趋势机器人实例 " + "(crypto_monitor_gate_bot,常见端口 5002)中启用。" + "币安 / Gate 主站 / OKX 可使用本页「顺势加仓」;完整趋势回调请打开该实例。" +) + + +def strategy_page_template_vars( + conn, + page: str, + *, + default_risk_percent: float = 2.0, + count_active_trends: Optional[Callable] = None, + trend_disabled_note: str = "", +) -> dict[str, Any]: + """render_main_page 在 conn.close() 前合并进 render_template 的变量。""" + if page == "strategy_roll": + return fetch_roll_page_data( + conn, + default_risk_percent=default_risk_percent, + count_active_trends=count_active_trends, + ) + if page == "strategy_trend": + return { + "trend_disabled_note": trend_disabled_note or DEFAULT_TREND_DISABLED_NOTE, + } + return {} diff --git a/策略交易说明.md b/策略交易说明.md index 4381e33..57faa7a 100644 --- a/策略交易说明.md +++ b/策略交易说明.md @@ -1,6 +1,6 @@ # 策略交易说明 -本文档说明仓库根目录 **共用策略逻辑** 与四个 `crypto_monitor_*` 实例中的 **策略交易** 入口(导航栏「策略·趋势回调」「策略·顺势加仓」)。 +本文档说明仓库根目录 **共用策略逻辑** 与四个 `crypto_monitor_*` 实例中的 **策略交易** 入口(顶栏「策略交易」,页内子 Tab:趋势回调 / 顺势加仓)。 --- @@ -11,9 +11,10 @@ strategy_trend_lib.py # 趋势回调:网格价、补仓拆分、边界校 strategy_roll_lib.py # 顺势加仓:总风险反推、斐波限价、最多 3 腿(纯计算) strategy_db.py # roll_groups / roll_legs 表结构 strategy_config.py # 各所 app → 统一回调配置(交易所 API) -strategy_register.py # Flask 路由:/strategy/trend、/strategy/roll +strategy_register.py # Flask POST:/strategy/roll/preview、/strategy/roll/execute +strategy_ui.py # 主站 index 页数据(滚仓组、持仓列表等) strategy_exchange_*.py # 适配器说明(实际下单仍走各所 app 的 ccxt) -strategy_templates/ # 顺势加仓页、趋势禁用提示页 +strategy_templates/ # 主站内嵌 panel(subnav、roll、trend 禁用说明) ``` | 层级 | 职责 | @@ -28,22 +29,26 @@ strategy_templates/ # 顺势加仓页、趋势禁用提示页 ## 二、导航与页面 -| 路由 | 名称 | 说明 | -|------|------|------| -| `/strategy/trend` | 趋势回调 | **完整功能仅在 `crypto_monitor_gate_bot`**;其它所显示说明页 | -| `/strategy/roll` | 顺势加仓 | **四所均可用**(须已有同向持仓) | +顶栏一项 **「策略交易」**(高亮含 `/strategy/trend` 与 `/strategy/roll`),页内子导航切换: + +| 路由 | 子 Tab | 说明 | +|------|--------|------| +| `/strategy/trend` | 趋势回调 | **完整功能仅在 `crypto_monitor_gate_bot`**;其它所在主站 `index.html` 内嵌说明(不再跳转独立 HTML) | +| `/strategy/roll` | 顺势加仓 | **四所均可用**(须已有同向持仓),与实盘页同一布局 | | `/trade` | 实盘下单 | 首仓、以损定仓、移动保本(不变) | +各所 `app.py` 注册 `@app.route("/strategy/trend|roll")` → `render_main_page(...)`;`install_strategy_trading` 仅注册滚仓 POST API。 + --- ## 三、趋势回调(延续 Gate 趋势机器人逻辑) -- **位置**:`crypto_monitor_gate_bot` → **策略·趋势回调**(原「交易执行」页内区块已迁出)。 +- **位置**:`crypto_monitor_gate_bot` → **策略交易 → 趋势回调**(与 Gate 主站同一顶栏风格,非独立站点)。 - **行为**:与《[crypto_monitor_gate_bot/趋势回调策略说明.md](./crypto_monitor_gate_bot/趋势回调策略说明.md)》一致——预览 → 确认执行 → 首仓 50% + 交易所止损 + 多档 **自动** 市价补仓 + 程序监控止盈。 - **共用代码**:`parse_and_compute_trend_pullback_plan` 中网格/拆档已改为调用 `strategy_trend_lib`。 - **互斥**:与「机器人下单监控」持仓上限、运行中趋势计划互斥(逻辑未改)。 -其它三所打开 `/strategy/trend` 会提示:请使用 Gate 趋势机器人实例。 +其它三所打开 **策略交易 → 趋势回调** 会在主站内嵌说明:完整功能请使用 Gate 趋势机器人实例(常见 `:5002`)。 ---