Стратегия AMS ES RSI переносит логику советника MetaTrader Expert_AMS_ES_RSI в StockSharp. Она сочетает свечные модели «утренняя/вечерняя звезда» с подтверждением по индикатору RSI. Покупки выполняются при появлении бычьей утренней звезды в зоне перепроданности RSI, продажи — при возникновении медвежьей вечерней звезды вместе с сигналом перекупленности. Выход из позиций осуществляется при обратном пересечении RSI заданных уровней.
Предпосылки рынка
Подходит для любых инструментов, формирующих стандартные свечи OHLC. Изначально советник предназначался для рынка Forex и индексных фьючерсов.
Предполагается наличие читаемых свечных формаций. На сверхшумных тиковых данных сигналы могут быть недостоверными.
Логика входа
Подписаться на выбранный таймфрейм (по умолчанию 1 час) и дождаться формирования трёх закрытых свечей.
Рассчитать средний размер тела за последние BodyAveragePeriod свечей (по умолчанию 3).
Определить утреннюю звезду, если выполняются условия:
Свеча 3 — выраженно медвежья (Open - Close больше среднего тела).
Свеча 2 имеет маленькое тело (менее половины среднего) и формирует гэп вниз относительно свечи 3.
Свеча 1 закрывается выше середины тела свечи 3.
Аналогично выявить вечернюю звезду для медвежьего сигнала.
Подтвердить длинный вход, когда текущее значение RSI ниже LongEntryRsi (по умолчанию 40). Для коротких позиций RSI должен быть выше ShortEntryRsi (по умолчанию 60).
Размещать рыночные ордера, используя параметр Volume стратегии.
Логика выхода
Закрывать длинные позиции при нисходящем пересечении RSI уровней UpperExitRsi (по умолчанию 70) или LowerExitRsi (по умолчанию 30).
Закрывать короткие позиции при восходящем пересечении этих же границ.
Жёсткие стоп-лосс/тейк-профит не применяются. Управление риском следует реализовывать внешними средствами либо корректировкой порогов.
Параметры
Имя
Описание
Значение по умолчанию
Диапазон
CandleType
Тип свечей для подписки.
Часовой таймфрейм
Любые поддерживаемые свечи
RsiPeriod
Период расчёта RSI.
47
Оптимизация (10–70)
BodyAveragePeriod
Количество свечей для среднего размера тела.
3
Оптимизация (2–6)
LongEntryRsi
Максимум RSI для входа в лонг.
40
Оптимизация (20–50)
ShortEntryRsi
Минимум RSI для входа в шорт.
60
Оптимизация (50–80)
LowerExitRsi
Нижняя граница выхода при пересечении вверх.
30
Оптимизация (20–40)
UpperExitRsi
Верхняя граница выхода при пересечении вниз.
70
Оптимизация (60–80)
Особенности реализации
Используется высокоуровневый API StockSharp с автоматической подпиской на свечи.
Индикаторные значения поступают через Bind; обращения к GetValue не требуются.
Хранится только небольшой буфер из трёх свечей для проверки паттерна.
В OnStarted вызывается StartProtection() для активации встроенных механизмов защиты.
Рекомендации по использованию
Запустите стратегию на выбранном инструменте и убедитесь, что коннектор предоставляет свечной ряд.
Подбирайте уровни RSI с учётом волатильности актива: более широкие пороги снижают частоту сделок, но повышают качество сигналов.
При необходимости подключите внешние модули управления объёмом, чтобы имитировать фиксированный лот оригинального советника.
Для тестирования убедитесь, что исторические данные содержат гэпы — они важны для корректного распознавания звёзд.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Morning/Evening Star + RSI strategy.
/// Buys on morning star with low RSI, sells on evening star with high RSI.
/// </summary>
public class AmsEsRsiStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _rsiLow;
private readonly StrategyParam<decimal> _rsiHigh;
private ICandleMessage _prevCandle;
private ICandleMessage _prevPrevCandle;
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 AmsEsRsiStrategy()
{
_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 oversold threshold", "Signals");
_rsiHigh = Param(nameof(RsiHigh), 60m)
.SetDisplay("RSI High", "RSI overbought threshold", "Signals");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevCandle = null;
_prevPrevCandle = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevCandle = null;
_prevPrevCandle = 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 && _prevPrevCandle != null)
{
var prevBody = Math.Abs(_prevCandle.ClosePrice - _prevCandle.OpenPrice);
var prevRange = _prevCandle.HighPrice - _prevCandle.LowPrice;
var isSmallBody = prevRange > 0 && prevBody < prevRange * 0.3m;
var firstBearish = _prevPrevCandle.OpenPrice > _prevPrevCandle.ClosePrice;
var currBullish = candle.ClosePrice > candle.OpenPrice;
var isMorningStar = firstBearish && isSmallBody && currBullish;
var firstBullish = _prevPrevCandle.ClosePrice > _prevPrevCandle.OpenPrice;
var currBearish = candle.OpenPrice > candle.ClosePrice;
var isEveningStar = firstBullish && isSmallBody && currBearish;
if (isMorningStar && rsiValue < RsiLow && Position <= 0)
BuyMarket();
else if (isEveningStar && rsiValue > RsiHigh && Position >= 0)
SellMarket();
}
_prevPrevCandle = _prevCandle;
_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 ams_es_rsi_strategy(Strategy):
def __init__(self):
super(ams_es_rsi_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
self._prev_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(ams_es_rsi_strategy, self).OnReseted()
self._prev_candle = None
self._prev_prev_candle = None
def OnStarted2(self, time):
super(ams_es_rsi_strategy, self).OnStarted2(time)
self._prev_candle = None
self._prev_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 and self._prev_prev_candle is not None:
prev_body = abs(float(self._prev_candle.ClosePrice) - float(self._prev_candle.OpenPrice))
prev_range = float(self._prev_candle.HighPrice) - float(self._prev_candle.LowPrice)
is_small_body = prev_range > 0 and prev_body < prev_range * 0.3
first_bearish = float(self._prev_prev_candle.OpenPrice) > float(self._prev_prev_candle.ClosePrice)
curr_bullish = float(candle.ClosePrice) > float(candle.OpenPrice)
is_morning_star = first_bearish and is_small_body and curr_bullish
first_bullish = float(self._prev_prev_candle.ClosePrice) > float(self._prev_prev_candle.OpenPrice)
curr_bearish = float(candle.OpenPrice) > float(candle.ClosePrice)
is_evening_star = first_bullish and is_small_body and curr_bearish
if is_morning_star and rsi_val < self.RsiLow and self.Position <= 0:
self.BuyMarket()
elif is_evening_star and rsi_val > self.RsiHigh and self.Position >= 0:
self.SellMarket()
self._prev_prev_candle = self._prev_candle
self._prev_candle = candle
def CreateClone(self):
return ams_es_rsi_strategy()