Files
eth_hedge_sim/backend/app/sim/pricing.py
T
2026-07-26 16:07:20 +08:00

112 lines
3.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""成交价与手续费:滑点 = 1×f。"""
from __future__ import annotations
from dataclasses import asdict, dataclass
@dataclass(slots=True)
class PriceResult:
base_px: float
fill_px: float
fee: float
slip: float
notional: float
def to_dict(self) -> dict[str, float]:
return asdict(self)
def option_intrinsic(*, option_side: str, strike: float, spot: float) -> float:
"""多头期权内在价值(USDT/ETH)。call=max(SK,0)put=max(KS,0)。"""
s = float(spot)
k = float(strike)
side = str(option_side).lower().strip()
if side in ("call", "c"):
return max(s - k, 0.0)
if side in ("put", "p"):
return max(k - s, 0.0)
return 0.0
def resolve_option_close_bid(
*,
bid: float | None,
mark: float | None,
intrinsic: float | None,
bypass_liquidity: bool,
) -> float | None:
"""
平仓用买一价;多头卖出不得低于内在价值(SIM 防到期垃圾盘口)。
bypass 时:买一缺失可用标记/内在价值兜底。
"""
candidates: list[float] = []
if bid is not None and bid >= 0:
candidates.append(float(bid))
if bypass_liquidity and mark is not None and mark >= 0:
candidates.append(float(mark))
if intrinsic is not None and intrinsic >= 0:
candidates.append(float(intrinsic))
if not candidates:
return None
# 常规:有买一时,仍用 max(买一, 内在价值) 抬到合理底价
# bypassmax(买一, 标记, 内在价值)
if bypass_liquidity:
return max(candidates)
if bid is None:
return None
if intrinsic is not None and intrinsic >= 0:
return max(float(bid), float(intrinsic))
return float(bid)
def perp_fill(
*,
side: str,
action: str,
bid: float,
ask: float,
qty_eth: float,
fee_rate: float,
) -> PriceResult:
"""
side: long|short(持仓方向意图:开仓要建立的方向 / 平仓时原持仓方向)
action: open|close
开多/平空: 吃卖一 ×(1+f)
开空/平多: 吃买一 ×(1-f)
"""
f = float(fee_rate)
buying = (action == "open" and side == "long") or (action == "close" and side == "short")
if buying:
base = float(ask)
fill = base * (1.0 + f)
else:
base = float(bid)
fill = base * (1.0 - f)
notional = abs(fill * qty_eth)
fee = notional * f
slip = abs(fill - base) * qty_eth
return PriceResult(base_px=base, fill_px=fill, fee=fee, slip=slip, notional=notional)
def option_fill(
*,
action: str,
bid: float,
ask: float,
qty_eth: float,
fee_rate: float,
) -> PriceResult:
"""开仓买入吃卖一;平仓卖出吃买一。"""
f = float(fee_rate)
if action == "open":
base = float(ask)
fill = base * (1.0 + f)
else:
base = float(bid)
fill = base * (1.0 - f)
notional = abs(fill * qty_eth)
fee = notional * f
slip = abs(fill - base) * qty_eth
return PriceResult(base_px=base, fill_px=fill, fee=fee, slip=slip, notional=notional)