AML RSI Meeting Lines Strategy — порт на StockSharp советника MetaTrader 5 Expert_AML_RSI.mq5. Исходная система сочетает распознавание японских свечных моделей «Meeting Lines» и индикатор RSI. В процессе конвертации сохранены ключевые торговые правила, а выполнение перенесено на высокоуровневый API StockSharp с подписками на свечи и встроенными индикаторами.
Логика торговли
Подписка на выбранный тип свечей и обработка только завершённых баров.
Расчёт скользящего среднего по размерам тел свечей позволяет определить «длинные» свечи, необходимые для модели Meeting Lines.
Хранение значений RSI на двух предыдущих свечах обеспечивает подтверждение и выход из позиции.
Бычий сигнал: две свечи формируют модель Meeting Lines, а RSI ниже порогового уровня — открывается длинная позиция.
Медвежий сигнал: зеркальная конфигурация и RSI выше порога — открывается короткая позиция.
Выход: пересечение RSI настроенных уровней 30 и 70 в противоположную сторону закрывает текущую позицию.
Для сделок используются методы BuyMarket, SellMarket и ClosePosition, что позволяет автоматически переворачиваться при появлении противоположного сигнала.
Параметры
Имя
Назначение
Значение по умолчанию
CandleType
Таймфрейм для анализа свечных моделей.
Часовые свечи
RsiPeriod
Период расчёта RSI.
11
BodyAveragePeriod
Количество свечей для усреднения тел.
3
BullishRsiLevel
Максимальное значение RSI для подтверждения бычьей модели.
40
BearishRsiLevel
Минимальное значение RSI для подтверждения медвежьей модели.
60
LowerExitLevel
Уровень RSI, при пробое вверх закрывающий шорты.
30
UpperExitLevel
Уровень RSI, при пробое вниз закрывающий лонги.
70
Все параметры реализованы через StrategyParam<T> и доступны для оптимизации в дизайнере StockSharp.
Управление рисками
В OnStarted вызывается StartProtection(), что задействует встроенный мониторинг позиций.
Перед открытием новой сделки стратегия проверяет, не требуется ли закрытие текущей позиции по сигналам RSI.
Рыночные ордера учитывают текущий объём позиции, чтобы переворот выполнялся одним вызовом.
Особенности конвертации
Усреднение тел свечей реализовано индикатором SimpleMovingAverage, который получает модуль разницы Open и Close, аналогично функции AvgBody в MQL5.
Проверка RSI повторяет оригинальные условия RSI(1) и RSI(2) — используются значения двух предыдущих свечей.
Комментарии переписаны на английском языке, а код оформлен в соответствии с требованиями репозитория (tab-отступы и file-scoped namespace).
Как использовать
Запустите стратегию на нужном инструменте и выберите соответствующий тип свечей.
При необходимости скорректируйте уровни RSI и период усреднения под специфику рынка.
Перед реальной торговлей протестируйте стратегию на истории и в симуляции.
Для тонкой настройки используйте оптимизацию параметров в Designer или в бэктестере StockSharp.
Дисклеймер
Стратегия предоставляется исключительно в учебных целях. Перед использованием на реальном счёте необходимо провести всестороннее тестирование.
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()