Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to correctly calculate Fisher Transform indicator

I'm writing a small technical analysis library that consists of items that are not availabile in TA-lib. I've started with an example I found on cTrader and matched it against the code found in the TradingView version.

Here's the Pine Script code from TradingView:

len = input(9, minval=1, title="Length")

high_ = highest(hl2, len)
low_ = lowest(hl2, len)

round_(val) => val > .99 ? .999 : val < -.99 ? -.999 : val

value = 0.0
value := round_(.66 * ((hl2 - low_) / max(high_ - low_, .001) - .5) + .67 * nz(value[1]))

fish1 = 0.0
fish1 := .5 * log((1 + value) / max(1 - value, .001)) + .5 * nz(fish1[1])

fish2 = fish1[1]

Here's my attempt to implement the indicator:

    public class FisherTransform : IndicatorBase
    {
        public int Length = 9;

        public decimal[] Fish { get; set; }
        public decimal[] Trigger { get; set; }

        decimal _maxHigh;
        decimal _minLow;
 
        private decimal _value1;
        private decimal _lastValue1;

        public FisherTransform(IEnumerable<Candle> candles, int length) 
            : base(candles)
        {
            Length = length;
            RequiredCount = Length;
            _lastValue1 = 1;
        }

        protected override void Initialize()
        {
            Fish = new decimal[Series.Length];
            Trigger = new decimal[Series.Length];
        }

        public override void Compute(int startIndex = 0, int? endIndex = null)
        {
            if (endIndex == null)
                endIndex = Series.Length;

            for (int index = 0; index < endIndex; index++)
            {
                if (index == 1)
                {
                    Fish[index - 1] = 1;
                }
              
                _minLow = Series.Average.Lowest(Length, index);
                _maxHigh = Series.Average.Highest(Length, index);

                _value1 = Maths.Normalize(0.66m * ((Maths.Divide(Series.Average[index] - _minLow, Math.Max(_maxHigh - _minLow, 0.001m)) - 0.5m) + 0.67m * _lastValue1));

                _lastValue1 = _value1;

                Fish[index] = 0.5m * Maths.Log(Maths.Divide(1 + _value1, Math.Max(1 - _value1, .001m))) + 0.5m * Fish[index - 1];
                Trigger[index] = Fish[index - 1];
            }
        }
    }

IndicatorBase class and CandleSeries class

Math Helpers

The problem

The output values appear to be within the expected range however my Fisher Transform cross-overs do not match up with what I am seeing on TradingView's version of the indicator.

Question

How do I properly implement the Fisher Transform indicator in C#? I'd like this to match TradingView's Fisher Transform output.

What I Know

I've check my data against other indicators that I have personally written and indicators from TA-Lib and those indicators pass my unit tests. I've also checked my data against the TradingView data candle by candle and found that my data matches as expected. So I don't suspect my data is the issue.

Specifics

CSV Data - NFLX 5 min agg

Pictured below is the above-shown Fisher Transform code applied to a TradingView chart. My goal is to match this output as close as possible.

enter image description here

Fisher Cyan Trigger Magenta

Expected Outputs:

Crossover completed at 15:30 ET

  • Approx Fisher Value is 2.86

  • Approx Trigger Value is 1.79

Crossover completed at 10:45 ET

  • Approx Fisher Value is -3.67

  • Approx Trigger Value is -3.10

My Actual Outputs:

Crossover completed at 15:30 ET

  • My Fisher Value is 1.64

  • My Trigger Value is 1.99

Crossover completed at 10:45 ET

  • My Fisher Value is -1.63

  • My Trigger Value is -2.00

Bounty

To make your life easier I'm including a small console application complete with passing and failing unit tests. All unit tests are conducted against the same data set. The passing unit tests are from a tested working Simple Moving Average indicator. The failing unit tests are against the Fisher Transform indicator in question.

Project Files (updated 5/14)

Help get my FisherTransform tests to pass and I'll award the bounty.

enter image description here

Just comment if you need any additional resources or information.

Alternative Answers that I'll consider

  • Submit your own working FisherTransform in C#

  • Explain why my FisherTransform is actually working as expected

like image 952
Dan Beaulieu Avatar asked May 12 '19 00:05

Dan Beaulieu


People also ask

Does Fisher indicator repaint?

This indicator never repaints and if you want a reliable indicators, search all indicators coded by Igorad. Goodluck! I have tested about 12 of the fisher based indicators and found most to repaint but 3 do not.

What is inverse Fisher transform?

The Inverse Fisher Transform (IFISH) was authored by John Ehlers. The IFISH applies some math functions and constants to a weighted moving average (wma) of the relative strength index (rsi) of the closing price to calculate its oscillator position. The user may change the input (close) and period lengths.


Video Answer


1 Answers

The code has two errors.

1) wrong extra brackets. The correct line is:

_value1 = Maths.Normalize(0.66m * (Maths.Divide(Series.Average[index] - _minLow, Math.Max(_maxHigh - _minLow, 0.001m)) - 0.5m) + 0.67m * _lastValue1);

2) Min and max functions must be:

public static decimal Highest(this decimal[] series, int length, int index)
{
    var maxVal = series[index]; // <----- HERE WAS AN ERROR!

    var lookback = Math.Max(index - length, 0);

    for (int i = index; i-- > lookback;)
        maxVal = Math.Max(series[i], maxVal);

    return maxVal;
}

public static decimal Lowest(this decimal[] series, int length, int index)
{
    var minVal = series[index]; // <----- HERE WAS AN ERROR!

    var lookback = Math.Max(index - length, 0);

    for (int i = index; i-- > lookback;)
    {
        //if (series[i] != 0) // <----- HERE WAS AN ERROR!
            minVal = Math.Min(series[i], minVal);
    }

    return minVal;
}

3) confusing test params. Please recheck your unittest values. AFTER THE UPDATE TESTS STILL NOT FIXED. For an example, the first FisherTransforms_ValuesAreReasonablyClose_First() has mixed values

var fish = result.Fish.Last(); //is equal to -3.1113144510775780365063063706
var trig = result.Trigger.Last(); //is equal to -3.6057793808025449204415435710

// TradingView Values for NFLX 5m chart at 10:45 ET
var fisherValue = -3.67m;
var triggerValue = -3.10m;
like image 132
Andrey Chistyakov Avatar answered Oct 03 '22 06:10

Andrey Chistyakov