Files
crypto_monitor/tests/test_options_pricing.py
T
dekun 3570a6900e Add OKX options expiry and close breakeven to hub monitor and dashboard.
Expose bePx-based expiry balance and mark-to-close breakeven on positions so monitor and dashboard can show both labels per contract.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-07 16:10:03 +08:00

157 lines
4.2 KiB
Python

"""期权定价单测。"""
from lib.options.options_pricing_lib import (
calc_order_size,
premium_per_sheet,
sheets_from_eth_amount,
total_premium,
)
from lib.exchange.okx_options_lib import format_option_px, inst_family_from_inst_id, round_option_px
def test_inst_family_from_inst_id():
assert inst_family_from_inst_id("ETH-USD_UM-260707-1790-C") == "ETH-USD_UM"
assert inst_family_from_inst_id("BTC-USD-260925-60000-C") == "BTC-USD"
def test_round_option_px():
assert round_option_px(14.9184, "0.2", "sell") == 14.8
assert round_option_px(14.81, "0.2", "buy") == 15.0
assert format_option_px(14.8, "0.2") == "14.8"
def test_premium_per_sheet():
assert abs(premium_per_sheet(15.6, 0.01) - 0.156) < 1e-9
def test_total_premium_half_eth():
assert abs(total_premium(15.6, 0.5) - 7.8) < 1e-9
def test_sheets_from_eth():
assert sheets_from_eth_amount(0.5, 0.01) == 50
def test_calc_order_size_budget():
r = calc_order_size(
quote_per_unit=15.6,
ct_mult=0.01,
min_sz=1,
budget_usdc=10,
budget_buffer=0.95,
budget_cap=10,
)
assert r["ok"] is True
assert r["sheets"] >= 1
assert r["total_premium"] <= 10
def test_calc_order_size_sheets():
r = calc_order_size(
quote_per_unit=15.6,
ct_mult=0.01,
min_sz=1,
sheets=3,
budget_cap=10,
)
assert r["ok"] is True
assert r["sheets"] == 3
assert abs(r["total_premium"] - 0.468) < 1e-9
def test_option_moneyness():
from lib.options.options_pricing_lib import option_moneyness, option_moneyness_label
assert option_moneyness(opt_type="C", strike=1700, index_px=1800) == "itm"
assert option_moneyness(opt_type="C", strike=1900, index_px=1800) == "otm"
assert option_moneyness_label("itm") == "实值"
assert option_moneyness_label("otm") == "虚值"
def test_calc_order_size_too_small():
r = calc_order_size(
quote_per_unit=2000.0,
ct_mult=0.01,
min_sz=1,
budget_usdc=10,
budget_buffer=0.95,
budget_cap=10,
)
assert r["ok"] is False
def test_expiry_breakeven_from_api():
from lib.options.options_pricing_lib import expiry_breakeven_px
assert expiry_breakeven_px(
opt_type="C", strike=3500, avg_px=15.6, be_px_api=3516.2
) == 3516.2
def test_expiry_breakeven_call_put():
from lib.options.options_pricing_lib import expiry_breakeven_px
assert expiry_breakeven_px(opt_type="C", strike=3500, avg_px=15.6) == 3515.6
assert expiry_breakeven_px(opt_type="P", strike=3500, avg_px=15.6) == 3484.4
def test_close_breakeven_at_mark_equals_avg():
from lib.options.options_pricing_lib import close_breakeven_idx
assert close_breakeven_idx(
opt_type="C", idx_px=3480, mark_px=15.6, avg_px=15.6
) == 3480.0
assert close_breakeven_idx(
opt_type="P", idx_px=3480, mark_px=15.6, avg_px=15.6
) == 3480.0
def test_close_breakeven_with_delta():
from lib.options.options_pricing_lib import close_breakeven_idx
# mark below avg, delta 0.5 ETH on 0.5 ETH position -> slope 1
be = close_breakeven_idx(
opt_type="C",
idx_px=3480,
mark_px=14.6,
avg_px=15.6,
delta_pa=0.5,
pos=50,
ct_mult=0.01,
)
assert be == 3481.0
def test_format_options_breakeven_line():
from lib.options.options_pricing_lib import format_options_breakeven_line
s = format_options_breakeven_line(
expiry_be_px=3515.6, close_be_px=3498.0, idx_px=3480.0
)
assert "到期平衡3516" in s
assert "平掉回本3498" in s
assert "指数3480" in s
def test_format_position_row_breakeven():
from lib.exchange.okx_options_lib import format_position_row
row = format_position_row(
{
"instId": "ETH-USD_UM-260703-1800-C",
"pos": "50",
"avgPx": "15.6",
"markPx": "16.2",
"idxPx": "3480",
"bePx": "3515.6",
"optType": "C",
"stk": "3500",
"deltaPA": "0.45",
"upl": "0.3",
"uplRatio": "0.02",
}
)
assert row["expiry_be_px"] == 3515.6
assert row["idx_px"] == 3480.0
assert row["close_be_px"] is not None
assert row["dist_expiry_be"] == 35.6