This strategy is an interpretation of the original MQL5 expert advisor "MA Rounding Candle". It uses two smoothed moving averages applied to candle open and close prices. The relative position of these averages defines the colour of a synthetic candle: green when the smoothed close is above the open, red when the close is below the open and gray when they are equal. A change in colour from the previous bar generates trade signals.
Algorithm
For every completed candle the open and close values are smoothed with a simple moving average of configurable length.
The candle colour is defined by comparing the smoothed values:
Up candle – smoothed close is higher than smoothed open.
Down candle – smoothed close is lower than smoothed open.
Neutral – both values are equal.
If the previous candle was up and the current candle is not up, the strategy enters a long position and closes any short.
If the previous candle was down and the current candle is not down, the strategy enters a short position and closes any long.
Parameters
MaLength – period of the smoothing moving averages (default 12).
CandleType – timeframe of the processed candles.
Notes
The strategy demonstrates how to recreate signals from a custom indicator using only built‑in StockSharp tools. No stop loss or take profit is applied; positions are reversed immediately when the opposite signal appears.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// MA Rounding Candle strategy.
/// Opens a long position when a smoothed candle is bullish and a short position when it is bearish.
/// </summary>
public class MaRoundingCandleStrategy : Strategy
{
private readonly StrategyParam<int> _maLength;
private readonly StrategyParam<DataType> _candleType;
private ExponentialMovingAverage _openMa;
private ExponentialMovingAverage _closeMa;
private int _prevColor = 1;
public MaRoundingCandleStrategy()
{
_maLength = Param(nameof(MaLength), 12)
.SetDisplay("MA Length", "Moving average length", "Parameters");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame());
}
public int MaLength { get => _maLength.Value; set => _maLength.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_openMa = default;
_closeMa = default;
_prevColor = 1;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_openMa = new ExponentialMovingAverage { Length = MaLength };
_closeMa = new ExponentialMovingAverage { Length = MaLength };
Indicators.Add(_openMa);
Indicators.Add(_closeMa);
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _openMa);
DrawIndicator(area, _closeMa);
DrawOwnTrades(area);
}
StartProtection(null, null);
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var openVal = _openMa.Process(candle.OpenPrice, candle.OpenTime, true).ToDecimal();
var closeVal = _closeMa.Process(candle.ClosePrice, candle.OpenTime, true).ToDecimal();
if (!_openMa.IsFormed || !_closeMa.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var color = openVal < closeVal ? 2 : openVal > closeVal ? 0 : 1;
if (_prevColor == 2 && color != 2 && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (_prevColor == 0 && color != 0 && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prevColor = color;
}
}
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
from indicator_extensions import *
class ma_rounding_candle_strategy(Strategy):
def __init__(self):
super(ma_rounding_candle_strategy, self).__init__()
self._ma_length = self.Param("MaLength", 12) \
.SetDisplay("MA Length", "Moving average length", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4)))
self._open_ma = None
self._close_ma = None
self._prev_color = 1
@property
def ma_length(self):
return self._ma_length.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(ma_rounding_candle_strategy, self).OnReseted()
self._open_ma = None
self._close_ma = None
self._prev_color = 1
def OnStarted2(self, time):
super(ma_rounding_candle_strategy, self).OnStarted2(time)
self._open_ma = ExponentialMovingAverage()
self._open_ma.Length = self.ma_length
self._close_ma = ExponentialMovingAverage()
self._close_ma.Length = self.ma_length
self.Indicators.Add(self._open_ma)
self.Indicators.Add(self._close_ma)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._open_ma)
self.DrawIndicator(area, self._close_ma)
self.DrawOwnTrades(area)
def process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
open_result = process_float(self._open_ma, candle.OpenPrice, candle.OpenTime, True)
close_result = process_float(self._close_ma, candle.ClosePrice, candle.OpenTime, True)
if not self._open_ma.IsFormed or not self._close_ma.IsFormed:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
open_val = float(open_result)
close_val = float(close_result)
if open_val < close_val:
color = 2
elif open_val > close_val:
color = 0
else:
color = 1
if self._prev_color == 2 and color != 2 and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self._prev_color == 0 and color != 0 and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_color = color
def CreateClone(self):
return ma_rounding_candle_strategy()