Trend Following Strategy Based on EMA Lines

Author: ChaoZhang, Date: 2024-02-05 14:21:18



This strategy is based on 3 EMA lines of different periods. It judges the current trend direction by whether the price is above the EMA lines. When the short-term EMA line crosses above the long-term EMA line, a buy signal is generated. When the short-term EMA line crosses below the long-term EMA line, a sell signal is generated. This strategy tracks the trend runs and closes positions in time when trend reverses.

Strategy Logic

The strategy uses 3 EMA lines, which are 10-day, 20-day and 50-day respectively. The judging rules are:

  1. When both 10-day EMA and 20-day EMA are above 50-day EMA, it is defined as an uptrend;

  2. When both 10-day EMA and 20-day EMA are below 50-day EMA, it is defined as a downtrend;

  3. When short-term EMA lines (10-day and 20-day) cross above long-term EMA line (50-day), a buy signal is generated;

  4. When short-term EMA lines (10-day and 20-day) cross below long-term EMA line (50-day), a sell signal is generated;

  5. Hold long position during uptrend and hold short position during downtrend;

  6. Close current directional position when trend reverses (short-term EMA crosses long-term EMA).

The strategy captures profit by timely closing positions to lock in gains and alternating between long and short positions.

Advantage Analysis

The advantages of this strategy are:

  1. The rules are simple and clear, easy to understand and implement;
  2. Using EMA lines to determine trend avoids interference from short-term market fluctuations;
  3. Timely closing positions to track trend runs avoids expanding losses;
  4. No need to predict market direction with high winning rate by tracking trends.

Risk Analysis

There are also some risks in this strategy:

  1. During range-bound markets, EMA lines may crossover frequently, resulting in high trading costs from frequently opening and closing positions;

  2. Trend determination by EMA may fail after price gap, missing good entry opportunities.

To optimize the risks, some methods can be used:

  1. Open position rules can be relaxed properly when EMAs are close to avoid over-trading;

  2. Determine trend combining other indicators to avoid EMA failure.

Optimization Directions

The strategy can be optimized from the following aspects:

  1. Parameter optimization. Test different EMA period combinations to find the optimal parameters;

  2. Trading cost optimization. Optimize open position rules properly to reduce unnecessary frequent trading;

  3. Stop loss strategy optimization. Set reasonable stop loss level to control single loss;

  4. Combine other indicators. Use MACD, KDJ and other indicators to assist in determining optimal entry timing.


In general, this strategy is quite simple and practical. It uses EMA to determine trend direction with proper stop loss strategy to effectively control risks. There are also rooms for optimization. By combining parameter optimization, stop loss strategy and other indicators, the performance of this strategy can be further improved.

start: 2024-01-28 00:00:00
end: 2024-01-31 04:00:00
period: 45m
basePeriod: 5m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]

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

//study("EMA 10,20 59",overlay=true)
strategy("EMA 10,20 59",overlay=true)
infoBox     = input(true, title="infoBox", type=input.bool)
infoBox2    = input(false, title="infoBox2", type=input.bool)
BuySellSignal_Bool = input(false, title="Buy & SellSignal", type=input.bool)
infoBoxSize = input(title="infoBoxSize", defval=size.large, options=[, size.tiny, size.small, size.normal, size.large, size.huge])
ema1Value   = input(10)
ema2Value   = input(20)
ema3Value   = input(59)
maxLoss = input(3000)
ema1        = ema(close,ema1Value)
ema2        = ema(close,ema2Value)
ema3        = ema(close,ema3Value)
objcnt      = 0
buyTitle    = tostring(close[1])
myProfit    = float(0)


Buytrend = (ema1 and ema2 > ema3) and (ema1[1] and ema2[1] > ema3[1])
BarssinceBuyTrend = barssince(Buytrend)
BarssinceSellTrend = barssince(not Buytrend)
closeAtBuyTrend = close[1]
bgcolor(Buytrend ? :,transp=70)

BuySignal = Buytrend and not Buytrend[1] and BuySellSignal_Bool

BuySignalOut = Buytrend and (crossunder(ema1,ema2)) and BuySellSignal_Bool
BarssinceBuy = barssince(BuySignal)
bgcolor(BuySignal ? : na , transp=30)
bgcolor(BuySignalOut ? : na , transp=30)

