Files
CoinOX/tests/test_options_sync.py
T
dekun 88b7fb7a0a Initial CoinOX instance: coin-margined options + USDT hedge.
Forked from crypto_monitor OKX instance (copy-only). Keeps standalone options, perp-options and options-options hedge; drops standalone perp entrypoints; forces coin margin; adds sim wallets; default port 5010.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 00:18:40 +08:00

311 lines
11 KiB
Python

"""期权平仓/到期状态同步单测."""
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