Open flare9x opened 6 years ago
You should use triple backticks for code in Github issues https://help.github.com/articles/creating-and-highlighting-code-blocks/
thanks!
# Band Pass Filter 5-1
function BandPassFilter(x::Array{Float64}; n::Int64=30, bandwidth::Float64=.3)::Array{Float64}
@assert n<size(x,1) && n>0 "Argument n out of bounds."
alpha2 = (cosd(.25*bandwidth*360 / n) + sind(.25*bandwidth*360 / n) - 1) / cosd(.25*bandwidth*360 /n)
beta1 = cosd(360 / n);
gamma1 = 1 / cosd(360*bandwidth / n)
alpha1 = gamma1 - sqrt(gamma1*gamma1 - 1)
HP = zeros(x)
BP = zeros(x)
@inbounds for i in 3:length(x)
HP[i] = (1 + alpha2 / 2)*(x[i] - x[i-1]) + (1- alpha2)*HP[i-1]
BP[i] = .5*(1 - alpha1)*(HP[i] - HP[i-2]) + beta1*(1 + alpha1)*BP[i-1] - alpha1*BP[i-2]
end
# Signal
Signal = zeros(x)
Peak = zeros(x)
@inbounds for i in 2:length(BP)
Peak[i] = .991*Peak[i-1]
if abs(BP[i]) > Peak[i]
Peak[i] = abs(BP[i])
Signal[i] = BP[i] / Peak[i]
else
Signal[i] = BP[i] / Peak[i]
end
end
# Replace Nan to 0
@inbounds for i in 1:length(Signal)
if isnan(Signal[i]) == 1
Signal[i] = 0.0
else
Signal[i] = Signal[i]
end
end
# Trigger
alpha2 = (cosd(1.5*bandwidth*360 / n) + sind(1.5*bandwidth*360 / n) - 1) / cosd(1.5*bandwidth*360 /n)
BP_Trigger = zeros(x)
i=1
@inbounds for i = 2:length(x)
BP_Trigger[i] = (1 + alpha2 / 2)*(Signal[i] - Signal[i-1]) +(1 -alpha2)*BP_Trigger[i-1]
end
return BP_Trigger
end
@flare9x Thanks for the idea and for the good head start here. I'm familiar with some of John Ehlers's ideas — I implemented the MESA Adaptive Moving Average way back when I first started this project (function name mama
), so you might want to take a look at that as well?
In the meantime I will try to make some time to get cracking on these other indicators as well. Looking forward to researching some of these, I think a lot of his ideas make a lot of sense so I'm excited to get back to reviewing some of his work and getting these implemented.
Cheers and thanks again!
Your welcome! I am so far cross checking with Mr Ehlers implementation in tradestation and ensure obtaining the same result within Julia (essentially changing tradestation code to Julia). These are designed to have as minimal lag as possible so they are more responsive vs traditional. Look forward to building them out - I have not seen a full implementation yet so be good to have them all coded in this package :)
Had trouble with Code Listing 5-2. Dominant Cycle Measured by Zero Crossings of the Band-Pass Filter - have all correct except for the DC portion of the calculation. Moved on to next and will revisit. Hurst below and same results as Ehlers implementation in his book Cycle analytics for traders.
# Ehlers Hurst 6-1
function hurst(x::Array{Float64}; n::Int64=30,)::Array{Float64}
@assert n<size(x,1) && n>0 "Argument n out of bounds."
@assert iseven(n) "n must be an even number."
half_n = Int64(n/2)
a1 = exp(-1.414*3.14159 / 20) # smoothes by 20 period same as equation 3-3- may wish to make this a argument in the function?
b1 = 2*a1*cosd(1.414*180 / 20) # smoothes by 20 period same as equation 3-3- may wish to make this a argument in the function?
c2 = b1
c3 = -a1*a1
c1 = 1 - c2 - c3
# Find rolling maximum and minimum
HH = zeros(x)
LL = zeros(x)
N3 = zeros(x)
@inbounds for i = n:size(x,1)
HH[i] = maximum(x[i-n+1:i])
LL[i] = minimum(x[i-n+1:i])
N3[i] = (HH[i] - LL[i]) / n
end
# Rolling min and max half of n
HH = zeros(x)
LL = zeros(x)
N1 = zeros(x)
@inbounds for i = half_n:size(x,1)
HH[i] = maximum(x[i-half_n+1:i])
LL[i] = minimum(x[i-half_n+1:i])
N1[i] = (HH[i] - LL[i]) / half_n
end
# Set trailing close half of n
HH = [fill(0,half_n); x[1:length(x)-half_n]]
LL = [fill(0,half_n); x[1:length(x)-half_n]]
HH_out = zeros(x)
LL_out = zeros(x)
N2 = zeros(x)
@inbounds for i = half_n:size(x,1)
HH_out[i] = maximum(HH[i-half_n+1:i])
LL_out[i] = minimum(LL[i-half_n+1:i])
N2[i] = (HH_out[i] - LL_out[i])/(half_n)
end
# Hurst
Dimen = zeros(x)
Hurst = zeros(x)
SmoothHurst = zeros(x)
@inbounds for i = 3:size(x,1)
if N1[i] > 0 && N2[i] > 0 && N3[i] > 0
Dimen[i] = .5*((log(N1[i]+ N2[i]) - log(N3[i])) / log(2) + Dimen[i-1])
Hurst[i] = 2 - Dimen[i]
SmoothHurst[i] = c1*(Hurst[i] + Hurst[i-1]) / 2 + c2*SmoothHurst[i-1]+ c3*SmoothHurst[i-2];
end
end
return SmoothHurst
end
Roofing filters from chapter 7:
# HP-LP Roofing Filter 7-1
function HpLpRoofingFilter(x::Array{Float64})::Array{Float64}
@assert n<size(x,1) && n>0 "Argument n out of bounds."
# Highpass filter cyclic components whose periods are shorter than 48 bars
alpha1 = (cosd(360 / 48) + sind(360 / 48) - 1) / cosd(360 / 48)
HP = zeros(x)
@inbounds for i = 2:size(x,1)
HP[i] = (1 - alpha1 / 2)*(x[i] - x[i-1]) + (1 - alpha1)*HP[i-1]
end
# Smooth with a Super Smoother Filter from equation 3-3
a1 = exp(-1.414*3.14159 / 10) # may wish to make this an argument in function
b1 = 2*a1*cosd(1.414*180 / 10) # may wish to make this an argument in function
c2 = b1
c3 = -a1*a1
c1 = 1 - c2 - c3
LP_HP_Filt = zeros(x)
@inbounds for i = 3:size(x,1)
LP_HP_Filt[i] = c1*(HP[i] + HP[i-1]) / 2 + c2*LP_HP_Filt[i-1] + c3*LP_HP_Filt[i-2]
end
return LP_HP_Filt
end
# zero mean roofing filter 7-2
function ZeroMeanRoofingFilter_one(x::Array{Float64})::Array{Float64}
@assert n<size(x,1) && n>0 "Argument n out of bounds."
# Highpass filter cyclic components whose periods are shorter than 48 bars
alpha1 = (cosd(360 / 48) + sind(360 / 48) - 1) /cosd(360 / 48)
HP = zeros(x)
@inbounds for i = 2:size(data1_c,1)
HP[i] = (1 - alpha1 / 2)*(x[i] - x[i-1]) +(1 - alpha1)*HP[i-1]
end
#Smooth with a Super Smoother Filter from equation 3-3
a1 = exp(-1.414*3.14159 / 10)
b1 = 2*a1*cosd(1.414*180 / 10)
c2 = b1
c3 = -a1*a1
c1 = 1 - c2 - c3
Zero_Mean_Filt = zeros(x)
Zero_Mean_Filt2 = zeros(x)
@inbounds for i = 3:size(x,1)
Zero_Mean_Filt[i] = c1*(HP[i] + HP[i-1]) / 2 + c2*Zero_Mean_Filt[i-1] + c3*Zero_Mean_Filt[i-2]
Zero_Mean_Filt2[i] = (1 - alpha1 / 2)*(Filt[i] - Filt[i-1]) + (1 - alpha1)*Filt2[i-1]
end
return Zero_Mean_Filt
end
function ZeroMeanRoofingFilter_two(x::Array{Float64})::Array{Float64}
@assert n<size(x,1) && n>0 "Argument n out of bounds."
# Highpass filter cyclic components whose periods are shorter than 48 bars
alpha1 = (cosd(360 / 48) + sind(360 / 48) - 1) /cosd(360 / 48)
HP = zeros(x)
@inbounds for i = 2:size(data1_c,1)
HP[i] = (1 - alpha1 / 2)*(x[i] - x[i-1]) +(1 - alpha1)*HP[i-1]
end
#Smooth with a Super Smoother Filter from equation 3-3
a1 = exp(-1.414*3.14159 / 10)
b1 = 2*a1*cosd(1.414*180 / 10)
c2 = b1
c3 = -a1*a1
c1 = 1 - c2 - c3
Zero_Mean_Filt = zeros(x)
Zero_Mean_Filt2 = zeros(x)
@inbounds for i = 3:size(x,1)
Zero_Mean_Filt[i] = c1*(HP[i] + HP[i-1]) / 2 + c2*Zero_Mean_Filt[i-1] + c3*Zero_Mean_Filt[i-2]
Zero_Mean_Filt2[i] = (1 - alpha1 / 2)*(Zero_Mean_Filt[i] - Zero_Mean_Filt[i-1]) + (1 - alpha1)*Zero_Mean_Filt2[i-1]
end
return Zero_Mean_Filt2
end
# Roofing filter as indicator 7-3
function RoofingFilterIndicator(x::Array{Float64}; n1::Int64=40,n2::Int64=80)::Array{Float64}
@assert n<size(x,1) && n>0 "Argument n out of bounds."
LPPeriod = n1
HPPeriod = n2
#Highpass filter cyclic components whose periods are shorter than 48 bars
alpha1 = (cosd(.707*360 / HPPeriod) + sind(.707*360 /HPPeriod) - 1) / cosd(.707*360 / HPPeriod)
HP = zeros(x)
@inbounds for i = 3:length(x)
HP[i] = (1 - alpha1 / 2)*(1 - alpha1 / 2)*(x[i] - 2*x[i-1] + x[i-2]) + 2*(1 - alpha1)*HP[i-1] - (1 - alpha1)*(1 - alpha1)*HP[i-2]
end
#Smooth with a Super Smoother Filter from equation 3-3
a1 = exp(-1.414*3.14159 / LPPeriod)
b1 = 2*a1*cosd(1.414*180 / LPPeriod)
c2 = b1
c3 = -a1*a1
c1 = 1 - c2 - c3
Roof_filt_Indicator = zeros(x)
@inbounds for i = 3:length(x)
Roof_filt_Indicator[i] = c1*(HP[i] + HP[i-1]) / 2 + c2*Roof_filt_Indicator[i-1] + c3*Roof_filt_Indicator[i-2]
end
return Roof_filt_Indicator
end
Modified stochastic:
# Modified Stochastic 7-4
function ModifiedStochastic(x::Array{Float64}; n::Int64=20)::Array{Float64}
@assert n<size(x,1) && n>0 "Argument n out of bounds."
#Highpass filter cyclic components whose periods are shorter than 48 bars
alpha1 = (cosd(.707*360 / 48) + sind(.707*360 / 48) - 1) /cosd(.707*360 / 48)
HP = zeros(x)
@inbounds for i = 3:size(x,1)
HP[i] = (1 - alpha1 / 2)*(1 - alpha1 / 2)*(x[i] - 2*x[i-1]+ x[i-2]) + 2*(1 - alpha1)*HP[i-1] - (1 - alpha1)*(1 -alpha1)*HP[i-2]
end
#Smooth with a Super Smoother Filter from equation 3-3
a1 = exp(-1.414*3.14159 / 10)
b1 = 2*a1*cosd(1.414*180 / 10)
c2 = b1
c3 = -a1*a1
c1 = 1 - c2 - c3
Filt = zeros(x)
@inbounds for i = 3:size(x,1)
Filt[i] = c1*(HP[i] + HP[i-1]) / 2 + c2*Filt[i-1] + c3*Filt[i-2]
end
# Highest and lowest filt over n width
HighestC = zeros(x)
LowestC = zeros(x)
Stoc = zeros(x)
MyStochastic = zeros(x)
@inbounds for i = n:size(x,1)
HighestC[i] = maximum(Filt[i-n+1:i])
LowestC[i] = minimum(Filt[i-n+1:i])
Stoc[i] = (Filt[i] - LowestC[i]) / (HighestC[i] - LowestC[i])
MyStochastic[i] = c1*(Stoc[i] + Stoc[i-1]) / 2 + c2*MyStochastic[i-1] + c3*MyStochastic[i-2]
end
return MyStochastic
end
Modified RSI
# Modified RSI 7-5
function ModifiedRSI(x::Array{Float64}; n::Int64=10)::Array{Float64}
@assert n<size(x,1) && n>0 "Argument n out of bounds."
#Highpass filter cyclic components whose periods areshorter than 48 bars
alpha1 = (cosd(.707*360 / 48) + sind(.707*360 / 48) - 1) /cosd(.707*360 / 48)
HP = zeros(x)
@inbounds for i =3:size(x,1)
HP[i] = (1 - alpha1 / 2)*(1 - alpha1 / 2)*(x[i] - 2*x[i-1] +x[i-2]) + 2*(1 - alpha1)*HP[i-1] - (1 - alpha1)*(1 -alpha1)*HP[i-2]
end
#Smooth with a Super Smoother Filter from equation 3-3
a1 = exp(-1.414*3.14159 / 10)
b1 = 2*a1*cosd(1.414*180 / 10)
c2 = b1
c3 = -a1*a1
c1 = 1 - c2 - c3
Filt = zeros(x)
@inbounds for i = 3:size(x,1)
Filt[i] = c1*(HP[i] + HP[i-1]) / 2 + c2*Filt[i-1] + c3*Filt[i-2]
end
ClosesUp = zeros(x)
ClosesDn = zeros(x)
filtdiff = zeros(x)
posDiff= zeros(x)
negDiff= zeros(x)
# pos and neg diffs
@inbounds for i = 2:size(x,1)
# difference
filtdiff[i] = Filt[i] - Filt[i-1]
if filtdiff[i] > 0
posDiff[i] = filtdiff[i]
elseif filtdiff[i] < 0
negDiff[i] = abs(filtdiff[i])
end
end
# Running Sums of Filt
posSum = zeros(x)
negSum = zeros(x)
denom = zeros(x)
rsi= zeros(x)
@inbounds for i = n:size(x,1)
posSum[i] = sum(posDiff[i-n+1:i])
negSum[i] = sum(negDiff[i-n+1:i])
denom[i] = posSum[i]+negSum[i]
end
# RSI
MyRSI = zeros(x)
@inbounds for i = 3:size(x,1)
if denom != 0 && denom[i-1] != 0
MyRSI[i] = c1*(posSum[i] /denom[i] + posSum[i-1] / denom[i-1]) / 2 + c2*MyRSI[i-1] +c3*MyRSI[i-2]
end
end
return MyRSI
end
I'l now continue to update the file here + TO DO list.
https://gist.github.com/flare9x/86fd4d5dc574eb2532355af7027e83a2#file-cycle_analytics_for_traders-jl
You might start your code blocks using:
```julia
so it will be highlight as Julia code
You should create a package for that (not just a gist)
For Julia 0.6 see https://docs.julialang.org/en/v0.6.4/manual/packages/ For Julia 0.7 and above see https://docs.julialang.org/en/latest/stdlib/Pkg/ (more precisely https://docs.julialang.org/en/latest/stdlib/Pkg/#Creating-your-own-packages-1 ) and https://discourse.julialang.org/t/ann-introducing-upgradathon-fridays/12047/3
That will be nice if you could from Tradestation both output (as csv) some input data and values of several indicators (also as CSV)
So those values could be used as unit tests.
Thanks for the suggestion! Although not sure if its adding more than what can be done in this package. I am working on other things such as candlesticks etc.. I either do that or @dysonance doesn't mind me contributing to it here! Whatever works
Thanks for the suggestion! Although not sure if its adding more than what can be done in this package. I am working on other things such as candlesticks etc.. I either do that or @dysonance doesn't mind me contributing to it here! Whatever works
Please, keep up the good work. Thank you!
Still looking for some help? Happy to collaborate!
@flare9x Absolutely! Any effort you can give is welcome with open arms. Feel free to fork the repo and open a pull request with any improvements or additions if that works for you. Let me know if I can provide any guidance and/or what I can do to make the collaboration process easier.
Hey I just saw this thread. I did some implementations of Ehler's work a while ago if anyone is interested:
"""
Exponential moving average (EMA)
"""
function ema(pₜ::AbstractVector{T}, α::Real=.07) where {T<:Real}
@assert length(pₜ)>1 "pₜ must not be a singleton."
cα = 1-α
maₜ = zeros(length(pₜ))
maₜ[1] = pₜ[1]
@inbounds for t in 2:length(pₜ)
maₜ[t] = α*pₜ[t] + cα*maₜ[t-1]
end
maₜ
end
"""
Ehlers Fisher Transform
Transforms the PDF of the input to approximately Gaussian
source: pp. 3, Cybernetic Analysis for Stocks and Futures by John Ehlers
"""
fisher(pₜ) = .5*log((1+pₜ)/(1-pₜ))
"""
Ehlers Generalized Linear DSP Filter.
Degree of two (`wₒ` like [wₒ₂, wₒ₁, 0] where wₒ₂>0, wₒ₁>0) is recommended by Ehlers for recursive filters.
All array inputs (including weight arrays `wᵢ`, `wₒ`) are in ascending time order.
Filter components are added instead of subtracted (as in the book) so that the filter weights in the indicator implementations exactly match Ehlers's code. Ehlers usually adds the components instead of subtracting when building filters even though in
the provided reference he subtracts.
source: pp. 11, Cycle Analytics for Traders by John Ehlers
"""
function dsp!(fₜ, pₜ, wᵢ, wₒ)
τ = length(wᵢ)
@assert τ == length(wₒ)
for t in τ:length(pₜ)
nonrec = sum(wᵢ .* pₜ[t-τ+1:t])
rec = sum(wₒ .* fₜ[t-τ+1:t])
fₜ[t] = nonrec + rec
end
fₜ
end
function dsp(pₜ, wᵢ, wₒ)
dsp!(zeros(length(pₜ)), pₜ, wᵢ, wₒ)
end
"""
Generalized Smoothing / Non-Recursive Filter.
"""
dsp(pₜ, wᵢ) = slidedot(pₜ, wᵢ)
"""
Ehlers Symmetric Low Pass Finite Impluse Response (FIR) Filter.
This is a WMA with weights like `[1, 2, ..., 2, 1]`
source: pp. 33, Cybernetic Analysis for Stocks and Futures by John Ehlers
"""
function symlowpass(pₜ, τ::Integer=4)
w = repeat([2], τ)
w[begin] = w[end] = 1
dsp(pₜ, w) ./ sum(w)
end
"""
Simple Momentum
"""
function simplemom(pₜ, τ::Integer=2)
momₜ = zeros(size(pₜ))
for t in 1+τ:length(pₜ)
momₜ[t] = 2pₜ[t] - pₜ[t-τ]
end
momₜ
end
"""
Ehlers Instantaneous Trendline Filter
source: pp. 24, Cybernetic Analysis for Stocks and Futures by John Ehlers
"""
function itrend(pₜ, α::Real=.07)
# Initialize first 7 bars to shorten convergence time:
tₒ = 7
trendₜ = zeros(length(pₜ))
trendₜ[begin:tₒ] = symlowpass(pₜ[begin:tₒ], 3)
α² = α^2
wᵢ = [-(α-.75α²), .5α², α-.25α²]
wₒ = [-(1-α)^2, 2(1-α), 0]
dsp!(trendₜ, pₜ, wᵢ, wₒ)
end
"""
Ehlers Instantaneous Trendline Strategy
source: pp. 26, Cybernetic Analysis for Stocks and Futures by John Ehlers
"""
function itrend_xostrat(pₜ, α::Real=.07, τ::Integer=2)
trendₜ = itrend(pₜ, α)
momₜ = simplemom(trendₜ, τ)
buyₜ = crossover(momₜ, trendₜ)
sellₜ = crossover(trendₜ, momₜ)
buyₜ, sellₜ
end
"""
Ehlers Cyber Cycle Indicator
source: pp. 34, Cybernetic Analysis for Stocks and Futures by John Ehlers
"""
function cybercycle(pₜ, α::Real=.07)
# Initialize first 7 bars to shorten convergence time:
tₒ = 7
ccₜ = zeros(length(pₜ))
ccₜ[begin:tₒ] = dsp(pₜ[begin:tₒ], [1, -2, 1]) ./ 4
β = (1 - .5α)^2
wᵢ = β * ([1, -2, 1])
wₒ = [-(1-α)^2, 2(1-α), 0]
dsp!(ccₜ, symlowpass(pₜ), wᵢ, wₒ)
end
"""
Ehlers Cyber Cycle Trading Strategy
Signals are generated from signal[t] and signal[t-1] crossovers
source: pp. 38, Cybernetic Analysis for Stocks and Futures by John Ehlers
"""
function cybercycle_xostrat(pₜ, α::Real=.07, τ::Integer=9)
ccₜ = cybercycle(pₜ, α)
α₂ = 1 / (τ + 1)
signalₜ = ema(ccₜ, α₂)
signalₜ₋₁ = signalₜ[begin:end-1]
signalₜ = signalₜ[begin+1:end]
buyₜ = crossover(signalₜ₋₁, signalₜ)
sellₜ = crossover(signalₜ, signalₜ₋₁)
insert!(buyₜ, 1, false)
insert!(sellₜ, 1, false)
buyₜ, sellₜ
end
"""
Ehlers Center of Gravity (CG) Oscillator
source: pp. 49, Cybernetic Analysis for Stocks and Futures by John Ehlers
"""
function cg(pₜ, τ::Integer=10)
cgratio = dsp(pₜ, 1:τ) ./ slidesum(pₜ, τ)
-cgratio .+ ((τ+1)/2)
end
"""
Ehlers Relative Vigor Index
source: pp. 58, Cybernetic Analysis for Stocks and Futures by John Ehlers
"""
function rvi(oₜ, hₜ, lₜ, cₜ, τ::Integer=10)
co = slidesum(symlowpass(cₜ .- oₜ), τ)
hl = slidesum(symlowpass(hₜ .- lₜ), τ)
co ./ hl
end
function rvi(ohlcₜ::AbstractMatrix, τ::Integer=10)
rvi(ohlcₜ[:, 1], ohlcₜ[:, 2], ohlcₜ[:, 3], ohlcₜ[:, 4], τ)
end
"""
Ehlers Relative Vigor Index - Adaptive
"""
function arvi()
end
"""
Ehlers Super Smoother Filter
source: pp. 33, Cycle Analytics for Traders by John Ehlers
"""
function supersmooth(pₜ, τ::Integer=10)
α = ℯ^(-π√2/τ)
α² = α^2
β = 2α*cosd(180√2/τ)
c = 1 - β + α²
dsp(pₜ, .5c*([0, 1, 1]), [-α², β, 0])
end
"""
Ehlers Super Smoother Crossover Strat
τ₁ > τ₂: trend following
τ₁ < τ₂: mean reversion
"""
function supersmooth_xostrat(pₜ, τ₁::Integer=3, τ₂::Integer=7)
fastₜ = supersmooth(pₜ, τ₁)
slowₜ = supersmooth(pₜ, τ₂)
buyₜ = crossover(fastₜ, slowₜ)
sellₜ = crossover(slowₜ, fastₜ)
buyₜ, sellₜ
end
"""
Ehlers Decycler Oscillator Strat
source: pp. 41, Cycle Analytics for Traders by John Ehlers
"""
function decycler(pₜ, f::Integer=60)
α = (cosd(360/f) + sind(360/f) - 1) / cosd(360/f)
wᵢ = [.5α, .5α]
wₒ = [1-α, 0]
dsp(pₜ, wᵢ, wₒ)
end
"""
Ehlers Decycler Oscillator
source: pp. 44, Cycle Analytics for Traders by John Ehlers
"""
function decycler_osc(pₜ, f₁::Integer=30, f₂::Integer=60)
function decyclercomp(pₜ, f::Integer)
c = (√2/2)*360
α = (cosd(c/f) + sind(c/f) - 1) / cosd(c/f)
β = (1 - .5α)^2
wᵢ = [β, -2β, β]
wₒ = [-(1-α)^2, 2(1-α), 0]
dsp(pₜ, wᵢ, wₒ)
end
decyclercomp(pₜ, f₂) .- decyclercomp(pₜ, f₁)
end
"""
Ehlers Roofing Filter
The Roofing Filter is a wide bandwidth bandpass filter,
combining a wide high pass filter with a wide low pass (supersmoother) filter.
For reference Ehlers's example sets the pass band periods from 10 bars to 48 bars.
The theory is the high pass filter removes irrelevant low frequency components
and the low pass filter removes aliasing noise from sampling at the wrong frequency.
source: pp. 78, Cycle Analytics for Traders by John Ehlers
"""
function roof(pₜ, τₗ::Integer=10, τₕ::Integer=48)
α = (cosd(360/τₕ) + sind(360/τₕ) - 1) / cosd(360/τₕ)
wᵢ₀ = 1 - α/2
hpₜ = dsp(pₜ, wᵢ₀*([-1, 1]), [1-α, 0])
supersmooth(hpₜ, τₗ)
end
"""
Alternate Roofing Filter used for Autocorrelation Periodogram
source: pp. 94-98, 103-109 Cycle Analytics for Traders by John Ehlers
"""
function roof_acp(pₜ, τₗ::Integer=10, τₕ::Integer=48)
α = (cosd((.5√2)*360/τₕ) + sind((.5√2)*360/τₕ) - 1) / cosd((.5√2)*360/τₕ)
wᵢ = (1 - α/2)^2 * ([1, -2, 1])
wₒ = [-(1-α)^2, 2(1-α), 0]
hpₜ = dsp(pₜ, wᵢ, wₒ)
supersmooth(hpₜ, τₗ)
end
Hey!
Sorry been neck deep in projects. Working on John Ehlers indicators from his latest book. Here are a few to get started:
When I get a chance I will take a look at the other implementations you made for the RS hurst. Ehlers has a hurst function which is also interesting and maybe of more value than the RS method.
More to come!