MACD EMA Crossover Trend Tracking Strategy

Author: ChaoZhang, Date: 2024-02-18 15:17:36



This strategy determines the trend direction by calculating the crossover between the MACD indicator and its signal line moving average, and judges the strength of the current trend with the EMA indicator to track the trend. It goes long when the MACD line breaks through the signal line upward and goes short when breaking through downward. The EMA line can also judge the strength of the trend to filter out false breakouts.

Strategy Logic

The core of this strategy is to determine the trend direction and entry timing based on the MACD indicator. The crossover between the MACD line and the signal line indicates a reversal in the price trend. Therefore, long and short positions are determined according to the breakout direction. Specifically, when the closing price is above the EMA line and the MACD line breaks through the signal line from below, go long; when the closing price is below the EMA line and the MACD line breaks through the signal line from above, go short.

The EMA line serves to assist in judging the trend. If the price is above the EMA line, it indicates an upward trend. At this time, a breakthrough from the MACD below is likely to form a golden cross signal. If the price is below the EMA line, it indicates a downward trend. At this time, a breakthrough from above the MACD is likely to form a death cross signal. The EMA length also determines the mid-to-long term degree of the trend judgment.

In this way, we can enter the market in a timely manner when the price begins to reverse to form a new trend, achieving a trend tracking effect.

Advantage Analysis

This strategy combines dual judgment conditions, taking into account both the trend direction of prices and using indicators to determine specific entry timing, avoiding the risk of false breakouts, and enhances the reliability of the strategy. Compared with using the MACD indicator alone, this strategy can more accurately determine the start of a new trend.

The application of the EMA line also enables the strategy to filter out the effects of short-term fluctuations and lock in medium and long term trends to some extent. This is very helpful for developing the effectiveness of the MACD indicator in judging reversal.

In addition, the strategy sets conditions for both long and short, which can be applied to bull and bear kite markets, thus enhancing the adaptability of the strategy.

Risk Analysis

The main risk of this strategy is that the MACD indicator itself has a high probability of misjudging Fakeout signals. At this point, the auxiliary function of the EMA line is needed, but failures can still happen in special market conditions.

In addition, the strategy adopts a profit factor to set stop loss and take profit conditions, which involves some subjectivity. Improper settings may also affect strategy performance.

Finally, the strategy simply sets the position size to 100% of the account’s equity without considering the issue of fund management, which also poses some risks in live trading.

Optimization Directions

The main optimization directions for this strategy include:

  1. Increase other indicators for judgment to form multiple indicator combinations to further avoid the probability of MACD generating wrong signals. For example, KDJ and BOLL can be considered.

  2. The EMA line length can be multi-parameter optimized to find the optimal parameters for judging trend direction.

  3. The MACD parameters can also be further optimized to find the most accurate values for determining reversal timing.

  4. Add a capital management module. For example, the profit factor can be used as a dynamic input, and slippage stops can also be set.

  5. Test the effects on different types of contracts, such as cryptocurrencies, index futures, etc. to find the most suitable trading variety.


Overall, this MACD EMA Crossover Trend Tracking strategy is relatively simple and practical. It ensures signal reliability through dual indicator conditions and locks in profits through reasonable stop loss and take profit methods. The main optimization space lies in parameter selection, indicator combinations, capital management, etc. With further optimization and testing, it is believed that this strategy can become one of the most efficient trend tracking strategies.

start: 2024-01-01 00:00:00
end: 2024-01-31 23:59:59
period: 1h
basePeriod: 15m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]


strategy(title="MACD EMA Strategy", shorttitle="MACD EMA STRAT", overlay = true, pyramiding = 0, max_bars_back=3000, calc_on_order_fills = false, commission_type =  strategy.commission.percent, commission_value = 0, default_qty_type = strategy.percent_of_equity, default_qty_value = 100, initial_capital=5000, currency=currency.USD)

// Time Range

// STEP 2:
// See if this bar's time happened on/after start date
afterStartDate = true

