Ver en GitHub

Estrategia de Patrón de Envolvente Alcista

Esta configuración busca una reversión alcista pronunciada cuando una vela envuelve completamente la barra bajista anterior. Dicha formación suele poner fin a una caída a corto plazo e insinúa un renovado impulso ascendente. El filtro de tendencia bajista opcional cuenta velas rojas consecutivas para confirmar el agotamiento de los vendedores.

Las pruebas indican un rendimiento anual promedio de aproximadamente el 76%. Funciona mejor en el mercado forex.

Durante la operación en vivo, el algoritmo observa cada vela entrante y mantiene un registro de la barra anterior. Si la nueva vela cierra más alto de lo que abre y su cuerpo envuelve la barra anterior, se activa una entrada larga. El stop se coloca justo por debajo del mínimo del patrón para limitar el riesgo.

Las operaciones permanecen abiertas hasta que se activa el stop o alguna otra señal sugiere una salida discrecional. Dado que la confirmación de barras bajistas previas fortalece la configuración, la estrategia evita perseguir reversiones débiles.

Detalles

  • Criterios de entrada: La vela alcista envuelve la barra bajista anterior, con tendencia bajista opcional presente.
  • Largo/Corto: Solo largos.
  • Criterios de salida: Stop-loss o discrecional.
  • Stops: Sí, por debajo del mínimo del patrón.
  • Valores predeterminados:
    • CandleType = 15 minute
    • StopLossPercent = 1
    • RequireDowntrend = true
    • DowntrendBars = 3
  • Filtros:
    • Categoría: Patrón
    • Dirección: Largo
    • Indicadores: Candlestick
    • Stops: Sí
    • Complejidad: Intermedio
    • Marco temporal: Intradía
    • Estacionalidad: No
    • Redes neuronales: No
    • Divergencia: No
    • Nivel de riesgo: Medio
using System;
using System.Collections.Generic;

using Ecng.Common;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Bullish Engulfing strategy.
/// Enters long on bullish engulfing pattern below SMA.
/// Enters short on bearish engulfing pattern above SMA.
/// Exits via SMA crossover.
/// </summary>
public class EngulfingBullishStrategy : Strategy
{
	private readonly StrategyParam<int> _maPeriod;
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _cooldownBars;

	private ICandleMessage _previousCandle;
	private int _cooldown;

	/// <summary>
	/// MA Period.
	/// </summary>
	public int MAPeriod
	{
		get => _maPeriod.Value;
		set => _maPeriod.Value = value;
	}

	/// <summary>
	/// Candle type.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Cooldown bars.
	/// </summary>
	public int CooldownBars
	{
		get => _cooldownBars.Value;
		set => _cooldownBars.Value = value;
	}

	/// <summary>
	/// Constructor.
	/// </summary>
	public EngulfingBullishStrategy()
	{
		_maPeriod = Param(nameof(MAPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("MA Period", "Period for SMA", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles to use", "General");

		_cooldownBars = Param(nameof(CooldownBars), 500)
			.SetRange(1, 1000)
			.SetDisplay("Cooldown Bars", "Bars to wait between trades", "General");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_previousCandle = null;
		_cooldown = default;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_previousCandle = null;
		_cooldown = 0;

		var sma = new SimpleMovingAverage { Length = MAPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(sma, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, sma);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, decimal smaValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		if (_cooldown > 0)
		{
			_cooldown--;
			_previousCandle = candle;
			return;
		}

		if (_previousCandle != null)
		{
			var isPrevBearish = _previousCandle.ClosePrice < _previousCandle.OpenPrice;
			var isPrevBullish = _previousCandle.ClosePrice > _previousCandle.OpenPrice;
			var isCurrBullish = candle.ClosePrice > candle.OpenPrice;
			var isCurrBearish = candle.ClosePrice < candle.OpenPrice;

			var bullishEngulfing = isPrevBearish && isCurrBullish &&
				candle.ClosePrice > _previousCandle.OpenPrice &&
				candle.OpenPrice < _previousCandle.ClosePrice;

			var bearishEngulfing = isPrevBullish && isCurrBearish &&
				candle.ClosePrice < _previousCandle.OpenPrice &&
				candle.OpenPrice > _previousCandle.ClosePrice;

			if (Position == 0 && bullishEngulfing && candle.ClosePrice < smaValue)
			{
				BuyMarket();
				_cooldown = CooldownBars;
			}
			else if (Position == 0 && bearishEngulfing && candle.ClosePrice > smaValue)
			{
				SellMarket();
				_cooldown = CooldownBars;
			}
			else if (Position > 0 && candle.ClosePrice < smaValue)
			{
				SellMarket();
				_cooldown = CooldownBars;
			}
			else if (Position < 0 && candle.ClosePrice > smaValue)
			{
				BuyMarket();
				_cooldown = CooldownBars;
			}
		}

		_previousCandle = candle;
	}
}