*The Fisher Transform converts data to or from a Gaussian distribution. It was first used in algorithmic trading by John Ehlers (1) , and became a common part of indicators since then. In a TASC February 2022 article, Ehlers described a new indicator, the Elegant Oscillator, based on the Inverse Fisher Transform. Let’s have a look at this indicator and how it’s used in a trading system.*

First, the Fisher Transform and its inverse in code:

var Fisher(vars Data) { var V = clamp(Data[0],-0.999,0.999); return 0.5*log((1.+V)/(1.-V)); } var FisherInv(vars Data) { var V = exp(2.*Data[0]); return (V-1.)/(V+1.); }

The Inverse Fisher Transform (IFT) is used in the Elegant Oscillator to convert a normalized derivative of a price series to the +/-1 range. The normalization is done by dividing by the square root of the sum of squares, a sort of N-dimensional distance. Using the IFT is supposedly a better method than simply clipping the data. The result is smoothed by Ehlers’ ‘SuperSmoother’, a low-lag lowpass filter. The Elegant Oscillator code in C for Zorro:

var EO(vars Data,int Length) { vars Derivs = series(Data[0]-Data[2]); var RMS = sqrt(SumSq(Derivs,Length)/Length); var NDeriv = Derivs[0]/RMS; vars IFishs = series(FisherInv(&NDeriv)); return Smooth(IFishs,20); }

**SumSq()** is a helper function for summing up the squares of a data series, and **Smooth()** is Ehlers’ ‘SuperSmoother’ that’s already in the Zorro library. Since the **FisherInv** function needs only a data series of length 1, I could simply pass a pointer to the **NDeriv** variable instead of a series of it. For comparison, here’s the simple code for hard clipping the data:

var HardClip(vars Data) { var Deriv = Data[0]-Data[2]; vars Clips = series(clamp(Deriv,-1,1)); return FIR6(Clips); }

The clipped data is this time smoothed with a finite response filter (FIR6). Here’s a SPY chart with the Elegant Oscillator (upper red line), the Inverse Fisher Transform smoothed with a finite response filter (lower red line), and the hard clipped variant (blue line).

Of the 3, the super smoothed Elegant Oscillator makes the best impression and appears to generate the best signals. According to Ehlers, its peaks and valleys that exceed a threshold can be used for mean reversion trading. Let’s put that to the test. The code:

void run() { StartDate = 20200301; EndDate = 20210501; BarPeriod = 1440; asset("SPY"); vars Signals = series(EO(seriesC(),50)); var Threshold = 0.5; if(Signals[0] > Threshold && peak(Signals)) enterShort(); else if(Signals[0] < -Threshold && valley(Signals)) enterLong(); }

The resulting chart:

Indeed, 5 of 7 trades in that time period were winning, producing an overall positive result with a profit factor above 6. Of course, 7 trades won’t tell much, so I encorage anyone to experiment with different instruments and different time periods for determining the real value of the EO oscillator for mean reversion trading.

The oscillator and trading strategy can be downloaded from the 2021 script repository.

(1) John Ehlers, Cybernetic Analysis of Stocks and Futures, Wiley 2004

Interesting stuff!

In the function HardClip, the variable RMS is calculated but not used. Was that omitted from the calculation below it?

Could you please include this SumSq helper function?

var SumSq(vars Data,int Length)

{

var Ex = 0;

int i;

for(i=0; i<Length; i++)

Ex += Data[i]*Data[i];

return Ex;

}

And RMS was indeed a leftover, I’ll remove it.

Well… First tryouts negative. Ain’t finding a good use of it. Nevertheless – thanks for a blog post!

Have you found any of Ehler’s work actually useful in making profitable trading algos? I wasted thousands of dollars on his workshop.

I dont know about his workshops, but found his work absolutely useful, at least the algorithms from his books. It may be not so with some of his articles in TASC. But I can tell that we use his spectral filter functions all the time and with good success. You just have to know what they do and when to use them.