Ver en GitHub

Estrategia X2MA Digit DM 361

Esta estrategia combina dos medias móviles con el Índice de Dirección Promedio (ADX). Se abre una posición larga cuando la media móvil rápida está por encima de la lenta y el índice direccional positivo (+DI) es mayor que el negativo (-DI). Se abre una posición corta cuando la media móvil rápida está por debajo de la lenta y -DI es mayor que +DI.

La estrategia utiliza protecciones de stop-loss y take-profit basadas en porcentajes. Las velas para los cálculos se toman del marco temporal especificado.

Parámetros

  • Fast MA Length – longitud de la media móvil rápida.
  • Slow MA Length – longitud de la media móvil lenta.
  • ADX Length – período para el cálculo del Índice de Dirección Promedio.
  • Stop Loss % – tamaño del stop-loss en porcentaje del precio de entrada.
  • Take Profit % – tamaño del take-profit en porcentaje del precio de entrada.
  • Candle Type – marco temporal de las velas utilizadas para el procesamiento.
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>
/// Strategy based on two moving averages and directional movement index.
/// Long when fast MA is above slow MA and +DI exceeds -DI.
/// Short when fast MA is below slow MA and -DI exceeds +DI.
/// </summary>
public class X2MaDigitDm361Strategy : Strategy
{
	private readonly StrategyParam<int> _fastMaLength;
	private readonly StrategyParam<int> _slowMaLength;
	private readonly StrategyParam<int> _adxLength;
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<decimal> _stopLossPercent;
	private readonly StrategyParam<decimal> _takeProfitPercent;

	/// <summary>
	/// Fast moving average length.
	/// </summary>
	public int FastMaLength
	{
		get => _fastMaLength.Value;
		set => _fastMaLength.Value = value;
	}

	/// <summary>
	/// Slow moving average length.
	/// </summary>
	public int SlowMaLength
	{
		get => _slowMaLength.Value;
		set => _slowMaLength.Value = value;
	}

	/// <summary>
	/// ADX calculation length.
	/// </summary>
	public int AdxLength
	{
		get => _adxLength.Value;
		set => _adxLength.Value = value;
	}

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

	/// <summary>
	/// Stop loss percent.
	/// </summary>
	public decimal StopLossPercent
	{
		get => _stopLossPercent.Value;
		set => _stopLossPercent.Value = value;
	}

	/// <summary>
	/// Take profit percent.
	/// </summary>
	public decimal TakeProfitPercent
	{
		get => _takeProfitPercent.Value;
		set => _takeProfitPercent.Value = value;
	}

	/// <summary>
	/// Initializes a new instance of <see cref="X2MaDigitDm361Strategy"/>.
	/// </summary>
	public X2MaDigitDm361Strategy()
	{
		_fastMaLength = Param(nameof(FastMaLength), 5)
			.SetGreaterThanZero()
			.SetDisplay("Fast MA Length", "Length of fast moving average", "Moving Averages")
			
			.SetOptimize(5, 25, 1);

		_slowMaLength = Param(nameof(SlowMaLength), 12)
			.SetGreaterThanZero()
			.SetDisplay("Slow MA Length", "Length of slow moving average", "Moving Averages")
			
			.SetOptimize(3, 15, 1);

		_adxLength = Param(nameof(AdxLength), 14)
			.SetGreaterThanZero()
			.SetDisplay("ADX Length", "Length of Average Directional Index", "Directional Movement")
			
			.SetOptimize(7, 28, 7);

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candles timeframe", "General");

		_stopLossPercent = Param(nameof(StopLossPercent), 1m)
			.SetGreaterThanZero()
			.SetDisplay("Stop Loss %", "Stop loss percent", "Risk Management")
			
			.SetOptimize(0.5m, 3m, 0.5m);

		_takeProfitPercent = Param(nameof(TakeProfitPercent), 2m)
			.SetGreaterThanZero()
			.SetDisplay("Take Profit %", "Take profit percent", "Risk Management")
			
			.SetOptimize(1m, 5m, 0.5m);
	}

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

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

		var fastMa = new SMA { Length = FastMaLength };
		var slowMa = new SMA { Length = SlowMaLength };
		var adx = new AverageDirectionalIndex { Length = AdxLength };

		var subscription = SubscribeCandles(CandleType);

		subscription
			.BindEx(fastMa, slowMa, adx, ProcessCandle)
			.Start();

		StartProtection(
			takeProfit: new Unit(TakeProfitPercent, UnitTypes.Percent),
			stopLoss: new Unit(StopLossPercent, UnitTypes.Percent),
			isStopTrailing: false,
			useMarketOrders: true);

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

	private void ProcessCandle(ICandleMessage candle, IIndicatorValue fastMaValue, IIndicatorValue slowMaValue, IIndicatorValue adxValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		if (!fastMaValue.IsFinal || !slowMaValue.IsFinal || !adxValue.IsFinal)
			return;

		var fast = fastMaValue.ToDecimal();
		var slow = slowMaValue.ToDecimal();
		var adx = (AverageDirectionalIndexValue)adxValue;
		var plusDi = adx.Dx.Plus;
		var minusDi = adx.Dx.Minus;

		if (plusDi is null || minusDi is null)
			return;

		if (fast > slow && plusDi > minusDi && Position <= 0)
		{
			BuyMarket();
		}
		else if (fast < slow && minusDi > plusDi && Position >= 0)
		{
			SellMarket();
		}
	}
}