@@ -368,3 +368,67 @@ def handle_data(context, data):
368368 item ["statusReason" ] == "target_already_met"
369369 for item in result ["orderLedger" ]
370370 )
371+
372+
373+ def test_crypto_lot_rounding_is_filled_without_a_tail_retry ():
374+ frame = _frame ([58_700 , 58_700 , 58_700 ])
375+ code = """
376+ def initialize(context):
377+ g.symbol = "Crypto:BTC/USDT@swap"
378+ g.sent = False
379+ context.set_universe([g.symbol])
380+ context.subscribe(frequency="1m")
381+
382+ def handle_data(context, data):
383+ if not g.sent:
384+ order_target_percent(g.symbol, 0.95, reason="entry")
385+ g.sent = True
386+ """
387+ result = StrategyV2BacktestRunner (
388+ code = code ,
389+ frames = {"Crypto:BTC/USDT@swap" : frame },
390+ initial_capital = 10_000 ,
391+ commission = 0.0005 ,
392+ slippage = 0.0005 ,
393+ ).run ()
394+
395+ assert result ["totalExecutions" ] == 1
396+ assert result ["rawTrades" ][0 ]["status" ] == "filled"
397+ assert result ["attribution" ]["orderStatus" ] == {
398+ "filled" : 1 ,
399+ "partial" : 0 ,
400+ "deferred" : 0 ,
401+ "rejected" : 0 ,
402+ }
403+ assert not any (
404+ item ["statusReason" ] == "target_already_met"
405+ for item in result ["orderLedger" ]
406+ )
407+
408+
409+ def test_crypto_target_reversals_do_not_retry_untradable_tail_quantities ():
410+ frame = _frame ([58_700 ] * 6 )
411+ code = """
412+ def initialize(context):
413+ g.symbol = "Crypto:BTC/USDT@swap"
414+ g.step = 0
415+ context.set_universe([g.symbol])
416+ context.subscribe(frequency="1m")
417+
418+ def handle_data(context, data):
419+ target = 0.95 if g.step % 2 == 0 else -0.95
420+ order_target_percent(g.symbol, target, reason="regime_change")
421+ g.step += 1
422+ """
423+ result = StrategyV2BacktestRunner (
424+ code = code ,
425+ frames = {"Crypto:BTC/USDT@swap" : frame },
426+ initial_capital = 10_000 ,
427+ commission = 0.0005 ,
428+ slippage = 0.0005 ,
429+ ).run ()
430+
431+ assert result ["totalExecutions" ] == 5
432+ assert {item ["status" ] for item in result ["rawTrades" ]} == {"filled" }
433+ assert result ["attribution" ]["orderStatus" ]["partial" ] == 0
434+ assert result ["attribution" ]["orderStatus" ]["rejected" ] == 0
0 commit comments