38ffbf728b
Stop falling back to ATM quotes for unrealized/close PnL after ATM drifts or restart. Co-authored-by: Cursor <cursoragent@cursor.com>
54 lines
1.5 KiB
Python
54 lines
1.5 KiB
Python
"""期权合约 ID 工具:从持仓合约还原同到期同行权价的 Call/Put 对。"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from .expiry import expiry_ms_from_ymd
|
|
from .types import OptionPair
|
|
|
|
|
|
def flip_option_side(inst_id: str) -> str | None:
|
|
"""ETH-...-1880-P ↔ ...-C;币安 ETH-YYMMDD-STRIKE-P ↔ -C。"""
|
|
s = (inst_id or "").strip()
|
|
if not s:
|
|
return None
|
|
if s.endswith("-C"):
|
|
return s[:-1] + "P"
|
|
if s.endswith("-P"):
|
|
return s[:-1] + "C"
|
|
if s.endswith("-c"):
|
|
return s[:-1] + "p"
|
|
if s.endswith("-p"):
|
|
return s[:-1] + "c"
|
|
return None
|
|
|
|
|
|
def pair_from_option_inst(inst_id: str) -> OptionPair | None:
|
|
"""由任一腿合约 ID 还原同 strike/expiry 的 OptionPair。"""
|
|
from .okx.parse import parse_option_inst_id
|
|
from .binance.parse import parse_option_symbol
|
|
|
|
s = (inst_id or "").strip()
|
|
if not s:
|
|
return None
|
|
ymd, strike, side = parse_option_inst_id(s)
|
|
if ymd is None:
|
|
ymd, strike, side = parse_option_symbol(s)
|
|
if ymd is None or strike is None or side not in ("C", "P"):
|
|
return None
|
|
other = flip_option_side(s)
|
|
if not other:
|
|
return None
|
|
call_id = s if side == "C" else other
|
|
put_id = s if side == "P" else other
|
|
try:
|
|
ems = expiry_ms_from_ymd(ymd)
|
|
except ValueError:
|
|
return None
|
|
return OptionPair(
|
|
expiry_ymd=ymd,
|
|
expiry_ms=int(ems),
|
|
strike=float(strike),
|
|
call_inst_id=call_id,
|
|
put_inst_id=put_id,
|
|
)
|