from strategy_roll_lib import ( preview_roll, resolve_roll_stop_spec, roll_stop_after_fill, unified_stop_from_avg, ) def test_resolve_roll_stop_spec_treats_small_value_as_offset_pct(): mode, val = resolve_roll_stop_spec(new_stop_loss=1.0, entry_ref=63.976) assert mode == "offset" assert val == 1.0 def test_resolve_roll_stop_spec_treats_price_as_absolute(): mode, val = resolve_roll_stop_spec(new_stop_loss=64.6, entry_ref=63.976) assert mode == "absolute" assert val == 64.6 def test_unified_stop_from_avg_short_one_percent(): sl = unified_stop_from_avg("short", 63.976, 1.0) assert abs(sl - 63.976 * 1.01) < 1e-6 def test_preview_roll_offset_mode_not_breakeven(): preview, err = preview_roll( direction="short", symbol="HYPE/USDT", qty_existing=3.0, entry_existing=65.0, initial_take_profit=60.0, add_mode="market", stop_offset_pct=1.0, risk_percent=2.0, capital_base_usdt=1000.0, add_price=64.0, legs_done=1, ) assert err is None assert preview["stop_mode"] == "offset" assert preview["stop_offset_pct"] == 1.0 avg = preview["avg_entry_after"] sl = preview["new_stop_loss"] assert sl > avg * 1.009 assert sl < avg * 1.011 def test_roll_stop_after_fill_recomputes_from_actual_fill(): sl = roll_stop_after_fill( "short", qty_before=3.0, entry_before=65.0, add_qty=5.0, fill_price=63.5, stop_offset_pct=1.0, ) avg = (3 * 65.0 + 5 * 63.5) / 8.0 assert abs(sl - avg * 1.01) < 1e-6