Easy Robot is a momentum-following Expert Advisor that trades once per completed hourly candle. When the previous candle closes bullish the strategy opens a new long position; when it closes bearish it opens a short. Only one position can be active at any time, fully mirroring the original MetaTrader 4 logic.
Trade Rules
Subscribe to the hourly candle type selected by the CandleType parameter (defaults to H1).
Once a candle is finished, compare its close with the open:
Close > Open: send a market buy order if no position is open.
Close < Open: send a market sell order if flat.
The position size uses the strategy Volume property, exactly like the MQL version that relied on CheckVolumeValue with a default of 0.01 lots.
Stop-loss and take-profit levels rely on an Average True Range indicator with period AtrPeriod (default 14):
Stop distance = ATR * StopFactor.
Take distance = ATR * TakeFactor.
Both distances are normalised by the minimal tick/pip distance so protective orders are never placed closer than the broker allows.
Protective orders are registered immediately after the market order through SetStopLoss and SetTakeProfit, providing the same behaviour as OrderSend with sl and tp parameters.
Optional trailing is activated when UseTrailingStop is true. After the trade accumulates TrailingStartPips profit (MetaTrader pips, i.e. points adjusted for 3/5 decimal quotes), the stop is moved closer by TrailingStepPips and is pushed further only when new profit extremes are reached. Trailing respects the broker’s minimal stop distance to avoid invalid modifications.
Quotes for stop calculations use the best bid/ask when available, falling back to the last price or candle close, matching the original Bid/Ask references.
Parameters
Name
Default
Description
TakeFactor
4.2
ATR multiplier for take-profit distance (maps to TakeFactor input in MQL).
StopFactor
4.9
ATR multiplier for stop-loss distance (maps to StopFactor).
UseTrailingStop
true
Enables MetaTrader-style trailing (UseTstop).
TrailingStartPips
40
Profit in pips before trailing can start (Tstart).
TrailingStepPips
19
Pip step applied when trailing updates (Tstep).
AtrPeriod
14
ATR calculation period for volatility sizing.
CandleType
H1
Candle series used for signals and ATR input.
Notes
The strategy resets stored entry and stop prices whenever the position returns to zero, ensuring a clean state for the next signal.
Minimal stop distance is estimated via the instrument pip size (or price step when pip size is not available). This reproduces the SC helper from the MQL include file.
StartProtection() is called once at start so the platform can manage emergency exits if needed.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Easy Robot strategy: simple EMA + RSI trend following.
/// Buys when close above EMA and RSI above 50.
/// Sells when close below EMA and RSI below 50.
/// </summary>
public class EasyRobotStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<int> _rsiPeriod;
private bool _wasBullish;
private bool _hasPrevSignal;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public EasyRobotStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_emaPeriod = Param(nameof(EmaPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("EMA Period", "EMA period", "Indicators");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_wasBullish = false;
_hasPrevSignal = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrevSignal = false;
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ema, rsi, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal ema, decimal rsi)
{
if (candle.State != CandleStates.Finished) return;
var close = candle.ClosePrice;
var isBullish = close > ema && rsi > 50;
if (_hasPrevSignal && isBullish != _wasBullish)
{
if (isBullish && Position <= 0)
BuyMarket();
else if (!isBullish && close < ema && rsi < 50 && Position >= 0)
SellMarket();
}
_wasBullish = isBullish;
_hasPrevSignal = true;
}
}
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, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class easy_robot_strategy(Strategy):
def __init__(self):
super(easy_robot_strategy, self).__init__()
self._ema_period = self.Param("EmaPeriod", 50) \
.SetDisplay("EMA Period", "EMA period", "Indicators")
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "RSI period", "Indicators")
self._ema = None
self._rsi = None
self._was_bullish = False
self._has_prev_signal = False
@property
def ema_period(self):
return self._ema_period.Value
@property
def rsi_period(self):
return self._rsi_period.Value
def OnReseted(self):
super(easy_robot_strategy, self).OnReseted()
self._ema = None
self._rsi = None
self._was_bullish = False
self._has_prev_signal = False
def OnStarted2(self, time):
super(easy_robot_strategy, self).OnStarted2(time)
self._ema = ExponentialMovingAverage()
self._ema.Length = self.ema_period
self._rsi = RelativeStrengthIndex()
self._rsi.Length = self.rsi_period
self._has_prev_signal = False
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(30)))
subscription.Bind(self._ema, self._rsi, self._process_candle)
subscription.Start()
def _process_candle(self, candle, ema_value, rsi_value):
if candle.State != CandleStates.Finished:
return
if not self._ema.IsFormed or not self._rsi.IsFormed:
return
close = float(candle.ClosePrice)
ema_val = float(ema_value)
rsi_val = float(rsi_value)
is_bullish = close > ema_val and rsi_val > 50.0
if self._has_prev_signal and is_bullish != self._was_bullish:
if is_bullish and self.Position <= 0:
self.BuyMarket()
elif not is_bullish and close < ema_val and rsi_val < 50.0 and self.Position >= 0:
self.SellMarket()
self._was_bullish = is_bullish
self._has_prev_signal = True
def CreateClone(self):
return easy_robot_strategy()