Files
eth_hedge_sim/backend/tests/test_p1_p2_rules.py
T
dekun cce26e87b5 Add dual exit modes: fixed USDT or premium multiple.
Net PnL (after estimated close fees) drives auto close; Plan/Settings expose the choice.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-25 09:17:50 +08:00

104 lines
2.8 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_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