chore: restore codebase to state before 2026-08-11 changes
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -102,7 +102,8 @@ class TestHedgePlanCalc(unittest.TestCase):
|
||||
a = {"opt_type": "C", "strike": 3300, "sheets": 1, "ct_mult": 0.01, "premium_paid": 5}
|
||||
b = {"opt_type": "P", "strike": 3100, "sheets": 1, "ct_mult": 0.01, "premium_paid": 5}
|
||||
p = build_options_options_preview(
|
||||
profit_rr=2,
|
||||
target_price_up=3500,
|
||||
target_price_down=3000,
|
||||
index_px=3200,
|
||||
leg_a=a,
|
||||
leg_b=b,
|
||||
@@ -110,11 +111,11 @@ class TestHedgePlanCalc(unittest.TestCase):
|
||||
self.assertEqual(p["summary"]["premium_paid"], 10)
|
||||
self.assertTrue(p["summary"]["expiry_is_loss"])
|
||||
self.assertEqual(p["summary"]["rr_risk_premium"], 10)
|
||||
self.assertEqual(p["summary"]["oo_profit_rr"], 2)
|
||||
self.assertAlmostEqual(p["summary"]["target_profit"], 20.0, places=4)
|
||||
self.assertEqual(len(p["scenarios"]), 3)
|
||||
self.assertEqual(p["scenarios"][0]["id"], "rr_target")
|
||||
self.assertEqual(p["scenarios"][1]["id"], "expiry_flat")
|
||||
self.assertIsNotNone(p["summary"]["rr_at_up"])
|
||||
self.assertAlmostEqual(p["summary"]["rr_at_up"], p["summary"]["at_target_up_total"] / 10, places=4)
|
||||
self.assertEqual(len(p["scenarios"]), 4)
|
||||
self.assertEqual(p["scenarios"][0]["id"], "target_up")
|
||||
self.assertEqual(p["scenarios"][1]["id"], "target_down")
|
||||
|
||||
def test_oo_legacy_single_target_still_works(self):
|
||||
a = {"opt_type": "C", "strike": 3300, "sheets": 1, "ct_mult": 0.01, "premium_paid": 5}
|
||||
@@ -123,21 +124,6 @@ class TestHedgePlanCalc(unittest.TestCase):
|
||||
self.assertEqual(p["target_price_up"], 3500)
|
||||
self.assertEqual(p["target_price_down"], 3500)
|
||||
|
||||
def test_oo_legacy_up_down_rr_fields(self):
|
||||
a = {"opt_type": "C", "strike": 3300, "sheets": 1, "ct_mult": 0.01, "premium_paid": 5}
|
||||
b = {"opt_type": "P", "strike": 3100, "sheets": 1, "ct_mult": 0.01, "premium_paid": 5}
|
||||
p = build_options_options_preview(
|
||||
target_price_up=3500,
|
||||
target_price_down=3000,
|
||||
index_px=3200,
|
||||
leg_a=a,
|
||||
leg_b=b,
|
||||
)
|
||||
self.assertIsNotNone(p["summary"]["rr_at_up"])
|
||||
self.assertAlmostEqual(p["summary"]["rr_at_up"], p["summary"]["at_target_up_total"] / 10, places=4)
|
||||
self.assertEqual(p["scenarios"][0]["id"], "target_up")
|
||||
self.assertEqual(p["scenarios"][1]["id"], "target_down")
|
||||
|
||||
def test_perp_short_pnl(self):
|
||||
self.assertEqual(
|
||||
perp_pnl(direction="short", entry=100, exit_px=90, contracts=1, contract_size=1),
|
||||
|
||||
@@ -155,32 +155,6 @@ class TestHedgeHistoryStats(unittest.TestCase):
|
||||
self.assertEqual(targets["ETH-USD_UM-260719-1850-P"]["target_index"], 1800)
|
||||
self.assertEqual(targets["ETH-USD_UM-260719-1890-C"]["managed_by"], "hedge_plan")
|
||||
|
||||
def test_active_options_targets_rr_mode_marks_managed(self):
|
||||
conn = _mem()
|
||||
pid = insert_plan(
|
||||
conn,
|
||||
{
|
||||
"plan_type": "options_options",
|
||||
"status": "active",
|
||||
"underlying": "ETH",
|
||||
"oo_profit_rr": 2,
|
||||
},
|
||||
)
|
||||
insert_leg(
|
||||
conn,
|
||||
{
|
||||
"plan_id": pid,
|
||||
"leg_role": "option_a",
|
||||
"inst_id": "ETH-USD_UM-260719-1890-C",
|
||||
"opt_type": "C",
|
||||
"status": "open",
|
||||
},
|
||||
)
|
||||
targets = active_options_targets_by_inst(conn)
|
||||
self.assertEqual(targets["ETH-USD_UM-260719-1890-C"]["managed_by"], "hedge_plan")
|
||||
self.assertIsNone(targets["ETH-USD_UM-260719-1890-C"]["target_index"])
|
||||
self.assertEqual(targets["ETH-USD_UM-260719-1890-C"]["oo_profit_rr"], 2.0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
"""期权合约列表缓存与限频退避."""
|
||||
from __future__ import annotations
|
||||
|
||||
import time
|
||||
import unittest
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from lib.exchange import okx_options_lib as m
|
||||
|
||||
|
||||
class FetchOptionInstrumentsCacheTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
m.invalidate_option_instruments_cache()
|
||||
|
||||
def tearDown(self):
|
||||
m.invalidate_option_instruments_cache()
|
||||
|
||||
def test_cache_hit_skips_second_api_call(self):
|
||||
ex = MagicMock()
|
||||
ex.public_get_public_instruments.return_value = {
|
||||
"data": [
|
||||
{
|
||||
"instId": "ETH-USD_UM-260812-2000-C",
|
||||
"state": "live",
|
||||
"expTime": "9999999999999",
|
||||
}
|
||||
]
|
||||
}
|
||||
a = m.fetch_option_instruments(ex, "ETH-USD_UM")
|
||||
b = m.fetch_option_instruments(ex, "ETH-USD_UM")
|
||||
self.assertEqual(len(a), 1)
|
||||
self.assertEqual(len(b), 1)
|
||||
self.assertEqual(ex.public_get_public_instruments.call_count, 1)
|
||||
|
||||
@patch("lib.exchange.okx_options_lib.time.sleep", return_value=None)
|
||||
def test_rate_limit_falls_back_to_stale_cache(self, _sleep):
|
||||
ex = MagicMock()
|
||||
ex.public_get_public_instruments.return_value = {
|
||||
"data": [{"instId": "ETH-USD_UM-260812-2000-C", "state": "live"}]
|
||||
}
|
||||
first = m.fetch_option_instruments(ex, "ETH-USD_UM")
|
||||
self.assertEqual(len(first), 1)
|
||||
# 过期 TTL,但仍在 stale 窗口
|
||||
with m._INSTRUMENTS_CACHE_LOCK:
|
||||
m._INSTRUMENTS_CACHE["ETH-USD_UM"]["updated_at"] = time.time() - 120
|
||||
ex.public_get_public_instruments.side_effect = Exception(
|
||||
'okx {"msg":"Too Many Requests","code":"50011"}'
|
||||
)
|
||||
second = m.fetch_option_instruments(ex, "ETH-USD_UM")
|
||||
self.assertEqual(len(second), 1)
|
||||
self.assertEqual(second[0]["instId"], "ETH-USD_UM-260812-2000-C")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -1,4 +1,4 @@
|
||||
"""期权目标委托单元测试(盈亏比 + 旧指数兼容)."""
|
||||
"""期权目标位委托单元测试."""
|
||||
from __future__ import annotations
|
||||
|
||||
import sqlite3
|
||||
@@ -8,7 +8,6 @@ from lib.options.options_target_lib import (
|
||||
ensure_target_tables,
|
||||
list_active_targets,
|
||||
list_closing_targets,
|
||||
profit_rr_hit,
|
||||
run_options_target_closes,
|
||||
target_hit,
|
||||
upsert_target_monitor,
|
||||
@@ -22,67 +21,7 @@ class OptionsTargetLibTests(unittest.TestCase):
|
||||
self.assertTrue(target_hit(opt_type="P", index_px=1800, target_index=1850))
|
||||
self.assertFalse(target_hit(opt_type="P", index_px=1900, target_index=1850))
|
||||
|
||||
def test_profit_rr_hit(self):
|
||||
# premium=10, rr=2 → need pnl≥20 → recycle≥30 → bid*sheets*ct ≥30
|
||||
self.assertTrue(
|
||||
profit_rr_hit(premium=10, bid=30, sheets=1, ct_mult=1, profit_rr=2)
|
||||
)
|
||||
self.assertFalse(
|
||||
profit_rr_hit(premium=10, bid=29.9, sheets=1, ct_mult=1, profit_rr=2)
|
||||
)
|
||||
self.assertFalse(
|
||||
profit_rr_hit(premium=10, bid=None, sheets=1, ct_mult=1, profit_rr=2)
|
||||
)
|
||||
|
||||
def test_upsert_rr_and_trigger_close(self):
|
||||
conn = sqlite3.connect(":memory:")
|
||||
conn.row_factory = sqlite3.Row
|
||||
ensure_target_tables(conn)
|
||||
out = upsert_target_monitor(
|
||||
conn,
|
||||
inst_id="ETH-USD_UM-260717-1900-C",
|
||||
profit_rr=2,
|
||||
opt_type="C",
|
||||
sheets=1,
|
||||
)
|
||||
self.assertTrue(out["ok"])
|
||||
self.assertEqual(out.get("profit_rr"), 2.0)
|
||||
self.assertEqual(len(list_active_targets(conn)), 1)
|
||||
|
||||
closed = []
|
||||
|
||||
def close_fn(inst_id: str):
|
||||
closed.append(inst_id)
|
||||
return {
|
||||
"ok": True,
|
||||
"submitted_sheets": 1,
|
||||
"premium_received": 30.0,
|
||||
"close_ord_id": "oid1",
|
||||
"fully_closed": True,
|
||||
"remaining_sheets": 0,
|
||||
}
|
||||
|
||||
# bid=30, ct=1 → pnl=20 ≥ 2*10; premium 来自持仓字段
|
||||
n = run_options_target_closes(
|
||||
conn,
|
||||
[
|
||||
{
|
||||
"inst_id": "ETH-USD_UM-260717-1900-C",
|
||||
"idx_px": 1885,
|
||||
"opt_type": "C",
|
||||
"pos": 1,
|
||||
"ct_mult": 1,
|
||||
"premium_paid": 10,
|
||||
}
|
||||
],
|
||||
close_fn=close_fn,
|
||||
bid_fn=lambda _i: 30.0,
|
||||
)
|
||||
self.assertEqual(n, 1)
|
||||
self.assertEqual(closed, ["ETH-USD_UM-260717-1900-C"])
|
||||
self.assertEqual(len(list_active_targets(conn)), 0)
|
||||
|
||||
def test_upsert_and_trigger_close_legacy_index(self):
|
||||
def test_upsert_and_trigger_close(self):
|
||||
conn = sqlite3.connect(":memory:")
|
||||
conn.row_factory = sqlite3.Row
|
||||
ensure_target_tables(conn)
|
||||
@@ -168,6 +107,7 @@ class OptionsTargetLibTests(unittest.TestCase):
|
||||
self.assertEqual(len(list_active_targets(conn)), 0)
|
||||
self.assertEqual(len(list_closing_targets(conn)), 1)
|
||||
|
||||
# 模拟后续 sync 异常也不会再推:closing 重试静默
|
||||
n2 = run_options_target_closes(
|
||||
conn,
|
||||
pos,
|
||||
@@ -180,6 +120,7 @@ class OptionsTargetLibTests(unittest.TestCase):
|
||||
self.assertEqual(len(list_closing_targets(conn)), 0)
|
||||
|
||||
def test_commit_before_wechat_survives_later_rollback(self):
|
||||
"""状态在推送前已 commit,外层异常回滚不应让委托回到 active."""
|
||||
conn = sqlite3.connect(":memory:")
|
||||
conn.row_factory = sqlite3.Row
|
||||
ensure_target_tables(conn)
|
||||
@@ -208,10 +149,12 @@ class OptionsTargetLibTests(unittest.TestCase):
|
||||
close_fn=close_fn,
|
||||
send_wechat=notices.append,
|
||||
)
|
||||
# 模拟 loop 后续 sync 抛错后 close 未再 commit —— 但 status 已提前 commit
|
||||
conn.rollback()
|
||||
self.assertEqual(len(notices), 1)
|
||||
self.assertEqual(len(list_active_targets(conn)), 0)
|
||||
|
||||
# 下一轮不应再次触发推送
|
||||
n2 = run_options_target_closes(
|
||||
conn,
|
||||
[{"inst_id": "ETH-USD_UM-260715-1870-P", "idx_px": 1860, "opt_type": "P"}],
|
||||
|
||||
Reference in New Issue
Block a user