feat: 盈亏比与亏损额度展示,市价FAK报单,修复止盈止损保存失败

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-25 14:33:05 +08:00
parent 367f32dd82
commit 63beda3c71
5 changed files with 125 additions and 88 deletions
+40 -78
View File
@@ -531,6 +531,9 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
"current_price": mark,
"margin": pos_metrics.get("margin"),
"position_pct": pos_metrics.get("position_pct"),
"risk_amount": pos_metrics.get("risk_amount") if sl is not None else None,
"risk_pct": pos_metrics.get("risk_pct") if sl is not None else None,
"rr_ratio": pos_metrics.get("rr_ratio") if sl is not None and tp is not None else None,
"float_pnl": float_pnl,
"est_fee": fee_info["total_fee"],
"est_fee_open": fee_info["open_fee"],
@@ -818,7 +821,7 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
@app.route("/api/trading/monitor/upsert", methods=["POST"])
@login_required
def api_trading_monitor_upsert():
"""为已有 CTP 持仓补充/更新本地止盈止损监控。"""
"""为已有持仓补充/更新本地止盈止损监控。"""
d = request.get_json(silent=True) or {}
sym = (d.get("symbol_code") or d.get("symbol") or "").strip()
direction = (d.get("direction") or "long").strip().lower()
@@ -834,87 +837,46 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
if sl is None and tp is None:
return jsonify({"ok": False, "error": "请至少填写止损或止盈"}), 400
mode = get_trading_mode(get_setting)
if not ctp_status(mode).get("connected"):
return jsonify({"ok": False, "error": "请先连接 CTP"}), 400
has_pos = False
for p in _ctp_positions(mode):
if int(p.get("lots") or 0) <= 0:
continue
if (p.get("direction") or "long") != direction:
continue
if _match_ctp_symbol(p.get("symbol") or "", sym):
has_pos = True
lots = int(p.get("lots") or lots)
entry = float(p.get("avg_price") or entry or 0)
sym = (p.get("symbol") or sym).strip()
break
if not has_pos:
return jsonify({"ok": False, "error": "柜台无对应持仓"}), 400
conn = get_db()
try:
init_strategy_tables(conn)
mon = None
for r in conn.execute(
"SELECT * FROM trade_order_monitors WHERE status='active'"
).fetchall():
row = dict(r)
if row.get("direction") != direction:
continue
if _match_ctp_symbol(sym, row.get("symbol") or ""):
mon = row
break
codes = ths_to_codes(sym)
now_s = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
if "trailing_be" in d:
trailing_be = 1 if d.get("trailing_be") else 0
elif mon:
trailing_be = int(mon.get("trailing_be") or 0)
else:
trailing_be = 0
ensure_monitor_order_columns(conn)
if mon:
initial_sl = mon.get("initial_stop_loss")
if sl is not None and initial_sl is None:
initial_sl = sl
conn.execute(
"""UPDATE trade_order_monitors SET stop_loss=?, take_profit=?, lots=?, entry_price=?,
initial_stop_loss=?, trailing_be=?
WHERE id=?""",
(
sl, tp, lots, entry or mon.get("entry_price"),
initial_sl, trailing_be,
mon["id"],
),
)
mid = mon["id"]
else:
conn.execute(
"""INSERT INTO trade_order_monitors (
symbol, symbol_name, market_code, direction, lots, entry_price,
stop_loss, take_profit, initial_stop_loss, trailing_be,
open_time, monitor_type, status
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?, 'active')""",
(
sym,
codes.get("name", sym) if codes else sym,
codes.get("market_code", "") if codes else "",
direction,
lots,
entry,
sl,
tp,
sl,
trailing_be,
now_s,
"manual",
),
)
mid = conn.execute("SELECT last_insert_rowid()").fetchone()[0]
mon = _find_active_monitor(conn, sym, direction)
has_pos = bool(mon)
ths_sym = sym
if ctp_status(mode).get("connected"):
for p in _ctp_positions(mode, refresh_if_empty=False):
if int(p.get("lots") or 0) <= 0:
continue
if (p.get("direction") or "long") != direction:
continue
if _match_ctp_symbol(p.get("symbol") or "", sym):
has_pos = True
lots = int(p.get("lots") or lots)
entry = float(p.get("avg_price") or entry or 0)
ths_sym = _ctp_pos_to_ths_code(p) or sym
break
if not has_pos:
return jsonify({"ok": False, "error": "未找到对应持仓"}), 400
trailing_be = 1 if d.get("trailing_be") else (
int(mon.get("trailing_be") or 0) if mon else 0
)
mid = _upsert_open_monitor(
conn,
sym=ths_sym,
direction=direction,
lots=lots,
price=entry,
sl=sl,
tp=tp,
trailing_be=trailing_be,
)
conn.commit()
mon_row = conn.execute(
"SELECT * FROM trade_order_monitors WHERE id=?", (mid,),
).fetchone()
return jsonify({"ok": True, "monitor_id": mid, "message": "止盈止损已保存,程序本地监控"})
_push_position_snapshot_async()
return jsonify({
"ok": True,
"monitor_id": mid,
"message": "止盈止损已保存,程序本地监控",
})
finally:
conn.close()