Lean  $LEAN_TAG$
FisherTransform.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 
18 using System;
19 
21 {
22  /// <summary>
23  /// The Fisher transform is a mathematical process which is used to convert any data set to a modified
24  /// data set whose Probability Distribution Function is approximately Gaussian. Once the Fisher transform
25  /// is computed, the transformed data can then be analyzed in terms of it's deviation from the mean.
26  ///
27  /// The equation is y = .5 * ln [ 1 + x / 1 - x ] where
28  /// x is the input
29  /// y is the output
30  /// ln is the natural logarithm
31  ///
32  /// The Fisher transform has much sharper turning points than other indicators such as MACD
33  ///
34  /// For more info, read chapter 1 of Cybernetic Analysis for Stocks and Futures by John F. Ehlers
35  ///
36  /// We are implementing the latest version of this indicator found at Fig. 4 of
37  /// http://www.mesasoftware.com/papers/UsingTheFisherTransform.pdf
38  /// </summary>
40  {
41  private const double _alpha = .33;
42  private double _previous;
43  private readonly Minimum _medianMin;
44  private readonly Maximum _medianMax;
45 
46  /// <summary>
47  /// Initializes a new instance of the FisherTransform class with the default name and period
48  /// </summary>
49  /// <param name="period">The period of the WMA</param>
50  public FisherTransform(int period)
51  : this($"FISH({period})", period)
52  {
53  }
54 
55  /// <summary>
56  /// A Fisher Transform of Prices
57  /// </summary>
58  /// <param name="name">string - the name of the indicator</param>
59  /// <param name="period">The number of periods for the indicator</param>
60  public FisherTransform(string name, int period)
61  : base(name)
62  {
63  // Initialize the local variables
64  _medianMax = new Maximum("MedianMax", period);
65  _medianMin = new Minimum("MedianMin", period);
66  WarmUpPeriod = period;
67  }
68 
69  /// <summary>
70  /// Gets a flag indicating when this indicator is ready and fully initialized
71  /// </summary>
72  public override bool IsReady => _medianMax.IsReady && _medianMax.IsReady;
73 
74  /// <summary>
75  /// Required period, in data points, for the indicator to be ready and fully initialized.
76  /// </summary>
77  public int WarmUpPeriod { get; }
78 
79  /// <summary>
80  /// Computes the next value in the transform.
81  /// value1 is a function used to normalize price withing the last _period day range.
82  /// value1 is centered on its midpoint and then doubled so that value1 wil swing between -1 and +1.
83  /// value1 is also smoothed with an exponential moving average whose alpha is 0.33.
84  ///
85  /// Since the smoothing may allow value1 to exceed the _period day price range, limits are introduced to
86  /// preclude the transform from blowing up by having an input larger than unity.
87  /// </summary>
88  /// <param name="input">IndicatorDataPoint - the time and value of the next price</param>
89  protected override decimal ComputeNextValue(IBaseDataBar input)
90  {
91  var price = (input.Low + input.High) / 2m;
92  _medianMin.Update(input.Time, price);
93  _medianMax.Update(input.Time, price);
94 
95  if (!IsReady) return 0;
96 
97  var x = 0.0;
98  var y = 0.0;
99  var minL = _medianMin.Current.Value;
100  var maxH = _medianMax.Current.Value;
101 
102  if (minL != maxH)
103  {
104  x = _alpha * 2 * ((double)((price - minL) / (maxH - minL)) - .5) + (1 - _alpha) * _previous;
105  y = FisherTransformFunction(x);
106  }
107  _previous = x;
108 
109  return Convert.ToDecimal(y) + .5m * Current.Value;
110  }
111 
112  /// <summary>
113  /// Resets this indicator to its initial state
114  /// </summary>
115  public override void Reset()
116  {
117  _previous = 0;
118  _medianMax.Reset();
119  _medianMin.Reset();
120  base.Reset();
121  }
122 
123  /// <summary>
124  /// The Fisher transform is a mathematical process which is used to convert any data set to a modified
125  /// data set whose Probability Distribution Function is approximately Gaussian. Once the Fisher transform
126  /// is computed, the transformed data can then be analyzed in terms of it's deviation from the mean.
127  ///
128  /// The equation is y = .5 * ln [ 1 + x / 1 - x ] where
129  /// x is the input
130  /// y is the output
131  /// ln is the natural logarithm
132  ///
133  /// The Fisher transform has much sharper turning points than other indicators such as MACD
134  ///
135  /// For more info, read chapter 1 of Cybernetic Analysis for Stocks and Futures by John F. Ehlers
136  /// </summary>
137  /// <param name="x">Input</param>
138  /// <returns>Output</returns>
139  private double FisherTransformFunction(double x)
140  {
141  if (x > .999)
142  {
143  x = .999;
144  }
145  if (x < -.999)
146  {
147  x = -.999;
148  }
149 
150  return .5 * Math.Log((1.0 + x) / (1.0 - x));
151  }
152  }
153 }