fix: OKX 持仓张数优先读 info.pos,滚仓后同步 order_amount

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-02 22:40:41 +08:00
parent 394793b9d2
commit be7896cc25
4 changed files with 51 additions and 22 deletions
+13 -10
View File
@@ -2817,17 +2817,19 @@ def exchange_private_api_configured():
def _position_row_effective_contracts(p): def _position_row_effective_contracts(p):
"""张数:OKX 以 info.pos 为准,再兜底 ccxt contracts 等(与 Binance/Gate 多字段一致)。"""
if not p:
return 0.0
info = p.get("info", {}) or {} info = p.get("info", {}) or {}
contracts = p.get("contracts") for val in (info.get("pos"), p.get("contracts"), info.get("positionAmt"), info.get("size")):
if contracts is None: if val is None or val == "":
raw_pos = info.get("pos") continue
try: try:
contracts = abs(float(raw_pos)) if raw_pos is not None else 0.0 x = abs(float(val))
except Exception: if x > 0:
contracts = 0.0 return x
try: except (TypeError, ValueError):
return float(contracts) continue
except Exception:
return 0.0 return 0.0
@@ -6685,7 +6687,7 @@ def api_price_snapshot():
"SELECT id,symbol,monitor_type,direction,upper,lower,fib_entry_price,fib_stop_loss,fib_take_profit,fib_limit_order_id,created_at FROM key_monitors" "SELECT id,symbol,monitor_type,direction,upper,lower,fib_entry_price,fib_stop_loss,fib_take_profit,fib_limit_order_id,created_at FROM key_monitors"
).fetchall() ).fetchall()
order_rows = conn.execute( order_rows = conn.execute(
"SELECT id,symbol,exchange_symbol,direction,trigger_price,stop_loss,initial_stop_loss,take_profit,margin_capital,leverage," "SELECT id,symbol,exchange_symbol,direction,trigger_price,stop_loss,initial_stop_loss,take_profit,margin_capital,leverage,order_amount,"
"time_close_enabled,time_close_hours,time_close_at_ms,opened_at_ms FROM order_monitors WHERE status='active'" "time_close_enabled,time_close_hours,time_close_at_ms,opened_at_ms FROM order_monitors WHERE status='active'"
).fetchall() ).fetchall()
@@ -6878,6 +6880,7 @@ def api_price_snapshot():
"float_pnl": round(pnl, 2), "float_pnl": round(pnl, 2),
"float_pct": pnl_pct, "float_pct": pnl_pct,
"plan_margin": round(margin, 2) if margin else None, "plan_margin": round(margin, 2) if margin else None,
"order_amount": float(r["order_amount"]) if r["order_amount"] not in (None, "") else None,
"exchange_initial_margin": None, "exchange_initial_margin": None,
"exchange_notional": None, "exchange_notional": None,
"exchange_mark_price": None, "exchange_mark_price": None,
+11 -8
View File
@@ -24,21 +24,24 @@ def _coerce_float(*values: Any) -> float | None:
def position_contracts(p: dict[str, Any]) -> float: def position_contracts(p: dict[str, Any]) -> float:
raw = p.get("contracts")
if raw is not None:
try:
return float(raw)
except (TypeError, ValueError):
pass
info = p.get("info") or {} info = p.get("info") or {}
if not isinstance(info, dict): if not isinstance(info, dict):
info = {} info = {}
for k in ("positionAmt", "positionamt", "pos", "size"): # OKX 等:info.pos 为交易所张数,优先于 ccxt contracts(加仓后后者可能滞后)
for k in ("pos", "positionAmt", "positionamt", "size"):
if k in info: if k in info:
try: try:
v = float(info[k]) v = float(info[k])
if v != 0: if v != 0:
return v return abs(v)
except (TypeError, ValueError):
pass
raw = p.get("contracts")
if raw is not None:
try:
v = float(raw)
if v != 0:
return abs(v)
except (TypeError, ValueError): except (TypeError, ValueError):
pass pass
return 0.0 return 0.0
+10 -2
View File
@@ -418,9 +418,17 @@ def _execute_pending_roll_leg(
"UPDATE roll_groups SET leg_count=?, current_stop_loss=?, updated_at=? WHERE id=?", "UPDATE roll_groups SET leg_count=?, current_stop_loss=?, updated_at=? WHERE id=?",
(filled + 1, sl, _now(cfg), gid), (filled + 1, sl, _now(cfg), gid),
) )
live_qty = qty + float(amount)
try:
pos2 = cfg["get_position"](ex_sym, direction) or {}
q2 = float(pos2.get("contracts") or 0)
if q2 > 0:
live_qty = q2
except Exception:
pass
conn.execute( conn.execute(
"UPDATE order_monitors SET stop_loss=? WHERE id=? AND status='active'", "UPDATE order_monitors SET stop_loss=?, order_amount=? WHERE id=? AND status='active'",
(sl, mon["id"]), (sl, float(live_qty), mon["id"]),
) )
notify = cfg.get("send_wechat") notify = cfg.get("send_wechat")
+15
View File
@@ -0,0 +1,15 @@
from lib.hub.hub_position_metrics import position_contracts
def test_position_contracts_prefers_okx_info_pos_over_stale_ccxt():
p = {
"contracts": 0.81,
"side": "short",
"info": {"pos": "-1.62", "posSide": "short"},
}
assert position_contracts(p) == 1.62
def test_position_contracts_falls_back_to_ccxt_contracts():
p = {"contracts": 2.5, "info": {}}
assert position_contracts(p) == 2.5