Ver en GitHub

Estrategia de Tendencia EMA con Entrada Heikin Ashi

Estrategia que usa Bandas de Bollinger en velas Heikin Ashi con un filtro de tendencia EMA de marco temporal superior. Compra tras velas Heikin Ashi bajistas consecutivas tocando la banda inferior seguidas de una vela alcista por encima cuando la EMA rápida del marco temporal superior está sobre la EMA lenta. Vende a la inversa.

Tras entrar, se toma un primer objetivo igual al riesgo y el stop se ajusta usando los extremos de la vela anterior.

Detalles

  • Criterios de entrada:
    • Largo: al menos dos velas HA bajistas tocando la banda inferior, luego alcista por encima con la EMA rápida del marco temporal superior por encima de la EMA lenta
    • Corto: al menos dos velas HA alcistas tocando la banda superior, luego bajista por debajo con la EMA rápida del marco temporal superior por debajo de la EMA lenta
  • Largo/Corto: Ambos
  • Criterios de salida:
    • Largo: primer objetivo en 1R, luego trailing stop en mínimos anteriores
    • Corto: primer objetivo en 1R, luego trailing stop en máximos anteriores
  • Stops: Mínimo/máximo de la vela anterior
  • Valores predeterminados:
    • BollingerPeriod = 20
    • BollingerDeviation = 2m
    • FastEmaPeriod = 9
    • SlowEmaPeriod = 21
    • CandleType = TimeSpan.FromMinutes(5).TimeFrame()
    • HigherTimeframe = TimeSpan.FromMinutes(180).TimeFrame()
  • Filtros:
    • Categoría: Patrón
    • Dirección: Ambos
    • Indicadores: Bollinger Bands, Heikin Ashi, EMA
    • Stops: Sí
    • Complejidad: Intermedio
    • Marco temporal: Medio plazo
    • 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;

public class EmaTrendHeikinAshiEntryStrategy : Strategy
{
	private readonly StrategyParam<int> _fastEmaPeriod;
	private readonly StrategyParam<int> _slowEmaPeriod;
	private readonly StrategyParam<DataType> _candleType;
	private decimal _prevFastEma;
	private decimal _prevSlowEma;

	public int FastEmaPeriod { get => _fastEmaPeriod.Value; set => _fastEmaPeriod.Value = value; }
	public int SlowEmaPeriod { get => _slowEmaPeriod.Value; set => _slowEmaPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public EmaTrendHeikinAshiEntryStrategy()
	{
		_fastEmaPeriod = Param(nameof(FastEmaPeriod), 120)
			.SetGreaterThanZero()
			.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
		_slowEmaPeriod = Param(nameof(SlowEmaPeriod), 450)
			.SetGreaterThanZero()
			.SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles to use", "General");
	}

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

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFastEma = 0m;
		_prevSlowEma = 0m;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		var fastEma = new ExponentialMovingAverage { Length = FastEmaPeriod };
		var slowEma = new ExponentialMovingAverage { Length = SlowEmaPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fastEma, slowEma, ProcessCandle).Start();
		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, fastEma);
			DrawIndicator(area, slowEma);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastEmaValue, decimal slowEmaValue)
	{
		if (candle.State != CandleStates.Finished) return;
		if (_prevFastEma == 0m || _prevSlowEma == 0m)
		{
			_prevFastEma = fastEmaValue;
			_prevSlowEma = slowEmaValue;
			return;
		}
		if (_prevFastEma <= _prevSlowEma && fastEmaValue > slowEmaValue && Position <= 0)
			BuyMarket();
		else if (_prevFastEma >= _prevSlowEma && fastEmaValue < slowEmaValue && Position >= 0)
			SellMarket();
		_prevFastEma = fastEmaValue;
		_prevSlowEma = slowEmaValue;
	}
}