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:
@@ -129,8 +129,26 @@ class StrategyEngine:
|
||||
risk_exit_unit = self.ledger.get_setting_float("risk_exit_unit", 15.0)
|
||||
risk_last_k = self.ledger.get_setting_float("risk_last_k", 0.0)
|
||||
risk_preview: dict[str, Any] | None = None
|
||||
# 以损定仓:监控页展示「下一次开仓」实时估算,避免仍显示上次手填/过期名义
|
||||
if sizing_mode == "risk_based":
|
||||
pos_status = str(upl.get("status") or "flat")
|
||||
trade_locked = pos_status in (
|
||||
"open",
|
||||
"half_open",
|
||||
"option_closed_perp_pending",
|
||||
"opening",
|
||||
)
|
||||
locked_exit = None
|
||||
try:
|
||||
from .exits import read_locked_exit_target
|
||||
|
||||
locked_exit = read_locked_exit_target(upl)
|
||||
except Exception:
|
||||
locked_exit = None
|
||||
if trade_locked and locked_exit is not None:
|
||||
# 持仓中:出场目标锁定,不再用盘口重算覆盖
|
||||
net_target = float(locked_exit)
|
||||
exit_amt = float(locked_exit)
|
||||
# 以损定仓:仅空仓时用实时估算覆盖展示;持仓中保持开仓锁定名义/k/目标
|
||||
if sizing_mode == "risk_based" and not trade_locked:
|
||||
try:
|
||||
from .risk_sizing import preview_risk_sizing
|
||||
|
||||
@@ -154,6 +172,16 @@ class StrategyEngine:
|
||||
except Exception:
|
||||
logger.exception("risk sizing preview for state() failed")
|
||||
risk_preview = {"ok": False, "detail": "以损定仓预览失败"}
|
||||
elif sizing_mode == "risk_based" and trade_locked:
|
||||
risk_preview = {
|
||||
"ok": True,
|
||||
"locked": True,
|
||||
"detail": "持仓中已锁定本组成交目标与名义,平仓后再自动计算",
|
||||
"net_profit_target": net_target,
|
||||
"k": risk_last_k if risk_last_k > 0 else None,
|
||||
"perp_qty_eth": perp_qty,
|
||||
"option_qty_eth": opt_qty,
|
||||
}
|
||||
rest_until = row["rest_until_ms"]
|
||||
rest_left = 0
|
||||
if rest_until:
|
||||
@@ -199,6 +227,7 @@ class StrategyEngine:
|
||||
"risk_exit_unit": risk_exit_unit,
|
||||
"risk_last_k": risk_last_k if risk_last_k > 0 else None,
|
||||
"risk_sizing_preview": risk_preview,
|
||||
"risk_sizing_locked": bool(trade_locked and sizing_mode == "risk_based"),
|
||||
"min_option_hours": min_hours,
|
||||
"min_option_leverage": min_opt_lev,
|
||||
"atm_open_offset_enabled": atm_off_on,
|
||||
@@ -687,6 +716,18 @@ class StrategyEngine:
|
||||
|
||||
if st_pos == "open":
|
||||
upl = self.matcher.unrealized()
|
||||
from .exits import lock_trade_exit_target, read_locked_exit_target
|
||||
|
||||
locked_exit = read_locked_exit_target(upl)
|
||||
if locked_exit is None and upl.get("group_id"):
|
||||
try:
|
||||
locked_exit = lock_trade_exit_target(
|
||||
self.db,
|
||||
group_id=str(upl["group_id"]),
|
||||
initial_premium=float(upl.get("initial_premium") or 0),
|
||||
)
|
||||
except Exception:
|
||||
logger.exception("backfill exit lock failed")
|
||||
expired = check_expiry_close(expiry_ms=self._position_expiry_ms(upl))
|
||||
decision = check_exits(
|
||||
net_pnl=float(upl.get("net_pnl") or 0),
|
||||
@@ -694,6 +735,7 @@ class StrategyEngine:
|
||||
net_profit_target=net_target,
|
||||
premium_exit_multiple=prem_mult,
|
||||
initial_premium=float(upl.get("initial_premium") or 0),
|
||||
locked_exit_target=locked_exit,
|
||||
)
|
||||
pending_close = st["phase"] in ("liquidity_wait", "closing")
|
||||
if expired.should_close or decision.should_close or pending_close:
|
||||
@@ -800,6 +842,14 @@ class StrategyEngine:
|
||||
self._set_state(phase="idle", last_error="以损定仓计算异常,暂不开仓")
|
||||
return
|
||||
|
||||
# OKX:交易账户 USDC 不够开期权时,市价 USDT→USDC(目标=所需×2);够则跳过
|
||||
try:
|
||||
from .auto_usdc import ensure_okx_trading_usdc
|
||||
|
||||
ensure_okx_trading_usdc(self.db)
|
||||
except Exception:
|
||||
logger.exception("auto USDC top-up failed")
|
||||
|
||||
try:
|
||||
cap = assess_open_capacity(self.db)
|
||||
if cap.get("perp_can_open") is False or cap.get("option_can_open") is False:
|
||||
|
||||
Reference in New Issue
Block a user