ABE BE RSI — порт советника MetaTrader Expert_ABE_BE_RSI. Стратегия сочетает японские свечные модели «бычье/медвежье поглощение» с подтверждением импульса через индекс относительной силы (RSI). Для формирования сигнала требуется две подряд завершённые свечи с паттерном поглощения, а также значение RSI последней закрытой свечи в заданном диапазоне. Дополнительно отслеживаются пересечения RSI с ключевыми уровнями, что позволяет вовремя закрывать или переворачивать позицию. Такое поведение максимально повторяет исходный механизм голосов в MQL-версии.
Логика торговли
Определение паттерна поглощения
После закрытия каждой свечи анализируются две предыдущие:
Для бычьего сигнала свеча t-2 должна быть медвежьей, свеча t-1 — бычьей.
Тело свечи t-1 должно превышать средний размер тел за последние MovingAveragePeriod свечей.
Свеча t-1 закрывается выше открытия свечи t-2 и открывается ниже её закрытия, что обеспечивает полное поглощение.
Средняя точка свечи t-2 расположена ниже скользящей средней по закрытиям, подтверждая локальный нисходящий тренд.
Для медвежьего сигнала условия зеркальны: более старая свеча бычья, новая — медвежья с крупным телом, полностью покрывающим тело предыдущей свечи, при этом средняя точка старой свечи находится выше скользящей средней закрытий.
Фильтрация по RSI
Покупка разрешена, если RSI последней закрытой свечи ниже BullishEntryLevel (по умолчанию 40).
Продажа разрешена, если RSI последней закрытой свечи выше BearishEntryLevel (по умолчанию 60).
Управление выходами
Пересечения RSI с двумя уровнями управляют закрытием позиций:
Короткие позиции закрываются, когда RSI поднимается выше ExitLowerLevel (30) или ExitUpperLevel (70) после нахождения ниже этих уровней.
Длинные позиции закрываются при обратном пересечении сверху вниз.
Исполнение заявок
Все операции выполняются рыночными заявками. При смене направления текущая позиция закрывается, затем открывается новая с базовым объёмом Volume, что соответствует фиксированному лоту в оригинальном советнике.
Параметры
Параметр
Описание
Значение по умолчанию
Volume
Объём сделки в контрактах.
0.1
RsiPeriod
Период расчёта RSI.
11
MovingAveragePeriod
Период скользящих средних по телам и закрытиям свечей.
5
BullishEntryLevel
Максимальное значение RSI для подтверждения бычьего сигнала.
40
BearishEntryLevel
Минимальное значение RSI для подтверждения медвежьего сигнала.
60
ExitLowerLevel
Нижний уровень RSI, используемый для фиксации прибыли/убытка.
30
ExitUpperLevel
Верхний уровень RSI для закрытия позиций.
70
CandleType
Тип/период свечей, с которыми работает стратегия.
1 час
Все параметры реализованы через StrategyParam, поэтому поддерживают оптимизацию в Designer и Runner.
Набор индикаторов
Relative Strength Index — основной фильтр импульса, задаёт входные и выходные уровни.
Простая скользящая средняя закрытий — оценивает локальный тренд и помогает отфильтровать ложные поглощения.
Простая скользящая средняя тел свечей — проверяет, что новая свеча действительно крупнее типичных баров.
Рекомендации по использованию
Обработка выполняется только по завершённым свечам (CandleStates.Finished), чтобы избежать преждевременных сигналов.
Внутри стратегии хранится лишь минимально необходимый набор значений (две последние свечи и их индикаторы), что соответствует требованиям репозитория по эффективности.
В OnStarted вызывается StartProtection(), что активирует стандартные защитные механизмы StockSharp при появлении позиции.
Отличия от оригинального советника
Система голосов MetaTrader заменена на прямые торговые действия с теми же условиями.
Управление капиталом сведено к одному параметру Volume, аналогичному фиксированному лоту Money_FixLot_Lots.
Модуль трейлинг-стопа отсутствует, как и в исходном наборе модулей (TrailingNone).
Рекомендации по тестированию
Запустите стратегию в Designer или Runner на инструментах, где свечные разворотные модели показывают устойчивые результаты (например, основные валютные пары).
Перед запуском уточните значения RSI и скользящих средних для вашего инструмента; дефолтные настройки совпадают с MetaTrader-версией.
Используйте оптимизацию, чтобы подобрать иные пороги или период усреднения под конкретный рынок.
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// ABE BE RSI strategy: Engulfing pattern with RSI confirmation.
/// Bullish engulfing + oversold RSI for long, bearish engulfing + overbought RSI for short.
/// </summary>
public class AbeBeRsiStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _oversold;
private readonly StrategyParam<decimal> _overbought;
private readonly StrategyParam<int> _signalCooldownCandles;
private readonly List<ICandleMessage> _candles = new();
private int _candlesSinceTrade;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public decimal Oversold { get => _oversold.Value; set => _oversold.Value = value; }
public decimal Overbought { get => _overbought.Value; set => _overbought.Value = value; }
public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }
public AbeBeRsiStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI period", "Indicators");
_oversold = Param(nameof(Oversold), 40m)
.SetDisplay("Oversold", "RSI oversold level", "Signals");
_overbought = Param(nameof(Overbought), 60m)
.SetDisplay("Overbought", "RSI overbought level", "Signals");
_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 6)
.SetGreaterThanZero()
.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_candles.Clear();
_candlesSinceTrade = SignalCooldownCandles;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_candles.Clear();
_candlesSinceTrade = SignalCooldownCandles;
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 (_candlesSinceTrade < SignalCooldownCandles)
_candlesSinceTrade++;
_candles.Add(candle);
if (_candles.Count > 5)
_candles.RemoveAt(0);
if (_candles.Count >= 2)
{
var curr = _candles[^1];
var prev = _candles[^2];
var bullishEngulfing = prev.OpenPrice > prev.ClosePrice
&& curr.ClosePrice > curr.OpenPrice
&& curr.OpenPrice <= prev.ClosePrice
&& curr.ClosePrice >= prev.OpenPrice;
var bearishEngulfing = prev.ClosePrice > prev.OpenPrice
&& curr.OpenPrice > curr.ClosePrice
&& curr.OpenPrice >= prev.ClosePrice
&& curr.ClosePrice <= prev.OpenPrice;
if (bullishEngulfing && rsiValue < Oversold && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
BuyMarket();
_candlesSinceTrade = 0;
}
else if (bearishEngulfing && rsiValue > Overbought && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
SellMarket();
_candlesSinceTrade = 0;
}
}
}
}
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 abe_be_rsi_strategy(Strategy):
def __init__(self):
super(abe_be_rsi_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30)))
self._rsi_period = self.Param("RsiPeriod", 14)
self._oversold = self.Param("Oversold", 40.0)
self._overbought = self.Param("Overbought", 60.0)
self._signal_cooldown_candles = self.Param("SignalCooldownCandles", 6)
self._candles = []
self._candles_since_trade = 6
@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 Oversold(self):
return self._oversold.Value
@Oversold.setter
def Oversold(self, value):
self._oversold.Value = value
@property
def Overbought(self):
return self._overbought.Value
@Overbought.setter
def Overbought(self, value):
self._overbought.Value = value
@property
def SignalCooldownCandles(self):
return self._signal_cooldown_candles.Value
@SignalCooldownCandles.setter
def SignalCooldownCandles(self, value):
self._signal_cooldown_candles.Value = value
def OnReseted(self):
super(abe_be_rsi_strategy, self).OnReseted()
self._candles.clear()
self._candles_since_trade = self.SignalCooldownCandles
def OnStarted2(self, time):
super(abe_be_rsi_strategy, self).OnStarted2(time)
self._candles.clear()
self._candles_since_trade = self.SignalCooldownCandles
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
if self._candles_since_trade < self.SignalCooldownCandles:
self._candles_since_trade += 1
rsi_val = float(rsi_value)
self._candles.append(candle)
if len(self._candles) > 5:
self._candles.pop(0)
if len(self._candles) >= 2:
curr = self._candles[-1]
prev = self._candles[-2]
bullish_engulfing = (float(prev.OpenPrice) > float(prev.ClosePrice)
and float(curr.ClosePrice) > float(curr.OpenPrice)
and float(curr.OpenPrice) <= float(prev.ClosePrice)
and float(curr.ClosePrice) >= float(prev.OpenPrice))
bearish_engulfing = (float(prev.ClosePrice) > float(prev.OpenPrice)
and float(curr.OpenPrice) > float(curr.ClosePrice)
and float(curr.OpenPrice) >= float(prev.ClosePrice)
and float(curr.ClosePrice) <= float(prev.OpenPrice))
if bullish_engulfing and rsi_val < self.Oversold and self.Position <= 0 and self._candles_since_trade >= self.SignalCooldownCandles:
self.BuyMarket()
self._candles_since_trade = 0
elif bearish_engulfing and rsi_val > self.Overbought and self.Position >= 0 and self._candles_since_trade >= self.SignalCooldownCandles:
self.SellMarket()
self._candles_since_trade = 0
def CreateClone(self):
return abe_be_rsi_strategy()