The strategy replicates the MetaTrader 5 "55 MA" expert advisor by comparing two points of a 55-period moving average and trading whenever their difference exceeds a configurable threshold. All calculations are performed on completed candles within a user-defined intraday session, and trade direction can optionally be inverted. The algorithm preserves the original behaviour where a short position is opened whenever no bullish condition is met.
Trading Logic
Subscribe to the selected candle series and calculate a moving average with the chosen length, method and applied price.
Maintain the most recent moving-average values in a buffer so that the values at bar indexes BarA and BarB can be accessed even when a horizontal MA shift is used.
When a finished candle arrives inside the [StartHour, EndHour) window:
Retrieve the MA value at BarA + MaShift and BarB + MaShift.
If the value at BarA exceeds the value at BarB by more than DifferenceThreshold, open a long position unless ReverseSignals is enabled.
If the value at BarA is lower than the value at BarB by more than DifferenceThreshold, open a short position (or a long position when ReverseSignals is enabled).
Otherwise the strategy keeps the original EA behaviour and triggers a short entry.
Orders are always sent at the market using the strategy Volume. When CloseOppositePositions is enabled the requested size is increased to flatten any opposite exposure before establishing the new position.
Optional stop-loss and take-profit protections are attached through StartProtection. Distances are expressed in pips, where one pip equals PriceStep multiplied by 10 for instruments quoted with 3 or 5 decimal digits.
Inputs
Name
Type
Default
Description
CandleType
DataType
1-minute time frame
Candle series used for calculations and signals.
StopLossPips
int
30
Stop-loss distance in pips. Set to 0 to disable.
TakeProfitPips
int
50
Take-profit distance in pips. Set to 0 to disable.
StartHour
int
8
Inclusive hour (0-23) that marks the start of the trading session.
EndHour
int
21
Exclusive hour (0-23) that marks the end of the trading session. Must be greater than StartHour.
DifferenceThreshold
decimal
0.0001
Minimal absolute difference between the compared MA values that triggers a directional signal.
BarA
int
0
Index of the first bar used for the MA comparison (0 = current candle).
BarB
int
1
Index of the second bar used for the MA comparison.
ReverseSignals
bool
false
Inverts the bullish and bearish conditions.
CloseOppositePositions
bool
false
If enabled, increases the order size to close any position in the opposite direction before opening the new trade.
MaShift
int
0
Horizontal shift applied to the moving average line. Positive values access older MA points.
Price used as MA input (Close, Open, High, Low, Median, Typical, Weighted).
Position Management
Set the strategy Volume to control the base trade size. It is combined with the current position when CloseOppositePositions is active.
Stop-loss and take-profit protections are optional. They are attached only when the respective pip distance is greater than zero.
Notes
The trading window works in instrument time; signals outside [StartHour, EndHour) are skipped.
When MaShift produces negative indexes the strategy waits until enough history accumulates, mirroring the original EA behaviour where shifted buffers can return EMPTY_VALUE.
Because the original expert always defaults to a sell order when the difference threshold is not met, the converted strategy keeps the same logic for full fidelity. Adjust DifferenceThreshold if this behaviour is undesirable.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// 55 MA bar comparison strategy. Compares candle body with MA direction.
/// </summary>
public class FiftyFiveMaBarComparisonStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _maPeriod;
private decimal? _prevMa;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int MaPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
public FiftyFiveMaBarComparisonStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_maPeriod = Param(nameof(MaPeriod), 55)
.SetGreaterThanZero()
.SetDisplay("MA Period", "Moving average period", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevMa = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevMa = null;
var sma = new SimpleMovingAverage { Length = MaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal maVal)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevMa = maVal;
return;
}
if (_prevMa == null)
{
_prevMa = maVal;
return;
}
var close = candle.ClosePrice;
var bullishBar = candle.ClosePrice > candle.OpenPrice;
var bearishBar = candle.ClosePrice < candle.OpenPrice;
var maRising = maVal > _prevMa.Value;
var maFalling = maVal < _prevMa.Value;
_prevMa = maVal;
// Bullish bar + rising MA + close above MA → buy
if (bullishBar && maRising && close > maVal && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Bearish bar + falling MA + close below MA → sell
else if (bearishBar && maFalling && close < maVal && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
}
}
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 SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class fifty_five_ma_bar_comparison_strategy(Strategy):
def __init__(self):
super(fifty_five_ma_bar_comparison_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._ma_period = self.Param("MaPeriod", 55) \
.SetDisplay("MA Period", "Moving average period", "Indicators")
self._prev_ma = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def MaPeriod(self):
return self._ma_period.Value
def OnReseted(self):
super(fifty_five_ma_bar_comparison_strategy, self).OnReseted()
self._prev_ma = None
def OnStarted2(self, time):
super(fifty_five_ma_bar_comparison_strategy, self).OnStarted2(time)
self._prev_ma = None
sma = SimpleMovingAverage()
sma.Length = self.MaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(sma, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
def _on_process(self, candle, ma_value):
if candle.State != CandleStates.Finished:
return
mv = float(ma_value)
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_ma = mv
return
if self._prev_ma is None:
self._prev_ma = mv
return
close = float(candle.ClosePrice)
open_price = float(candle.OpenPrice)
bullish_bar = close > open_price
bearish_bar = close < open_price
ma_rising = mv > self._prev_ma
ma_falling = mv < self._prev_ma
self._prev_ma = mv
# Bullish bar + rising MA + close above MA
if bullish_bar and ma_rising and close > mv and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Bearish bar + falling MA + close below MA
elif bearish_bar and ma_falling and close < mv and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
def CreateClone(self):
return fifty_five_ma_bar_comparison_strategy()