Golden Cross Keltner Channel Trend Following Strategy

Author: ChaoZhang, Date: 2023-11-02 14:31:10



The Golden Cross Keltner Channel Trend Following Strategy is a strategy that only trades in the direction of the trend. It combines the moving average golden cross and Keltner Channel as entry signals to capture the trend direction.


This strategy uses two moving averages, a short-term and a long-term moving average, to form golden crosses and death crosses to determine the trend direction. At the same time, it uses user-defined multiples to plot the upper and lower rails of the Keltner Channel and generate trading signals when prices break through the channel.

Specifically, the strategy first checks if the long-term moving average is above the short-term moving average, indicating a golden cross and an upward trend. If the short-term MA is below the long-term MA, it is a death cross, indicating a downward trend.

Based on the trend determination, if the price breaks above the upper rail, a long signal is generated. If the price breaks below the lower rail, a short signal is generated. Users can adjust the MA periods and channel width to customize the strategy parameters.

After entry, the strategy uses user-defined ATR multiples for take-profit and stop-loss. It also provides additional break-even and stop-loss conditions for more flexible position control.

Advantage Analysis

This strategy combines the advantages of trend following and channel breakouts, enabling effective trend identification and opportunity capturing. The main advantages are:

  1. Golden cross filters out false signals not aligned with the major trend.

  2. Channel breakout with trend direction improves entry accuracy.

  3. Take-profit and stop-loss preserve profits and control risks.

  4. Flexible parameter adjustments suit different products and environments.

  5. Goes both long and short, expanding applicability.

Risk Analysis

Despite the advantages, some risks need attention:

  1. Missing reversal opportunities.

  2. Trend changes may lead to losses.

  3. Improper parameters may cause over-trading or sparse trading.

  4. Overnight risk exists.

  5. Curve fitting risk.

Solutions include parameter optimization, timely MA period adjustment, and position sizing control.

Optimization Directions

There is room for further improvements:

  1. Adding more indicators to build a multi-factor model and improve accuracy. E.g. MACD, RSI.

  2. Parameter optimization via machine learning for market adaptability.

  3. Dynamic take-profit and stop-loss rules to balance profitability and reward.

  4. Dynamic position sizing based on volatility.

  5. Research optimal parameters for different products.

  6. Reduce trading frequency to minimize fees.


The Golden Cross Keltner Channel Trend Following Strategy is generally a stable and reliable trend following system. By combining trend filtering and channel breakouts, it identifies high-probability opportunities aligned with the trend direction. Further optimizations and enhancements can make it a robust trading framework.

start: 2022-10-26 00:00:00
end: 2023-11-01 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]

// This source code is subject to the terms of the Mozilla Public License 2.0 at
// © OversoldPOS

// strategy("Keltner Channel Strategy by OversoldPOS", overlay=true,initial_capital = 100000,default_qty_type = strategy.percent_of_equity,default_qty_value = 10, commission_type = strategy.commission.cash_per_order, commission_value = 7)

// Parameters
length = input(21, title="MA Length")
Entrymult = input(1, title="Entry ATR")
profit_mult = input(4, title="Profit Taker")
exit_mult = input(-1, title="Exit ATR")

// Moving Average Type Input
ma_type = input.string("SMA", title="Moving Average Type", options=["SMA", "EMA", "WMA"])

// Calculate Keltner Channels for different ATR multiples
atr_value = ta.atr(length)

basis = switch ma_type
    "SMA" => ta.sma(close, length)
    "EMA" => ta.ema(close, length)
    "WMA" => ta.wma(close, length)

EntryKeltLong = basis + Entrymult * ta.atr(10)
EntryKeltShort = basis - Entrymult * ta.atr(10)
upper_channel1 = basis + 1 * ta.atr(10)
lower_channel1 = basis - 1 * ta.atr(10)
upper_channel2 = basis + 2 * ta.atr(10)
lower_channel2 = basis - 2 * ta.atr(10)
upper_channel3 = basis + 3 * ta.atr(10)
lower_channel3 = basis - 3 * ta.atr(10)
upper_channel4 = basis + 4 * ta.atr(10)
lower_channel4 = basis - 4 * ta.atr(10)

// Entry condition parameters
long_entry_condition = input(true, title="Long Positions")
short_entry_condition = input(true, title="Enable Short Positions")

// Additional conditions for long and short entries
is_long_entry = ta.ema(close, 20) > ta.ema(close, 50)
is_short_entry = ta.ema(close, 20) < ta.ema(close, 50)

// Additional conditions for long and short entries
MAShort =  input(50, title="Short MA for Golden Cross")
MALong =  input(200, title="Long MA for Golden Cross")
is_long_entry2 = ta.ema(close, MAShort) > ta.ema(close, MALong)
is_short_entry2 = ta.ema(close, MAShort) < ta.ema(close, MALong)

// Exit condition parameters
long_exit_condition1_enabled = input(true, title="Enable Long Profit Taker")
long_exit_condition2_enabled = input(true, title="Enable Long Stop")
short_exit_condition1_enabled = input(true, title="Enable Short Profit Taker")
short_exit_condition2_enabled = input(true, title="Enable Short Stop")

// Take Profit condition parameters
take_profit_enabled = input(true, title="Enable Take Profit Condition")

Takeprofit = basis + profit_mult * atr_value
STakeprofit = basis - profit_mult * atr_value

// Long entry condition
long_condition = long_entry_condition and ta.crossover(close, EntryKeltLong) and is_long_entry2

// Short entry condition
short_condition = short_entry_condition and ta.crossunder(close, EntryKeltShort) and is_short_entry2

// Exit conditions
long_exit_condition1 = long_exit_condition1_enabled and close > Takeprofit
long_exit_condition2 = long_exit_condition2_enabled and close < basis + exit_mult * atr_value
short_exit_condition1 = short_exit_condition1_enabled and close < STakeprofit
short_exit_condition2 = short_exit_condition2_enabled and close > basis - exit_mult * atr_value

// Strategy logic
if (long_condition)
    strategy.entry("Long", strategy.long)
if (short_condition)
    strategy.entry("Short", strategy.short)

if (long_exit_condition1 or long_exit_condition2)

if (short_exit_condition1 or short_exit_condition2)

// Moving Averages
var float MA1 = na
var float MA2 = na

if (ma_type == "SMA")
    MA1 := ta.sma(close, MAShort)
    MA2 := ta.sma(close, MALong)
else if (ma_type == "EMA")
    MA1 := ta.ema(close, MAShort)
    MA2 := ta.ema(close, MALong)
else if (ma_type == "WMA")
    MA1 := ta.wma(close, MAShort)
    MA2 := ta.wma(close, MALong)

// Plotting Keltner Channels with adjusted transparency
transparentColor = color.rgb(255, 255, 255, 56)

plot(upper_channel1, color=transparentColor, title="Upper Channel 1")
plot(lower_channel1, color=transparentColor, title="Lower Channel 1")
plot(upper_channel2, color=transparentColor, title="Upper Channel 2")
plot(lower_channel2, color=transparentColor, title="Lower Channel 2")
plot(upper_channel3, color=transparentColor, title="Upper Channel 3")
plot(lower_channel3, color=transparentColor, title="Lower Channel 3")
plot(upper_channel4, color=transparentColor, title="Upper Channel 4")
plot(lower_channel4, color=transparentColor, title="Lower Channel 4")
plot(basis, color=color.white, title="Basis")
plot(MA1, color=color.rgb(4, 248, 216), linewidth=2, title="Middle MA")
plot(MA2, color=color.rgb(220, 7, 248), linewidth=2, title="Long MA")