Lean  $LEAN_TAG$
TimeSeriesIndicator.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 using System.Collections.Generic;
17 using System.Linq;
18 
20 {
21  /// <summary>
22  /// The base class for any Time Series-type indicator, containing methods common to most of such models.
23  /// </summary>
24  public abstract class TimeSeriesIndicator : IndicatorBase<IndicatorDataPoint>, IIndicatorWarmUpPeriodProvider
25  {
26  /// <summary>
27  /// "Integration" constants
28  /// </summary>
29  protected double[] _diffHeads { get; set; }
30 
31  /// <summary>
32  /// Required period, in data points, for the indicator to be ready and fully initialized.
33  /// </summary>
34  public abstract int WarmUpPeriod { get; }
35 
36  /// <summary>
37  /// A constructor for a basic Time Series indicator.
38  /// </summary>
39  /// <param name="name">The name of this indicator</param>
40  protected TimeSeriesIndicator(string name)
41  : base(name)
42  {
43  }
44 
45  /// <summary>
46  /// Differences a time series d times.
47  /// </summary>
48  /// <param name="series">Series to difference</param>
49  /// <param name="d">The differencing order</param>
50  /// <param name="diffHeads">"Integration" constants</param>
51  public static double[] DifferenceSeries(int d, double[] series, out double[] diffHeads)
52  {
53  diffHeads = new double[d];
54  if (d == 0)
55  {
56  return null;
57  }
58 
59  var localSeries = series;
60  for (var j = 1; j <= d; j++)
61  {
62  var result = new double[localSeries.Length - 1];
63  diffHeads[j - 1] = localSeries.Last();
64 
65  for (var i = 0; i <= localSeries.Length - 2; i++)
66  {
67  result[i] = localSeries[i] - localSeries[i + 1];
68  }
69 
70  localSeries = result;
71  }
72 
73  return localSeries;
74  }
75 
76  /// <summary>
77  /// Undoes the differencing of a time series which has been differenced using <see cref="DifferenceSeries" />.
78  /// https://github.com/statsmodels/statsmodels/blob/04f00006a7aeb1c93d6894caa420698400da6c33/statsmodels/tsa/tsatools.py#L758
79  /// </summary>
80  /// <param name="series">Series to un-difference</param>
81  /// <param name="diffHeads">Series of "integration" constants for un-differencing</param>
82  public static double[] InverseDifferencedSeries(double[] series, double[] diffHeads)
83  {
84  var localDiffs = new Stack<double>(diffHeads.Reverse());
85  var localSeries = series.ToList();
86  while (localDiffs.Count > 0)
87  {
88  var first = localDiffs.Pop();
89  localSeries.Add(first);
90  localSeries = CumulativeSum(localSeries, true);
91  }
92 
93  return localSeries.ToArray();
94  }
95 
96  /// <summary>
97  /// Returns an array of lagged series for each of {1,...,p} lags.
98  /// </summary>
99  /// <param name="p">Max lag order</param>
100  /// <param name="series">Series to calculate the lags of</param>
101  /// <param name="includeT">Whether or not to include t with its lags in the output array</param>
102  /// <returns>A list such that index i returns the series for i+1 lags</returns>
103  public static double[][] LaggedSeries(int p, double[] series, bool includeT = false)
104  {
105  // P-defined lagging - for each X_t, return double[] of the relevant lagged terms
106  var toArray = new List<double[]>();
107  for (var t = p; t < series.Length; t++)
108  {
109  var localLag = new List<double>();
110  for (var j = includeT ? 0 : 1; j <= p; j++)
111  {
112  localLag.Add(series[t - j]);
113  }
114 
115  toArray.Add(localLag.ToArray());
116  }
117 
118  return toArray.ToArray();
119  }
120 
121  /// <summary>
122  /// Returns a series where each spot is taken by the cumulative sum of all points up to and including
123  /// the value at that spot in the original series.
124  /// </summary>
125  /// <param name="series">Series to cumulatively sum over.</param>
126  /// <param name="reverse">Whether to reverse the series before applying the cumulative sum.</param>
127  /// <returns>Cumulatively summed series.</returns>
128  public static List<double> CumulativeSum(List<double> series, bool reverse = false)
129  {
130  var localSeries = series;
131  if (reverse)
132  {
133  localSeries.Reverse(); // For top-down
134  }
135 
136  var sums = 0d;
137  var outSeries = new List<double>();
138  foreach (var val in localSeries)
139  {
140  sums += val;
141  outSeries.Add(sums);
142  }
143 
144  if (reverse)
145  {
146  outSeries.Reverse(); // Return to original order
147  }
148 
149  return outSeries;
150  }
151  }
152 }