修复趋势回调企业微信推送

This commit is contained in:
dekun
2026-05-29 17:48:19 +08:00
parent 82b1ba3755
commit 7af2717331
2 changed files with 140 additions and 60 deletions
+66 -24
View File
@@ -4470,8 +4470,34 @@ def _trend_weighted_avg(old_avg, old_amt, fill_px, add_amt):
return float(fill_px or 0)
def _trend_plan_stop_status(result_label):
if result_label == "止盈":
return "stopped_tp"
if result_label == "止损":
return "stopped_sl"
return "stopped_manual"
def _trend_plan_trade_exists(conn, plan_id):
try:
return conn.execute(
"SELECT id FROM trade_records WHERE trend_plan_id=? LIMIT 1",
(int(plan_id),),
).fetchone() is not None
except Exception:
return False
def _trend_finalize_plan(conn, row, result_label, exit_price, closed_at=None):
"""平仓后记账、撤单、结束计划。"""
plan_id = int(row["id"])
active = conn.execute(
"SELECT * FROM trend_pullback_plans WHERE id=? AND status='active'",
(plan_id,),
).fetchone()
if not active:
return
row = active
sym = row["symbol"]
direction = row["direction"] or "long"
ex_sym = row["exchange_symbol"] or normalize_exchange_symbol(sym)
@@ -4492,24 +4518,18 @@ def _trend_finalize_plan(conn, row, result_label, exit_price, closed_at=None):
cancel_gate_swap_trigger_orders(ex_sym)
except Exception:
pass
st = _trend_plan_stop_status(result_label)
cur = conn.execute(
"UPDATE trend_pullback_plans SET status=?, message=? WHERE id=? AND status='active'",
(st, res, plan_id),
)
if not getattr(cur, "rowcount", 0):
return
conn.commit()
if _trend_plan_trade_exists(conn, plan_id):
return
session_date = row["session_date"] or get_trading_day()
session_capital = update_session_capital(conn, session_date, pnl_amount)
send_wechat_msg(
build_wechat_close_message(
symbol=sym,
direction=direction,
result=f"{res}{MONITOR_TYPE_TREND}",
pnl_amount=pnl_amount,
hold_seconds=hold_seconds,
trigger_price=avg_e,
current_price=float(exit_price),
stop_loss=float(row["stop_loss"]),
take_profit=float(row["take_profit"]),
close_order_id="-",
extra_note="计划本金口径:启动时合约可用余额快照;止盈由程序监控",
session_capital_fallback=session_capital,
)
)
insert_trade_record(
conn,
symbol=sym,
@@ -4530,13 +4550,25 @@ def _trend_finalize_plan(conn, row, result_label, exit_price, closed_at=None):
result=res,
opened_at=opened_at,
closed_at=closed_at,
trend_plan_id=int(row["id"]),
trend_plan_id=plan_id,
)
st = "stopped_tp" if result_label == "止盈" else ("stopped_sl" if result_label == "止损" else "stopped_manual")
conn.execute(
"UPDATE trend_pullback_plans SET status=?, message=? WHERE id=?",
(st, res, row["id"]),
send_wechat_msg(
build_wechat_close_message(
symbol=sym,
direction=direction,
result=f"{res}{MONITOR_TYPE_TREND}",
pnl_amount=pnl_amount,
hold_seconds=hold_seconds,
trigger_price=avg_e,
current_price=float(exit_price),
stop_loss=float(row["stop_loss"]),
take_profit=float(row["take_profit"]),
close_order_id="-",
extra_note="计划本金口径:启动时合约可用余额快照;止盈由程序监控",
session_capital_fallback=session_capital,
)
)
conn.commit()
def check_trend_pullback_plans():
@@ -6508,11 +6540,21 @@ def stop_trend_pullback(pid):
cancel_all_open_orders_for_symbol(ex_sym)
except Exception:
pass
_trend_finalize_plan(conn, row, "手动平仓", exit_p)
conn.commit()
try:
_trend_finalize_plan(conn, row, "手动平仓", exit_p)
except Exception as e:
conn.execute(
"UPDATE trend_pullback_plans SET status='stopped_manual', message=? "
"WHERE id=? AND status='active'",
(f"结束异常:{e}", pid),
)
conn.commit()
conn.close()
flash(f"计划已结束但记账可能不完整:{e}")
return redirect(url_for("strategy_trend_page"))
conn.close()
flash("已结束趋势回调计划(市价平仓、撤单)")
return redirect("/trade")
return redirect(url_for("strategy_trend_page"))
@app.route("/delete_trend_plan_history/<int:pid>", methods=["POST"])
+74 -36
View File
@@ -291,8 +291,34 @@ def _weighted_avg(old_avg, old_amt, fill_px, add_amt):
return float(fill_px or 0)
def _plan_stop_status(result_label: str) -> str:
if result_label == "止盈":
return "stopped_tp"
if result_label == "止损":
return "stopped_sl"
return "stopped_manual"
def _trend_plan_trade_exists(conn, plan_id: int) -> bool:
try:
return conn.execute(
"SELECT id FROM trade_records WHERE trend_plan_id=? LIMIT 1",
(int(plan_id),),
).fetchone() is not None
except Exception:
return False
def _finalize_plan(cfg: dict, conn, row, result_label: str, exit_price: float) -> None:
m = _m(cfg)
plan_id = int(row["id"])
active = conn.execute(
"SELECT * FROM trend_pullback_plans WHERE id=? AND status='active'",
(plan_id,),
).fetchone()
if not active:
return
row = active
sym = row["symbol"]
direction = row["direction"] or "long"
ex_sym = row["exchange_symbol"] or m.normalize_exchange_symbol(sym)
@@ -308,31 +334,22 @@ def _finalize_plan(cfg: dict, conn, row, result_label: str, exit_price: float) -
direction, float(row["add_upper"]), float(row["stop_loss"]), margin_cap, lev
)
planned_rr = m.calc_rr_ratio(direction, avg_e, float(row["stop_loss"]), float(row["take_profit"]))
session_date = row["session_date"] or m.get_trading_day()
session_capital = m.update_session_capital(conn, session_date, pnl_amount)
try:
cancel_symbol_orders(cfg, ex_sym)
except Exception:
pass
extra = getattr(m, "build_wechat_close_message", None)
send = getattr(m, "send_wechat_msg", None)
if callable(extra) and callable(send):
send(
extra(
symbol=sym,
direction=direction,
result=f"{res}{MONITOR_TYPE_TREND}",
pnl_amount=pnl_amount,
hold_seconds=hold_seconds,
trigger_price=avg_e,
current_price=float(exit_price),
stop_loss=float(row["stop_loss"]),
take_profit=float(row["take_profit"]),
close_order_id="-",
extra_note="计划本金口径:启动时合约可用余额快照;止盈由程序监控",
session_capital_fallback=session_capital,
)
)
st = _plan_stop_status(result_label)
cur = conn.execute(
"UPDATE trend_pullback_plans SET status=?, message=? WHERE id=? AND status='active'",
(st, res, plan_id),
)
if not getattr(cur, "rowcount", 0):
return
conn.commit()
if _trend_plan_trade_exists(conn, plan_id):
return
session_date = row["session_date"] or m.get_trading_day()
session_capital = m.update_session_capital(conn, session_date, pnl_amount)
kwargs = dict(
conn=conn,
symbol=sym,
@@ -355,18 +372,29 @@ def _finalize_plan(cfg: dict, conn, row, result_label: str, exit_price: float) -
closed_at=closed_at,
)
if "trend_plan_id" in inspect.signature(m.insert_trade_record).parameters:
m.insert_trade_record(**kwargs, trend_plan_id=int(row["id"]))
m.insert_trade_record(**kwargs, trend_plan_id=plan_id)
else:
m.insert_trade_record(**kwargs)
st = (
"stopped_tp"
if result_label == "止盈"
else ("stopped_sl" if result_label == "止损" else "stopped_manual")
)
conn.execute(
"UPDATE trend_pullback_plans SET status=?, message=? WHERE id=?",
(st, res, row["id"]),
)
extra = getattr(m, "build_wechat_close_message", None)
send = getattr(m, "send_wechat_msg", None)
if callable(extra) and callable(send):
send(
extra(
symbol=sym,
direction=direction,
result=f"{res}{MONITOR_TYPE_TREND}",
pnl_amount=pnl_amount,
hold_seconds=hold_seconds,
trigger_price=avg_e,
current_price=float(exit_price),
stop_loss=float(row["stop_loss"]),
take_profit=float(row["take_profit"]),
close_order_id="-",
extra_note="计划本金口径:启动时合约可用余额快照;止盈由程序监控",
session_capital_fallback=session_capital,
)
)
conn.commit()
def check_trend_pullback_plans(cfg: dict) -> None:
@@ -801,7 +829,7 @@ def register_trend_routes(app: Flask, cfg: dict) -> None:
if not row:
conn.close()
flash("未找到运行中的趋势回调计划")
return redirect("/trade")
return _redirect_trend()
m = _m(cfg)
ex_sym = row["exchange_symbol"] or m.normalize_exchange_symbol(row["symbol"])
direction = row["direction"] or "long"
@@ -821,13 +849,23 @@ def register_trend_routes(app: Flask, cfg: dict) -> None:
if not m.is_no_position_error(str(e)):
conn.close()
flash(f"平仓失败:{e}")
return redirect("/trade")
return _redirect_trend()
try:
cancel_symbol_orders(cfg, ex_sym)
except Exception:
pass
_finalize_plan(cfg, conn, row, "手动平仓", exit_p)
conn.commit()
try:
_finalize_plan(cfg, conn, row, "手动平仓", exit_p)
except Exception as e:
conn.execute(
"UPDATE trend_pullback_plans SET status='stopped_manual', message=? "
"WHERE id=? AND status='active'",
(f"结束异常:{e}", pid),
)
conn.commit()
conn.close()
flash(f"计划已结束但记账可能不完整:{e}")
return _redirect_trend()
conn.close()
flash("已结束趋势回调计划")
return redirect("/trade")
return _redirect_trend()