[blackcat] L2 Ehlers DFT-Adapted RSI

จำนวนเข้าชม 1599
Level: 2


John F. Ehlers introuced his DFT-ADAPTED RELATIVE STRENGTH INDEX ( RSI ) in Jan, 2007.


In "Fourier Transform For Traders" in Jan, 2007, John Ehlers presented an interesting technique of improving the resolution of spectral analysis that could be used to effectively measure market cycles. Better resolution is obtained by a surprisingly simple modification of the discrete Fourier transform. John Ehlers suggests using the discrete Fourier transform (DFT) to tune indicators. Here, I demonstrate this by building a DFT-adapted relative strength index ( RSI ) strategy.

Rather than display the RSI for a single cycle length across the entire chart, Ehlers DFT adaptive RSI value reflects the DFT-calculated dominant cycle length RSI . If the dominant cycle changes from 14 to 18 bars, the RSI length parameter changes accordingly. Computationally, this requires the strategy to continuously update values for all possible RSI cycle lengths via a "for" loop and array.

In details, a full-featured formula that implements a high-pass filter ( HP ) and a six-tap low-pass finite impulse response (FIR) filter on input, then does discrete Fourier transform calculations. I has taken liberty of adding extra parameters so the user can modify the analysis window length and the high-pass filter cutoff frequency in real time using the parameters window. Once the suite of possible RSI values is calculated, we use the DFT to select the relevant RSI for the current bar. The strategy then trades according to J. Welles Wilder's original rules for the RSI .

Key Signal


Pros and Cons

100% John F. Ehlers definition translation, even variable names are the same. This help readers who would like to use pine to read his book.


The 71th script for Blackcat1402 John F. Ehlers Week publication.
Based on original work of Ehlers , I added ALMA smoothing on DFT-adapted relative strength index ( RSI ) so that clearer trend can be observed.


In real life, I am a prolific inventor. I have successfully applied for more than 60 international and regional patents in the past 12 years. But in the past two years or so, I have tried to transfer my creativity to the development of trading strategies. Tradingview is the ideal platform for me. I am selecting and contributing some of the hundreds of scripts to publish in Tradingview community. Welcome everyone to interact with me to discuss these interesting pine scripts.

The scripts posted are categorized into 5 levels according to my efforts or manhours put into these works.

Level 1 : interesting script snippets or distinctive improvement from classic indicators or strategy. Level 1 scripts can usually appear in more complex indicators as a function module or element.

Level 2 : composite indicator/strategy. By selecting or combining several independent or dependent functions or sub indicators in proper way, the composite script exhibits a resonance phenomenon which can filter out noise or fake trading signal to enhance trading confidence level.

Level 3 : comprehensive indicator/strategy. They are simple trading systems based on my strategies. They are commonly containing several or all of entry signal, close signal, stop loss, take profit, re-entry, risk management, and position sizing techniques. Even some interesting fundamental and mass psychological aspects are incorporated.

Level 4 : script snippets or functions that do not disclose source code. Interesting element that can reveal market laws and work as raw material for indicators and strategies. If you find Level 1~2 scripts are helpful, Level 4 is a private version that took me far more efforts to develop.

Level 5 : indicator/strategy that do not disclose source code. private version of Level 3 script with my accumulated script processing skills or a large number of custom functions. I had a private function library built in past two years. Level 5 scripts use many of them to achieve private trading strategy.

จากใจ TradingView ผู้เขียนสคริปต์นี้ได้เผยแพร่เป็นโอเพนซอร์ส เพื่อให้ผู้ค้าสามารถเข้าใจและตรวจสอบได้ ยินดีด้วย! คุณสามารถใช้มันได้ฟรี แต่การใช้โค๊ดนี้ซ้ำเพื่อการเผยเเพร่ อยู่ภายใต้ กฎของเรา คุณสามารถตั้งเป็นรายการโปรดเพื่อใช้กับชาร์ตได้

"Win$ & Donate w/ This" Address:
BTC: 1GeuxGE6UUato7AgMnNUjSg56mSzQ6Wxxk
USDT ERC20: 0xfd4d0eb131e81f44530849c1a966cb261dd6bda2
ETH: 0xfd4d0eb131e81f44530849c1a966cb261dd6bda2
LINK: 0xfd4d0eb131e81f44530849


Though I will say there is no reason to go through all that below when the dominant cycle period can just be used in the built-in rsi() function
There is a bug in the RSI calc code where multiple history variables are being referenced ie. nz(array.get(NetChgAvg,Count)){1} in the following lines which doesn't work properly.

array.set(NetChgAvg,Count, nz(array.get(NetChgAvg,Count)){1} + nz(array.get(SF,Count)) * ( Change - nz(array.get(NetChgAvg,Count)){1}))
array.set(TotChgAvg,Count, nz(array.get(TotChgAvg,Count)){1}+ nz(array.get(SF,Count)) * ( AbsChange - nz(array.get(TotChgAvg,Count)){1}))

If you plot the DFT_RSI it won't look like an rsi. It can be corrected by doing something like keeping tract of the prev values in an array.

var prevNetChgAvg = array.new_float(52)
var prevTotChgAvg = array.new_float(52)

for Count = 1 to Window
if bar_index == 1
array.set(SF, Count, 1 / Count)
array.set(NetChgAvg, Count, (Price - nz(Price)) / Count)
array.set(TotChgAvg, Count, sma( AbsChange, Count ))

array.set(prevNetChgAvg,Count, (Price - nz(Price)) / Count)
array.set(prevTotChgAvg,Count, sma( AbsChange, Count ))
pnet = nz(array.get(prevNetChgAvg, Count))
ptot = nz(array.get(prevTotChgAvg,Count))

cnet = pnet + nz(array.get(SF,Count)) * (Change - pnet)
ctot = ptot + nz(array.get(SF,Count)) * (AbsChange - ptot)

array.set(NetChgAvg,Count, cnet)
array.set(TotChgAvg,Count, ctot)

array.set(prevNetChgAvg,Count, cnet)
array.set(prevTotChgAvg,Count, ctot)

//array.set(NetChgAvg,Count, nz(array.get(NetChgAvg,Count)) + nz(array.get(SF,Count)) * ( Change - nz(array.get(NetChgAvg,Count))))
//array.set(TotChgAvg,Count, nz(array.get(TotChgAvg,Count)) + nz(array.get(SF,Count)) * ( AbsChange - nz(array.get(TotChgAvg,Count))))

if nz(array.get(TotChgAvg,Count)) != 0
array.set(RSIArray,Count, (50 *( nz(array.get(NetChgAvg,Count)) / nz(array.get(TotChgAvg,Count)) + 1 )))
array.set(RSIArray,Count, 50)