Lean  $LEAN_TAG$
PriceScaleFactorEnumerator.cs
1 /*
2  * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
3  * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  *
15 */
16 
17 using System;
18 using System.Collections;
19 using System.Collections.Generic;
20 using QuantConnect.Data;
23 
25 {
26  /// <summary>
27  /// This enumerator will update the <see cref="SubscriptionDataConfig.PriceScaleFactor"/> when required
28  /// and adjust the raw <see cref="BaseData"/> prices based on the provided <see cref="SubscriptionDataConfig"/>.
29  /// Assumes the prices of the provided <see cref="IEnumerator"/> are in raw mode.
30  /// </summary>
31  public class PriceScaleFactorEnumerator : IEnumerator<BaseData>
32  {
33  private readonly IEnumerator<BaseData> _rawDataEnumerator;
34  private readonly SubscriptionDataConfig _config;
35  private readonly IFactorFileProvider _factorFileProvider;
36  private DateTime _nextTradableDate;
37  private IFactorProvider _factorFile;
38  private bool _liveMode;
39  private DateTime? _endDate;
40 
41  /// <summary>
42  /// Explicit interface implementation for <see cref="Current"/>
43  /// </summary>
44  object IEnumerator.Current => Current;
45 
46  /// <summary>
47  /// Last read <see cref="BaseData"/> object from this type and source
48  /// </summary>
49  public BaseData Current
50  {
51  get;
52  private set;
53  }
54 
55  /// <summary>
56  /// Creates a new instance of the <see cref="PriceScaleFactorEnumerator"/>.
57  /// </summary>
58  /// <param name="rawDataEnumerator">The underlying raw data enumerator</param>
59  /// <param name="config">The <see cref="SubscriptionDataConfig"/> to enumerate for.
60  /// Will determine the <see cref="DataNormalizationMode"/> to use.</param>
61  /// <param name="factorFileProvider">The <see cref="IFactorFileProvider"/> instance to use</param>
62  /// <param name="liveMode">True, is this is a live mode data stream</param>
63  /// <param name="endDate">The enumerator end date</param>
64  /// <remarks>
65  /// For <see cref="DataNormalizationMode.ScaledRaw"/> normalization mode,
66  /// the prices are scaled to the prices on the <paramref name="endDate"/>
67  /// </remarks>
69  IEnumerator<BaseData> rawDataEnumerator,
71  IFactorFileProvider factorFileProvider,
72  bool liveMode = false,
73  DateTime? endDate = null)
74  {
75  _config = config;
76  _liveMode = liveMode;
77  _nextTradableDate = DateTime.MinValue;
78  _rawDataEnumerator = rawDataEnumerator;
79  _factorFileProvider = factorFileProvider;
80  _endDate = endDate;
81  }
82 
83  /// <summary>
84  /// Dispose of the underlying enumerator.
85  /// </summary>
86  public void Dispose()
87  {
88  _rawDataEnumerator.Dispose();
89  }
90 
91  /// <summary>
92  /// Advances the enumerator to the next element of the collection.
93  /// </summary>
94  /// <returns>
95  /// True if the enumerator was successfully advanced to the next element;
96  /// False if the enumerator has passed the end of the collection.
97  /// </returns>
98  public bool MoveNext()
99  {
100  var underlyingReturnValue = _rawDataEnumerator.MoveNext();
101  Current = _rawDataEnumerator.Current;
102 
103  if (underlyingReturnValue
104  && Current != null
105  && _factorFileProvider != null
106  && _config.DataNormalizationMode != DataNormalizationMode.Raw)
107  {
108  var priceScaleFrontier = Current.GetUpdatePriceScaleFrontier();
109  if (priceScaleFrontier >= _nextTradableDate)
110  {
111  _factorFile = _factorFileProvider.Get(_config.Symbol);
112  _config.PriceScaleFactor = _factorFile.GetPriceScale(priceScaleFrontier.Date, _config.DataNormalizationMode, _config.ContractDepthOffset, _config.DataMappingMode, _endDate);
113 
114  // update factor files every day
115  _nextTradableDate = priceScaleFrontier.Date.AddDays(1);
116  if (_liveMode)
117  {
118  // in live trading we add a offset to make sure new factor files are available
119  _nextTradableDate = _nextTradableDate.Add(Time.LiveAuxiliaryDataOffset);
120  }
121  }
122 
123  Current = Current.Normalize(_config.PriceScaleFactor, _config.DataNormalizationMode, _config.SumOfDividends);
124  }
125 
126  return underlyingReturnValue;
127  }
128 
129  /// <summary>
130  /// Reset the IEnumeration
131  /// </summary>
132  /// <remarks>Not used</remarks>
133  public void Reset()
134  {
135  throw new NotImplementedException("Reset method not implemented. Assumes loop will only be used once.");
136  }
137  }
138 }