Add OKX trading-account USDC auto-swap and lock exit target while in position.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-30 00:16:47 +08:00
parent f0b0b91f1b
commit 0837982714
16 changed files with 626 additions and 36 deletions
+20 -9
View File
@@ -133,28 +133,38 @@ class SimFundsWallets:
direction: str,
amount: float,
rate: float = 1.0,
account: str = "funding",
) -> dict[str, Any]:
"""资金账户内 USDT↔USDC 兑换。"""
"""USDT↔USDC 兑换。默认资金账户;account=trading 时在交易账户内兑(对齐 OKX 现货)。"""
amt = float(amount)
if amt <= 0:
return {"ok": False, "detail": "数量须大于 0"}
r = float(rate) if rate and rate > 0 else 1.0
d = (direction or "").strip().lower()
acct = (account or "funding").strip().lower()
if acct not in ("funding", "trading"):
return {"ok": False, "detail": "account 须为 funding / trading"}
snap = self.snapshot()
if acct == "funding":
usdt_key, usdc_key = "funding_usdt", "options_funding_usdc"
label = "资金账户"
else:
usdt_key, usdc_key = "trading_usdt", "options_trading_usdc"
label = "交易账户"
if d == "usdt_to_usdc":
src = float(snap["funding_usdt"])
src = float(snap[usdt_key])
if amt > src + 1e-9:
return {"ok": False, "detail": f"资金账户 USDT 不足(可用 {src:.4f}"}
return {"ok": False, "detail": f"{label} USDT 不足(可用 {src:.4f}"}
usdc = amt / r
snap["funding_usdt"] = src - amt
snap["options_funding_usdc"] = float(snap["options_funding_usdc"]) + usdc
snap[usdt_key] = src - amt
snap[usdc_key] = float(snap[usdc_key]) + usdc
elif d == "usdc_to_usdt":
src = float(snap["options_funding_usdc"])
src = float(snap[usdc_key])
if amt > src + 1e-9:
return {"ok": False, "detail": f"资金账户 USDC 不足(可用 {src:.4f}"}
return {"ok": False, "detail": f"{label} USDC 不足(可用 {src:.4f}"}
usdt = amt * r
snap["options_funding_usdc"] = src - amt
snap["funding_usdt"] = float(snap["funding_usdt"]) + usdt
snap[usdc_key] = src - amt
snap[usdt_key] = float(snap[usdt_key]) + usdt
else:
return {"ok": False, "detail": "direction 须为 usdt_to_usdc 或 usdc_to_usdt"}
self._set(**snap)
@@ -165,6 +175,7 @@ class SimFundsWallets:
"direction": d,
"amount": amt,
"rate": r,
"account": acct,
"wallets": self.view(),
"total_usdt_equiv": total,
}
+21 -2
View File
@@ -2,6 +2,7 @@
from __future__ import annotations
import logging
import time
from dataclasses import dataclass
from typing import Any
@@ -21,6 +22,8 @@ from .pricing import (
resolve_option_close_bid,
)
logger = logging.getLogger(__name__)
# 禁止新开仓的本地仓位状态(实盘防卡)
BLOCKING_STATUSES = frozenset(
{"open", "half_open", "option_closed_perp_pending", "opening"}
@@ -332,6 +335,15 @@ class Matcher:
)
self.db._conn.commit()
try:
from ..strategy.exits import lock_trade_exit_target
lock_trade_exit_target(
self.db, group_id=group_id, initial_premium=initial_premium
)
except Exception:
logger.exception("lock exit target failed group=%s", group_id)
return OpenResult(
ok=True,
group_id=group_id,
@@ -585,7 +597,8 @@ class Matcher:
"""UPDATE positions SET
group_id=NULL, perp_side=NULL, perp_qty_eth=0, perp_entry_px=NULL,
option_inst_id=NULL, option_side=NULL, option_qty_eth=0, option_qty_contracts=0,
option_entry_px=NULL, entry_index_px=NULL, initial_premium=0, status='flat'
option_entry_px=NULL, entry_index_px=NULL, initial_premium=0,
exit_target_usdt=NULL, status='flat'
WHERE id=1"""
)
self.db._conn.commit()
@@ -756,7 +769,8 @@ class Matcher:
"""UPDATE positions SET
group_id=NULL, perp_side=NULL, perp_qty_eth=0, perp_entry_px=NULL,
option_inst_id=NULL, option_side=NULL, option_qty_eth=0, option_qty_contracts=0,
option_entry_px=NULL, entry_index_px=NULL, initial_premium=0, status='flat'
option_entry_px=NULL, entry_index_px=NULL, initial_premium=0,
exit_target_usdt=NULL, status='flat'
WHERE id=1"""
)
self.db._conn.commit()
@@ -1098,6 +1112,11 @@ class Matcher:
"move_points": move,
"move_pct": move_pct,
"initial_premium": initial_premium,
"exit_target_usdt": (
float(pos["exit_target_usdt"])
if pos.get("exit_target_usdt") is not None
else None
),
"premium_gap": premium_gap,
"status": pos.get("status"),
}