Harden LIVE opens with slot claim and exchange reconcile.
Prevent duplicate opens by atomically claiming an opening slot, verifying exchange perp is flat before live orders, setting leverage from ledger, and preferring exchange position size when closing perps. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -14,6 +14,12 @@ from ..sim.matcher import CloseResult, Matcher, OpenResult
|
||||
from ..sim.pricing import option_expiry_settle, option_intrinsic
|
||||
from ..strategy.session import get_session
|
||||
from .okx_trade import OkxTradeClient
|
||||
from .reconcile import (
|
||||
assert_safe_to_open_live,
|
||||
claim_open_slot,
|
||||
perp_close_contracts_okx,
|
||||
release_open_slot_if_opening,
|
||||
)
|
||||
from .symbols import live_settings, resolve_perp_inst_id
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -87,14 +93,16 @@ class OkxLiveExecutor(Matcher):
|
||||
if err:
|
||||
return OpenResult(ok=False, detail=err)
|
||||
|
||||
s = live_settings()
|
||||
if self.has_open_position():
|
||||
st = self.position_status()
|
||||
return OpenResult(
|
||||
ok=False,
|
||||
detail=f"已有持仓/半仓状态({st}),请先修复或平仓",
|
||||
)
|
||||
claimed, claim_msg = claim_open_slot(self.db)
|
||||
if not claimed:
|
||||
return OpenResult(ok=False, detail=claim_msg)
|
||||
|
||||
safe, safe_msg = assert_safe_to_open_live(self)
|
||||
if not safe:
|
||||
release_open_slot_if_opening(self.db)
|
||||
return OpenResult(ok=False, detail=safe_msg)
|
||||
|
||||
s = live_settings()
|
||||
client = self._client()
|
||||
perp_inst = resolve_perp_inst_id(self.db)
|
||||
perp_qty = self.ledger.get_setting_float("perp_qty_eth", s.perp_qty_eth)
|
||||
@@ -112,6 +120,7 @@ class OkxLiveExecutor(Matcher):
|
||||
)
|
||||
except Exception as e:
|
||||
logger.exception("live open option failed")
|
||||
release_open_slot_if_opening(self.db)
|
||||
return OpenResult(ok=False, detail=f"实盘开期权失败: {e}")
|
||||
|
||||
# 以交易所实际成交张数回写名义
|
||||
@@ -124,11 +133,24 @@ class OkxLiveExecutor(Matcher):
|
||||
# 永续市价:按产品假设,失败原因实质为保证金不足 → 必须回滚期权
|
||||
try:
|
||||
ct_val = client.get_ct_val(perp_inst, inst_type="SWAP")
|
||||
perp_sz = max(1, int(round(perp_qty / ct_val)))
|
||||
perp_sz = perp_close_contracts_okx(
|
||||
client,
|
||||
perp_inst=perp_inst,
|
||||
perp_side=perp_side,
|
||||
perp_qty_eth=perp_qty,
|
||||
ct_val=ct_val,
|
||||
)
|
||||
if perp_side == "long":
|
||||
side, pos_side = "buy", "long"
|
||||
else:
|
||||
side, pos_side = "sell", "short"
|
||||
leverage = self.ledger.get_setting_float("leverage", s.leverage)
|
||||
try:
|
||||
client.set_leverage(
|
||||
perp_inst, leverage, mgn_mode="cross", pos_side=pos_side
|
||||
)
|
||||
except Exception as e_lev:
|
||||
logger.warning("okx set_leverage failed: %s", e_lev)
|
||||
perp_fill_live = client.place_market(
|
||||
inst_id=perp_inst,
|
||||
side=side,
|
||||
@@ -168,6 +190,7 @@ class OkxLiveExecutor(Matcher):
|
||||
group_id=group_id,
|
||||
detail=f"永续开仓失败(保证金)且期权回滚失败,已标记 half_open: {e} / {e2}",
|
||||
)
|
||||
release_open_slot_if_opening(self.db)
|
||||
return OpenResult(
|
||||
ok=False,
|
||||
detail=f"永续开仓失败(多为保证金不足),已回滚期权: {e}",
|
||||
@@ -604,7 +627,13 @@ class OkxLiveExecutor(Matcher):
|
||||
|
||||
try:
|
||||
ct_val = client.get_ct_val(perp_inst, inst_type="SWAP")
|
||||
perp_sz = max(1, int(round(perp_qty / ct_val)))
|
||||
perp_sz = perp_close_contracts_okx(
|
||||
client,
|
||||
perp_inst=perp_inst,
|
||||
perp_side=perp_side,
|
||||
perp_qty_eth=perp_qty,
|
||||
ct_val=ct_val,
|
||||
)
|
||||
if perp_side == "long":
|
||||
side, pos_side = "sell", "long"
|
||||
else:
|
||||
@@ -883,7 +912,13 @@ class OkxLiveExecutor(Matcher):
|
||||
client = self._client()
|
||||
try:
|
||||
ct_val = client.get_ct_val(perp_inst, inst_type="SWAP")
|
||||
perp_sz = max(1, int(round(perp_qty / ct_val)))
|
||||
perp_sz = perp_close_contracts_okx(
|
||||
client,
|
||||
perp_inst=perp_inst,
|
||||
perp_side=perp_side,
|
||||
perp_qty_eth=perp_qty,
|
||||
ct_val=ct_val,
|
||||
)
|
||||
if perp_side == "long":
|
||||
side, pos_side = "sell", "long"
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user