The AML RSI Meeting Lines Strategy is a StockSharp port of the MetaTrader 5 expert advisor Expert_AML_RSI.mq5. The original system combines Japanese candlestick pattern recognition with the Relative Strength Index (RSI) to trade bullish and bearish "Meeting Lines" reversals. This conversion keeps the core trading logic while adapting it to StockSharp's high-level API with candle subscriptions and built-in indicators.
Trading Logic
Subscribes to a configurable candle type and processes only finished candles.
Calculates a Simple Moving Average of candle body sizes to detect "long" candles that form Meeting Lines patterns.
Tracks RSI values on the two most recent completed candles for confirmation and exit signals.
Bullish setup: two-bar Meeting Lines reversal with RSI below the bullish threshold triggers long entries.
Bearish setup: mirrored pattern with RSI above the bearish threshold triggers short entries.
Position exits: RSI crossovers through configurable lower and upper levels close open trades in the opposite direction.
Uses BuyMarket, SellMarket, and ClosePosition helpers to manage exposure and automatically flips position size when a contrary signal appears.
Parameters
Name
Description
Default
CandleType
Timeframe used to evaluate candlestick patterns.
1 hour time frame
RsiPeriod
RSI lookback length.
11
BodyAveragePeriod
Number of candles for the average body size.
3
BullishRsiLevel
Maximum RSI that validates bullish Meeting Lines.
40
BearishRsiLevel
Minimum RSI that validates bearish Meeting Lines.
60
LowerExitLevel
RSI level that closes shorts on upward crosses.
30
UpperExitLevel
RSI level that closes longs on downward crosses.
70
All parameters are exposed as StrategyParam<T> objects so they can be optimized in the StockSharp designer.
Risk Management
StartProtection() is invoked in OnStarted to enable the framework's built-in position monitoring.
The strategy closes existing exposure whenever RSI crosses the configured exit boundaries before considering new signals.
Market orders automatically reverse the position by adding the absolute value of the current exposure to the configured volume.
Conversion Notes
Candlestick averaging uses SimpleMovingAverage fed with absolute candle bodies, mirroring the AvgBody helper from the MQL5 source.
RSI confirmation relies on the values from the two previous candles, reproducing the RSI(1) and RSI(2) checks from the original expert.
All comments in the code were rewritten in English and the structure follows the repository requirement of file-scoped namespaces with tab indentation.
Usage
Attach the strategy to a security in StockSharp and select the desired candle type.
Configure RSI and exit thresholds to match the trading venue or instrument volatility.
Run the strategy in paper trading first to validate pattern recognition before moving to live trading or optimization.
Use the provided parameters during optimization to fine-tune RSI levels and average body length for different markets.
Disclaimer
This strategy is provided for educational purposes only. Test thoroughly on historical data and in simulated environments before deploying it on live capital.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Meeting Lines + RSI strategy.
/// Buys on bullish meeting lines with low RSI, sells on bearish meeting lines with high RSI.
/// </summary>
public class AmlRsiMeetingLinesStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _rsiLow;
private readonly StrategyParam<decimal> _rsiHigh;
private ICandleMessage _prevCandle;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public decimal RsiLow { get => _rsiLow.Value; set => _rsiLow.Value = value; }
public decimal RsiHigh { get => _rsiHigh.Value; set => _rsiHigh.Value = value; }
public AmlRsiMeetingLinesStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI period", "Indicators");
_rsiLow = Param(nameof(RsiLow), 40m)
.SetDisplay("RSI Low", "RSI level for bullish entry", "Signals");
_rsiHigh = Param(nameof(RsiHigh), 60m)
.SetDisplay("RSI High", "RSI level for bearish entry", "Signals");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevCandle = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevCandle = null;
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(rsi, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue)
{
if (candle.State != CandleStates.Finished) return;
if (_prevCandle != null)
{
var avgBody = (Math.Abs(candle.ClosePrice - candle.OpenPrice) +
Math.Abs(_prevCandle.ClosePrice - _prevCandle.OpenPrice)) / 2m;
if (avgBody > 0)
{
var prevBearish = _prevCandle.OpenPrice > _prevCandle.ClosePrice;
var currBullish = candle.ClosePrice > candle.OpenPrice;
var closesNear = Math.Abs(candle.ClosePrice - _prevCandle.ClosePrice) < avgBody * 0.3m;
if (prevBearish && currBullish && closesNear && rsiValue < RsiLow && Position <= 0)
BuyMarket();
var prevBullish = _prevCandle.ClosePrice > _prevCandle.OpenPrice;
var currBearish = candle.OpenPrice > candle.ClosePrice;
var closesNear2 = Math.Abs(candle.ClosePrice - _prevCandle.ClosePrice) < avgBody * 0.3m;
if (prevBullish && currBearish && closesNear2 && rsiValue > RsiHigh && Position >= 0)
SellMarket();
}
}
_prevCandle = candle;
}
}
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 aml_rsi_meeting_lines_strategy(Strategy):
def __init__(self):
super(aml_rsi_meeting_lines_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5)))
self._rsi_period = self.Param("RsiPeriod", 14)
self._rsi_low = self.Param("RsiLow", 40.0)
self._rsi_high = self.Param("RsiHigh", 60.0)
self._prev_candle = None
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def RsiPeriod(self):
return self._rsi_period.Value
@RsiPeriod.setter
def RsiPeriod(self, value):
self._rsi_period.Value = value
@property
def RsiLow(self):
return self._rsi_low.Value
@RsiLow.setter
def RsiLow(self, value):
self._rsi_low.Value = value
@property
def RsiHigh(self):
return self._rsi_high.Value
@RsiHigh.setter
def RsiHigh(self, value):
self._rsi_high.Value = value
def OnReseted(self):
super(aml_rsi_meeting_lines_strategy, self).OnReseted()
self._prev_candle = None
def OnStarted2(self, time):
super(aml_rsi_meeting_lines_strategy, self).OnStarted2(time)
self._prev_candle = None
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(rsi, self._process_candle).Start()
def _process_candle(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
rsi_val = float(rsi_value)
if self._prev_candle is not None:
avg_body = (abs(float(candle.ClosePrice) - float(candle.OpenPrice))
+ abs(float(self._prev_candle.ClosePrice) - float(self._prev_candle.OpenPrice))) / 2.0
if avg_body > 0:
prev_bearish = float(self._prev_candle.OpenPrice) > float(self._prev_candle.ClosePrice)
curr_bullish = float(candle.ClosePrice) > float(candle.OpenPrice)
closes_near = abs(float(candle.ClosePrice) - float(self._prev_candle.ClosePrice)) < avg_body * 0.3
if prev_bearish and curr_bullish and closes_near and rsi_val < self.RsiLow and self.Position <= 0:
self.BuyMarket()
prev_bullish = float(self._prev_candle.ClosePrice) > float(self._prev_candle.OpenPrice)
curr_bearish = float(candle.OpenPrice) > float(candle.ClosePrice)
closes_near2 = abs(float(candle.ClosePrice) - float(self._prev_candle.ClosePrice)) < avg_body * 0.3
if prev_bullish and curr_bearish and closes_near2 and rsi_val > self.RsiHigh and self.Position >= 0:
self.SellMarket()
self._prev_candle = candle
def CreateClone(self):
return aml_rsi_meeting_lines_strategy()