0bps

Strategy vault / Trend following

Ehlers Instantaneous Trendline Strategy

The Ehlers Instantaneous Trendline strategy is proposed by John Ehlers in his book "Cybernetic Analysis for Stocks and Futures". It utilizes technical indicators to identify real-time trends of stocks/futures and…

Author
ChaoZhang
Complexity
Intermediate · 83 lines
Parameters
16
Backtest bar
1d · swing
Tested on
BTC/USDT · futures

IMG

Overview

The Ehlers Instantaneous Trendline strategy is proposed by John Ehlers in his book "Cybernetic Analysis for Stocks and Futures". It utilizes technical indicators to identify real-time trends of stocks/futures and open positions when trends reverse.

Strategy Logic

The core of this strategy is calculating the Instantaneous Trendline (IT). The formula for IT is:

it := (a-((a*a)/4.0))*src+0.5*a*a*src[1]-(a-0.75*a*a)*src[2]+2*(1-a )*it[1]-(1-a )*(1-a )*it[2]

where src is the price, a is a smoothing factor, default to 0.07. This formula is a second order filter that can smooth the price and generate trends.

Another key indicator is the lag line, calculated by:

lag = 2.0 * it - nz(it[2])

The lag line lags IT line by one bar. When price crosses above lag line, it signals an upside breakout, go long. When price crosses below lag line, it signals a downside breakout, go short.

In addition, the strategy sets stop loss orders to control risks.

Advantage Analysis

The advantages of this strategy include:

  1. IT line effectively filters noise and improves signal quality
  2. The 2nd order filter provides more tuning flexibility and robustness
  3. Lag line avoids unnecessary whipsaws within trends
  4. Incorporated stop loss controls risks at predefined levels
  5. Clean code structure, easy to understand and modify

Risk Analysis

There are also some risks with this strategy:

  1. Improper parameter tuning of IT/lag line may generate false signals
  2. Bad stop loss configuration could result in premature stop out or oversized loss
  3. High trading frequency leads to accumulated commission fees
  4. Long holding times increases loss magnification risk

These risks can be alleviated by:

  1. Applying machine learning for parameter optimization
  2. Setting adaptive stop loss levels
  3. Reducing position sizes to lower trade frequencies
  4. Incorporating holding period stop losses

Optimization Directions

This strategy can be further optimized in the following aspects:

  1. Test impacts of different filter parameters to find optimum
  2. Try combining other indicators to filter signals
  3. Improve entry logic to size up during trend acceleration stages
  4. Set up adaptive stop loss based on market volatility
  5. Conduct time series analysis on trading sessions and frequencies

Conclusion

Overall, the Ehlers Instantaneous Trendline strategy utilizes technical indicators to identify real-time trends in stocks/futures and open positions when trends reverse. It has the advantages of effective noise filtering, high parameter tuneability, clear signal generation logic, and incorporated risk control. With further optimization on parameter selection, signal filtering, position sizing and stop loss tuning, this strategy can achieve even better performance. The clear code structure also makes it easy to understand and modify. In summary, this is an efficient trend following system worth testing and improving.

Parameters

NameDefaultWhat it controls
v_input_1_hl20Source: hl2 | high | low | open | close | hlc3 | hlcc4 | ohlc4
v_input_20.07Alpha
v_input_3falseFill Trend Region
v_input_40.35rngFrac
v_input_50.015revPct
v_input_60Stop type: stop-order | market-order | None
v_input_70.5Spread
v_input_8falseCustom Backtesting Dates
v_input_92018Backtest Start Year
v_input_109Backtest Start Month
v_input_11trueBacktest Start Day
v_input_12falseBacktest Start Hour
v_input_132018Backtest Stop Year
v_input_1412Backtest Stop Month
v_input_1514Backtest Stop Day
v_input_1614Backtest Stop Hour

Source Pine Script

