Tripple MA
Strategy based on Triple Moving Average crossover
Testing indicates an average annual return of about 55%. It performs best in the stocks market.
Triple MA aligns three moving averages to define direction. When the shortest average is above the middle and long averages a long entry occurs. The reverse alignment opens shorts, and a cross of the short and middle lines closes the trade.
Using three averages helps filter out noise present in single-MA systems. This layered approach seeks to confirm momentum before committing to a trade.
Details
- Entry Criteria: Signals based on MA.
- Long/Short: Both directions.
- Exit Criteria: Opposite signal or stop.
- Stops: Yes.
- Default Values:
ShortMaPeriod= 5MiddleMaPeriod= 20LongMaPeriod= 50StopLossPercent= 2mCandleType= TimeSpan.FromMinutes(5)
- Filters:
- Category: Trend
- Direction: Both
- Indicators: MA
- Stops: Yes
- Complexity: Basic
- Timeframe: Intraday (5m)
- Seasonality: No
- Neural Networks: No
- Divergence: No
- Risk Level: Medium
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy based on Triple Moving Average crossover.
/// It enters long position when short MA > middle MA > long MA and short position when short MA < middle MA < long MA.
/// </summary>
public class TripleMAStrategy : Strategy
{
private readonly StrategyParam<int> _shortMaPeriod;
private readonly StrategyParam<int> _middleMaPeriod;
private readonly StrategyParam<int> _longMaPeriod;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
// Current state
private bool _prevIsShortAboveMiddle;
private bool _prevIsBullish;
private bool _prevIsBearish;
/// <summary>
/// Period for short moving average.
/// </summary>
public int ShortMaPeriod
{
get => _shortMaPeriod.Value;
set => _shortMaPeriod.Value = value;
}
/// <summary>
/// Period for middle moving average.
/// </summary>
public int MiddleMaPeriod
{
get => _middleMaPeriod.Value;
set => _middleMaPeriod.Value = value;
}
/// <summary>
/// Period for long moving average.
/// </summary>
public int LongMaPeriod
{
get => _longMaPeriod.Value;
set => _longMaPeriod.Value = value;
}
/// <summary>
/// Stop-loss percentage.
/// </summary>
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initialize the Triple MA strategy.
/// </summary>
public TripleMAStrategy()
{
_shortMaPeriod = Param(nameof(ShortMaPeriod), 100)
.SetDisplay("Short MA Period", "Period for short moving average", "Indicators")
.SetOptimize(3, 10, 1);
_middleMaPeriod = Param(nameof(MiddleMaPeriod), 250)
.SetDisplay("Middle MA Period", "Period for middle moving average", "Indicators")
.SetOptimize(15, 30, 5);
_longMaPeriod = Param(nameof(LongMaPeriod), 500)
.SetDisplay("Long MA Period", "Period for long moving average", "Indicators")
.SetOptimize(40, 100, 10);
_stopLossPercent = Param(nameof(StopLossPercent), 2m)
.SetDisplay("Stop Loss (%)", "Stop loss as a percentage of entry price", "Risk parameters")
.SetOptimize(1, 3, 0.5m);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevIsShortAboveMiddle = default;
_prevIsBullish = default;
_prevIsBearish = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Create indicators
var shortMa = new ExponentialMovingAverage { Length = ShortMaPeriod };
var middleMa = new ExponentialMovingAverage { Length = MiddleMaPeriod };
var longMa = new ExponentialMovingAverage { Length = LongMaPeriod };
// Create subscription and bind indicators
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(shortMa, middleMa, longMa, ProcessCandle)
.Start();
// Setup chart visualization if available
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, shortMa);
DrawIndicator(area, middleMa);
DrawIndicator(area, longMa);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal shortMaValue, decimal middleMaValue, decimal longMaValue)
{
// Skip unfinished candles
if (candle.State != CandleStates.Finished)
return;
// Check if strategy is ready to trade
if (!IsFormedAndOnlineAndAllowTrading())
return;
// Check the MA alignments
var isShortAboveMiddle = shortMaValue > middleMaValue;
var isMiddleAboveLong = middleMaValue > longMaValue;
// Check for MA crossover
var isShortCrossedMiddle = isShortAboveMiddle != _prevIsShortAboveMiddle;
// Check for alignment conditions
var isBullishAlignment = isShortAboveMiddle && isMiddleAboveLong;
var isBearishAlignment = !isShortAboveMiddle && !isMiddleAboveLong;
// Entry logic based on three MA alignment change
if (isBullishAlignment && !_prevIsBullish && Position <= 0)
{
BuyMarket(Volume + Math.Abs(Position));
}
else if (isBearishAlignment && !_prevIsBearish && Position >= 0)
{
SellMarket(Volume + Math.Abs(Position));
}
// Update previous state
_prevIsShortAboveMiddle = isShortAboveMiddle;
_prevIsBullish = isBullishAlignment;
_prevIsBearish = isBearishAlignment;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class triple_ma_strategy(Strategy):
"""
Strategy based on Triple Moving Average crossover.
Enters long when short MA > middle MA > long MA.
Enters short when short MA < middle MA < long MA.
"""
def __init__(self):
super(triple_ma_strategy, self).__init__()
self._short_ma_period = self.Param("ShortMaPeriod", 100).SetDisplay("Short MA Period", "Period for short moving average", "Indicators")
self._middle_ma_period = self.Param("MiddleMaPeriod", 250).SetDisplay("Middle MA Period", "Period for middle moving average", "Indicators")
self._long_ma_period = self.Param("LongMaPeriod", 500).SetDisplay("Long MA Period", "Period for long moving average", "Indicators")
self._stop_loss_percent = self.Param("StopLossPercent", 2.0).SetDisplay("Stop Loss (%)", "Stop loss as a percentage of entry price", "Risk parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_is_short_above_middle = False
self._prev_is_bullish = False
self._prev_is_bearish = False
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(triple_ma_strategy, self).OnReseted()
self._prev_is_short_above_middle = False
self._prev_is_bullish = False
self._prev_is_bearish = False
def OnStarted2(self, time):
super(triple_ma_strategy, self).OnStarted2(time)
short_ma = ExponentialMovingAverage()
short_ma.Length = self._short_ma_period.Value
middle_ma = ExponentialMovingAverage()
middle_ma.Length = self._middle_ma_period.Value
long_ma = ExponentialMovingAverage()
long_ma.Length = self._long_ma_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(short_ma, middle_ma, long_ma, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, short_ma)
self.DrawIndicator(area, middle_ma)
self.DrawIndicator(area, long_ma)
self.DrawOwnTrades(area)
def _process_candle(self, candle, short_val, middle_val, long_val):
if candle.State != CandleStates.Finished:
return
s = float(short_val)
m = float(middle_val)
l = float(long_val)
is_short_above_middle = s > m
is_middle_above_long = m > l
is_bullish = is_short_above_middle and is_middle_above_long
is_bearish = not is_short_above_middle and not is_middle_above_long
if is_bullish and not self._prev_is_bullish and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif is_bearish and not self._prev_is_bearish and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
self._prev_is_short_above_middle = is_short_above_middle
self._prev_is_bullish = is_bullish
self._prev_is_bearish = is_bearish
def CreateClone(self):
return triple_ma_strategy()