Эта стратегия — порт MetaTrader-советника Expert_AH_HM_RSI на платформу StockSharp. Она ищет свечные модели «молот» и «повешенный» на закрытых барах и подтверждает их фильтром Relative Strength Index (RSI). Логика управления позициями повторяет оригинальный эксперт: при появлении противоположного сигнала позиция разворачивается сразу же.
Логика торговли
Фильтр тренда — короткая простая скользящая средняя (период по умолчанию 2) помогает определить, находится ли рынок в локальном восходящем или нисходящем движении.
Свечная модель — анализируется последняя завершённая свеча.
Молот: тело находится в верхней трети диапазона свечи, текущая свеча открылась и закрылась ниже предыдущей, а её середина лежит ниже скользящей средней.
Повешенный: тело в верхней трети, открытие и закрытие выше предыдущей свечи, середина расположена выше скользящей средней.
Фильтр RSI:
Для покупок RSI должен быть ниже порога для молота (по умолчанию 40).
Для продаж RSI должен быть выше порога для повешенного (по умолчанию 60).
Исполнение сделок — при срабатывании сигнала стратегия выставляет заявку на объём Volume + |Position|, что обеспечивает мгновенный разворот при противоположном сигнале.
Выход — позиции закрываются, когда RSI пробивает вниз верхний уровень (70) или пробивает вверх нижний уровень (30), что повторяет схему «голосов» в исходном коде.
Индикаторы
RelativeStrengthIndex (период 33).
SimpleMovingAverage (период 2, рассчитывается по ценам закрытия).
Параметры
Имя
Описание
Значение по умолчанию
Volume
Базовый торговый объём.
1
RsiPeriod
Период RSI.
33
MaPeriod
Период скользящей средней.
2
HammerRsiThreshold
Максимальное значение RSI для подтверждения молота.
40
HangingManRsiThreshold
Минимальное значение RSI для подтверждения повешенного.
60
LowerExitLevel
Уровень RSI для закрытия коротких позиций при росте.
30
UpperExitLevel
Уровень RSI для закрытия длинных позиций при падении.
70
CandleType
Используемый таймфрейм свечей.
1 час
Все параметры доступны для оптимизации через интерфейс StockSharp.
Рекомендации по использованию
Стратегия работает только с завершёнными свечами — убедитесь, что источник данных отдаёт закрытые бары выбранного таймфрейма.
Благодаря подаче заявок на Volume + |Position| любая новая противоположная модель моментально разворачивает позицию.
Метод StartProtection() вызывается один раз при запуске, активируя встроенную защиту счёта.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Hammer/Hanging Man + RSI strategy.
/// Buys on hammer with low RSI, sells on hanging man with high RSI.
/// </summary>
public class AhHmRsiStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _rsiLow;
private readonly StrategyParam<decimal> _rsiHigh;
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 AhHmRsiStrategy()
{
_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 for buy", "Signals");
_rsiHigh = Param(nameof(RsiHigh), 60m)
.SetDisplay("RSI High", "RSI overbought threshold for sell", "Signals");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
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;
var body = Math.Abs(candle.ClosePrice - candle.OpenPrice);
var range = candle.HighPrice - candle.LowPrice;
if (range <= 0 || body <= 0) return;
var upperShadow = candle.HighPrice - Math.Max(candle.OpenPrice, candle.ClosePrice);
var lowerShadow = Math.Min(candle.OpenPrice, candle.ClosePrice) - candle.LowPrice;
var isHammer = lowerShadow > body * 2 && upperShadow < body;
var isHangingMan = upperShadow > body * 2 && lowerShadow < body;
if (isHammer && rsiValue < RsiLow && Position <= 0)
BuyMarket();
else if (isHangingMan && rsiValue > RsiHigh && Position >= 0)
SellMarket();
}
}
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 ah_hm_rsi_strategy(Strategy):
def __init__(self):
super(ah_hm_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)
@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 OnStarted2(self, time):
super(ah_hm_rsi_strategy, self).OnStarted2(time)
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)
body = abs(float(candle.ClosePrice) - float(candle.OpenPrice))
rng = float(candle.HighPrice) - float(candle.LowPrice)
if rng <= 0 or body <= 0:
return
upper_shadow = float(candle.HighPrice) - max(float(candle.OpenPrice), float(candle.ClosePrice))
lower_shadow = min(float(candle.OpenPrice), float(candle.ClosePrice)) - float(candle.LowPrice)
is_hammer = lower_shadow > body * 2 and upper_shadow < body
is_hanging_man = upper_shadow > body * 2 and lower_shadow < body
if is_hammer and rsi_val < self.RsiLow and self.Position <= 0:
self.BuyMarket()
elif is_hanging_man and rsi_val > self.RsiHigh and self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return ah_hm_rsi_strategy()