Exp RSIOMA V2 is a conversion of the original MetaTrader 5 expert advisor that trades on the RSIOMA oscillator (Relative Strength Index of Moving Average). The strategy reproduces the same ideas inside the StockSharp high level API: price data are smoothed, converted into a momentum series and fed into an RSI style accumulator. Trading decisions are taken when the oscillator changes direction or crosses predefined zones.
Trading Logic
Price preprocessing – the selected candle price (close by default) is smoothed with one of four moving average families (simple, exponential, smoothed or linear weighted).
Momentum calculation – the smoothed price is compared with the value from MomentumPeriod bars ago to obtain the momentum impulse.
RSIOMA computation – positive and negative momentum components are accumulated with an exponential smoothing of length RsiomaLength, producing the RSIOMA value in the [0; 100] range.
Signal evaluation – the most recent closed candles are inspected according to the chosen Mode:
Breakdown – reacts when RSIOMA leaves the main trend levels (MainTrendLong / MainTrendShort). When the oscillator exits the upper zone, shorts are closed and long entries are permitted; exiting the lower zone performs the opposite action.
Twist – looks for turning points. A buy occurs when the RSIOMA slope switches from falling to rising, while sells react to a rising-to-falling transition.
CloudTwist – emulates the coloured cloud logic from the MT5 indicator. Trades are opened when RSIOMA returns from oversold/overbought extremes back inside the channel, and opposite positions are closed at the same time.
Signals are evaluated on the bar specified by SignalBar (default: the previous fully closed candle), ensuring that only confirmed data are used.
Parameters
Name
Description
Default
OrderVolume
Default order volume used by market orders.
1
CandleType
Candle data series processed by the strategy.
4 hour timeframe
EnableLongEntries / EnableShortEntries
Allow opening new long/short positions.
true
EnableLongExits / EnableShortExits
Allow closing existing long/short positions.
true
Mode
Trading logic (Breakdown, Twist or CloudTwist).
Breakdown
PriceSmoothing
Moving average applied to the price before RSIOMA.
Exponential
RsiomaLength
RSIOMA averaging period.
14
MomentumPeriod
Lag between samples when computing momentum.
1
AppliedPrice
Candle price used for the oscillator (close, open, median, DeMark, etc.).
Close
MainTrendLong / MainTrendShort
RSIOMA levels that define overbought/oversold zones.
60 / 40
SignalBar
Number of closed bars back that should be analysed.
1
Implementation Notes
Only the smoothing families available in StockSharp are supported (simple, exponential, smoothed and linear weighted). Advanced modes from the MT5 version (JJMA, VIDYA, AMA, …) are not included.
The RSI averages are seeded using the first RsiomaLength momentum values to mirror the MetaTrader initialisation. Afterwards an exponential update is applied, matching the original expert advisor behaviour.
Positions are always closed before an opposite entry is issued. Entry permissions (EnableLongEntries, EnableShortEntries) and exit permissions (EnableLongExits, EnableShortExits) provide full control over the allowed directions.
SignalBar = 0 can be used to react to the current finished candle; higher values reproduce the MT5 ability to wait several bars before acting.
Usage
Add the strategy to a StockSharp project and assign the instrument you want to trade.
Configure the candle subscription through CandleType (default is 4-hour candles) and adjust thresholds if the symbol uses different volatility characteristics.
Select the preferred signal mode depending on whether you want breakout style entries (Breakdown), momentum turns (Twist) or cloud colour changes (CloudTwist).
Start the strategy. During execution the strategy subscribes to the chosen candle series, computes the RSIOMA chain and issues market orders when conditions are satisfied.
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>
/// RSIOMA strategy using RSI with overbought/oversold levels.
/// Buys when RSI crosses above oversold, sells when crosses below overbought.
/// </summary>
public class ExpRsiomaV2Strategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _overbought;
private readonly StrategyParam<decimal> _oversold;
private decimal? _prevRsi;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
public decimal Overbought
{
get => _overbought.Value;
set => _overbought.Value = value;
}
public decimal Oversold
{
get => _oversold.Value;
set => _oversold.Value = value;
}
public ExpRsiomaV2Strategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI calculation period", "Indicators");
_overbought = Param(nameof(Overbought), 65m)
.SetDisplay("Overbought", "Overbought RSI level", "Levels");
_oversold = Param(nameof(Oversold), 35m)
.SetDisplay("Oversold", "Oversold RSI level", "Levels");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevRsi = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevRsi = null;
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
var indArea = CreateChartArea();
if (indArea != null)
{
DrawIndicator(indArea, rsi);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevRsi = rsiValue;
return;
}
if (_prevRsi == null)
{
_prevRsi = rsiValue;
return;
}
// RSI crosses above oversold → buy signal
if (_prevRsi.Value <= Oversold && rsiValue > Oversold && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// RSI crosses below overbought → sell signal
else if (_prevRsi.Value >= Overbought && rsiValue < Overbought && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevRsi = rsiValue;
}
}
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 exp_rsioma_v2_strategy(Strategy):
def __init__(self):
super(exp_rsioma_v2_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "RSI calculation period", "Indicators")
self._overbought = self.Param("Overbought", 65.0) \
.SetDisplay("Overbought", "Overbought RSI level", "Levels")
self._oversold = self.Param("Oversold", 35.0) \
.SetDisplay("Oversold", "Oversold RSI level", "Levels")
self._prev_rsi = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def RsiPeriod(self):
return self._rsi_period.Value
@property
def Overbought(self):
return self._overbought.Value
@property
def Oversold(self):
return self._oversold.Value
def OnReseted(self):
super(exp_rsioma_v2_strategy, self).OnReseted()
self._prev_rsi = None
def OnStarted2(self, time):
super(exp_rsioma_v2_strategy, self).OnStarted2(time)
self._prev_rsi = None
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(rsi, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
ind_area = self.CreateChartArea()
if ind_area is not None:
self.DrawIndicator(ind_area, rsi)
def _on_process(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
rv = float(rsi_value)
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_rsi = rv
return
if self._prev_rsi is None:
self._prev_rsi = rv
return
ob = float(self.Overbought)
os_level = float(self.Oversold)
# RSI crosses above oversold
if self._prev_rsi <= os_level and rv > os_level and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# RSI crosses below overbought
elif self._prev_rsi >= ob and rv < ob and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_rsi = rv
def CreateClone(self):
return exp_rsioma_v2_strategy()