Ehler's Deviation-Scaled Fisher Transform Oscillator

Viewing 13 posts - 1 through 13 (of 13 total)
  • Author
    Posts
  • #81066 quote
    Bard
    Participant
    Master

    Hi,

    I’m wondering if someone would like to take a look at coding John Ehlers’ recently created/released new indicator called the Deviated Scaled Oscillator with the Fisher Transform for mean reversion swing traders. The oscillator was featured in this October’s Stocks and Commodities Magazine. For a full explanation please see the 5 screenshots I took of the article including the code.

    The theory behind the indicator is to remove the fat tails of a distribution to give a more perfect bell shaped Gaussian distribution which is necessary to trade low probability events at the extreme ends of the oscillator. This allows a price series to be placed into a probability distribution so that the probabilities of extreme moves corresponds to a normal standard deviation bell curve (distribution) which allows the prediction, in percentage terms, for the odds of a +2/-2 standard deviation move away from the mean price (centre of the bell curve).

    I also found the code today on https://www.tradingview.com/script/DdLQBt87-Ehlers-Fisherized-Deviation-Scaled-Oscillator/

    The code is as follows:

    //@version=3
    // Copyright (c) 2018-present, Alex Orekhov (everget)
    // Ehlers Fisherized Deviation-Scaled Oscillator script may be freely distributed under the MIT license.
    study("Ehlers Fisherized Deviation-Scaled Oscillator", shorttitle="EFDSO")
    
    length = input(title="Length", type=integer, defval=40, minval=1)
    ssfLength = input(title="Super Smoother Filter Length", type=integer, defval=20, minval=1)
    numberOfPoles = input(title="Number of Poles", type=integer, defval=2, options=[2, 3])
    overboughtLevel = input(title="Overbought Level", type=float, defval=2, step=0.1)
    oversoldLevel = input(title="Oversold Level", type=float, defval=-2, step=0.1)
    src = input(title="Source", type=source, defval=close)
    
    PI = 2 * asin(1)
    
    twoPoleSuperSmootherFilter(src, length) =>
        arg = sqrt(2) * PI / length
        a1 = exp(-arg)
        b1 = 2 * a1 * cos(arg)
        c2 = b1
        c3 = -pow(a1, 2)
        c1 = 1 - c2 - c3
        
        ssf = 0.0
        ssf := c1 * src + c2 * nz(ssf[1]) + c3 * nz(ssf[2])
    
    threePoleSuperSmootherFilter(src, length) =>
        arg = PI / length
        a1 = exp(-arg)
        b1 = 2 * a1 * cos(1.738 * arg)
        c1 = pow(a1, 2)
    
        coef2 = b1 + c1
        coef3 = -(c1 + b1 * c1)
        coef4 = pow(c1, 2)
        coef1 = 1 - coef2 - coef3 - coef4
    
        ssf = 0.0
        ssf := coef1 * src + coef2 * nz(ssf[1]) + coef3 * nz(ssf[2]) + coef4 * nz(ssf[3])
    
    zeros = src - nz(src[2])
    
    // Ehlers Super Smoother Filter 
    essf = numberOfPoles == 2
         ? twoPoleSuperSmootherFilter((zeros + zeros[1]) / 2, ssfLength)
         : threePoleSuperSmootherFilter((zeros + zeros[1]) / 2, ssfLength)
    
    // Rescale filter in terms of Standard Deviations
    scaledFilter = 0.0
    scaledFilter := stdev(essf, length) != 0
         ? essf / stdev(essf, length)
         : nz(scaledFilter[1])
    
    // Apply Fisher Transform to establish real Gaussian Probability Distribution
    efdso = 0.0
    efdso := abs(scaledFilter) < 2
         ? 0.5 * log((1 + scaledFilter / 2) / (1 - scaledFilter / 2))
         : nz(efdso[1])
    
    efdsoColor = efdso > overboughtLevel ? #0ebb23 : efdso < oversoldLevel ? #cc0000 : #674ea7
    plot(efdso, title="EFDSO", linewidth=2, color=efdsoColor, transp=0)
    
    hline(overboughtLevel, title="Overbought Level", linestyle=dotted, color=#e69138)
    hline(0, title="Zero Level", linestyle=dotted, color=#989898)
    hline(oversoldLevel, title="Oversold Level", linestyle=dotted, color=#e69138)

    Looks interesting and the article is definitely worth the read. The last two article images with the code will be posted separately.

    #81071 quote
    Bard
    Participant
    Master

    This short article gives a good overview of the Fisher Transform Oscillator:

    http://www.trade-robots.com/blog/the-fisher-transform-oscillator

    (hopefully the last 2 images from the article “Probability – Probably a Good Thing to Know, ” with the code, will upload on this second attempt)

    #82040 quote
    Bard
    Participant
    Master

    I’ve lifted John Ehler’s Fisherized Deviation-Scaled Oscillator code from the last image above from October’s Stocks and Commodities Magazine and “translated” it into PRT although it’s non functioning at the moment due to my lack of coding skills. It’d be great if anyone can take a look at it and get it to work and explain what I missed (I wondered about the arrays at the top of the magazine article code)?

    Cheers
    Bard

    Period = 40
    
    If Barindex=1 then
     // Super Smoother Filter
     a1= Exp(-1.414 * 3.14159 / (0.5*Period)) 
     b1= 2*a1 * Cos(1.414*180 / (0.5*Period)) 
     c2= b1
     c3= -a1 * a1
     c1= 1 - c2 - c3
    Endif
    
     // Produce nominal zero mean with zeros in the transfer response at DC & Nyquist with no spectral distortion
     // Nominally whitens the spectrum because 6db per octave rolloff
     Zeros= Close-Close[2]
    
     // Super Smoother Filter
    Filt= c1*(Zeros+Zeros[1])/2 + c2*Filt[1] + c3*Filt[2]
    
     // Compute Standard Deviation
     RMS= 0 //Root Mean Sqr
     For Count=0 to Period-1 
     RMS= RMS + Filt[Count]*Filt[Count]
    Next
    
     RMS=SQRT(RMS/Period)
    
    // Rescale Filter in terms of Standard Deviations
    If RMS<>0 Then ScaledFilt= Filt/RMS
    
    // Apply Fisher Transform to Establish Real Gaussian Prob Dist’n.
    If Abs(ScaledFilt) < 2 Then FisherFilt= 0.5*Log((1 + ScaledFilt/2) / (1-ScaledFilt/2))
    
    Return FisherFilt coloured (66,66,255) as “Fisher Filter", 0 style(dottedline) as "0"
    #82042 quote
    Nicolas
    Keymaster
    Master

    You were not too far to make it works! 🙂

    I think I get it sorted from your code:

    Period = 40
    
    If Barindex>Period then
    // Super Smoother Filter
    a1= Exp(-1.414 * 3.14159 / (0.5*Period))
    b1= 2*a1 * Cos(1.414*180 / (0.5*Period))
    c2= b1
    c3= -a1 * a1
    c1= 1 - c2 - c3
    
    // Produce nominal zero mean with zeros in the transfer response at DC & Nyquist with no spectral distortion
    // Nominally whitens the spectrum because 6db per octave rolloff
    Zeros= Close-Close[2]
    
    // Super Smoother Filter
    Filt= c1*(Zeros+Zeros[1])/2 + c2*Filt[1] + c3*Filt[2]
    
    // Compute Standard Deviation
    RMS= 0 //Root Mean Sqr
    For Count=0 to Period-1
    RMS= RMS + Filt[Count]*Filt[Count]
    Next
    
    RMS=SQRT(RMS/Period)
    
    // Rescale Filter in terms of Standard Deviations
    If RMS<>0 Then 
    ScaledFilt= Filt/RMS
    endif
    // Apply Fisher Transform to Establish Real Gaussian Prob Dist’n.
    If Abs(ScaledFilt) < 2 Then 
    FisherFilt= 0.5*Log((1 + ScaledFilt/2) / (1-ScaledFilt/2))
    Endif
    endif
    
    Return FisherFilt coloured (66,66,255) as "Fisher Filter", 0 style(dottedline) as "0"
    Bard thanked this post
    #82077 quote
    Bard
    Participant
    Master

    Great! Nice one @nicolas, I bolted different parts of your John Ehler’s indicator codes together. 😄

    I’m wondering why is the barindex “greater” than 40? I thought the Super Smoother Filter was being applied to data under 40 periods not over 40 periods? 

    And Ehler’s wrote “endif” where I placed it (on line 10), yet by moving that first “endif” to the very end of the calculations it now uses all the different components of the indicator to give that final output of FisherFilt,… so why is Ehler’s code not written with the “endif” moved to the very bottom?

    Also is there a way of normalising the output to only values between -3 and +3 std deviations?

    Cheers
    Bard

    #82078 quote
    Nicolas
    Keymaster
    Master

    I did not confirm that the code you wrote is the same as the original. I just solved the issue of why it was not displaying anything. About the barindex>period, it is necessary because otherwise the platform will not calculate it. We obviously need to have read at least more than the desired period to calculate it.

    Normalization is an easy process, I’m sure you’ll be able to make it 🙂

    Bard thanked this post
    #82085 quote
    Bard
    Participant
    Master

    Not too shabby results either, no optimisation, just bought on a crossover of -1 std deviation (and a cross under of 1 std dev to short it) and used the zero line as an exit.

    I then stuck it on a 2 year test on mean reverting currencies from Jan 2016 to Dec 2017 Daily:
    GBP/USD, EUR/HUF, GBP/EUR, & USD/CHF. (The USD/JPY had a 105% return but a 46% Drawdown). Pls See Screens.

    Obviously it can get you in on the wrong side of a trend but I don’t know if I’d ever be comfortable leaving an automated system on “autopilot!”

    #82119 quote
    Bard
    Participant
    Master

    I appreciate the “vote of confidence” lol, I tried using Ehler’s code from the third and last screenshot in this RocketRSI post: #6978 from https://www.prorealcode.com/topic/john-ehlers-rocket-rsi/

    but it’d didn’t accept the “Then FisherFilt” part, particularly: FisherFilt was highlighted in red in the indicator code window:

    If FisherFilt > 0.999 Then FisherFilt = 0.999
    Endif
    If FisherFilt < -0.999 Then FisherFilt = -0.999
    Endif

    I also saw @Despairs (Rocket RSI) version of code using “closes up” and “closes down:”

    //Accumulate "Closes Up" and "Closes Down"
    CU = 0
    CD = 0
    for count = 0 to Period -1 do
    if Filt[count] - Filt[count + 1] > 0 then
    CU = CU + Filt[count] - Filt[count + 1]
    endif
    if Filt[count] - Filt[count + 1] < 0 then
    CD = CD + Filt[count + 1] - Filt[count]
    endif
    next
    
    if CU + CD <> 0 then
    FisherFilt = ( CU - CD ) / ( CU + CD )
    endif
    
    FisherFilt = min(max(FisherFilt,-0.999),0.999)

    But that didn’t work either as I saw some std deviations of -3.5 and +4.0.
    Conceptually the idea is to take those FisherFilt output results and normalise them to the new range parameters. My first thought though is if 99.7% of values lie between -3 and +3 std deviations then how would you express 4.0, or even 6.0, std deviation moves on an oscillators right hand range scale?

    Actually I just refreshed my memory and looked this up: A 3-sigma event occurs 99.73 percent of the time under a normal distribution bell curve, a 4-sigma event: 99.999968 percent of the time and a 5-sigma outlier: 99.9999997 percent. (0.0000003 percent of the time). I’d like an oscillator scale with a 6 std deviation scale please and — assuming it’s not the end of the world — I’d take a largish bet on a reversion to the mean for that event. Double lol…  Wait why am I laughing? I’ve seen a Kase 7.5 Dev Stop exceeded a few times! 😄

    https://www.sixsigma-institute.org/Six_Sigma_DMAIC_Process_Measure_Phase_Process_Capability.php

    #82237 quote
    Nicolas
    Keymaster
    Master

    You can try this below version, where +100 or -100 state for 3 standard deviations:

    Period = 40
    
    If Barindex>Period then
    // Super Smoother Filter
    a1= Exp(-1.414 * 3.14159 / (0.5*Period))
    b1= 2*a1 * Cos(1.414*180 / (0.5*Period))
    c2= b1
    c3= -a1 * a1
    c1= 1 - c2 - c3
    
    // Produce nominal zero mean with zeros in the transfer response at DC & Nyquist with no spectral distortion
    // Nominally whitens the spectrum because 6db per octave rolloff
    Zeros= Close-Close[2]
    
    // Super Smoother Filter
    Filt= c1*(Zeros+Zeros[1])/2 + c2*Filt[1] + c3*Filt[2]
    
    // Compute Standard Deviation
    RMS= 0 //Root Mean Sqr
    For Count=0 to Period-1
    RMS= RMS + Filt[Count]*Filt[Count]
    Next
    
    RMS=SQRT(RMS/Period)
    
    // Rescale Filter in terms of Standard Deviations
    If RMS<>0 Then
    ScaledFilt= Filt/RMS
    endif
    // Apply Fisher Transform to Establish Real Gaussian Prob Dist’n.
    If Abs(ScaledFilt) < 2 Then
    FisherFilt= 0.5*Log((1 + ScaledFilt/2) / (1-ScaledFilt/2))
    Endif
     
    result = (fisherfilt*100)/(rms*3)
    
    endif
    
    Return result coloured (66,66,255) as "Fisher Filter", 0 style(dottedline) as "0"
    #82277 quote
    Bard
    Participant
    Master

    Thanks @nicolas, I see now that rms = the std deviation when there is a zero mean and the math looks right but the oscillator scale is not how I was expecting it? Pls see screens of the original code and the 3 std deviation code, cheers.

    #82288 quote
    Nicolas
    Keymaster
    Master

    My code has a scale of +100/-100, so you did something wrong somewhere with your copy/paste.

    #82296 quote
    Bard
    Participant
    Master

    Thanks for the screenshot, if it’s bounded by +/-100 why do the results go as high as 200, (it’s a 100% (covering 3 std devs)?
    I used the copy icon in the top right here on PRC and pasted as normal into PRT, yet I get this on the Swissy:

    #82425 quote
    Nicolas
    Keymaster
    Master

    The 100% scale made of 3 std dev of oscillator doesn’t mean that the oscillator is never going more than 3 standard deviation!

    Bard thanked this post
Viewing 13 posts - 1 through 13 (of 13 total)
  • You must be logged in to reply to this topic.

Ehler's Deviation-Scaled Fisher Transform Oscillator


ProBuilder: Indicators & Custom Tools

New Reply
Author
author-avatar
Bard @brad Participant
Summary

This topic contains 12 replies,
has 2 voices, and was last updated by Nicolas
7 years, 4 months ago.

Topic Details
Forum: ProBuilder: Indicators & Custom Tools
Language: English
Started: 09/22/2018
Status: Active
Attachments: 18 files
Logo Logo
Loading...