SellSignal = not Buytrend and Buytrend[1] and BuySellSignal_Bool
SellSignalOut = not Buytrend and (crossover(ema1,ema2)) and BuySellSignal_Bool
BarssinceSell = barssince(SellSignal)
bgcolor(SellSignal ? : na , transp=30)
bgcolor(SellSignalOut ? : na , transp=30)

buyProfit   = float(0)
cntBuy      =0
sellProfit  = float(0)
cntSell     =0
buyProfit   := Buytrend and not Buytrend[1]? nz(buyProfit[1]) + (close[BarssinceBuyTrend[1]]-close) : nz(buyProfit[1])
cntBuy      := Buytrend and not Buytrend[1]? nz(cntBuy[1]) + 1: nz(cntBuy[1])
sellProfit  := not Buytrend and Buytrend[1]? nz(sellProfit[1]) + (close-close[BarssinceSellTrend[1]]) : nz(sellProfit[1])
cntSell     := not Buytrend and Buytrend[1]? nz(cntSell[1]) + 1 : nz(cntSell[1])
totalProfit = buyProfit + sellProfit

// if (Buytrend and not Buytrend[1] and infoBox==true)
//     l = - (BarssinceBuyTrend[1]/2), na,text="Close = " + tostring(close) + "\n" + "Start = "+tostring(close[BarssinceBuyTrend[1]]) + "\n" + "Profit = "+tostring(close[BarssinceBuyTrend[1]]-close) ,style=label.style_labelup, yloc=yloc.belowbar,,size=infoBoxSize)
// if (not Buytrend and Buytrend[1] and infoBox==true)
//     l = - (BarssinceSellTrend[1]/2), na,text="Close = " + tostring(close) + "\n" + "Start = "+tostring(close[BarssinceSellTrend[1]]) + "\n" + "Profit = "+tostring(close-close[BarssinceSellTrend[1]]) ,style=label.style_labeldown, yloc=yloc.abovebar,,size=infoBoxSize)

// if (BuySignalOut and not BuySignalOut[1] and infoBox2==true)
// //    l = - (BarssinceBuy[0]/2), na,text="Close = " + tostring(close) + "\n" + "Start = "+tostring(close[BarssinceBuy[0]]) + "\n" + "Profit = "+tostring(close-close[BarssinceBuy[0]]) ,style=label.style_labelup, yloc=yloc.belowbar,color=color.purple,size=infoBoxSize
//     l =, na,text="Close = " + tostring(close) + "\n" + "Start = "+tostring(close[BarssinceBuy[0]]) + "\n" + "Profit = "+tostring(close-close[BarssinceBuy[0]]) ,style=label.style_labelup, yloc=yloc.belowbar,color=color.lime,size=infoBoxSize)
// if (SellSignalOut and not SellSignalOut[1] and infoBox2==true)
// //    l = - (BarssinceSell[0]/2), na,text="Close = " + tostring(close) + "\n" + "Start = "+tostring(close[BarssinceSell[0]]) + "\n" + "Profit = "+tostring(close[BarssinceSell[0]]-close) ,style=label.style_labeldown, yloc=yloc.abovebar,color=color.purple,size=infoBoxSize)
//     l =, na,text="Close = " + tostring(close) + "\n" + "Start = "+tostring(close[BarssinceSell[0]]) + "\n" + "Profit = "+tostring(close[BarssinceSell[0]]-close) ,style=label.style_labeldown, yloc=yloc.abovebar,color=color.fuchsia,size=infoBoxSize)

// l2 =, na, 'buyProfit in pip = '+tostring(buyProfit)+"\n"+  'cntBuy = '+tostring(cntBuy) +"\n"+  'sellProfit in pip = '+tostring(sellProfit)+"\n"+  'cntSell = '+tostring(cntSell) +"\n"+  'totalProfit in pip = '+tostring(totalProfit)     , 
//   color=totalProfit>0 ? :, 
//   textcolor=color.white,
//   style=label.style_labeldown, yloc=yloc.abovebar,
//   size=size.large)

// label.delete(l2[1])

if (Buytrend)
    strategy.close("short", comment = "Exit short")
    strategy.entry("long", true)
    strategy.exit("Max Loss", "long", loss = maxLoss)

//if BuySignalOut
   // strategy.close("long", comment = "Exit Long")
if (not Buytrend)
    // Enter trade and issue exit order on max loss.
    strategy.close("long", comment = "Exit Long")
    strategy.entry("short", false)
    strategy.exit("Max Loss", "short", loss = maxLoss)
//if SellSignalOut
    // Force trade exit.
    //strategy.close("short", comment = "Exit short")