From 64dcc7ab1949dc91d14eaa0b6ed3137e6baae559 Mon Sep 17 00:00:00 2001 From: Martin Molinero Date: Fri, 19 Jun 2026 12:51:06 -0300 Subject: [PATCH] Assert fill price and fresh hour bar in stale price regression algorithm HourResolutionMarketOrderStalePriceRegressionAlgorithm now asserts the order fills at the next hour bar's close price (not the stale previous bar nor the open), and that the fill bar is a real, freshly closed 11:00 bar rather than a fill-forwarded repeat. Co-Authored-By: Claude Opus 4.8 (1M context) --- ...arketOrderStalePriceRegressionAlgorithm.cs | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/Algorithm.CSharp/HourResolutionMarketOrderStalePriceRegressionAlgorithm.cs b/Algorithm.CSharp/HourResolutionMarketOrderStalePriceRegressionAlgorithm.cs index 2ee689e8cd38..75ddcbcc93c6 100644 --- a/Algorithm.CSharp/HourResolutionMarketOrderStalePriceRegressionAlgorithm.cs +++ b/Algorithm.CSharp/HourResolutionMarketOrderStalePriceRegressionAlgorithm.cs @@ -81,14 +81,38 @@ public override void OnOrderEvent(OrderEvent orderEvent) return; } - // The order must fill on the next hour bar close (11:00), not on the stale previous bar (10:00) + // The order must fill on the next hour bar (10:00 -> 11:00), not on the stale previous bar (10:00) var fillLocalTime = orderEvent.UtcTime.ConvertFromUtc(Securities[_spy].Exchange.TimeZone); var expectedFill = new DateTime(2013, 10, 8, 11, 0, 0); if (fillLocalTime != expectedFill) { throw new RegressionTestException( - $"Expected the order to fill at the next hour bar close {expectedFill} but filled at {fillLocalTime}"); + $"Expected the order to fill at the next hour bar {expectedFill} but filled at {fillLocalTime}"); + } + + // The fill must use a real, freshly closed hour bar - not a fill-forwarded repeat of an older bar - and + // that bar must be the next hour bar (ending 11:00). + var hourBar = Securities[_spy].GetLastData(); + if (hourBar == null || hourBar.IsFillForward) + { + throw new RegressionTestException( + $"Expected the order to fill on a real (non fill-forwarded) hour bar but got {(hourBar == null ? "no data" : "fill-forwarded data")} at {Time}"); + } + + if (hourBar.EndTime != expectedFill) + { + throw new RegressionTestException( + $"Expected the fill bar to end at the next hour {expectedFill} but it ended at {hourBar.EndTime}"); + } + + // It must fill at that hour bar's close price, not the stale previous bar's price nor the bar open. The + // order is placed mid-bar (after the bar opened), so the close - not the open - is used. + var hourBarClose = Securities[_spy].Close; + if (orderEvent.FillPrice != hourBarClose) + { + throw new RegressionTestException( + $"Expected the order to fill at the next hour bar close price {hourBarClose} but filled at {orderEvent.FillPrice}"); } }