Files
eth_hedge_sim/backend/tests/test_p1_p2_rules.py
T

120 lines
3.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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_expiry_close, 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_weekend_skip() -> None:
# 2026-07-24 周五可开;25/26 周六日不可开
fri = datetime(2026, 7, 24, 17, 0, tzinfo=_SH)
sat = datetime(2026, 7, 25, 12, 0, tzinfo=_SH)
sun = datetime(2026, 7, 26, 10, 0, tzinfo=_SH)
mon = datetime(2026, 7, 27, 9, 0, tzinfo=_SH)
assert can_open_new(fri, skip_weekends=True) is True
assert can_open_new(sat, skip_weekends=True) is False
assert can_open_new(sun, skip_weekends=True) is False
assert can_open_new(mon, skip_weekends=True) is True
assert can_open_new(sat, skip_weekends=False) is True
assert window_key(fri) == "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
def test_expiry_close() -> None:
assert check_expiry_close(expiry_ms=None).should_close is False
d = check_expiry_close(expiry_ms=1_000, now_ms=999)
assert d.should_close is False
d2 = check_expiry_close(expiry_ms=1_000, now_ms=1_000)
assert d2.should_close is True
assert d2.reason == "expiry"
d3 = check_expiry_close(expiry_ms=1_000, now_ms=1_001)
assert d3.should_close is True