Files
quantconnect--lean/Engine/DataFeeds/Enumerators/PriceScaleFactorEnumerator.cs
T
2026-07-13 13:02:50 +08:00

139 lines
5.6 KiB
C#

/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
using System.Collections;
using System.Collections.Generic;
using QuantConnect.Data;
using QuantConnect.Data.Auxiliary;
using QuantConnect.Interfaces;
namespace QuantConnect.Lean.Engine.DataFeeds.Enumerators
{
/// <summary>
/// This enumerator will update the <see cref="SubscriptionDataConfig.PriceScaleFactor"/> when required
/// and adjust the raw <see cref="BaseData"/> prices based on the provided <see cref="SubscriptionDataConfig"/>.
/// Assumes the prices of the provided <see cref="IEnumerator"/> are in raw mode.
/// </summary>
public class PriceScaleFactorEnumerator : IEnumerator<BaseData>
{
private readonly IEnumerator<BaseData> _rawDataEnumerator;
private readonly SubscriptionDataConfig _config;
private readonly IFactorFileProvider _factorFileProvider;
private DateTime _nextTradableDate;
private IFactorProvider _factorFile;
private bool _liveMode;
private DateTime? _endDate;
/// <summary>
/// Explicit interface implementation for <see cref="Current"/>
/// </summary>
object IEnumerator.Current => Current;
/// <summary>
/// Last read <see cref="BaseData"/> object from this type and source
/// </summary>
public BaseData Current
{
get;
private set;
}
/// <summary>
/// Creates a new instance of the <see cref="PriceScaleFactorEnumerator"/>.
/// </summary>
/// <param name="rawDataEnumerator">The underlying raw data enumerator</param>
/// <param name="config">The <see cref="SubscriptionDataConfig"/> to enumerate for.
/// Will determine the <see cref="DataNormalizationMode"/> to use.</param>
/// <param name="factorFileProvider">The <see cref="IFactorFileProvider"/> instance to use</param>
/// <param name="liveMode">True, is this is a live mode data stream</param>
/// <param name="endDate">The enumerator end date</param>
/// <remarks>
/// For <see cref="DataNormalizationMode.ScaledRaw"/> normalization mode,
/// the prices are scaled to the prices on the <paramref name="endDate"/>
/// </remarks>
public PriceScaleFactorEnumerator(
IEnumerator<BaseData> rawDataEnumerator,
SubscriptionDataConfig config,
IFactorFileProvider factorFileProvider,
bool liveMode = false,
DateTime? endDate = null)
{
_config = config;
_liveMode = liveMode;
_nextTradableDate = DateTime.MinValue;
_rawDataEnumerator = rawDataEnumerator;
_factorFileProvider = factorFileProvider;
_endDate = endDate;
}
/// <summary>
/// Dispose of the underlying enumerator.
/// </summary>
public void Dispose()
{
_rawDataEnumerator.Dispose();
}
/// <summary>
/// Advances the enumerator to the next element of the collection.
/// </summary>
/// <returns>
/// True if the enumerator was successfully advanced to the next element;
/// False if the enumerator has passed the end of the collection.
/// </returns>
public bool MoveNext()
{
var underlyingReturnValue = _rawDataEnumerator.MoveNext();
Current = _rawDataEnumerator.Current;
if (underlyingReturnValue
&& Current != null
&& _factorFileProvider != null
&& _config.DataNormalizationMode != DataNormalizationMode.Raw)
{
var priceScaleFrontier = Current.GetUpdatePriceScaleFrontier();
if (priceScaleFrontier >= _nextTradableDate)
{
_factorFile = _factorFileProvider.Get(_config.Symbol);
_config.PriceScaleFactor = _factorFile.GetPriceScale(priceScaleFrontier.Date, _config.DataNormalizationMode, _config.ContractDepthOffset, _config.DataMappingMode, _endDate);
// update factor files every day
_nextTradableDate = priceScaleFrontier.Date.AddDays(1);
if (_liveMode)
{
// in live trading we add a offset to make sure new factor files are available
_nextTradableDate = _nextTradableDate.Add(Time.LiveAuxiliaryDataOffset);
}
}
Current = Current.Normalize(_config.PriceScaleFactor, _config.DataNormalizationMode, _config.SumOfDividends);
}
return underlyingReturnValue;
}
/// <summary>
/// Reset the IEnumeration
/// </summary>
/// <remarks>Not used</remarks>
public void Reset()
{
throw new NotImplementedException("Reset method not implemented. Assumes loop will only be used once.");
}
}
}