/*backtest
start: 2022-12-13 00:00:00
end: 2023-12-19 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

//@version=3
strategy("Ehlers Instantaneous Trendline Strategy", shorttitle = "Ehlers Instantaneous Trendline Strategy", overlay = true, default_qty_type = strategy.percent_of_equity, default_qty_value = 100.0, pyramiding = 1, backtest_fill_limits_assumption = 1)
src = input(hl2, title="Source")
a = input(0.07, title="Alpha", step=0.01) 
fr = input(false, title="Fill Trend Region")
it = na
if (na(it[2]) or na(it[1]))
    it := (src + 2 * src[1] + src[2]) / 4.0
else
    it := (a-((a*a)/4.0))*src+0.5*a*a*src[1]-(a-0.75*a*a)*src[2]+2*(1-a )*it[1]-(1-a )*(1-a )*it[2]
lag = 2.0 * it - nz(it[2])
rngFrac = input(0.35)
revPct = input(0.015)
stopType = input(title="Stop type", defval = "stop-order", options = ["stop-order", "market-order", "None"])

diff = input(0.5, title = "Spread")
LongPrice(p) =>
    LongPrice = diff == 0 ? p : floor(p / diff) * diff

ShortPrice(p) =>
    ShortPrice = diff == 0 ? p : ceil(p / diff) * diff

strategy.cancel_all()
reverseTrade = false
if stopType == "market-order" 
    if  strategy.position_size > 0 and close < strategy.position_avg_price * (1 - revPct) 
        strategy.order("StopLoss open short", strategy.short, 2 * strategy.position_size, limit = close - 2 * diff)
        reverseTrade := true
    if  strategy.position_size < 0 and close > strategy.position_avg_price * (1 + revPct) 
        strategy.order("StopLoss open long", strategy.long, -2 * strategy.position_size, limit = close + 2 * diff)
        reverseTrade := true
    
if lag > it and not reverseTrade
    price = LongPrice(max(close - (high - low) * rngFrac, low))
    if strategy.position_size <= 0
        strategy.order("Open long", strategy.long, strategy.equity / price - strategy.position_size, limit = price)
        if stopType == "stop-order"
            strategy.order("StopLoss open long", strategy.short, 2 * strategy.equity / price, stop = ShortPrice(price * (1 - revPct)))
    else
        if stopType == "stop-order"
            strategy.order("StopLoss open short", strategy.short, 2 * strategy.position_size, stop = ShortPrice(strategy.position_avg_price * (1 - revPct)))
if lag < it and not reverseTrade
    price = ShortPrice(min(close - (high - low) * rngFrac, high))
    if strategy.position_size >= 0
        strategy.order("Open short", strategy.short, strategy.equity / price + strategy.position_size, limit = price)
        if stopType == "stop-order"
            strategy.order("StopLoss open short", strategy.long, 2 * strategy.equity / price, stop = LongPrice(price * (1 + revPct)))
    else
        if stopType == "stop-order"
            strategy.order("StopLoss open long", strategy.long, -2 * strategy.position_size, stop = LongPrice(strategy.position_avg_price * (1 + revPct)))


itPlot=plot(it, color=red, linewidth=1, title="Trend")
lagPlot=plot(lag, color=blue, linewidth=1, title="Trigger")
fill(itPlot, lagPlot, it < lag ? green : red,  transp=70)

// === Backtesting Dates ===
testPeriodSwitch = input(false, "Custom Backtesting Dates")
testStartYear = input(2018, "Backtest Start Year")
testStartMonth = input(9, "Backtest Start Month")
testStartDay = input(1, "Backtest Start Day")
testStartHour = input(0, "Backtest Start Hour")
testPeriodStart = timestamp(testStartYear,testStartMonth,testStartDay,testStartHour,0)
testStopYear = input(2018, "Backtest Stop Year")
testStopMonth = input(12, "Backtest Stop Month")
testStopDay = input(14, "Backtest Stop Day")
testStopHour = input(14, "Backtest Stop Hour")
testPeriodStop = timestamp(testStopYear,testStopMonth,testStopDay,testStopHour,0)
testPeriod() =>
    time >= testPeriodStart and time <= testPeriodStop ? true : false
isPeriod = testPeriodSwitch == true ? testPeriod() : true
// === /END
if not isPeriod
    strategy.cancel_all()
    strategy.close_all()

Published by ChaoZhang on the FMZ strategy square · last modified 2023-12-20. Collected in the Quant Trading Vault. Unvalidated research: re-test with your own data and costs before trusting it.

Build this with AgenKit

A spec is not a trading system. Paste this into your coding agent and AgenKit runs a specialist team — architecture, test-first build, risk gates, review — with paper trading on by default.

in Claude Code, Cursor, Codex & 4 more
/agenkit build a production-grade trading bot with a backtest engine, risk controls and paper trading by default from strategies/Ehlers-Instantaneous-Trendline-Strategy.md
  1. npx agenkit install engineering-kit in your project
  2. Paste the command into your agent and approve each phase
  3. Get tests, backtest, risk controls and a paper-trading switch

Understand it first

Before you run this, read the lesson behind the idea and how to backtest it honestly. Specs like this one are the survivors of an unknown number of trials; deflate their results accordingly.

Related specs

esc

Try , , or .

↑↓ move↵ open