Momentum Moving Average Consolidation Strategy

Author: ChaoZhang, Date: 2024-01-25 11:39:00



This strategy mainly uses the consolidation formed by the moving average lines HMA and EMA to determine the timing of buying. When HMA crosses above EMA, it is considered that the consolidation is over and a new upward trend is formed, so buy when HMA crosses above EMA at the same time.

The strategy also combines the RSI indicator to detect overbought and oversold conditions. It allows buying when RSI is below 70 and considers taking partial profits when RSI is above 80.

Strategy Principle

This strategy uses a moving average system constructed with 200-period EMA and HMA. Among them, the HMA indicator is a more sensitive moving average indicator designed based on EMA. When HMA crosses above EMA, it means that the consolidation stage is over and the stock price starts to rise. At this time, if the RSI indicator shows no overbought, a buy signal is generated.

In the case of an existing position, if the stock price falls back and HMA crosses below EMA again, indicating the beginning of a new consolidation, the entire position will be closed. At the same time, if RSI crosses above 80, 20% of the profits will be partially taken to prevent losses.

The transaction logic of this strategy is quite simple, mainly relying on the long and short crossings of HMA and EMA, combined with RSI’s highs and lows, to form a relatively robust trading strategy.

Advantage Analysis

The biggest advantage of this strategy is that by utilizing the consolidation trading pattern of EMA and HMA, most False Breaks can be filtered out, thereby improving the profit rate. At the same time, the auxiliary of the RSI indicator can also effectively control risks. The combination of the two makes this strategy very suitable for consolidation and volatility markets.

In addition, this strategy only uses 3 indicators and the logic is simple, which makes it easy to optimize parameters and backtest, which is conducive to the verification and improvement of strategies.

Risk Analysis

Although this strategy has some advantages, there are still some risks to note. For example, the holding time may be relatively long, requiring sufficient funds to support. If it encounters a period of sideways consolidation, it cannot exit quickly with a stop loss, which easily leads to the situation of expanding losses.

In addition, this strategy mainly relies on moving average indicators. If there is an abnormal breakthrough in prices, stop-loss measures may not be able to take effect, which will bring greater risks. In addition, parameter settings will also affect strategy performance and require extensive testing to find optimal parameters.

Optimization Directions

Considering the above risks, this strategy can be optimized in the following aspects:

  1. Combine volatility indicators to dynamically adjust positions based on market volatility.

  2. Increase trend indicator judgments to avoid unnecessary reversal trading.

  3. Optimize moving average parameters to make them closer to current market characteristics.

  4. Use time stops to avoid oversized single losses.


Overall, this is a relatively classic simple consolidation and volatility strategy. It is mainly used for short-term and medium-term trading of stock indexes and hot stocks, and can obtain relatively stable alpha values. With the optimization of parameters and strengthening risk control measures, the performance of this strategy still has great room for improvement.

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

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

strategy(title="EMA_HMA_RSI_Strategy", overlay=true, pyramiding=2,, default_qty_value=10000, initial_capital=10000, currency=currency.USD)  //default_qty_value=10, default_qty_type=strategy.fixed, 

//longCondition = crossover(sma(close, 14), sma(close, 28))
//if (longCondition)
    //strategy.entry("My Long Entry Id", strategy.long)

//shortCondition = crossunder(sma(close, 14), sma(close, 28))
//if (shortCondition)
  //  strategy.entry("My Short Entry Id", strategy.short)

HMA(src1, length1) =>  wma(2 * wma(src1, length1/2) - wma(src1, length1), round(sqrt(length1)))

var stopLossVal=0.00

//variables BEGIN
length=input(200,title="EMA and HMA Length")   //square root of 13

rsiLength=input(13, title="RSI Length")

takePartialProfits = input(true, title="Take Partial Profits (if this selected, RSI 13 higher reading over 80 is considered for partial closing ) ")

stopLoss = input(title="Stop Loss%", defval=8, minval=1)
//variables  END



//exitOnAroonOscCrossingDown = input(true, title="Exit when Aroon Osc cross down zero ")

// Drawings

//Aroon oscillator

arronUpper = 100 * (highestbars(high, length+1) + length)/length
aroonLower = 100 * (lowestbars(low, length+1) + length)/length

