Overview of the Strategy
This is a straightforward mean reversion long strategy implemented on the Micro E-mini S&P 500 futures (MES), utilizing the Relative Strength Index (RSI) as the primary indicator for trade signals. The strategy is designed to capitalize on short-term price movements when the market becomes oversold, expecting a potential bounce or reversion to the mean.
Purpose and Scope
The primary objective of this strategy is to serve as an educational example rather than a fully optimized trading system. It is intended to demonstrate the basic principles of constructing a mean reversion strategy and provide insights into how trades can be systematically entered and exited based on RSI signals.
Key Features of the Strategy
Indicator-Based Entry
The RSI indicator is used to identify oversold conditions, which may indicate a potential reversal or short-term price recovery.
A long position is initiated when the RSI value falls below a predefined threshold, such as 30, signaling an oversold market.
Exit Rules
The position is exited when the RSI returns to a higher level, indicating that the price has potentially reverted to the mean or shown sufficient recovery.
Additionally, the strategy includes a time-based exit, closing the position after a predetermined number of bars, regardless of price action. This ensures the trade does not linger indefinitely and aligns with short-term trading principles.
Simplicity and No Additional Filters
To maintain simplicity and focus on educational value, this strategy does not incorporate additional filters such as trend confirmation, volatility bands, or multi-timeframe analysis. It is intentionally kept basic to illustrate the core mechanics of mean reversion trading.
Educational Focus
The strategy is ideal for traders who are new to algorithmic or systematic trading and wish to understand how to:
Implement entry and exit conditions using technical indicators.
Apply risk management through predefined exits.
Test and analyze the performance of a simple trading rule before exploring more complex approaches.
Conclusion
While this example highlights the foundational concepts of mean reversion trading using RSI, traders are encouraged to expand upon it by adding enhancements like dynamic stop-loss levels, profit targets, or additional indicators to refine entry and exit signals. The provided framework is an excellent starting point for experimenting with trading ideas and learning the process of strategy development.
using Tickblaze.Scripts.Indicators;
namespace CC.Strategies.LongRSIMeanReversionStrategy;
public class LongRSIMeanReversionStrategy : Strategy
{
[NumericRange(2, 10)]
[Parameter("RSI Entry Period")]
public int RsiEntryPeriod { get; set; } = 2;
[NumericRange(2, 10)]
[Parameter("RSI Exit Period")]
public int RsiExitPeriod { get; set; } = 4;
[NumericRange(60, 90)]
[Parameter("RSI Exit Level")]
public int RsiExitValue { get; set; } = 70;
[NumericRange(10, 40)]
[Parameter("RSI Entry Level")]
public int RsiEntryValue { get; set; } = 25;
[NumericRange(0, 20)]
[Parameter("Exit - Number of bars")]
public int ExitNumberOfBars { get; set; } = 6;
[NumericRange(0, 1000)]
[Parameter("Position size")]
public int PositionSize { get; set; } = 1;
private RelativeStrengthIndex _rsi_entry;
private RelativeStrengthIndex _rsi_exit;
private int _entryIndex;
public LongRSIMeanReversionStrategy()
{
Name = "Long RSI Mean Reversion Strategy";
ShortName = "CC.LRSIMR";
Description = "A mean reversion strategy based on the Relative Strength Index (RSI) generating a long signal when the RSI falls below the entry level and exiting when it rises above the exit level or after number of the bars.";
}
protected override void Initialize()
{
_rsi_entry = new RelativeStrengthIndex(Bars.Close, RsiEntryPeriod, MovingAverageType.Simple, 1);
_rsi_exit = new RelativeStrengthIndex(Bars.Close, RsiExitPeriod, MovingAverageType.Simple, 1);
_rsi_entry.Result.Color = Color.Blue;
_rsi_exit.Result.Color = Color.Cyan;
_rsi_entry.Average.IsVisible = false;
_rsi_exit.Average.IsVisible = false;
_rsi_entry.OverboughtLevel.Value = RsiExitValue;
_rsi_entry.OversoldLevel.Value = RsiEntryValue;
_rsi_exit.OverboughtLevel.Value = RsiExitValue;
_rsi_exit.OversoldLevel.Value = RsiEntryValue;
_rsi_entry.ShowOnChart = true;
_rsi_exit.ShowOnChart = true;
}
protected override void OnBar(int index)
{
if (index == 0)
{
return;
}
var rsi_entry = new[] { _rsi_entry.Result[index], _rsi_entry.Result[index - 1] };
var rsi_exit = new[] { _rsi_exit.Result[index], _rsi_exit.Result[index - 1] };
if (Position?.Direction is OrderDirection.Long && _entryIndex > 0)
{
_entryIndex--;
}
if (rsi_entry[1] >= RsiEntryValue && RsiEntryValue > rsi_entry[0])
{
EnterMarket(OrderDirection.Long, "Long RSI Mean Reversion");
} else
if (rsi_exit[1] <= RsiExitValue && RsiExitValue < rsi_exit[0])
{
if (Position?.Direction is OrderDirection.Long)
{
ClosePosition("Exit RSI Mean Reversion");
_entryIndex = 0;
}
} else
if (Position?.Direction is OrderDirection.Long && _entryIndex == 0)
{
ClosePosition("Exit RSI Mean Reversion Bars");
}
}
private void EnterMarket(OrderDirection direction, string comment = "")
{
if (Position?.Direction == direction)
{
return;
}
_entryIndex = ExitNumberOfBars;
var price = Bars.Close[^1];
var action = direction is OrderDirection.Long ? OrderAction.Buy : OrderAction.SellShort;
var exitMultiplier = direction is OrderDirection.Long ? 1 : -1;
var quantity = PositionSize;
var marketOrder = ExecuteMarketOrder(action, quantity, TimeInForce.Day, comment);
}
}