"""期权平仓/到期状态同步单测.""" import sqlite3 from lib.exchange.okx_options_lib import ( format_option_history_row, format_usdc_amount, is_option_full_close_history, resolve_option_close_from_history, ) from lib.options.options_db import init_options_tables from lib.options.options_monitor_lib import sync_open_options_trades def test_format_usdc_amount(): assert format_usdc_amount(4.896) == "4.90" assert format_usdc_amount(4.9) == "4.90" assert format_usdc_amount(4.0) == "4.00" def test_is_option_full_close_history(): assert is_option_full_close_history({"type": "2"}) assert is_option_full_close_history({"type": "3"}) assert not is_option_full_close_history({"type": "1"}) assert not is_option_full_close_history({"type": "5"}) def test_format_option_history_row(): raw = { "instId": "BTC-USD_UM-260710-62000-P", "openAvgPx": "380", "closeAvgPx": "0", "closeTotalPos": "1", "openMaxPos": "1", "realizedPnl": "-3.99", "pnlRatio": "-1.049", "type": "2", "cTime": "1784000000000", "uTime": "1784088035000", "posId": "pos-btc", } row = format_option_history_row(raw, tick_sz="0.1", ct_mult=0.01) assert row["inst_id"] == "BTC-USD_UM-260710-62000-P" assert row["sheets"] == 1 assert row["realized_pnl"] == -3.99 assert row["status_label"] == "已平" assert row["open_avg_px_fmt"] == "380" assert row["premium_paid_fmt"] == "3.80" assert row["history_key"] == "ex:pos-btc:1784088035000" def test_resolve_option_close_from_history_picks_latest(): rows = [ {"instId": "ETH-USD_UM-260709-1700-P", "uTime": "1000", "realizedPnl": "-1.0", "closeAvgPx": "0"}, {"instId": "ETH-USD_UM-260709-1700-P", "uTime": "2000", "realizedPnl": "-1.24", "closeAvgPx": "0", "posId": "9"}, ] got = resolve_option_close_from_history(rows, open_ms=500) assert got is not None assert got["realized_pnl"] == -1.24 assert got["pos_id"] == "9" def test_resolve_option_close_from_history_matches_open_and_sheets(): rows = [ { "instId": "ETH-USD_UM-260806-1875-C", "cTime": "1785932775047", "uTime": "1785933936733", "realizedPnl": "-3.036", "closeAvgPx": "12.4", "closeTotalPos": "57", "posId": "same-pos", }, { "instId": "ETH-USD_UM-260806-1875-C", "cTime": "1785938392445", "uTime": "1785957764279", "realizedPnl": "16.937", "closeAvgPx": "41.0", "closeTotalPos": "66", "posId": "same-pos", }, ] # 本地时间相对交易所偏 8h 时,仍应按 cTime/张数对齐到正确一笔 early = resolve_option_close_from_history( rows, open_ms=1785902775000, close_ms=1785903937000, sheets=57 ) late = resolve_option_close_from_history( rows, open_ms=1785908392000, close_ms=1785927764000, sheets=66 ) assert early is not None and early["realized_pnl"] == -3.036 assert early["close_quote"] == 12.4 assert late is not None and late["realized_pnl"] == 16.937 assert late["close_quote"] == 41.0 def test_sync_open_options_trades_marks_expired_closed(): conn = sqlite3.connect(":memory:") conn.row_factory = sqlite3.Row init_options_tables(conn) conn.execute( """ INSERT INTO options_trades (inst_id, underlying, opt_type, strike, exp_time, sheets, eth_amount, open_quote, premium_paid, status) VALUES (?, 'ETH', 'P', 1700, '', 20, 0.2, 6.2, 1.24, 'open') """, ("ETH-USD_UM-260709-1700-P",), ) conn.commit() n = sync_open_options_trades( conn, live_inst_ids=set(), fetch_history_fn=lambda _inst: [], ) assert n == 1 row = conn.execute("SELECT status, premium_received, realized_pnl, signal_note FROM options_trades").fetchone() assert row["status"] == "closed" assert row["premium_received"] == 0.0 assert row["realized_pnl"] == -1.24 assert "到期结算" in (row["signal_note"] or "") def test_sync_open_options_trades_skips_without_close_evidence(): conn = sqlite3.connect(":memory:") conn.row_factory = sqlite3.Row init_options_tables(conn) conn.execute( """ INSERT INTO options_trades (inst_id, underlying, opt_type, strike, exp_time, sheets, eth_amount, open_quote, premium_paid, status, created_at) VALUES (?, 'BTC', 'P', 62000, '', 1, 0.01, 380.0, 3.8, 'open', '2026-08-05 08:00:00') """, ("BTC-USD_UM-261231-62000-P",), ) conn.commit() n = sync_open_options_trades( conn, live_inst_ids=set(), fetch_history_fn=lambda _inst: [], ) assert n == 0 row = conn.execute("SELECT status FROM options_trades").fetchone() assert row["status"] == "open" def test_reconcile_live_open_trades_reopens_sync_artifact(): conn = sqlite3.connect(":memory:") conn.row_factory = sqlite3.Row init_options_tables(conn) conn.execute( """ INSERT INTO options_trades (inst_id, underlying, opt_type, strike, exp_time, sheets, eth_amount, open_quote, premium_paid, status, closed_at) VALUES (?, 'BTC', 'P', 62000, '', 1, 0.01, 380.0, 3.8, 'closed', '2026-07-09 09:10:34') """, ("BTC-USD_UM-260710-62000-P",), ) conn.commit() from lib.options.options_monitor_lib import reconcile_live_open_trades n = reconcile_live_open_trades(conn, live_inst_ids={"BTC-USD_UM-260710-62000-P"}) assert n == 1 row = conn.execute("SELECT status, closed_at FROM options_trades").fetchone() assert row["status"] == "open" assert row["closed_at"] is None conn = sqlite3.connect(":memory:") conn.row_factory = sqlite3.Row init_options_tables(conn) conn.execute( """ INSERT INTO options_trades (inst_id, underlying, opt_type, strike, exp_time, sheets, eth_amount, open_quote, premium_paid, status, created_at) VALUES (?, 'ETH', 'P', 1700, '', 20, 0.2, 6.2, 1.24, 'open', '2026-07-08 02:32:44') """, ("ETH-USD_UM-260709-1700-P",), ) conn.commit() def _hist(_inst): return [ { "instId": "ETH-USD_UM-260709-1700-P", "uTime": "1784000000000", "realizedPnl": "-0.5", "closeAvgPx": "0.1", "posId": "pos-1", } ] n = sync_open_options_trades( conn, live_inst_ids=set(), fetch_history_fn=_hist, ) assert n == 1 row = conn.execute( "SELECT status, premium_received, realized_pnl, close_ord_id FROM options_trades" ).fetchone() assert row["status"] == "closed" assert row["realized_pnl"] == -0.5 assert row["premium_received"] == 0.74 assert row["close_ord_id"] == "pos-1" def test_backfill_closed_options_realized_pnl_from_history(): from lib.options.options_monitor_lib import backfill_closed_options_realized_pnl_from_history conn = sqlite3.connect(":memory:") conn.row_factory = sqlite3.Row init_options_tables(conn) conn.execute( """ INSERT INTO options_trades (inst_id, underlying, opt_type, strike, exp_time, sheets, eth_amount, open_quote, close_quote, premium_paid, premium_received, realized_pnl, status, created_at, closed_at, close_ord_id) VALUES (?, 'ETH', 'C', 1860, '', 43, 0.43, 22.4, 50.6, 9.632, 21.758, 12.126, 'closed', '2026-07-20 08:02:14', '2026-07-21 01:38:43', 'ord-1') """, ("ETH-USD_UM-260721-1860-C",), ) conn.commit() hist = [ { "instId": "ETH-USD_UM-260721-1860-C", "uTime": "1784564323000", "realizedPnl": "11.64", "closeAvgPx": "48.5", "closeTotalPos": "43", "posId": "pos-x", } ] n = backfill_closed_options_realized_pnl_from_history(conn, hist) assert n == 1 row = conn.execute( "SELECT realized_pnl, premium_received, close_quote FROM options_trades WHERE id=1" ).fetchone() assert row["realized_pnl"] == 11.64 assert abs(float(row["premium_received"]) - (9.632 + 11.64)) < 1e-6 assert float(row["close_quote"]) == 48.5 # idempotent assert backfill_closed_options_realized_pnl_from_history(conn, hist) == 0 def test_backfill_does_not_overwrite_earlier_close_with_later_pnl(): from lib.options.options_monitor_lib import backfill_closed_options_realized_pnl_from_history conn = sqlite3.connect(":memory:") conn.row_factory = sqlite3.Row init_options_tables(conn) conn.execute( """ INSERT INTO options_trades (inst_id, underlying, opt_type, strike, exp_time, sheets, eth_amount, open_quote, close_quote, premium_paid, realized_pnl, status, created_at, closed_at) VALUES (?, 'ETH', 'C', 1875, '', 57, 0.57, 16.6, 41.0, 9.462, 16.9368, 'closed', '2026-08-05 12:26:15', '2026-08-05 12:45:37') """, ("ETH-USD_UM-260806-1875-C",), ) conn.execute( """ INSERT INTO options_trades (inst_id, underlying, opt_type, strike, exp_time, sheets, eth_amount, open_quote, close_quote, premium_paid, realized_pnl, status, created_at, closed_at) VALUES (?, 'ETH', 'C', 1875, '', 66, 0.66, 14.2, 41.0, 9.372, 16.9368, 'closed', '2026-08-05 13:59:52', '2026-08-05 19:22:45') """, ("ETH-USD_UM-260806-1875-C",), ) conn.commit() hist = [ { "instId": "ETH-USD_UM-260806-1875-C", "uTime": "1785933936733", "cTime": "1785932775047", "realizedPnl": "-3.03616314", "closeAvgPx": "12.4", "closeTotalPos": "57", "posId": "3806091806281486337", }, { "instId": "ETH-USD_UM-260806-1875-C", "uTime": "1785957764279", "cTime": "1785938392445", "realizedPnl": "16.9368375", "closeAvgPx": "41.0", "closeTotalPos": "66", "posId": "3806091806281486337", }, ] n = backfill_closed_options_realized_pnl_from_history(conn, hist) assert n >= 1 rows = { int(r["id"]): r for r in conn.execute( "SELECT id, realized_pnl, close_quote FROM options_trades ORDER BY id" ).fetchall() } assert abs(float(rows[1]["realized_pnl"]) - (-3.0362)) < 1e-3 assert float(rows[1]["close_quote"]) == 12.4 assert abs(float(rows[2]["realized_pnl"]) - 16.9368) < 1e-3 assert float(rows[2]["close_quote"]) == 41.0