Lean  $LEAN_TAG$
PriceScalingExtensions.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.Linq;
19 using System.Collections.Generic;
20 
22 {
23  /// <summary>
24  /// Set of helper methods for factor files and price scaling operations
25  /// </summary>
26  public static class PriceScalingExtensions
27  {
28  /// <summary>
29  /// Resolves the price scale for a date given a factor file and required settings
30  /// </summary>
31  /// <param name="factorFile">The factor file to use</param>
32  /// <param name="dateTime">The date for the price scale lookup</param>
33  /// <param name="normalizationMode">The price normalization mode requested</param>
34  /// <param name="contractOffset">The contract offset, useful for continuous contracts</param>
35  /// <param name="dataMappingMode">The data mapping mode used, useful for continuous contracts</param>
36  /// <param name="endDateTime">The reference end date for scaling prices.</param>
37  /// <returns>The price scale to use</returns>
38  /// <exception cref="ArgumentException">
39  /// If <paramref name="normalizationMode"/> is <see cref="DataNormalizationMode.ScaledRaw"/> and <paramref name="endDateTime"/> is null
40  /// </exception>
41  /// <remarks>
42  /// For <see cref="DataNormalizationMode.ScaledRaw"/> normalization mode,
43  /// the prices are scaled to the prices on the <paramref name="endDateTime"/>
44  /// </remarks>
45  public static decimal GetPriceScale(
46  this IFactorProvider factorFile,
47  DateTime dateTime,
48  DataNormalizationMode normalizationMode,
49  uint contractOffset = 0,
50  DataMappingMode? dataMappingMode = null,
51  DateTime? endDateTime = null
52  )
53  {
54  if (factorFile == null)
55  {
56  if (normalizationMode is DataNormalizationMode.BackwardsPanamaCanal or DataNormalizationMode.ForwardPanamaCanal)
57  {
58  return 0;
59  }
60  return 1;
61  }
62 
63  var endDateTimeFactor = 1m;
64  if (normalizationMode == DataNormalizationMode.ScaledRaw)
65  {
66  if (endDateTime == null)
67  {
68  throw new ArgumentException(
69  $"{nameof(DataNormalizationMode.ScaledRaw)} normalization mode requires an end date for price scaling.");
70  }
71 
72  // For ScaledRaw, we need to get the price scale at the end date to adjust prices to that date instead of "today"
73  endDateTimeFactor = factorFile.GetPriceFactor(endDateTime.Value, normalizationMode, dataMappingMode, contractOffset);
74  }
75 
76  return factorFile.GetPriceFactor(dateTime, normalizationMode, dataMappingMode, contractOffset) / endDateTimeFactor;
77  }
78 
79  /// <summary>
80  /// Determines the symbol to use to fetch it's factor file
81  /// </summary>
82  /// <remarks>This is useful for futures where the symbol to use is the canonical</remarks>
83  public static Symbol GetFactorFileSymbol(this Symbol symbol)
84  {
85  return symbol.SecurityType == SecurityType.Future ? symbol.Canonical : symbol;
86  }
87 
88  /// <summary>
89  /// Helper method to return an empty factor file
90  /// </summary>
91  public static IFactorProvider GetEmptyFactorFile(this Symbol symbol)
92  {
93  if (symbol.SecurityType == SecurityType.Future)
94  {
95  return new MappingContractFactorProvider(symbol.ID.Symbol, Enumerable.Empty<MappingContractFactorRow>());
96  }
97  return new CorporateFactorProvider(symbol.ID.Symbol, Enumerable.Empty<CorporateFactorRow>());
98  }
99 
100  /// <summary>
101  /// Parses the contents as a FactorFile, if error returns a new empty factor file
102  /// </summary>
103  public static IFactorProvider SafeRead(string permtick, IEnumerable<string> contents, SecurityType securityType)
104  {
105  try
106  {
107  DateTime? minimumDate;
108 
109  contents = contents.Distinct();
110 
111  if (securityType == SecurityType.Future)
112  {
113  return new MappingContractFactorProvider(permtick, MappingContractFactorRow.Parse(contents, out minimumDate), minimumDate);
114  }
115  // FactorFileRow.Parse handles entries with 'inf' and exponential notation and provides the associated minimum tradeable date for these cases
116  // previously these cases were not handled causing an exception and returning an empty factor file
117  return new CorporateFactorProvider(permtick, CorporateFactorRow.Parse(contents, out minimumDate), minimumDate);
118  }
119  catch (Exception e)
120  {
121  if (securityType == SecurityType.Future)
122  {
123  return new MappingContractFactorProvider(permtick, Enumerable.Empty<MappingContractFactorRow>());
124  }
125  return new CorporateFactorProvider(permtick, Enumerable.Empty<CorporateFactorRow>());
126  }
127  }
128  }
129 }