"""以损定仓纯函数测试。""" from __future__ import annotations from app.strategy.risk_sizing import ( BASE_EXIT_USDT, BASE_OPTION_ETH, BASE_PERP_ETH, compute_k, floor_k_1dp, unit_cost, ) def test_floor_k_1dp() -> None: assert floor_k_1dp(1.29) == 1.2 assert floor_k_1dp(0.19) == 0.1 assert floor_k_1dp(0.09) == 0.0 assert floor_k_1dp(2.0) == 2.0 def test_compute_k_scales_1_2_15() -> None: # I=2000, A=20, fee=0.0005 → unit = 2*20 + 2000*0.0005*3 = 40 + 3 = 43 # budget=43 → k=1.0 r = compute_k(budget=43.0, index_px=2000.0, option_ask=20.0, fee_rate=0.0005) assert r.ok assert r.k == 1.0 assert r.perp_qty_eth == BASE_PERP_ETH assert r.option_qty_eth == BASE_OPTION_ETH assert r.net_profit_target == BASE_EXIT_USDT assert r.max_loss is not None and r.max_loss <= 43.0 + 1e-6 assert r.budget == 43.0 def test_compute_k_custom_units() -> None: # option_unit=4 → premium unit = 20*4=80; fee=3; cost=83; budget=83 → k=1 r = compute_k( budget=83.0, index_px=2000.0, option_ask=20.0, fee_rate=0.0005, perp_unit=0.5, option_unit=4.0, exit_unit=30.0, ) assert r.ok assert r.k == 1.0 assert r.perp_qty_eth == 0.5 assert r.option_qty_eth == 4.0 assert r.net_profit_target == 30.0 def test_money_rounds_2dp() -> None: r = compute_k(budget=50.123456, index_px=1900.0, option_ask=18.5, fee_rate=0.0005) assert r.ok assert r.budget == round(50.123456, 2) assert r.max_loss is not None assert abs(r.max_loss * 100 - round(r.max_loss * 100)) < 1e-9 def test_compute_k_never_exceeds_budget() -> None: r = compute_k(budget=50.0, index_px=1900.0, option_ask=18.5, fee_rate=0.0005) assert r.ok assert r.k is not None assert abs(r.k * 10 - round(r.k * 10)) < 1e-9 # 一位小数 assert r.max_loss is not None and r.max_loss <= 50.0 + 1e-6 assert r.perp_qty_eth == round(1.0 * r.k, 4) assert r.option_qty_eth == round(2.0 * r.k, 4) assert r.net_profit_target == round(15.0 * r.k, 4) def test_compute_k_too_small() -> None: # unit≈43, budget=2 → k_raw≪0.1 r = compute_k(budget=2.0, index_px=2000.0, option_ask=20.0, fee_rate=0.0005) assert not r.ok assert "最小仓" in r.detail or "k=" in r.detail def test_unit_cost() -> None: assert abs(unit_cost(index_px=2000, option_ask=20, fee_rate=0.0005) - 43.0) < 1e-9