Lean  $LEAN_TAG$
Correlation.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;
18 
20 {
21  /// <summary>
22  /// The Correlation Indicator is a valuable tool in technical analysis, designed to quantify the degree of
23  /// relationship between the price movements of a target security (e.g., a stock or ETF) and a reference
24  /// market index. It measures how closely the target’s price changes are aligned with the fluctuations of
25  /// the index over a specific period of time, providing insights into the target’s susceptibility to market
26  /// movements.
27  /// A positive correlation indicates that the target tends to move in the same direction as the market index,
28  /// while a negative correlation suggests an inverse relationship. A correlation close to 0 implies a weak or
29  /// no linear relationship.
30  /// Commonly, the SPX index is employed as the benchmark for the overall market when calculating correlation,
31  /// ensuring a consistent and reliable reference point. This helps traders and investors make informed decisions
32  /// regarding the risk and behavior of the target security in relation to market trends.
33  /// </summary>
35  {
36  /// <summary>
37  /// RollingWindow to store the data points of the target symbol
38  /// </summary>
39  private readonly RollingWindow<double> _targetDataPoints;
40 
41  /// <summary>
42  /// RollingWindow to store the data points of the reference symbol
43  /// </summary>
44  private readonly RollingWindow<double> _referenceDataPoints;
45 
46  /// <summary>
47  /// Correlation of the target used in relation with the reference
48  /// </summary>
49  private decimal _correlation;
50 
51  /// <summary>
52  /// Period required for calcualte correlation
53  /// </summary>
54  private readonly decimal _period;
55 
56  /// <summary>
57  /// Correlation type
58  /// </summary>
59  private readonly CorrelationType _correlationType;
60 
61  /// <summary>
62  /// Symbol of the reference used
63  /// </summary>
64  private readonly Symbol _referenceSymbol;
65 
66  /// <summary>
67  /// Symbol of the target used
68  /// </summary>
69  private readonly Symbol _targetSymbol;
70 
71  /// <summary>
72  /// Required period, in data points, for the indicator to be ready and fully initialized.
73  /// </summary>
74  public int WarmUpPeriod { get; private set; }
75 
76  /// <summary>
77  /// Gets a flag indicating when the indicator is ready and fully initialized
78  /// </summary>
79  public override bool IsReady => _targetDataPoints.Samples >= WarmUpPeriod && _referenceDataPoints.Samples >= WarmUpPeriod;
80 
81  /// <summary>
82  /// Creates a new Correlation indicator with the specified name, target, reference,
83  /// and period values
84  /// </summary>
85  /// <param name="name">The name of this indicator</param>
86  /// <param name="targetSymbol">The target symbol of this indicator</param>
87  /// <param name="period">The period of this indicator</param>
88  /// <param name="referenceSymbol">The reference symbol of this indicator</param>
89  /// <param name="correlationType">Correlation type</param>
90  public Correlation(string name, Symbol targetSymbol, Symbol referenceSymbol, int period, CorrelationType correlationType = CorrelationType.Pearson)
91  : base(name)
92  {
93  // Assert the period is greater than two, otherwise the correlation can not be computed
94  if (period < 2)
95  {
96  throw new ArgumentException($"Period parameter for Correlation indicator must be greater than 2 but was {period}");
97  }
98 
99  WarmUpPeriod = period + 1;
100  _period = period;
101 
102  _referenceSymbol = referenceSymbol;
103  _targetSymbol = targetSymbol;
104 
105  _correlationType = correlationType;
106 
107  _targetDataPoints = new RollingWindow<double>(period);
108  _referenceDataPoints = new RollingWindow<double>(period);
109 
110  }
111 
112  /// <summary>
113  /// Creates a new Correlation indicator with the specified target, reference,
114  /// and period values
115  /// </summary>
116  /// <param name="targetSymbol">The target symbol of this indicator</param>
117  /// <param name="period">The period of this indicator</param>
118  /// <param name="referenceSymbol">The reference symbol of this indicator</param>
119  /// <param name="correlationType">Correlation type</param>
120  public Correlation(Symbol targetSymbol, Symbol referenceSymbol, int period, CorrelationType correlationType = CorrelationType.Pearson)
121  : this($"Correlation({period})", targetSymbol, referenceSymbol, period, correlationType)
122  {
123  }
124 
125  /// <summary>
126  /// Computes the next value for this indicator from the given state.
127  ///
128  /// As this indicator is receiving data points from two different symbols,
129  /// it's going to compute the next value when the amount of data points
130  /// of each of them is the same. Otherwise, it will return the last correlation
131  /// value computed
132  /// </summary>
133  /// <param name="input">The input value of this indicator on this time step.
134  /// It can be either from the target or the reference symbol</param>
135  /// <returns>The correlation value of the target used in relation with the reference</returns>
136  protected override decimal ComputeNextValue(IBaseDataBar input)
137  {
138  var inputSymbol = input.Symbol;
139  if (inputSymbol == _targetSymbol)
140  {
141  _targetDataPoints.Add((double)input.Value);
142  }
143  else if (inputSymbol == _referenceSymbol)
144  {
145  _referenceDataPoints.Add((double)input.Value);
146  }
147  else
148  {
149  throw new ArgumentException("The given symbol was not target or reference symbol");
150  }
151  ComputeCorrelation();
152  return _correlation;
153  }
154 
155  /// <summary>
156  /// Computes the correlation value usuing symbols values
157  /// correlation values assing into _correlation property
158  /// </summary>
159  private void ComputeCorrelation()
160  {
161  if (_targetDataPoints.Count < _period || _referenceDataPoints.Count < _period)
162  {
163  _correlation = 0;
164  return;
165  }
166  var newCorrelation = 0d;
167  if (_correlationType == CorrelationType.Pearson)
168  {
169  newCorrelation = MathNet.Numerics.Statistics.Correlation.Pearson(_targetDataPoints, _referenceDataPoints);
170  }
171  if (_correlationType == CorrelationType.Spearman)
172  {
173  newCorrelation = MathNet.Numerics.Statistics.Correlation.Spearman(_targetDataPoints, _referenceDataPoints);
174  }
175  if (newCorrelation.IsNaNOrZero())
176  {
177  newCorrelation = 0;
178  }
179  _correlation = Extensions.SafeDecimalCast(newCorrelation);
180  }
181 
182  /// <summary>
183  /// Resets this indicator to its initial state
184  /// </summary>
185  public override void Reset()
186  {
187  _targetDataPoints.Reset();
188  _referenceDataPoints.Reset();
189  _correlation = 0;
190  base.Reset();
191  }
192  }
193 }