Ver no GitHub

Simple Engulfing Strategy

Overview

The Simple Engulfing Strategy replicates the behaviour of the MetaTrader 4 experts "simple engulf mt4 buy" and "simple engulf mt4 sell". Both experts detect engulfing candlestick patterns and open trades in a single direction. The StockSharp port merges both advisors into one configurable strategy so that the trader can reproduce the original buy-only, sell-only or combined behaviour inside the StockSharp framework.

The strategy listens to completed candles only, which matches the bar-close execution style used by the MetaTrader version. All order placement uses the high-level StockSharp API (SubscribeCandles, Bind, BuyMarket, SellMarket, and StartProtection) to stay close to the StockSharp coding guidelines.

Trading Logic

  1. Build candles based on the configured CandleType.
  2. Wait for the current candle to finish and keep the previous completed candle in memory.
  3. Calculate the current candle body size in pips. Reject the pattern when it is below MinBodyPips or above MaxBodyPips (if the maximum filter is enabled with a positive value).
  4. Detect a bullish engulfing pattern when:
    • The previous candle is bearish (close below open).
    • The current candle is bullish (close above open).
    • The current open is below or equal to the previous close.
    • The current close is above or equal to the previous open.
  5. Detect a bearish engulfing pattern using the mirrored conditions.
  6. When a valid pattern appears, make sure automated trading is allowed (IsFormedAndOnlineAndAllowTrading()) and that the configured direction allows the trade:
    • BuyOnly replicates the "simple engulf mt4 buy" robot.
    • SellOnly replicates the "simple engulf mt4 sell" robot.
    • Both enables bi-directional trading.
  7. Use the configured TradeVolume for every entry. If the strategy is currently positioned on the opposite side it closes the position and flips by adding the absolute position size to the entry order, matching the MetaTrader behaviour when switching from short to long (or vice versa).
  8. Optional stop-loss and take-profit levels are applied through StartProtection using price-based units. They convert the pip distances into instrument price increments so that StockSharp manages protective orders in the same way as the original experts.

Parameters

Name Default Description
CandleType TimeFrame(15 minutes) Candle type and aggregation interval used to detect patterns.
TradeVolume 0.01 Order volume per entry, identical to the MetaTrader experts.
StopLossPips 20 Stop-loss distance expressed in pips. Set to 0 to disable the protective order.
TakeProfitPips 20 Take-profit distance expressed in pips. Set to 0 to disable the protective order.
MinBodyPips 0 Minimum candle body (in pips) required for a valid engulfing pattern.
MaxBodyPips 50 Maximum candle body (in pips) allowed for a valid engulfing pattern. Use 0 to remove the upper filter.
Direction BuyOnly Defines which side(s) of the original advisors should be executed (BuyOnly, SellOnly, or Both).

Practical Notes

  • The pip size adapts to the traded instrument automatically by analysing the instrument's PriceStep and number of decimal places. This ensures the pip filters and protective orders behave like the MetaTrader inputs on both 4-digit and 5-digit forex symbols.
  • Protective orders are sent only when StopLossPips or TakeProfitPips are positive. Otherwise, the strategy leaves exits to discretionary management or other automation modules.
  • Because the strategy waits for fully finished candles, signals are generated at the close of each bar, avoiding intra-bar repainting.
  • High-level API calls keep the implementation concise and follow the project guideline of preferring ready-made StockSharp components over manual order handling.

Differences from the Original

  • Both MetaTrader advisors are combined into a single strategy with a Direction parameter instead of two separate files.
  • Logging and charting helpers from StockSharp (optional candle and trade plots) are added for better visibility when running inside StockSharp terminals.
  • Risk management uses StockSharp's StartProtection helper, which internally manages stop-loss and take-profit orders via the StockSharp engine. The resulting behaviour is equivalent to using hard stops in 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;
	}
}