emasrc = close
res = input(title="EMA Timeframe", type=input.resolution, defval="15")
len1 = input(title="EMA Length", type=input.integer, defval=206)
col1 = color.yellow
// Calculate EMA
ema1 = ema(emasrc, len1)
emaSmooth = security(syminfo.tickerid, res, ema1, barmerge.gaps_on, barmerge.lookahead_off)
// Draw EMA
plot(emaSmooth, title="EMA", linewidth=1, color=col1)

fast_length = input(title="Fast Length", type=input.integer, defval=15)
slow_length = input(title="Slow Length", type=input.integer, defval=24)
src = input(title="Source", type=input.source, defval=close)
signal_length = input(title="Signal Smoothing", type=input.integer, minval = 1, maxval = 50, defval = 9)
sma_source = input(title="Simple MA (Oscillator)", type=input.bool, defval=true)
sma_signal = input(title="Simple MA (Signal Line)", type=input.bool, defval=true)
zeroline = 0

// Plot colors
col_grow_above = #26A69A
col_grow_below = #FFCDD2
col_fall_above = #B2DFDB
col_fall_below = #EF5350
col_macd = #0094ff
col_signal = #ff6a00

// Calculating
fast_ma = sma_source ? sma(src, fast_length) : ema(src, fast_length)
slow_ma = sma_source ? sma(src, slow_length) : ema(src, slow_length)
macd = fast_ma - slow_ma
signal = sma_signal ? sma(macd, signal_length) : ema(macd, signal_length)
hist = macd - signal
//plot(hist, title="Histogram", style=plot.style_columns, color=(hist>=0 ? (hist[1] < hist ? col_grow_above : col_fall_above) : (hist[1] < hist ? col_grow_below : col_fall_below) ), transp=0 )
//plot(macd, title="MACD", color=col_macd, transp=0)
//plot(signal, title="Signal", color=col_signal, transp=0)
//plot(zeroline, title="Zero Line",, transp=0)


enablelong = input(true, title="Enable long?")

//Long Signal
upcondition = close > emaSmooth and close[1] > emaSmooth[1]
macdunderhis = macd < zeroline
macdcrossup = crossover(macd, signal)

longcondition = upcondition and macdunderhis and macdcrossup

//strategy buy long
if (longcondition) and (afterStartDate) and strategy.opentrades < 1 and (enablelong == true)
    strategy.entry("long", strategy.long)


enableshort = input(true, title="Enable short?")

//Short Signal
downcondition = close < emaSmooth and close[1] < emaSmooth[1]
macdoverhis = macd > zeroline
macdcrosunder = crossunder(macd, signal)

shortcondition = downcondition and macdoverhis and macdcrosunder

//strategy buy short
if (shortcondition) and (afterStartDate) and strategy.opentrades < 1 and (enableshort == true)
    strategy.entry("short", strategy.short)

//////////////////////////////////////EXIT CONDITION//////////////////////////////////////////////////////////////////////////////////
bought = strategy.position_size[1] < strategy.position_size
sold = strategy.position_size[1] > strategy.position_size
barsbought = barssince(bought)
barssold = barssince(sold)
//////LOWEST LOW//////
//Lowest Low LONG
profitfactorlong = input(title="ProfitfactorLong", type=input.float, step=0.1, defval=1.9)
loLen = input(title="Lowest Low Lookback", type=input.integer,
  defval=46, minval=2)
stop_level_long = lowest(low, loLen)[1]

if strategy.position_size>0 
    profit_level_long = strategy.position_avg_price + ((strategy.position_avg_price - stop_level_long[barsbought])*profitfactorlong)
    strategy.exit(id="TP/ SL", stop=stop_level_long[barsbought], limit=profit_level_long)

//Lowest Low SHORT
profitfactorshort = input(title="ProfitfactorShort", type=input.float, step=0.1, defval=2.1)
highLen = input(title="highest high lookback", type=input.integer,
  defval=25, minval=2)
stop_level_short = highest(high, highLen)[1]

if strategy.position_size<0 
    profit_level_short = strategy.position_avg_price - ((stop_level_short[barssold] - strategy.position_avg_price)*profitfactorshort)
    strategy.exit(id="TP/ SL", stop=stop_level_short[barssold], limit=profit_level_short)
plot(stop_level_long, title="SL Long", linewidth=1,
plot(stop_level_short, title="SL Short", linewidth=1,