Add configurable futures roll date#9538
Conversation
Adds a TradingDaysBeforeExpiry mapping mode for continuous futures and threads the tradeable-day offset and contract month cycle through subscription, history, universe, mapping-event, and Python wrapper paths. Reuses LastTradingDay map-file rows for the new mode and applies the optional contract month cycle when walking continuous future contract depth. Adds coverage for LastTradingDay row reuse, contract-month-cycle depth walking, and tradeable-day offset handling. Verification: dotnet build Tests/QuantConnect.Tests.csproj --no-restore -clp:ErrorsOnly --verbosity quiet
|
Dear All, To provide some context, I actually reached out to Alex from QC team via QC ticket and gave him the draft specs for the proposed changes before he raised #9440, after which i provided a very comprehensive follow-up comment in #9440 detailing the proposed changes. So, I hope that #9538 would eventually land. Coming back to #9538, the mapping-side design looks right to me: shifting the map-file search date forward by the tradeable-day offset, applied consistently in both However, price normalization was not threaded through, and the failure is silent:
Note that simply aliasing to Suggestions to make this mergeable:
Happy to help test. This PR implements #9440, currently among the top-voted items on the QC roadmap. ContinuousFutureTradingDaysBeforeExpiryRegressionAlgorithm.cs |
Local test results confirming the review above (commit 44003ff)Environment: Windows, .NET SDK v 10.0.301, LEAN v2.5.0.0, fresh clone with Method: matched A/B backtest using the regression algorithm below (ES continuous contract, 2013-07-01 → 2014-01-01, ### Run A — Roll timing works. Mapping events fired on 2013-09-18 and 2013-12-18 — exactly 2 tradeable days earlier than the control's 09-20 / 12-20. Assertions (1) and (2) passed. The PR's core mapping mechanism is validated. The series is not price-adjusted. Across 26,670 compared bars, max |adjusted/raw − 1| = 0.000624 — the continuous price equals the raw contract price on every bar: 2013-10-07 09:31:00 - adjusted continuous close: 1669.5, raw ES VMKLFZIH2MTD: 1669.375, ratio: 1.000075 A second run reproduced the failure identically (same max deviation to six decimal places). ### Run B — control, Completes cleanly. Ratios ~0.9346 on every sampled bar (max deviation 0.065880), matching the shipped 2013-10-07 09:31:00 - adjusted continuous close: 1560.27..., raw ES VMKLFZIH2MTD: 1669.375, ratio: 0.934647 ### Scope of the bug Notably, (Note: the Regression algorithm usedContinuousFutureTradingDaysBeforeExpiryRegressionAlgorithm.cs Once the normalization gap is fixed, this algorithm should pass under both modes; the |
|
Thanks for the detailed review and local repro. I agree that the adjusted-normalization path should not silently fall through to default factors for I pushed
Verified in the Lean foundation container: dotnet test Tests/QuantConnect.Tests.csproj --filter "FullyQualifiedName~RejectsTradingDaysBeforeExpiryForAdjustedFutureFactorFiles" -clp:ErrorsOnly --verbosity quiet
dotnet test Tests/QuantConnect.Tests.csproj --filter "FullyQualifiedName~FactorFileTests" -clp:ErrorsOnly --verbosity quietBoth passed. This keeps the shifted-roll mapping path honest while leaving the larger question of dynamic shifted-roll factor computation/data-pipeline support for QC guidance. |
|
@scarab-systems : Thanks for the swift response! Much appreciated! Here are further testings and findings from me. Hopefully they can be of help. Follow-up on cb09f22: guard verified (with one placement finding) + contractMonthCycle empirically validatedGuard check. Re-ran the earlier A/B harness (mode 4 +
contractMonthCycle verification. Extended the observation period to Jul 2013 – Feb 2016
variation1_clean.txt With this, the full mapping-side feature set of #9440 (month cycle, depth within cycle, shifted |
Move the TradingDaysBeforeExpiry adjusted-normalization guard into DataManager subscription setup so unsupported configurations fail before subscription workers are scheduled. Keep the factor-provider guard as a backstop and add DataManager coverage for BackwardsRatio, BackwardsPanamaCanal, and ForwardPanamaCanal.
|
Thanks again for the detailed follow-up, and apologies for the delay in responding. We wanted to take the time to check the failure boundary carefully rather than just leave the guard where it was. We pushed We left the mapping-side behavior unchanged given your verification of month cycle, depth, and shifted We also looked into the remaining shifted-roll factor-generation side. We did not include that in this update because it seems like the right implementation should follow QC's preferred factor approach, but if QC would like us to take that on, we're happy to provide the follow-up implementation. Validation in
|
Summary
DataMappingMode.TradingDaysBeforeExpiryfor continuous futures that need to roll before the normal last-trading-day mapping date.LastTradingDaymap-file rows for the new mapping mode and applies the optional contract month cycle when walking continuous future contract depth.Motivation
Fixes #9440.
The issue describes two related continuous futures needs:
Testing
dotnet build Tests/QuantConnect.Tests.csproj --no-restore -clp:ErrorsOnly --verbosity quietAdded focused tests for:
TradingDaysBeforeExpiryreusingLastTradingDaymap-file rows;I was able to build the test project locally. Direct local NUnit execution in my Linux container aborted during global Python/test-host initialization before the selected tests ran, so CI should be the authoritative full test run.