/* * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ using QuantConnect.Data.Market; using System; namespace QuantConnect.Indicators { /// /// The Fisher transform is a mathematical process which is used to convert any data set to a modified /// data set whose Probability Distribution Function is approximately Gaussian. Once the Fisher transform /// is computed, the transformed data can then be analyzed in terms of it's deviation from the mean. /// /// The equation is y = .5 * ln [ 1 + x / 1 - x ] where /// x is the input /// y is the output /// ln is the natural logarithm /// /// The Fisher transform has much sharper turning points than other indicators such as MACD /// /// For more info, read chapter 1 of Cybernetic Analysis for Stocks and Futures by John F. Ehlers /// /// We are implementing the latest version of this indicator found at Fig. 4 of /// http://www.mesasoftware.com/papers/UsingTheFisherTransform.pdf /// public class FisherTransform : BarIndicator, IIndicatorWarmUpPeriodProvider { private const double _alpha = .33; private double _previous; private readonly Minimum _medianMin; private readonly Maximum _medianMax; /// /// Initializes a new instance of the FisherTransform class with the default name and period /// /// The period of the WMA public FisherTransform(int period) : this($"FISH({period})", period) { } /// /// A Fisher Transform of Prices /// /// string - the name of the indicator /// The number of periods for the indicator public FisherTransform(string name, int period) : base(name) { // Initialize the local variables _medianMax = new Maximum("MedianMax", period); _medianMin = new Minimum("MedianMin", period); WarmUpPeriod = period; } /// /// Gets a flag indicating when this indicator is ready and fully initialized /// public override bool IsReady => _medianMax.IsReady && _medianMax.IsReady; /// /// Required period, in data points, for the indicator to be ready and fully initialized. /// public int WarmUpPeriod { get; } /// /// Computes the next value in the transform. /// value1 is a function used to normalize price withing the last _period day range. /// value1 is centered on its midpoint and then doubled so that value1 wil swing between -1 and +1. /// value1 is also smoothed with an exponential moving average whose alpha is 0.33. /// /// Since the smoothing may allow value1 to exceed the _period day price range, limits are introduced to /// preclude the transform from blowing up by having an input larger than unity. /// /// IndicatorDataPoint - the time and value of the next price protected override decimal ComputeNextValue(IBaseDataBar input) { var price = (input.Low + input.High) / 2m; _medianMin.Update(input.EndTime, price); _medianMax.Update(input.EndTime, price); if (!IsReady) return 0; var x = 0.0; var y = 0.0; var minL = _medianMin.Current.Value; var maxH = _medianMax.Current.Value; if (minL != maxH) { x = _alpha * 2 * ((double)((price - minL) / (maxH - minL)) - .5) + (1 - _alpha) * _previous; y = FisherTransformFunction(x); } _previous = x; return Convert.ToDecimal(y) + .5m * Current.Value; } /// /// Resets this indicator to its initial state /// public override void Reset() { _previous = 0; _medianMax.Reset(); _medianMin.Reset(); base.Reset(); } /// /// The Fisher transform is a mathematical process which is used to convert any data set to a modified /// data set whose Probability Distribution Function is approximately Gaussian. Once the Fisher transform /// is computed, the transformed data can then be analyzed in terms of it's deviation from the mean. /// /// The equation is y = .5 * ln [ 1 + x / 1 - x ] where /// x is the input /// y is the output /// ln is the natural logarithm /// /// The Fisher transform has much sharper turning points than other indicators such as MACD /// /// For more info, read chapter 1 of Cybernetic Analysis for Stocks and Futures by John F. Ehlers /// /// Input /// Output private double FisherTransformFunction(double x) { if (x > .999) { x = .999; } if (x < -.999) { x = -.999; } return .5 * Math.Log((1.0 + x) / (1.0 - x)); } } }