The RSI MA on RSI Dual strategy recreates the MetaTrader expert advisor "RSI_MAonRSI_Dual" inside StockSharp. It watches two relative strength indexes with different lookback periods and applies a common moving average on top of each RSI stream. Trading decisions are taken when the smoothed RSI lines cross one another while remaining on the same side of a configurable neutral level.
The conversion keeps the behaviour of the original robot, including time filtering and the ability to restrict trading direction or to reverse the signal logic.
Indicators
Fast RSI – Relative Strength Index with configurable period.
Slow RSI – Relative Strength Index with its own period.
Moving average on RSI – Simple moving average calculated on top of each RSI value stream. Both RSIs use the same smoothing length.
All three indicators share the same applied price (close price by default). The two smoothed RSI lines are drawn on a dedicated chart panel for monitoring.
Entry rules
Wait for both smoothed RSI values to form on the current completed bar.
Long setup
The fast smoothed RSI crosses above the slow smoothed RSI (current value above, previous value below).
Both smoothed RSIs are below the neutral level (50 by default).
Short setup
The fast smoothed RSI crosses below the slow smoothed RSI (current value below, previous value above).
Both smoothed RSIs are above the neutral level.
Optionally reverse the signal directions using the ReverseSignals parameter.
Signals generated on the same bar are ignored (one entry per bar).
Position management
AllowLong and AllowShort control whether the strategy may open positions in each direction.
CloseOpposite closes an existing position before entering the opposite side, replicating the original EA logic.
OnlyOnePosition forbids opening a new position when any position is already active.
Market orders are issued with the strategy Volume.
Time filter
Enable or disable the trading session filter with UseTimeFilter. When enabled, trades are allowed only between SessionStart and SessionEnd. Sessions that cross midnight are supported. The timestamps are evaluated in the exchange time zone provided by the incoming candle messages.
Parameters
Name
Description
CandleType
Candle series analysed by the strategy.
FastRsiPeriod
Period of the fast RSI.
SlowRsiPeriod
Period of the slow RSI.
MaPeriod
Moving-average length used to smooth both RSI streams.
AppliedPrice
Price type forwarded into the RSI calculations.
NeutralLevel
RSI threshold that separates bullish and bearish zones.
AllowLong / AllowShort
Enable or disable trading direction.
ReverseSignals
Swap long and short signals.
CloseOpposite
Close the opposite position before entering a new one.
OnlyOnePosition
Permit at most one open position.
UseTimeFilter
Activate the trading session filter.
SessionStart / SessionEnd
Trading window boundaries.
Differences from the original EA
Money management, stop-loss and trailing-stop blocks of the original MQL5 code are not reproduced. The StockSharp strategy places market orders using the fixed Volume configured on the strategy.
All logging and diagnostic alerts were removed; StockSharp logging should be used instead if required.
Platform-specific transaction tracking is replaced with StockSharp order-state events.
Despite these differences, the core entry logic and directional filters match the source expert advisor.
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>
/// Dual moving averages calculated on top of RSI values.
/// Fast RSI MA crossing slow RSI MA generates entry signals.
/// </summary>
public class RsiMaOnRsiDualStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastRsiPeriod;
private readonly StrategyParam<int> _slowRsiPeriod;
private readonly StrategyParam<int> _maPeriod;
private RelativeStrengthIndex _fastRsi;
private RelativeStrengthIndex _slowRsi;
private readonly Queue<decimal> _fastRsiHistory = new();
private readonly Queue<decimal> _slowRsiHistory = new();
private decimal? _previousFastMa;
private decimal? _previousSlowMa;
public RsiMaOnRsiDualStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle type", "Candles processed by the strategy.", "General");
_fastRsiPeriod = Param(nameof(FastRsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("Fast RSI period", "Length of the fast RSI smoothing window.", "Indicators");
_slowRsiPeriod = Param(nameof(SlowRsiPeriod), 28)
.SetGreaterThanZero()
.SetDisplay("Slow RSI period", "Length of the slow RSI smoothing window.", "Indicators");
_maPeriod = Param(nameof(MaPeriod), 12)
.SetGreaterThanZero()
.SetDisplay("MA period", "Number of RSI values averaged by the smoothing moving average.", "Indicators");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastRsiPeriod
{
get => _fastRsiPeriod.Value;
set => _fastRsiPeriod.Value = value;
}
public int SlowRsiPeriod
{
get => _slowRsiPeriod.Value;
set => _slowRsiPeriod.Value = value;
}
public int MaPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_previousFastMa = null;
_previousSlowMa = null;
_fastRsiHistory.Clear();
_slowRsiHistory.Clear();
_fastRsi = null!;
_slowRsi = null!;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_previousFastMa = null;
_previousSlowMa = null;
_fastRsiHistory.Clear();
_slowRsiHistory.Clear();
_fastRsi = new RelativeStrengthIndex { Length = FastRsiPeriod };
_slowRsi = new RelativeStrengthIndex { Length = SlowRsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_fastRsi, _slowRsi, ProcessCandle)
.Start();
var priceArea = CreateChartArea();
if (priceArea != null)
{
DrawCandles(priceArea, subscription);
DrawOwnTrades(priceArea);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastRsiValue, decimal slowRsiValue)
{
if (candle.State != CandleStates.Finished)
return;
_fastRsiHistory.Enqueue(fastRsiValue);
_slowRsiHistory.Enqueue(slowRsiValue);
while (_fastRsiHistory.Count > MaPeriod)
_fastRsiHistory.Dequeue();
while (_slowRsiHistory.Count > MaPeriod)
_slowRsiHistory.Dequeue();
if (!_fastRsi.IsFormed || !_slowRsi.IsFormed)
return;
if (_fastRsiHistory.Count < MaPeriod || _slowRsiHistory.Count < MaPeriod)
return;
// Calculate SMA of each RSI
var fastSum = 0m;
var fastHistory = _fastRsiHistory.ToArray();
foreach (var v in fastHistory)
fastSum += v;
var fastMa = fastSum / MaPeriod;
var slowSum = 0m;
var slowHistory = _slowRsiHistory.ToArray();
foreach (var v in slowHistory)
slowSum += v;
var slowMa = slowSum / MaPeriod;
if (_previousFastMa is null || _previousSlowMa is null)
{
_previousFastMa = fastMa;
_previousSlowMa = slowMa;
return;
}
var crossUp = _previousFastMa < _previousSlowMa && fastMa > slowMa;
var crossDown = _previousFastMa > _previousSlowMa && fastMa < slowMa;
var volume = Volume;
if (volume <= 0)
volume = 1;
if (crossUp)
{
if (Position <= 0)
BuyMarket(volume);
}
else if (crossDown)
{
if (Position >= 0)
SellMarket(volume);
}
_previousFastMa = fastMa;
_previousSlowMa = slowMa;
}
}