From b09499e2a2cc9108b63aef5af98418fb27deae81 Mon Sep 17 00:00:00 2001 From: Josue Nina Date: Wed, 7 Jan 2026 15:50:53 -0500 Subject: [PATCH 1/8] Fix HistoryRequest DataMappingMode default to use security configuration --- Algorithm/QCAlgorithm.History.cs | 11 ++++++++++- Common/Data/HistoryRequestFactory.cs | 4 ++++ Tests/Algorithm/AlgorithmHistoryTests.cs | 25 ++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/Algorithm/QCAlgorithm.History.cs b/Algorithm/QCAlgorithm.History.cs index 7ab90facb8af..57ccc41c2d2a 100644 --- a/Algorithm/QCAlgorithm.History.cs +++ b/Algorithm/QCAlgorithm.History.cs @@ -1298,6 +1298,14 @@ private IEnumerable GetMatchingSubscriptions(Symbol symb // Determine resolution using the data type resolution = GetResolution(symbol, resolution, dataType); + var dataMappingMode = DataMappingMode.OpenInterest; + // For futures, use the DataMappingMode of the first subscription excluding FutureUniverse types + // or default to OpenInterest if none exists + if (symbol.SecurityType == SecurityType.Future) + { + dataMappingMode = subscriptions.FirstOrDefault(e => !typeof(FutureUniverse).IsAssignableFrom(e.Type))?.DataMappingMode ?? DataMappingMode.OpenInterest; + } + // we were giving a specific type let's fetch it return new[] { new SubscriptionDataConfig( dataType, @@ -1311,7 +1319,8 @@ private IEnumerable GetMatchingSubscriptions(Symbol symb isCustom, LeanData.GetCommonTickTypeForCommonDataTypes(dataType, symbol.SecurityType), true, - UniverseSettings.GetUniverseNormalizationModeOrDefault(symbol.SecurityType))}; + UniverseSettings.GetUniverseNormalizationModeOrDefault(symbol.SecurityType), + dataMappingMode)}; } // let's try to respect already added user settings, even if resolution/type don't match, like Tick vs Bars diff --git a/Common/Data/HistoryRequestFactory.cs b/Common/Data/HistoryRequestFactory.cs index f03aaaf7b6ab..5edf9019ece8 100644 --- a/Common/Data/HistoryRequestFactory.cs +++ b/Common/Data/HistoryRequestFactory.cs @@ -101,6 +101,10 @@ public HistoryRequest CreateHistoryRequest(SubscriptionDataConfig subscription, { request.DataMappingMode = dataMappingMode.Value; } + else + { + request.DataMappingMode = subscription.DataMappingMode; + } if (dataNormalizationMode != null) { diff --git a/Tests/Algorithm/AlgorithmHistoryTests.cs b/Tests/Algorithm/AlgorithmHistoryTests.cs index 68ff1646e18c..c28350d952dc 100644 --- a/Tests/Algorithm/AlgorithmHistoryTests.cs +++ b/Tests/Algorithm/AlgorithmHistoryTests.cs @@ -3968,6 +3968,31 @@ public void DailyFuturesHistoryDoesNotIncludeSundaysAndReturnsCorrectSliceCountF } } + [Test] + public void FutureHistoryDataMappingModeUsesSecurityConfigurationWhenNotExplicit() + { + var algorithm = GetAlgorithm(new DateTime(2013, 10, 28)); + + // Configure with LastTradingDay, don't specify in history request + var future1 = algorithm.AddFuture(Futures.Indices.SP500EMini, dataNormalizationMode: DataNormalizationMode.BackwardsRatio, dataMappingMode: DataMappingMode.LastTradingDay, contractDepthOffset: 0); + + // Configure with OpenInterest, but explicitly request LastTradingDay in history + var future2 = algorithm.AddFuture(Futures.Indices.SP500EMini, dataNormalizationMode: DataNormalizationMode.BackwardsRatio, dataMappingMode: DataMappingMode.OpenInterest, contractDepthOffset: 0); + + // Both should return the same data, first one uses security configuration, second one explicitly requests LastTradingDay + var history1 = algorithm.History(future1.Symbol, new DateTime(2007, 1, 1), new DateTime(2012, 1, 1)).ToList(); + var history2 = algorithm.History(future2.Symbol, new DateTime(2007, 1, 1), new DateTime(2012, 1, 1), dataMappingMode: DataMappingMode.LastTradingDay).ToList(); + + Assert.AreEqual(history1.Count, history2.Count); + Assert.Greater(history1.Count, 0); + for (int i = 0; i < history1.Count; i++) + { + Assert.AreEqual(history1[i].NewSymbol, history2[i].NewSymbol); + Assert.AreEqual(history1[i].OldSymbol, history2[i].OldSymbol); + Assert.AreEqual(history1[i].Time, history2[i].Time); + } + } + public class CustomFundamentalTestData : BaseData { private static DateTime _currentDate; From 08a23e0ce89b0c552c8da8a8b8a20b169ecc3d6b Mon Sep 17 00:00:00 2001 From: Josue Nina Date: Thu, 8 Jan 2026 14:07:27 -0500 Subject: [PATCH 2/8] Solve review comments --- Algorithm/QCAlgorithm.History.cs | 24 +++++-- Common/Data/HistoryRequestFactory.cs | 29 ++------ Tests/Algorithm/AlgorithmHistoryTests.cs | 92 +++++++++++++++++++----- 3 files changed, 99 insertions(+), 46 deletions(-) diff --git a/Algorithm/QCAlgorithm.History.cs b/Algorithm/QCAlgorithm.History.cs index 57ccc41c2d2a..f7c5460cce42 100644 --- a/Algorithm/QCAlgorithm.History.cs +++ b/Algorithm/QCAlgorithm.History.cs @@ -1298,12 +1298,23 @@ private IEnumerable GetMatchingSubscriptions(Symbol symb // Determine resolution using the data type resolution = GetResolution(symbol, resolution, dataType); + // Default values var dataMappingMode = DataMappingMode.OpenInterest; - // For futures, use the DataMappingMode of the first subscription excluding FutureUniverse types - // or default to OpenInterest if none exists + var extendedMarketHours = UniverseSettings.ExtendedMarketHours; + var dataNormalizationMode = UniverseSettings.GetUniverseNormalizationModeOrDefault(symbol.SecurityType); + var contractDepthOffset = (uint)Math.Abs(UniverseSettings.ContractDepthOffset); + + // For futures, inherit values from existing subscriptions (excluding FutureUniverse) if (symbol.SecurityType == SecurityType.Future) { - dataMappingMode = subscriptions.FirstOrDefault(e => !typeof(FutureUniverse).IsAssignableFrom(e.Type))?.DataMappingMode ?? DataMappingMode.OpenInterest; + var existingConfig = subscriptions.FirstOrDefault(e => !typeof(FutureUniverse).IsAssignableFrom(e.Type)); + if (existingConfig != null) + { + dataMappingMode = existingConfig.DataMappingMode; + extendedMarketHours = existingConfig.ExtendedMarketHours; + dataNormalizationMode = existingConfig.DataNormalizationMode; + contractDepthOffset = existingConfig.ContractDepthOffset; + } } // we were giving a specific type let's fetch it @@ -1314,13 +1325,14 @@ private IEnumerable GetMatchingSubscriptions(Symbol symb entry.DataTimeZone, entry.ExchangeHours.TimeZone, UniverseSettings.FillForward, - UniverseSettings.ExtendedMarketHours, + extendedMarketHours, true, isCustom, LeanData.GetCommonTickTypeForCommonDataTypes(dataType, symbol.SecurityType), true, - UniverseSettings.GetUniverseNormalizationModeOrDefault(symbol.SecurityType), - dataMappingMode)}; + dataNormalizationMode, + dataMappingMode, + contractDepthOffset)}; } // let's try to respect already added user settings, even if resolution/type don't match, like Tick vs Bars diff --git a/Common/Data/HistoryRequestFactory.cs b/Common/Data/HistoryRequestFactory.cs index 5edf9019ece8..746fa44efdc6 100644 --- a/Common/Data/HistoryRequestFactory.cs +++ b/Common/Data/HistoryRequestFactory.cs @@ -92,29 +92,12 @@ public HistoryRequest CreateHistoryRequest(SubscriptionDataConfig subscription, TickType = subscription.TickType }; - if (extendedMarketHours != null) - { - request.IncludeExtendedMarketHours = extendedMarketHours.Value; - } - - if (dataMappingMode != null) - { - request.DataMappingMode = dataMappingMode.Value; - } - else - { - request.DataMappingMode = subscription.DataMappingMode; - } - - if (dataNormalizationMode != null) - { - request.DataNormalizationMode = dataNormalizationMode.Value; - } - - if (contractDepthOffset != null) - { - request.ContractDepthOffset = (uint)Math.Abs(contractDepthOffset.Value); - } + request.IncludeExtendedMarketHours = extendedMarketHours ?? subscription.ExtendedMarketHours; + request.DataMappingMode = dataMappingMode ?? subscription.DataMappingMode; + request.DataNormalizationMode = dataNormalizationMode ?? subscription.DataNormalizationMode; + request.ContractDepthOffset = contractDepthOffset != null + ? (uint)Math.Abs(contractDepthOffset.Value) + : subscription.ContractDepthOffset; return request; } diff --git a/Tests/Algorithm/AlgorithmHistoryTests.cs b/Tests/Algorithm/AlgorithmHistoryTests.cs index c28350d952dc..72e9fac5ec4d 100644 --- a/Tests/Algorithm/AlgorithmHistoryTests.cs +++ b/Tests/Algorithm/AlgorithmHistoryTests.cs @@ -3968,28 +3968,86 @@ public void DailyFuturesHistoryDoesNotIncludeSundaysAndReturnsCorrectSliceCountF } } - [Test] - public void FutureHistoryDataMappingModeUsesSecurityConfigurationWhenNotExplicit() - { - var algorithm = GetAlgorithm(new DateTime(2013, 10, 28)); + [TestCase(false)] + [TestCase(true)] + public void HistoryRequestUsesSecurityConfigOrExplicitValues(bool explicitParameters) + { + var start = new DateTime(2013, 10, 28); + var algorithm = GetAlgorithm(start); + var future = algorithm.AddFuture( + Futures.Indices.SP500EMini, + dataNormalizationMode: DataNormalizationMode.BackwardsRatio, + dataMappingMode: DataMappingMode.LastTradingDay, + contractDepthOffset: 0, + extendedMarketHours: true); + + var customTestHistoryProvider = new CustomTestHistoryProvider(); + algorithm.SetHistoryProvider(customTestHistoryProvider); + algorithm.HistoryProvider.Initialize(new HistoryProviderInitializeParameters( + null, + null, + _dataProvider, + _cacheProvider, + _mapFileProvider, + _factorFileProvider, + null, + false, + new DataPermissionManager(), + algorithm.ObjectStore, + algorithm.Settings)); - // Configure with LastTradingDay, don't specify in history request - var future1 = algorithm.AddFuture(Futures.Indices.SP500EMini, dataNormalizationMode: DataNormalizationMode.BackwardsRatio, dataMappingMode: DataMappingMode.LastTradingDay, contractDepthOffset: 0); + List history; - // Configure with OpenInterest, but explicitly request LastTradingDay in history - var future2 = algorithm.AddFuture(Futures.Indices.SP500EMini, dataNormalizationMode: DataNormalizationMode.BackwardsRatio, dataMappingMode: DataMappingMode.OpenInterest, contractDepthOffset: 0); + if (!explicitParameters) + { + history = algorithm.History( + future.Symbol, + new DateTime(2007, 1, 1), + new DateTime(2012, 1, 1)).ToList(); + } + else + { + history = algorithm.History( + future.Symbol, + new DateTime(2007, 1, 1), + new DateTime(2012, 1, 1), + dataNormalizationMode: DataNormalizationMode.Raw, + dataMappingMode: DataMappingMode.OpenInterest, + contractDepthOffset: 0, + extendedMarketHours: false).ToList(); + } + + Assert.AreEqual(1, customTestHistoryProvider.HistoryRequests.Count); + Assert.Greater(history.Count, 0); - // Both should return the same data, first one uses security configuration, second one explicitly requests LastTradingDay - var history1 = algorithm.History(future1.Symbol, new DateTime(2007, 1, 1), new DateTime(2012, 1, 1)).ToList(); - var history2 = algorithm.History(future2.Symbol, new DateTime(2007, 1, 1), new DateTime(2012, 1, 1), dataMappingMode: DataMappingMode.LastTradingDay).ToList(); + var request = customTestHistoryProvider.HistoryRequests[0]; - Assert.AreEqual(history1.Count, history2.Count); - Assert.Greater(history1.Count, 0); - for (int i = 0; i < history1.Count; i++) + if (!explicitParameters) + { + // Without explicit parameters: uses values from security configuration + Assert.AreEqual(DataNormalizationMode.BackwardsRatio, request.DataNormalizationMode); + Assert.AreEqual(DataMappingMode.LastTradingDay, request.DataMappingMode); + Assert.AreEqual(true, request.IncludeExtendedMarketHours); + Assert.AreEqual(0, request.ContractDepthOffset); + } + else + { + // With explicit parameters: uses values from history request + Assert.AreEqual(DataNormalizationMode.Raw, request.DataNormalizationMode); + Assert.AreEqual(DataMappingMode.OpenInterest, request.DataMappingMode); + Assert.AreEqual(false, request.IncludeExtendedMarketHours); + Assert.AreEqual(0, request.ContractDepthOffset); + } + } + + private class CustomTestHistoryProvider : SubscriptionDataReaderHistoryProvider + { + public List HistoryRequests { get; } = new List(); + + public override IEnumerable GetHistory(IEnumerable requests, DateTimeZone sliceTimeZone) { - Assert.AreEqual(history1[i].NewSymbol, history2[i].NewSymbol); - Assert.AreEqual(history1[i].OldSymbol, history2[i].OldSymbol); - Assert.AreEqual(history1[i].Time, history2[i].Time); + HistoryRequests.AddRange(requests); + return base.GetHistory(requests, sliceTimeZone); } } From 836464d79413e664cd300f4b51bc8c4b261c1832 Mon Sep 17 00:00:00 2001 From: Josue Nina Date: Thu, 8 Jan 2026 15:34:22 -0500 Subject: [PATCH 3/8] Make HistoryRequest inherit existing subscription configuration values generically --- Algorithm/QCAlgorithm.History.cs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/Algorithm/QCAlgorithm.History.cs b/Algorithm/QCAlgorithm.History.cs index f7c5460cce42..4d9861254c21 100644 --- a/Algorithm/QCAlgorithm.History.cs +++ b/Algorithm/QCAlgorithm.History.cs @@ -1304,17 +1304,14 @@ private IEnumerable GetMatchingSubscriptions(Symbol symb var dataNormalizationMode = UniverseSettings.GetUniverseNormalizationModeOrDefault(symbol.SecurityType); var contractDepthOffset = (uint)Math.Abs(UniverseSettings.ContractDepthOffset); - // For futures, inherit values from existing subscriptions (excluding FutureUniverse) - if (symbol.SecurityType == SecurityType.Future) + // Inherit values from existing subscriptions (excluding FutureUniverse) + var existingConfig = subscriptions.FirstOrDefault(e => !typeof(FutureUniverse).IsAssignableFrom(e.Type)); + if (existingConfig != null) { - var existingConfig = subscriptions.FirstOrDefault(e => !typeof(FutureUniverse).IsAssignableFrom(e.Type)); - if (existingConfig != null) - { - dataMappingMode = existingConfig.DataMappingMode; - extendedMarketHours = existingConfig.ExtendedMarketHours; - dataNormalizationMode = existingConfig.DataNormalizationMode; - contractDepthOffset = existingConfig.ContractDepthOffset; - } + dataMappingMode = existingConfig.DataMappingMode; + extendedMarketHours = existingConfig.ExtendedMarketHours; + dataNormalizationMode = existingConfig.DataNormalizationMode; + contractDepthOffset = existingConfig.ContractDepthOffset; } // we were giving a specific type let's fetch it From e912b772d77d034baf9b681a1312e242c7259b87 Mon Sep 17 00:00:00 2001 From: Josue Nina Date: Fri, 9 Jan 2026 03:27:35 -0500 Subject: [PATCH 4/8] Exclude any class that inherits from BaseChainUniverseData --- Algorithm/QCAlgorithm.History.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Algorithm/QCAlgorithm.History.cs b/Algorithm/QCAlgorithm.History.cs index 4d9861254c21..bd8d43bf86d3 100644 --- a/Algorithm/QCAlgorithm.History.cs +++ b/Algorithm/QCAlgorithm.History.cs @@ -1304,8 +1304,8 @@ private IEnumerable GetMatchingSubscriptions(Symbol symb var dataNormalizationMode = UniverseSettings.GetUniverseNormalizationModeOrDefault(symbol.SecurityType); var contractDepthOffset = (uint)Math.Abs(UniverseSettings.ContractDepthOffset); - // Inherit values from existing subscriptions (excluding FutureUniverse) - var existingConfig = subscriptions.FirstOrDefault(e => !typeof(FutureUniverse).IsAssignableFrom(e.Type)); + // Inherit values from existing subscriptions + var existingConfig = subscriptions.FirstOrDefault(e => !typeof(BaseChainUniverseData).IsAssignableFrom(e.Type)); if (existingConfig != null) { dataMappingMode = existingConfig.DataMappingMode; From ab1338d762d884d50f7a3cbbf14c0058abc5d464 Mon Sep 17 00:00:00 2001 From: Josue Nina Date: Fri, 9 Jan 2026 09:47:28 -0500 Subject: [PATCH 5/8] Reuse existing filter for user configuration --- Algorithm/QCAlgorithm.History.cs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/Algorithm/QCAlgorithm.History.cs b/Algorithm/QCAlgorithm.History.cs index bd8d43bf86d3..1b8758eda624 100644 --- a/Algorithm/QCAlgorithm.History.cs +++ b/Algorithm/QCAlgorithm.History.cs @@ -1283,6 +1283,9 @@ private IEnumerable GetMatchingSubscriptions(Symbol symb } else { + // let's try to respect already added user settings, even if resolution/type don't match, like Tick vs Bars + var userConfigIfAny = subscriptions.FirstOrDefault(x => LeanData.IsCommonLeanDataType(x.Type) && !x.IsInternalFeed); + // If type was specified and not a lean data type and also not abstract, we create a new subscription if (type != null && !LeanData.IsCommonLeanDataType(type) && !type.IsAbstract) { @@ -1305,13 +1308,12 @@ private IEnumerable GetMatchingSubscriptions(Symbol symb var contractDepthOffset = (uint)Math.Abs(UniverseSettings.ContractDepthOffset); // Inherit values from existing subscriptions - var existingConfig = subscriptions.FirstOrDefault(e => !typeof(BaseChainUniverseData).IsAssignableFrom(e.Type)); - if (existingConfig != null) + if (userConfigIfAny != null) { - dataMappingMode = existingConfig.DataMappingMode; - extendedMarketHours = existingConfig.ExtendedMarketHours; - dataNormalizationMode = existingConfig.DataNormalizationMode; - contractDepthOffset = existingConfig.ContractDepthOffset; + dataMappingMode = userConfigIfAny.DataMappingMode; + extendedMarketHours = userConfigIfAny.ExtendedMarketHours; + dataNormalizationMode = userConfigIfAny.DataNormalizationMode; + contractDepthOffset = userConfigIfAny.ContractDepthOffset; } // we were giving a specific type let's fetch it @@ -1332,9 +1334,6 @@ private IEnumerable GetMatchingSubscriptions(Symbol symb contractDepthOffset)}; } - // let's try to respect already added user settings, even if resolution/type don't match, like Tick vs Bars - var userConfigIfAny = subscriptions.FirstOrDefault(x => LeanData.IsCommonLeanDataType(x.Type) && !x.IsInternalFeed); - var res = GetResolution(symbol, resolution, type); return SubscriptionManager .LookupSubscriptionConfigDataTypes(symbol.SecurityType, res, From 5e31dee5010bf07885eb55e32a5b8d267ca66466 Mon Sep 17 00:00:00 2001 From: Josue Nina Date: Fri, 9 Jan 2026 11:46:24 -0500 Subject: [PATCH 6/8] Solve review comments --- Algorithm/QCAlgorithm.History.cs | 28 +++++++++------------------- Common/Data/HistoryRequestFactory.cs | 25 +++++++++++++++++++------ 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/Algorithm/QCAlgorithm.History.cs b/Algorithm/QCAlgorithm.History.cs index 1b8758eda624..209a9f06352b 100644 --- a/Algorithm/QCAlgorithm.History.cs +++ b/Algorithm/QCAlgorithm.History.cs @@ -1286,6 +1286,11 @@ private IEnumerable GetMatchingSubscriptions(Symbol symb // let's try to respect already added user settings, even if resolution/type don't match, like Tick vs Bars var userConfigIfAny = subscriptions.FirstOrDefault(x => LeanData.IsCommonLeanDataType(x.Type) && !x.IsInternalFeed); + // Inherit values from existing subscriptions or use defaults + var extendedMarketHours = userConfigIfAny?.ExtendedMarketHours ?? UniverseSettings.ExtendedMarketHours; + var dataNormalizationMode = userConfigIfAny?.DataNormalizationMode ?? UniverseSettings.GetUniverseNormalizationModeOrDefault(symbol.SecurityType); + var contractDepthOffset = userConfigIfAny?.ContractDepthOffset ?? (uint)Math.Abs(UniverseSettings.ContractDepthOffset); + // If type was specified and not a lean data type and also not abstract, we create a new subscription if (type != null && !LeanData.IsCommonLeanDataType(type) && !type.IsAbstract) { @@ -1301,21 +1306,6 @@ private IEnumerable GetMatchingSubscriptions(Symbol symb // Determine resolution using the data type resolution = GetResolution(symbol, resolution, dataType); - // Default values - var dataMappingMode = DataMappingMode.OpenInterest; - var extendedMarketHours = UniverseSettings.ExtendedMarketHours; - var dataNormalizationMode = UniverseSettings.GetUniverseNormalizationModeOrDefault(symbol.SecurityType); - var contractDepthOffset = (uint)Math.Abs(UniverseSettings.ContractDepthOffset); - - // Inherit values from existing subscriptions - if (userConfigIfAny != null) - { - dataMappingMode = userConfigIfAny.DataMappingMode; - extendedMarketHours = userConfigIfAny.ExtendedMarketHours; - dataNormalizationMode = userConfigIfAny.DataNormalizationMode; - contractDepthOffset = userConfigIfAny.ContractDepthOffset; - } - // we were giving a specific type let's fetch it return new[] { new SubscriptionDataConfig( dataType, @@ -1330,7 +1320,7 @@ private IEnumerable GetMatchingSubscriptions(Symbol symb LeanData.GetCommonTickTypeForCommonDataTypes(dataType, symbol.SecurityType), true, dataNormalizationMode, - dataMappingMode, + userConfigIfAny?.DataMappingMode ?? DataMappingMode.OpenInterest, contractDepthOffset)}; } @@ -1354,14 +1344,14 @@ private IEnumerable GetMatchingSubscriptions(Symbol symb entry.DataTimeZone, entry.ExchangeHours.TimeZone, UniverseSettings.FillForward, - userConfigIfAny?.ExtendedMarketHours ?? UniverseSettings.ExtendedMarketHours, + extendedMarketHours, true, false, x.Item2, true, - userConfigIfAny?.DataNormalizationMode ?? UniverseSettings.GetUniverseNormalizationModeOrDefault(symbol.SecurityType), + dataNormalizationMode, userConfigIfAny?.DataMappingMode ?? UniverseSettings.GetUniverseMappingModeOrDefault(symbol.SecurityType, symbol.ID.Market), - userConfigIfAny?.ContractDepthOffset ?? (uint)Math.Abs(UniverseSettings.ContractDepthOffset)); + contractDepthOffset); }) // lets make sure to respect the order of the data types, if used on a history request will affect outcome when using pushthrough for example .OrderByDescending(config => GetTickTypeOrder(config.SecurityType, config.TickType)); diff --git a/Common/Data/HistoryRequestFactory.cs b/Common/Data/HistoryRequestFactory.cs index 746fa44efdc6..f03aaaf7b6ab 100644 --- a/Common/Data/HistoryRequestFactory.cs +++ b/Common/Data/HistoryRequestFactory.cs @@ -92,12 +92,25 @@ public HistoryRequest CreateHistoryRequest(SubscriptionDataConfig subscription, TickType = subscription.TickType }; - request.IncludeExtendedMarketHours = extendedMarketHours ?? subscription.ExtendedMarketHours; - request.DataMappingMode = dataMappingMode ?? subscription.DataMappingMode; - request.DataNormalizationMode = dataNormalizationMode ?? subscription.DataNormalizationMode; - request.ContractDepthOffset = contractDepthOffset != null - ? (uint)Math.Abs(contractDepthOffset.Value) - : subscription.ContractDepthOffset; + if (extendedMarketHours != null) + { + request.IncludeExtendedMarketHours = extendedMarketHours.Value; + } + + if (dataMappingMode != null) + { + request.DataMappingMode = dataMappingMode.Value; + } + + if (dataNormalizationMode != null) + { + request.DataNormalizationMode = dataNormalizationMode.Value; + } + + if (contractDepthOffset != null) + { + request.ContractDepthOffset = (uint)Math.Abs(contractDepthOffset.Value); + } return request; } From fc6c68ea42bc1a92500cce113b2c98c19a3e2294 Mon Sep 17 00:00:00 2001 From: Josue Nina Date: Fri, 9 Jan 2026 11:58:49 -0500 Subject: [PATCH 7/8] Normalize DataMappingMode --- Algorithm/QCAlgorithm.History.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Algorithm/QCAlgorithm.History.cs b/Algorithm/QCAlgorithm.History.cs index 209a9f06352b..e5cf06d18314 100644 --- a/Algorithm/QCAlgorithm.History.cs +++ b/Algorithm/QCAlgorithm.History.cs @@ -1289,6 +1289,7 @@ private IEnumerable GetMatchingSubscriptions(Symbol symb // Inherit values from existing subscriptions or use defaults var extendedMarketHours = userConfigIfAny?.ExtendedMarketHours ?? UniverseSettings.ExtendedMarketHours; var dataNormalizationMode = userConfigIfAny?.DataNormalizationMode ?? UniverseSettings.GetUniverseNormalizationModeOrDefault(symbol.SecurityType); + var dataMappingMode = UniverseSettings.GetUniverseMappingModeOrDefault(symbol.SecurityType, symbol.ID.Market); var contractDepthOffset = userConfigIfAny?.ContractDepthOffset ?? (uint)Math.Abs(UniverseSettings.ContractDepthOffset); // If type was specified and not a lean data type and also not abstract, we create a new subscription @@ -1320,7 +1321,7 @@ private IEnumerable GetMatchingSubscriptions(Symbol symb LeanData.GetCommonTickTypeForCommonDataTypes(dataType, symbol.SecurityType), true, dataNormalizationMode, - userConfigIfAny?.DataMappingMode ?? DataMappingMode.OpenInterest, + dataMappingMode, contractDepthOffset)}; } @@ -1350,7 +1351,7 @@ private IEnumerable GetMatchingSubscriptions(Symbol symb x.Item2, true, dataNormalizationMode, - userConfigIfAny?.DataMappingMode ?? UniverseSettings.GetUniverseMappingModeOrDefault(symbol.SecurityType, symbol.ID.Market), + dataMappingMode, contractDepthOffset); }) // lets make sure to respect the order of the data types, if used on a history request will affect outcome when using pushthrough for example From ac7798ec2d7faf6fa0195f7dcffde4d173c23181 Mon Sep 17 00:00:00 2001 From: Josue Nina Date: Fri, 9 Jan 2026 12:09:22 -0500 Subject: [PATCH 8/8] Minor fix --- Algorithm/QCAlgorithm.History.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Algorithm/QCAlgorithm.History.cs b/Algorithm/QCAlgorithm.History.cs index e5cf06d18314..41caa59528cc 100644 --- a/Algorithm/QCAlgorithm.History.cs +++ b/Algorithm/QCAlgorithm.History.cs @@ -1289,7 +1289,7 @@ private IEnumerable GetMatchingSubscriptions(Symbol symb // Inherit values from existing subscriptions or use defaults var extendedMarketHours = userConfigIfAny?.ExtendedMarketHours ?? UniverseSettings.ExtendedMarketHours; var dataNormalizationMode = userConfigIfAny?.DataNormalizationMode ?? UniverseSettings.GetUniverseNormalizationModeOrDefault(symbol.SecurityType); - var dataMappingMode = UniverseSettings.GetUniverseMappingModeOrDefault(symbol.SecurityType, symbol.ID.Market); + var dataMappingMode = userConfigIfAny?.DataMappingMode ?? UniverseSettings.GetUniverseMappingModeOrDefault(symbol.SecurityType, symbol.ID.Market); var contractDepthOffset = userConfigIfAny?.ContractDepthOffset ?? (uint)Math.Abs(UniverseSettings.ContractDepthOffset); // If type was specified and not a lean data type and also not abstract, we create a new subscription