from datetime import datetime from zoneinfo import ZoneInfo from app.sim.liquidity import bid_mark_ok from app.sim.pricing import option_fill, perp_fill from app.strategy.clock import can_open_new, window_key from app.strategy.exits import check_exits from app.strategy.signal import decide _SH = ZoneInfo("Asia/Shanghai") def test_signal_buy_call_short_perp() -> None: s = decide(20.0, 15.0) assert s is not None assert s.option_side == "call" assert s.perp_side == "short" def test_signal_buy_put_long_perp() -> None: s = decide(10.0, 16.0) assert s is not None assert s.option_side == "put" assert s.perp_side == "long" def test_signal_equal() -> None: assert decide(10.0, 10.0) is None def test_exit_fixed_and_premium_multiple() -> None: fixed = check_exits( net_pnl=15.0, exit_mode="fixed_usdt", net_profit_target=15, premium_exit_multiple=1, initial_premium=40, ) assert fixed.reason == "fixed_usdt" assert fixed.target == 15 assert ( check_exits( net_pnl=14.9, exit_mode="fixed_usdt", net_profit_target=15, premium_exit_multiple=1, initial_premium=40, ).should_close is False ) prem = check_exits( net_pnl=40.0, exit_mode="premium_multiple", net_profit_target=15, premium_exit_multiple=1, initial_premium=40, ) assert prem.reason == "premium_multiple" assert prem.target == 40 half = check_exits( net_pnl=20.0, exit_mode="premium_multiple", net_profit_target=15, premium_exit_multiple=0.5, initial_premium=40, ) assert half.should_close is True assert half.target == 20 def test_perp_pricing() -> None: r = perp_fill(side="long", action="open", bid=100, ask=101, qty_eth=1, fee_rate=0.001) assert abs(r.fill_px - 101 * 1.001) < 1e-9 def test_option_open_close_pricing() -> None: o = option_fill(action="open", bid=10, ask=12, qty_eth=2, fee_rate=0.001) assert o.fill_px > 12 c = option_fill(action="close", bid=10, ask=12, qty_eth=2, fee_rate=0.001) assert c.fill_px < 10 def test_window_always_open() -> None: n = datetime(2026, 7, 24, 17, 0, tzinfo=_SH) assert can_open_new(n) is True assert window_key(n) == "20260724" n2 = datetime(2026, 7, 24, 10, 0, tzinfo=_SH) assert can_open_new(n2) is True assert window_key(n2) == "20260724" def test_bid_mark_deviation_30pct() -> None: # |7-10|/10 = 30% → 允许(≤30%) ok, _ = bid_mark_ok(bid=7.0, mark=10.0, max_dev_pct=30) assert ok is True ok2, _ = bid_mark_ok(bid=6.9, mark=10.0, max_dev_pct=30) assert ok2 is False ok3, why = bid_mark_ok(bid=None, mark=10.0, max_dev_pct=30) assert ok3 is False assert "买一" in why