Exp RSIOMA Strategy
The Exp RSIOMA strategy uses the RSI of moving average (RSIOMA) indicator to trade trend reversals and breakouts. RSI values are smoothed by an additional moving average to form a signal line and histogram. The strategy supports four modes:
- Breakdown – trades when RSI crosses configured high/low levels.
- HistTwist – trades when histogram changes direction.
- SignalTwist – trades when the signal line changes direction.
- HistDisposition – trades when histogram crosses the signal line.
Positions can be opened or closed independently for long and short sides.
Details
- Entry Criteria: depends on
Mode - Long/Short: both
- Exit Criteria: opposite signal
- Stops: none
- Default Values:
CandleType= 4 hourRsiPeriod= 14SignalPeriod= 21HighLevel= 20LowLevel= -20
- Filters:
- Category: Trend
- Direction: Both
- Indicators: RSI
- Stops: No
- Complexity: Intermediate
- Timeframe: Intraday
- Seasonality: No
- Neural networks: No
- Divergence: No
- Risk level: Medium
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy based on the RSI crossover with an EMA of RSI (RSIOMA style).
/// Buys when RSI crosses above its EMA and sells when RSI crosses below.
/// </summary>
public class ExpRsiomaStrategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevRsi;
private decimal _prevEma;
private bool _hasPrev;
/// <summary>RSI calculation length.</summary>
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
/// <summary>EMA smoothing period.</summary>
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
/// <summary>Candle type.</summary>
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public ExpRsiomaStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 21)
.SetDisplay("RSI Period", "RSI calculation length", "Parameters")
.SetGreaterThanZero();
_emaPeriod = Param(nameof(EmaPeriod), 14)
.SetDisplay("EMA Period", "EMA smoothing period", "Parameters")
.SetGreaterThanZero();
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for candles", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevRsi = 0m;
_prevEma = 0m;
_hasPrev = false;
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var rsiEma = new ExponentialMovingAverage { Length = EmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, (candle, rsiValue) =>
{
if (candle.State != CandleStates.Finished)
return;
var emaResult = rsiEma.Process(new DecimalIndicatorValue(rsiEma, rsiValue, candle.ServerTime) { IsFinal = true });
if (!rsiEma.IsFormed)
return;
var emaValue = emaResult.ToDecimal();
if (_hasPrev)
{
var crossUp = _prevRsi <= _prevEma && rsiValue > emaValue;
var crossDown = _prevRsi >= _prevEma && rsiValue < emaValue;
if (crossUp && Position == 0)
BuyMarket();
else if (crossDown && Position == 0)
SellMarket();
}
_prevRsi = rsiValue;
_prevEma = emaValue;
_hasPrev = true;
})
.Start();
StartProtection(
takeProfit: new Unit(2, UnitTypes.Percent),
stopLoss: new Unit(1, UnitTypes.Percent)
);
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, Unit, UnitTypes
from StockSharp.Algo.Indicators import RelativeStrengthIndex, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class exp_rsioma_strategy(Strategy):
def __init__(self):
super(exp_rsioma_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 21)
self._ema_period = self.Param("EmaPeriod", 14)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5)))
self._prev_rsi = 0.0
self._prev_ema = 0.0
self._has_prev = False
self._rsi_ema = None
@property
def RsiPeriod(self):
return self._rsi_period.Value
@RsiPeriod.setter
def RsiPeriod(self, value):
self._rsi_period.Value = value
@property
def EmaPeriod(self):
return self._ema_period.Value
@EmaPeriod.setter
def EmaPeriod(self, value):
self._ema_period.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(exp_rsioma_strategy, self).OnStarted2(time)
self._has_prev = False
self._prev_rsi = 0.0
self._prev_ema = 0.0
self._rsi_ema = ExponentialMovingAverage()
self._rsi_ema.Length = self.EmaPeriod
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(rsi, self.ProcessCandle).Start()
self.StartProtection(
Unit(2.0, UnitTypes.Percent),
Unit(1.0, UnitTypes.Percent))
def ProcessCandle(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
rsi_val = float(rsi_value)
ema_result = process_float(self._rsi_ema, rsi_val, candle.OpenTime, True)
if not self._rsi_ema.IsFormed:
return
ema_val = float(ema_result)
if self._has_prev:
cross_up = self._prev_rsi <= self._prev_ema and rsi_val > ema_val
cross_down = self._prev_rsi >= self._prev_ema and rsi_val < ema_val
if cross_up and self.Position == 0:
self.BuyMarket()
elif cross_down and self.Position == 0:
self.SellMarket()
self._prev_rsi = rsi_val
self._prev_ema = ema_val
self._has_prev = True
def OnReseted(self):
super(exp_rsioma_strategy, self).OnReseted()
self._prev_rsi = 0.0
self._prev_ema = 0.0
self._has_prev = False
self._rsi_ema = None
def CreateClone(self):
return exp_rsioma_strategy()