Ver en GitHub

Estrategia de Cruce de Triple Media Móvil

Esta estrategia opera basándose en la relación entre tres medias móviles: rápida, media y lenta. Es una conversión del experto MQL X3MA_EA_V2_0.

Lógica de trading

  • Entrada
    • Cuando EnableEntryMediumSlowCross es verdadero, se abre una posición larga cuando la media móvil media cruza por encima de la lenta. El cruce inverso activa una entrada corta.
    • Cuando la opción es falsa, la estrategia espera que la media rápida cruce la media mientras ambas permanezcan del mismo lado de la lenta. Las posiciones largas requieren fast > medium > slow y las cortas requieren fast < medium < slow.
  • Salida
    • Cuando EnableExitFastSlowCross es verdadero, las posiciones abiertas se cierran cuando las medias rápida y lenta se cruzan en sentido contrario.

Todas las señales se evalúan en velas terminadas.

Parámetros

Nombre Descripción
FastMaLength Período de la media móvil rápida.
MediumMaLength Período de la media móvil media.
SlowMaLength Período de la media móvil lenta.
EnableEntryMediumSlowCross Permitir entradas en el cruce medio/lento.
EnableExitFastSlowCross Cerrar posiciones en el cruce rápido/lento.
CandleType Marco temporal de las velas.

Notas

La estrategia utiliza la API de alto nivel con SubscribeCandles y Bind. Los valores de los indicadores se acceden a través del callback ProcessCandle sin usar GetValue. La lógica de protección se activa con StartProtection() en OnStarted.

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>
/// Triple EMA crossover strategy.
/// </summary>
public class X3MaEaV20Strategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _midPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevFast;
	private decimal _prevMid;
	private bool _hasPrev;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int MidPeriod { get => _midPeriod.Value; set => _midPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public X3MaEaV20Strategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 10)
			.SetGreaterThanZero()
			.SetDisplay("Fast MA", "Fast EMA period", "MA");
		_midPeriod = Param(nameof(MidPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("Mid MA", "Mid EMA period", "MA");
		_slowPeriod = Param(nameof(SlowPeriod), 50)
			.SetGreaterThanZero()
			.SetDisplay("Slow MA", "Slow EMA period", "MA");
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candle type", "General");
	}

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

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = 0;
		_prevMid = 0;
		_hasPrev = false;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var mid = new ExponentialMovingAverage { Length = MidPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };

		SubscribeCandles(CandleType)
			.Bind(fast, mid, slow, ProcessCandle)
			.Start();
	}

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

		if (!_hasPrev)
		{
			_prevFast = fastVal;
			_prevMid = midVal;
			_hasPrev = true;
			return;
		}

		var crossUp = _prevFast <= _prevMid && fastVal > midVal;
		var crossDown = _prevFast >= _prevMid && fastVal < midVal;

		if (crossUp && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
		}
		else if (crossDown && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
		}

		_prevFast = fastVal;
		_prevMid = midVal;
	}
}