A Momentum Crossover Strategy Based on Exponential Moving Average

Author: ChaoZhang, Date: 2024-01-23 14:18:26



This strategy determines the trend direction based on the crossover of EMA lines with different periods and generates long and short signals accordingly. It mainly uses two moving averages - 10-day EMA and 20-day EMA. When the 10-day EMA crosses below the 20-day EMA, a short signal is triggered. When the 10-day EMA crosses above the 20-day EMA, a long signal is triggered. This strategy belongs to medium-term trading strategies.

Strategy Principles

The strategy utilizes two EMA lines, including the 10-day EMA and the 20-day EMA. The EMA lines can reflect the trend of prices effectively. When the shorter-term EMA line crosses above the longer-term EMA line, it indicates the price trend is turning from decline to rise, which is a long signal. When the shorter-term EMA line crosses below the longer-term EMA line, it indicates the price trend is turning from rise to decline, which is a short signal.

The strategy also combines the maximum and minimum values of price fluctuations to filter some trading signals. Trading signals are only triggered after the price fluctuations reach a certain extent. This can filter out some false signals to some degree.

Specifically, by tracking the time when maximum and minimum values are reached, the strategy judges whether a price trend has formed. Real trading signals are only triggered after the maximum or minimum values have lasted for some time.

Advantage Analysis

The strategy has the following advantages:

  1. Using EMA lines to determine trend direction can track market moves effectively
  2. Combining EMA lines of different periods can capture trading opportunities in medium-term
  3. Filtering signals by extreme values can remove some noise and avoid missing trading chances
  4. The logic is simple and clear, easy to understand and modify
  5. Parameters can be adjusted for different products and trading preferences, showing strong adaptability

Risk Analysis

There are also some risks with this strategy:

  1. EMA lines themselves have lagging effect, may miss short-term trend reversals
  2. The noise filtering is imperfect, some wrong trades may occur
  3. Parameters need proper adjustment to suit different market environments

The risks can be mitigated through:

  1. Adding other indicators for signal confirmation to avoid EMA line lagging issues
  2. Optimizing extreme value filtering conditions to improve signal reliability
  3. Adjusting parameters based on backtest results to optimize the strategy

Directions for Enhancement

The strategy can be further optimized in the following aspects:

  1. Incorporate other technical indicators like MACD and KD to improve signal accuracy
  2. Optimize EMA line parameters to better suit specific products
  3. Refine extreme value parameters to better judge price fluctuations
  4. Add stop loss mechanisms to control maximum loss per trade
  5. Test the strategy on different products to evaluate adaptability


In summary, this EMA crossover strategy is a simple and practical trend following strategy. It uses EMA lines to determine the major trend direction, combined with price fluctuation filtering for making trading decisions. It is easy to understand and adjust parameters, adaptable to medium-term trading. With further optimizations, this can become a worthwhile quantitative strategy to hold for the long term.

start: 2024-01-15 00:00:00
end: 2024-01-22 00:00:00
period: 3m
basePeriod: 1m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]

strategy("PierceMAStrat", overlay=true)

lenMA0 = input(title="Length 0",defval=2)
lenMA1=input(title="Length 1",defval=10)
lenMA2=input(title="Length 2", defval=20)
lenMA3 = input(title = "Length3", defval =50)

emaLen0 = ema(close, lenMA0)
emaLen1 = ema(close, lenMA1)
emaLen2 = ema(close, lenMA2)
emaLen3 = ema(close, lenMA3)

ascent = if emaLen1[1] < emaLen1[0]
descent = if emaLen1[1] > emaLen1[0]
TimeSinceAscensionStart = if ascent == true
    barssince(descent == true)

StartUp = if TimeSinceAscensionStart < 1

StartDown = if TimeSinceAscensionStart < 1

AscentBarCounter = barssince(StartUp == true)

DescentBarCounter = barssince(StartDown == true)

MaxAscent = if AscentBarCounter[1] > AscentBarCounter[0] and AscentBarCounter[1] > 10
MaxDescent = if DescentBarCounter[1] > DescentBarCounter[0] and DescentBarCounter[1] > 5
longCond = if crossover(emaLen1, emaLen2) and barssince(MaxDescent == true) > 3
shortCond = if crossunder(emaLen1, emaLen2) and barssince(MaxAscent == true) > 3

//longCond = (crossover(emaLen1, emaLen2) and (emaLen2 > emaLen3))
//shortCond = crossunder(emaLen1, emaLen2) and (emaLen2 < emaLen3)

if longCond == true
    strategy.entry("LONG", strategy.long)

if shortCond == true
    strategy.entry("SHORT", strategy.short)

plotshape(series=MaxAscent, title="MaximaReached", style=shape.triangledown, location=location.abovebar, color=green, text="MaximaReached", size=size.small)
plotshape(series=MaxDescent, title="MinimaReached", style=shape.triangleup, location=location.belowbar, color=red, text="MinimaReached", size=size.small)
//plotshape(series=StartUp, title="StartUp", style=shape.triangleup, location=location.belowbar, color=red, text="StartUp", size=size.tiny)
//plotshape(series=StartDown, title="StartDown", style=shape.triangleup, location=location.belowbar, color=green, text="StartDown", size=size.tiny)

//plotshape(series=(crossover(emaLen1, emaLen3)), title="GBXOVER", style=shape.triangleup, location=location.belowbar, color=green, text="GBXO", size=size.small)
//plotshape(series=(crossover(emaLen2, emaLen3)), title="RBXOVER", style=shape.triangledown, location=location.abovebar, color=orange, text="RBXO", size=size.small)
//plotshape(series=(crossover(emaLen1, emaLen2)), title="GRXOVER", style=shape.triangledown, location=location.abovebar, color=teal, text="GRXO", size=size.small)
//plotshape(series=(crossunder(emaLen1, emaLen2)), title="GRXUNDER", style=shape.triangledown, location=location.abovebar, color=purple, text="GRXU", size=size.small)
//plotshape(series=(crossunder(emaLen1, emaLen3)), title="GBXOVER", style=shape.triangleup, location=location.belowbar, color=yellow, text="GBXU", size=size.small)
//plotshape(series=(crossunder(emaLen2, emaLen3)), title="RBXOVER", style=shape.triangledown, location=location.abovebar, color=yellow, text="RBXU", size=size.small)
//plotshape(convergence, color=lime, style=shape.arrowup, text="CROSS")
plot(emaLen1, color=green, transp=0, linewidth=2)
plot(emaLen2, color=red, transp=30, linewidth=2)
plot(emaLen3, color=blue, transp=30, linewidth=2)