Ver en GitHub

Estrategia 3Commas HA & MA

Utiliza velas Heikin Ashi y un par de medias móviles exponenciales. Una operación larga ocurre cuando una vela HA bajista es seguida por una alcista mientras la MA rápida está por encima de la MA lenta. Los cortos siguen la configuración opuesta. Las posiciones se cierran cuando el precio cruza la MA lenta o alcanza el stop de swing.

Detalles

  • Criterios de entrada: Reversión de Heikin Ashi con confirmación de MA.
  • Largo/Corto: Ambas direcciones.
  • Criterios de salida: El precio cruza la MA lenta o stop.
  • Stops: Máximo/mínimo del swing.
  • Valores predeterminados:
    • MaFast = 9
    • MaSlow = 18
    • CandleType = TimeSpan.FromMinutes(1)
  • Filtros:
    • Categoría: Tendencia
    • Dirección: Ambos
    • Indicadores: Heikin Ashi, EMA
    • Stops: Sí
    • Complejidad: Intermedio
    • Marco temporal: Intradía
    • Estacionalidad: No
    • Redes neuronales: No
    • Divergencia: No
    • Nivel de riesgo: Medio
using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Heikin Ashi with moving averages.
/// </summary>
public class ThreeCommasHaMaStrategy : Strategy
{
	private readonly StrategyParam<int> _maFast;
	private readonly StrategyParam<int> _maSlow;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _haOpenPrev;
	private decimal _haClosePrev;
	private decimal _stopPrice;

	public int MaFast
	{
		get => _maFast.Value;
		set => _maFast.Value = value;
	}

	public int MaSlow
	{
		get => _maSlow.Value;
		set => _maSlow.Value = value;
	}

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public ThreeCommasHaMaStrategy()
	{
		_maFast = Param(nameof(MaFast), 9)
			.SetDisplay("MA Fast", "Fast moving average period", "MA");
		_maSlow = Param(nameof(MaSlow), 18)
			.SetDisplay("MA Slow", "Slow moving average period", "MA");
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles to use", "General");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_haOpenPrev = 0m;
		_haClosePrev = 0m;
		_stopPrice = 0m;
	}

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

		var ma1 = new ExponentialMovingAverage { Length = MaFast };
		var ma2 = new ExponentialMovingAverage { Length = MaSlow };

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

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

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

		var haClose = (candle.OpenPrice + candle.HighPrice + candle.LowPrice + candle.ClosePrice) / 4m;
		var haOpen = (_haOpenPrev == 0m && _haClosePrev == 0m) ? (candle.OpenPrice + candle.ClosePrice) / 2m : (_haOpenPrev + _haClosePrev) / 2m;
		var haBull = haClose > haOpen;
		var haBearPrev = _haClosePrev < _haOpenPrev;
		var haBullPrev = _haClosePrev > _haOpenPrev;

		if (haBearPrev && ma1 > ma2 && haBull && candle.ClosePrice > ma1 && Position <= 0)
		{
			_stopPrice = candle.LowPrice;
			BuyMarket();
		}
		else if (haBullPrev && ma1 < ma2 && !haBull && candle.ClosePrice < ma1 && Position >= 0)
		{
			_stopPrice = candle.HighPrice;
			SellMarket();
		}

		if (Position > 0 && candle.ClosePrice < ma2)
			SellMarket();
		else if (Position < 0 && candle.ClosePrice > ma2)
			BuyMarket();

		_haOpenPrev = haOpen;
		_haClosePrev = haClose;
	}
}