Close option before perp so the hedge stays while exiting the thin leg.
EOF Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+60
-42
@@ -270,6 +270,7 @@ class Matcher:
|
||||
"""
|
||||
全平一组。默认校验期权买一深度 + 买一/标记偏差(默认≤30%)。
|
||||
bypass_liquidity=True:紧急全平可绕过(仍需有可用买一价才能成交;无买一时用标记近似)。
|
||||
成交顺序:先平期权(薄)→ 再瞬时平永续(对冲先留着);永续盘口失败则回滚期权入账。
|
||||
"""
|
||||
s = get_settings()
|
||||
pos = self.current_position()
|
||||
@@ -329,14 +330,7 @@ class Matcher:
|
||||
perp_entry = float(pos["perp_entry_px"])
|
||||
opt_entry = float(pos["option_entry_px"])
|
||||
|
||||
pf = perp_fill(
|
||||
side=perp_side,
|
||||
action="close",
|
||||
bid=float(snap.perp.bid),
|
||||
ask=float(snap.perp.ask),
|
||||
qty_eth=perp_qty,
|
||||
fee_rate=fee_rate,
|
||||
)
|
||||
# 1) 先平期权(买一流动性差);永续对冲暂留
|
||||
of = option_fill(
|
||||
action="close",
|
||||
bid=float(close_bid),
|
||||
@@ -344,50 +338,53 @@ class Matcher:
|
||||
qty_eth=opt_qty,
|
||||
fee_rate=fee_rate,
|
||||
)
|
||||
opt_pnl = (of.fill_px - opt_entry) * opt_qty
|
||||
opt_cash = of.notional - of.fee
|
||||
self.ledger.apply_cash(
|
||||
opt_cash,
|
||||
kind="close_option",
|
||||
group_id=group_id,
|
||||
note=f"close option {reason}",
|
||||
)
|
||||
|
||||
# 永续盈亏
|
||||
# 2) 期权确认后再瞬时平永续(重取盘口)
|
||||
snap2 = sess.snapshot()
|
||||
if not snap2.perp or snap2.perp.bid is None or snap2.perp.ask is None:
|
||||
self.ledger.apply_cash(
|
||||
-opt_cash,
|
||||
kind="close_option_rollback",
|
||||
group_id=group_id,
|
||||
note=f"rollback option close {group_id}: perp book missing",
|
||||
)
|
||||
return CloseResult(
|
||||
ok=False,
|
||||
detail="期权已平但永续盘口不可用,已回滚期权入账",
|
||||
)
|
||||
|
||||
pf = perp_fill(
|
||||
side=perp_side,
|
||||
action="close",
|
||||
bid=float(snap2.perp.bid),
|
||||
ask=float(snap2.perp.ask),
|
||||
qty_eth=perp_qty,
|
||||
fee_rate=fee_rate,
|
||||
)
|
||||
if perp_side == "long":
|
||||
perp_pnl = (pf.fill_px - perp_entry) * perp_qty
|
||||
else:
|
||||
perp_pnl = (perp_entry - pf.fill_px) * perp_qty
|
||||
# 期权多头盈亏
|
||||
opt_pnl = (of.fill_px - opt_entry) * opt_qty
|
||||
cash_in = of.notional - of.fee + pf.fee * 0 # 收回权利金(扣卖出费);永续平仓费另扣
|
||||
# 永续平仓:实现盈亏入账并扣平仓手续费
|
||||
net = perp_pnl + opt_pnl - pf.fee - of.fee
|
||||
# 更清晰:现金变动 = 期权卖出净额 + 永续盈亏 - 永续平仓费
|
||||
# 开仓已付期权权利金+开仓费;平仓收回 of.notional 并付 of.fee;永续只记 pnl 与 fee
|
||||
cash_delta = (of.notional - of.fee) + perp_pnl - pf.fee
|
||||
|
||||
self.ledger.apply_cash(
|
||||
cash_delta,
|
||||
kind="close_settle",
|
||||
perp_pnl - pf.fee,
|
||||
kind="close_perp",
|
||||
group_id=group_id,
|
||||
note=f"close {reason}",
|
||||
note=f"close perp {reason}",
|
||||
)
|
||||
|
||||
net = perp_pnl + opt_pnl - pf.fee - of.fee
|
||||
|
||||
now = int(time.time() * 1000)
|
||||
with self.db._lock:
|
||||
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",
|
||||
"close",
|
||||
"flat",
|
||||
s.perp_inst_id,
|
||||
perp_qty,
|
||||
None,
|
||||
pf.base_px,
|
||||
pf.fill_px,
|
||||
pf.fee,
|
||||
pf.slip,
|
||||
pf.notional,
|
||||
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)
|
||||
@@ -408,6 +405,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",
|
||||
"close",
|
||||
"flat",
|
||||
s.perp_inst_id,
|
||||
perp_qty,
|
||||
None,
|
||||
pf.base_px,
|
||||
pf.fill_px,
|
||||
pf.fee,
|
||||
pf.slip,
|
||||
pf.notional,
|
||||
now + 1,
|
||||
),
|
||||
)
|
||||
g = self.db._conn.execute(
|
||||
"SELECT fees, slip_cost FROM groups WHERE group_id=?", (group_id,)
|
||||
).fetchone()
|
||||
@@ -436,7 +453,8 @@ class Matcher:
|
||||
"perp_pnl": perp_pnl,
|
||||
"option_pnl": opt_pnl,
|
||||
"net": net,
|
||||
"cash_delta": cash_delta,
|
||||
"close_sequence": ["option", "perp"],
|
||||
"cash_delta": opt_cash + perp_pnl - pf.fee,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
+4
-1
@@ -32,6 +32,8 @@
|
||||
|
||||
**开仓顺序**:先成交期权 → 确认后再市价成交永续。永续盘口失败则回滚期权扣款,不留半边仓。
|
||||
|
||||
**平仓顺序**:同样先平期权(买一薄)→ 再瞬时平永续。平期权期间永续对冲先留着;永续盘口失败则回滚期权入账。
|
||||
|
||||
永续杠杆默认 **3×**(可配)。同时最多 **1 组**仓,禁止叠仓开下一组。
|
||||
|
||||
### 2.1 开仓方向(ATM 相对现价优先)
|
||||
@@ -99,7 +101,7 @@
|
||||
|
||||
## 4. 平仓机制
|
||||
|
||||
任一触发 → **该组永续 + 期权全部平掉**。
|
||||
任一触发 → **该组永续 + 期权全部平掉**(先期权、后永续)。
|
||||
|
||||
### 4.1 净盈利达标(主出场)
|
||||
|
||||
@@ -254,3 +256,4 @@
|
||||
| 日期 | 说明 |
|
||||
|------|------|
|
||||
| 2026-07-25 | 初稿:对齐当前开平仓、周末跳过、到期全平、净盈利口径与资金建议 |
|
||||
| 2026-07-25 | 平仓顺序改为先期权后永续(与开仓同理:薄腿优先) |
|
||||
|
||||
Reference in New Issue
Block a user