fix(trend): align hub and four-exchange trend plan display

Unify gate_bot with shared enrich_trend_plan for strategy pages and hub monitor, reconcile DCA avg with live entry price, and fix missing fill price display.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-07 18:05:30 +08:00
parent e5576eaaed
commit 6a4ec69dba
7 changed files with 287 additions and 127 deletions
+10 -106
View File
@@ -3959,40 +3959,6 @@ def calc_trend_manual_breakeven_stop(direction, entry_price, offset_pct=None):
return e * (1.0 + pct / 100.0)
def enrich_active_trend_plan_row(row):
d = row_to_dict(row)
try:
d["breakeven_applied"] = int(d.get("breakeven_applied") or 0) != 0
except Exception:
d["breakeven_applied"] = False
ex_sym = d.get("exchange_symbol") or normalize_exchange_symbol(d.get("symbol") or "")
direction = (d.get("direction") or "long").lower()
m = get_live_position_exchange_metrics(ex_sym, direction)
if m and m.get("unrealized_pnl") is not None:
d["floating_pnl"] = float(m["unrealized_pnl"])
else:
d["floating_pnl"] = None
if m and m.get("mark_price") is not None:
d["floating_mark"] = float(m["mark_price"])
else:
d["floating_mark"] = None
try:
d["contract_size"] = float(get_contract_size(ex_sym))
except (TypeError, ValueError):
pass
from strategy_snapshot_lib import attach_trend_dca_levels
from strategy_trend_lib import calc_trend_plan_money_metrics
d = attach_trend_dca_levels(d)
money = calc_trend_plan_money_metrics(d)
if money.get("money_rr") is not None:
d["money_rr"] = money["money_rr"]
d["planned_rr"] = money["money_rr"]
if money.get("risk_amount_u") is not None:
d["risk_amount_u"] = money["risk_amount_u"]
return d
def opened_at_str_to_ms(opened_at_str):
if not opened_at_str:
return None
@@ -5412,30 +5378,6 @@ def render_main_page(page="trade"):
trend_active = conn.execute(
"SELECT COUNT(*) FROM trend_pullback_plans WHERE status='active'"
).fetchone()[0]
trend_plans_raw = conn.execute(
"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:
enriched = enrich_active_trend_plan_row(r)
trend_plans.append(enriched)
except Exception as e:
print(f"[render_main_page] enrich trend plan: {e}")
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:
@@ -5456,49 +5398,17 @@ def render_main_page(page="trade"):
and active_count < MAX_ACTIVE_POSITIONS
and int(trend_active or 0) == 0
)
trend_preview = None
trend_preview_levels = []
preview_expires_ms = None
trend_preview_expired = False
trend_preview_id_arg = ""
if page in ("strategy", "strategy_trend", "strategy_roll"):
_trend_cleanup_stale_previews(conn)
if page in ("strategy", "strategy_trend"):
trend_preview_id_arg = (request.args.get("preview_id") or "").strip()
if trend_preview_id_arg:
pr = conn.execute(
"SELECT * FROM trend_pullback_previews WHERE id=?",
(trend_preview_id_arg,),
).fetchone()
now_ms = int(time.time() * 1000)
if pr and int(pr["expires_at_ms"] or 0) >= now_ms:
from strategy_trend_lib import build_trend_preview_level_rows
trend_preview = row_to_dict(pr)
preview_expires_ms = int(pr["expires_at_ms"])
if not trend_preview.get("contract_size"):
try:
ensure_markets_loaded()
ex_sym = trend_preview.get("exchange_symbol") or trend_preview.get("symbol")
mk = exchange.market(ex_sym)
trend_preview["contract_size"] = float(mk.get("contractSize") or 1)
except Exception:
pass
trend_preview, trend_preview_levels = build_trend_preview_level_rows(trend_preview)
elif pr:
trend_preview_expired = True
strategy_extra = {}
if page == "strategy_records":
if page in ("strategy", "strategy_trend", "strategy_roll", "strategy_records"):
from strategy_ui import strategy_render_extras
strategy_extra = strategy_render_extras(conn, page)
elif page in ("strategy", "strategy_trend", "strategy_roll"):
from strategy_ui import fetch_roll_page_data
strategy_extra = fetch_roll_page_data(
strategy_extra = strategy_render_extras(
conn,
page,
default_risk_percent=float(RISK_PERCENT),
count_active_trends=lambda c, ta=trend_active: int(ta or 0),
request_obj=request,
trend_cfg=app.extensions.get("strategy_trend_cfg"),
)
orphan_positions: list = []
if page == "trade":
@@ -5540,20 +5450,9 @@ def render_main_page(page="trade"):
max_active_positions=MAX_ACTIVE_POSITIONS,
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,
trend_pullback_preview_ttl=TREND_PULLBACK_PREVIEW_TTL_SECONDS,
trend_preview=trend_preview,
trend_preview_levels=trend_preview_levels,
preview_expires_ms=preview_expires_ms,
trend_preview_expired=trend_preview_expired,
trend_preview_id_arg=trend_preview_id_arg,
trend_preview_max_drift_pct=TREND_PREVIEW_MAX_BALANCE_DRIFT_PCT,
trend_manual_breakeven_offset_pct=TREND_PULLBACK_MANUAL_BREAKEVEN_OFFSET_PCT,
list_window=list_window,
list_window_presets={
"utc_today": PRESET_UTC_TODAY,
@@ -8032,6 +7931,11 @@ try:
},
ohlcv_fn=_hub_fetch_ohlcv,
)
from strategy_trend_register import build_trend_config, patch_trend_hub_enrich
_hub_trend_cfg = build_trend_config(sys.modules[__name__])
app.extensions["strategy_trend_cfg"] = _hub_trend_cfg
patch_trend_hub_enrich(app, _hub_trend_cfg)
except Exception as _hub_err:
print(f"[hub_bridge] gate_bot: {_hub_err}")