Simple Engulfing Strategy воспроизводит работу советников MetaTrader 4 «simple engulf mt4 buy» и «simple engulf mt4 sell». Оригинальные советники ищут свечной паттерн «поглощение» и открывают сделки только в одном направлении. В версии для StockSharp оба робота объединены в один класс с параметром Direction, позволяющим выбрать работу только в лонг, только в шорт или в обе стороны.
Стратегия реагирует исключительно на завершённые свечи, что полностью соответствует логике MetaTrader. Для подписки на данные и выставления заявок применяются высокоуровневые методы StockSharp (SubscribeCandles, Bind, BuyMarket, SellMarket, StartProtection).
Логика торговли
Формировать свечи согласно параметру CandleType.
Обрабатывать сигналы только после закрытия очередной свечи, параллельно запоминая предыдущую завершённую свечу.
Рассчитывать размер тела текущей свечи в пунктах. Если он меньше MinBodyPips или больше MaxBodyPips (при активном верхнем фильтре), сигнал отбрасывается.
Условия бычьего поглощения:
Предыдущая свеча медвежья (закрытие ниже открытия).
Текущая свеча бычья (закрытие выше открытия).
Открытие текущей свечи не выше закрытия предыдущей.
Закрытие текущей свечи не ниже открытия предыдущей.
Условия медвежьего поглощения симметричны.
После появления паттерна проверяется доступность торговли (IsFormedAndOnlineAndAllowTrading()) и разрешено ли направление параметром Direction:
BuyOnly — поведение советника «simple engulf mt4 buy».
SellOnly — поведение советника «simple engulf mt4 sell».
Both — торговля в обе стороны.
Для входа используется объём TradeVolume. Если уже существует позиция противоположного знака, стратегия добавляет её абсолютный объём к заявке, тем самым закрывая старую позицию и разворачиваясь, как это делает оригинальный советник.
При положительных значениях StopLossPips или TakeProfitPips активируется StartProtection, который переводит расстояние в пунктах в реальное ценовое смещение и выставляет защитные заявки.
Параметры
Параметр
Значение по умолчанию
Описание
CandleType
15 минут
Тип и таймфрейм свечей для анализа.
TradeVolume
0.01
Объём каждой сделки, совпадает с настройкой MT4.
StopLossPips
20
Расстояние до стоп-лосса в пунктах. Ноль отключает защиту.
TakeProfitPips
20
Расстояние до тейк-профита в пунктах. Ноль отключает защиту.
MinBodyPips
0
Минимальный размер тела свечи в пунктах.
MaxBodyPips
50
Максимальный размер тела свечи в пунктах. Значение 0 отключает ограничение.
Direction
BuyOnly
Разрешённое направление торговли: только покупки, только продажи или оба варианта.
Практические рекомендации
Размер пункта вычисляется автоматически на основе PriceStep и количества знаков инструмента. Это позволяет корректно применять фильтры как на четырёх-, так и на пятизнаковых котировках.
Защитные заявки отправляются только при положительных StopLossPips или TakeProfitPips. В остальных случаях выход из позиции остаётся на усмотрение трейдера или других модулей.
Сигналы возникают строго на закрытии свечи, поэтому внутри свечи стратегия не «перерисовывается».
Код построен на высокоуровневом API StockSharp, что упрощает сопровождение и соблюдает требования проекта.
Отличия от оригинала
Два советника объединены в одну стратегию с параметром Direction вместо отдельных файлов.
Добавлены вспомогательные возможности StockSharp: при желании можно отобразить свечи и сделки на графике, а также вести журнал сообщений.
Управление защитными приказами реализовано через StartProtection, что обеспечивает поведение, аналогичное жёстким стопам в MetaTrader.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Simple Engulfing strategy: engulfing candlestick pattern with EMA filter.
/// Buys on bullish engulfing above EMA, sells on bearish engulfing below EMA.
/// </summary>
public class SimpleEngulfingStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaPeriod;
private decimal _prevOpen;
private decimal _prevClose;
private bool _hasPrev;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public SimpleEngulfingStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_emaPeriod = Param(nameof(EmaPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("EMA Period", "EMA trend filter period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevOpen = 0;
_prevClose = 0;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ema, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal emaValue)
{
if (candle.State != CandleStates.Finished) return;
if (_hasPrev)
{
var prevBearish = _prevClose < _prevOpen;
var currBullish = candle.ClosePrice > candle.OpenPrice;
var bullishEngulf = prevBearish && currBullish
&& candle.OpenPrice <= _prevClose && candle.ClosePrice >= _prevOpen;
var prevBullish = _prevClose > _prevOpen;
var currBearish = candle.ClosePrice < candle.OpenPrice;
var bearishEngulf = prevBullish && currBearish
&& candle.OpenPrice >= _prevClose && candle.ClosePrice <= _prevOpen;
if (bullishEngulf && candle.ClosePrice > emaValue && Position <= 0)
BuyMarket();
else if (bearishEngulf && candle.ClosePrice < emaValue && Position >= 0)
SellMarket();
}
_prevOpen = candle.OpenPrice;
_prevClose = candle.ClosePrice;
_hasPrev = true;
}
}
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class simple_engulfing_strategy(Strategy):
def __init__(self):
super(simple_engulfing_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30)))
self._ema_period = self.Param("EmaPeriod", 50)
self._prev_open = 0.0
self._prev_close = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def EmaPeriod(self):
return self._ema_period.Value
@EmaPeriod.setter
def EmaPeriod(self, value):
self._ema_period.Value = value
def OnReseted(self):
super(simple_engulfing_strategy, self).OnReseted()
self._prev_open = 0.0
self._prev_close = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(simple_engulfing_strategy, self).OnStarted2(time)
self._has_prev = False
ema = ExponentialMovingAverage()
ema.Length = self.EmaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(ema, self._process_candle).Start()
def _process_candle(self, candle, ema_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
open_price = float(candle.OpenPrice)
ema_val = float(ema_value)
if self._has_prev:
prev_bearish = self._prev_close < self._prev_open
curr_bullish = close > open_price
bullish_engulf = (prev_bearish and curr_bullish and
open_price <= self._prev_close and close >= self._prev_open)
prev_bullish = self._prev_close > self._prev_open
curr_bearish = close < open_price
bearish_engulf = (prev_bullish and curr_bearish and
open_price >= self._prev_close and close <= self._prev_open)
if bullish_engulf and close > ema_val and self.Position <= 0:
self.BuyMarket()
elif bearish_engulf and close < ema_val and self.Position >= 0:
self.SellMarket()
self._prev_open = open_price
self._prev_close = close
self._has_prev = True
def CreateClone(self):
return simple_engulfing_strategy()