Ver en GitHub

AML RSI Meeting Lines Strategy

Overview

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

  1. Attach the strategy to a security in StockSharp and select the desired candle type.
  2. Configure RSI and exit thresholds to match the trading venue or instrument volatility.
  3. Run the strategy in paper trading first to validate pattern recognition before moving to live trading or optimization.
  4. 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;
	}
}