Show option top-of-book size and open option before perp.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-25 12:57:16 +08:00
parent 21ca5cbfe0
commit 32e8de85cc
3 changed files with 78 additions and 36 deletions
+63 -33
View File
@@ -107,14 +107,7 @@ class Matcher:
ct_mult = self._ct_mult(option_inst_id)
opt_contracts = contracts_for_eth(opt_qty, ct_mult)
pf = perp_fill(
side=perp_side,
action="open",
bid=float(snap.perp.bid),
ask=float(snap.perp.ask),
qty_eth=perp_qty,
fee_rate=fee_rate,
)
# 1) 先成交期权(吃卖一);失败则整组不开
of = option_fill(
action="open",
bid=float(oq.bid or 0),
@@ -124,18 +117,53 @@ class Matcher:
)
initial_premium = of.fill_px * opt_qty # 锁定口径:成交价×名义,不含费
premium_cost = of.notional + of.fee
total_debit = premium_cost + pf.fee # 永续开仓只扣费;期权支付权利金+费
try:
self.ledger.apply_cash(
-total_debit,
kind="open_debit",
-premium_cost,
kind="open_option",
group_id=group_id,
note=f"open {group_id}",
note=f"open option {group_id}",
)
except RuntimeError as e:
return OpenResult(ok=False, detail=str(e))
# 2) 期权确认后再市价成交永续(重新取盘口)
snap2 = sess.snapshot()
if not snap2.perp or snap2.perp.bid is None or snap2.perp.ask is None:
self.ledger.apply_cash(
premium_cost,
kind="open_option_rollback",
group_id=group_id,
note=f"rollback option {group_id}: perp book missing",
)
return OpenResult(
ok=False,
detail="期权已成交但永续盘口不可用,已回滚期权",
)
pf = perp_fill(
side=perp_side,
action="open",
bid=float(snap2.perp.bid),
ask=float(snap2.perp.ask),
qty_eth=perp_qty,
fee_rate=fee_rate,
)
try:
self.ledger.apply_cash(
-pf.fee,
kind="open_perp_fee",
group_id=group_id,
note=f"open perp {group_id}",
)
except RuntimeError as e:
self.ledger.apply_cash(
premium_cost,
kind="open_option_rollback",
group_id=group_id,
note=f"rollback option {group_id}: {e}",
)
return OpenResult(ok=False, detail=f"期权已成交但永续扣费失败并已回滚: {e}")
now = int(time.time() * 1000)
with self.db._lock:
self.db._conn.execute(
@@ -160,26 +188,7 @@ class Matcher:
pf.slip + of.slip,
),
)
self.db._conn.execute(
"""INSERT INTO fills(group_id, leg, action, side, inst_id, qty_eth, qty_contracts,
base_px, fill_px, fee, slip, notional, ts_ms)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)""",
(
group_id,
"perp",
"open",
perp_side,
s.perp_inst_id,
perp_qty,
None,
pf.base_px,
pf.fill_px,
pf.fee,
pf.slip,
pf.notional,
now,
),
)
# 成交顺序:期权先、永续后(时间戳差 1ms 便于审计)
self.db._conn.execute(
"""INSERT INTO fills(group_id, leg, action, side, inst_id, qty_eth, qty_contracts,
base_px, fill_px, fee, slip, notional, ts_ms)
@@ -200,6 +209,26 @@ class Matcher:
now,
),
)
self.db._conn.execute(
"""INSERT INTO fills(group_id, leg, action, side, inst_id, qty_eth, qty_contracts,
base_px, fill_px, fee, slip, notional, ts_ms)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)""",
(
group_id,
"perp",
"open",
perp_side,
s.perp_inst_id,
perp_qty,
None,
pf.base_px,
pf.fill_px,
pf.fee,
pf.slip,
pf.notional,
now + 1,
),
)
self.db._conn.execute(
"""UPDATE positions SET
group_id=?, perp_side=?, perp_qty_eth=?, perp_entry_px=?,
@@ -233,6 +262,7 @@ class Matcher:
"option": of.to_dict(),
"initial_premium": initial_premium,
"fees": pf.fee + of.fee,
"open_sequence": ["option", "perp"],
},
)