aroonOsc  = arronUpper - aroonLower

aroonMidpoint = 0
//oscPlot = plot(aroonOsc,
//midLine= plot(aroonMidpoint,
//topLine = plot(90,style=plot.style_circles,
//bottomLine = plot(-90,style=plot.style_circles,

//fill(oscPlot, midLine, color=aroonOsc>0?, transp=50)
//fill(topLine,oscPlot, color=aroonOsc>90?color.purple:na, transp=25)

// RSI 
//plot(rsi13, title="RSI", linewidth=2, color=color.purple)
//hline(50, title="Middle Line", linestyle=hline.style_dotted)
//obLevel = hline(80, title="Overbought", linestyle=hline.style_dotted)
//osLevel = hline(30, title="Oversold", linestyle=hline.style_dotted)
//fill(obLevel, osLevel, title="Background", color=rsi13 >=30 ?, transp=65)  // longTermRSI >=50

hullColor = hma200 > hma200[2] ? #00ff00 : #ff0000

plot(hma200, title="HULL 200", color=hullColor,  transp=25)
plot(ema200, title="EMA 200",

strategy.initial_capital = 50000
strategy.entry(id="Long Entry", comment="LE", qty=(strategy.initial_capital * 0.10)/close, long=true,  when=strategy.position_size<1 and hma200 < ema200   and  hma200 > hma200[2]  and rsi13<70 )     //  // aroonOsc<0

if(strategy.position_size>=1 and  close < strategy.position_avg_price and  ( crossover(rsi13,30) or  crossover(rsi13,40) ) )   // hma200 < ema200   and  hma200 > hma200[2]   and hma200[2] < hma200[3] )  //and crossover(rsi13,30)  aroonOsc<0    //and hma200 > hma200[2]  and hma200[2] <= hma200[3]  //crossover(rsi13,30)
    qty1=(strategy.initial_capital * 0.10)/close
    //stopLossVal:= abs(strategy.position_size)>1 ?  ( (close > close[1] and close > open and close>strategy.position_avg_price) ? close[1]*(1-stopLoss*0.01) : stopLossVal ) : 0.00 
    strategy.entry(id="Long Entry", comment="Add", qty=qty1, long=true )     //crossover(close,ema34)  //and close>ema34  //crossover(rsi5Val,rsiBuyLine)  --   SL="+tostring(stopLossVal, "####.##")

//stopLossVal:= abs(strategy.position_size)>1 ? strategy.position_avg_price*(1-0.5) : 0.00 

stopLossVal:= abs(strategy.position_size)>1 ?  ( (close > close[1] and close > open and close>strategy.position_avg_price) ? close[1]*(1-stopLoss*0.01) : stopLossVal ) : 0.00 
//stopLossVal:= abs(strategy.position_size)>1 ?  strategy.position_avg_price*(1-stopLoss*0.01) :  0.00

barcolor(color=strategy.position_size>=1? rsi13>80 ? color.purple:

//close partial
    strategy.close(id="Long Entry", comment="Partial X  points="+tostring(close - strategy.position_avg_price, "####.##"),  qty_percent=20 , when=abs(strategy.position_size)>=1 and crossunder(rsi13, 80)  and close > strategy.position_avg_price  )   //close<ema55 and rsi5Val<20 //ema34<ema55

//close All
  //  strategy.close(id="Long Entry", comment="Exit All points="+tostring(close - strategy.position_avg_price, "####.##"),  when=abs(strategy.position_size)>=1 and crossunder(aroonOsc, 0) )   //close<ema55 and rsi5Val<20 //ema34<ema55  //close<ema89

//close All on stop loss
strategy.close(id="Long Entry", comment="Stoploss X points="+tostring(close - strategy.position_avg_price, "####.##"),  when=abs(strategy.position_size)>=1 and close < stopLossVal  )  //close<ema55 and rsi5Val<20 //ema34<ema55  //close<ema89

strategy.close(id="Long Entry", comment="hmaXema X points="+tostring(close - strategy.position_avg_price, "####.##"),  when=abs(strategy.position_size)>=1 and close > strategy.position_avg_price  and  crossunder(hma200,ema200)  )  //close<ema55 and rsi5Val<20 //ema34<ema55  //close<ema89