The Basic RSI EA Template Strategy replicates the MetaTrader 4 expert advisor "Basic Rsi EA Template.mq4" (MQL/26750). It watches the Relative Strength Index (RSI) on the selected candle series and reacts when momentum stretches into configurable overbought or oversold zones. The StockSharp conversion keeps the simple one-position workflow and the protective stop/take logic of the original robot while adopting the high-level subscription API.
Strategy Logic
Indicators
Relative Strength Index (RSI) with a configurable period calculated on the chosen candle type.
Entry Conditions
Long setup: when RSI falls below OversoldLevel and the strategy has no open position, it sends a market buy order for the configured OrderVolume.
Short setup: when RSI rises above OverboughtLevel and the strategy has no open position, it sends a market sell order for the configured OrderVolume.
The algorithm works in a netting mode: only one position can exist at any time. If a long position is active the strategy waits for it to close before a short entry (and vice versa).
Exit Conditions
Protective stop: StopLossPips converts into an absolute price distance using the instrument tick size. Once the price retraces by that amount the built-in protection engine closes the position.
Take profit: TakeProfitPips is processed the same way—when price moves in favor by the configured distance the position is closed for profit.
There is no additional trailing or signal-based exit. The strategy relies purely on the protective distances or manual intervention to exit trades, mirroring the minimalist design of the original template.
Risk and Volume Handling
OrderVolume defines the fixed amount submitted with every market order (default 0.01 lots, matching the MQL sample).
The strategy does not pyramid nor hedge. If a protective stop or take-profit closes the active trade the algorithm becomes flat and waits for the next RSI trigger.
Parameters
CandleType: candle series used for signal generation (default: 1-minute time frame).
RsiPeriod: number of bars in the RSI window (default: 14).
OverboughtLevel: RSI threshold that allows short entries (default: 70).
OversoldLevel: RSI threshold that allows long entries (default: 30).
StopLossPips: stop distance in pips converted to absolute price units (default: 30 pips).
TakeProfitPips: profit target in pips converted to absolute price units (default: 20 pips).
OrderVolume: fixed volume for market orders (default: 0.01).
Implementation Notes
Uses SubscribeCandles(...).Bind(rsi, ProcessCandle) so indicator values flow directly into the processing method without manual buffer management.
CreateProtectionUnit recreates the MQL pip handling: instruments with 3 or 5 decimals use a 10x multiplier to map pips to price steps.
All indicator checks run on finished candles to avoid multiple orders on the same bar.
The conversion assumes a netting account, unlike MetaTrader's hedging mode. Consequently, opposite trades close the current position instead of creating multiple tickets.
Inline comments and logs are in English to help future maintenance.
Usage Tips
Adjust CandleType to the instrument and timeframe you wish to trade (e.g., switch to hourly candles for swing setups).
Tune StopLossPips and TakeProfitPips so they match the instrument volatility; the protective distances are essential for risk control.
Combine the strategy with StockSharp portfolio or risk modules if you need advanced money management beyond the template logic.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Basic RSI template: buys when RSI is oversold, sells when RSI is overbought.
/// </summary>
public class BasicRsiEaTemplateStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _overboughtLevel;
private readonly StrategyParam<decimal> _oversoldLevel;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
public decimal OverboughtLevel
{
get => _overboughtLevel.Value;
set => _overboughtLevel.Value = value;
}
public decimal OversoldLevel
{
get => _oversoldLevel.Value;
set => _oversoldLevel.Value = value;
}
public BasicRsiEaTemplateStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI calculation period", "Indicators");
_overboughtLevel = Param(nameof(OverboughtLevel), 70m)
.SetDisplay("Overbought Level", "RSI overbought threshold", "Indicators");
_oversoldLevel = Param(nameof(OversoldLevel), 30m)
.SetDisplay("Oversold Level", "RSI oversold threshold", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
decimal? prevRsi = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, (candle, rsiValue) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (prevRsi.HasValue)
{
var crossBelowOversold = prevRsi.Value >= OversoldLevel && rsiValue < OversoldLevel;
var crossAboveOverbought = prevRsi.Value <= OverboughtLevel && rsiValue > OverboughtLevel;
if (crossBelowOversold && Position <= 0)
BuyMarket();
else if (crossAboveOverbought && Position >= 0)
SellMarket();
}
prevRsi = rsiValue;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, rsi);
DrawOwnTrades(area);
}
}
}
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 RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class basic_rsi_ea_template_strategy(Strategy):
def __init__(self):
super(basic_rsi_ea_template_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "RSI calculation period", "Indicators")
self._overbought_level = self.Param("OverboughtLevel", 70.0) \
.SetDisplay("Overbought Level", "RSI overbought threshold", "Indicators")
self._oversold_level = self.Param("OversoldLevel", 30.0) \
.SetDisplay("Oversold Level", "RSI oversold threshold", "Indicators")
self._rsi = None
self._prev_rsi = None
@property
def rsi_period(self):
return self._rsi_period.Value
@property
def overbought_level(self):
return self._overbought_level.Value
@property
def oversold_level(self):
return self._oversold_level.Value
def OnReseted(self):
super(basic_rsi_ea_template_strategy, self).OnReseted()
self._rsi = None
self._prev_rsi = None
def OnStarted2(self, time):
super(basic_rsi_ea_template_strategy, self).OnStarted2(time)
self._rsi = RelativeStrengthIndex()
self._rsi.Length = self.rsi_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(30)))
subscription.Bind(self._rsi, self._process_candle)
subscription.Start()
def _process_candle(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
if not self._rsi.IsFormed:
return
rsi = float(rsi_value)
if self._prev_rsi is not None:
cross_below_oversold = self._prev_rsi >= self.oversold_level and rsi < self.oversold_level
cross_above_overbought = self._prev_rsi <= self.overbought_level and rsi > self.overbought_level
if cross_below_oversold and self.Position <= 0:
self.BuyMarket()
elif cross_above_overbought and self.Position >= 0:
self.SellMarket()
self._prev_rsi = rsi
def CreateClone(self):
return basic_rsi_ea_template_strategy()