Ver en GitHub

Estrategia MaDelta

La estrategia MaDelta mide la diferencia entre una media móvil rápida y una lenta. La diferencia se escala por un multiplicador y se eleva a la tercera potencia, produciendo un valor oscilante px. Dos umbrales dinámicos separados por Delta (en pips) rastrean el máximo y mínimo reciente de este valor. Cuando px rompe por encima del umbral superior, la estrategia cambia a sesgo largo; cuando px cae por debajo del umbral inferior, cambia a sesgo corto. Las posiciones existentes opuestas al nuevo sesgo se cierran y se abre una nueva operación en la dirección de la señal.

El enfoque captura eficazmente las ráfagas de momentum cuando la distancia entre las dos medias móviles se expande rápidamente. Elevar al cubo la diferencia exagera los movimientos fuertes mientras filtra las pequeñas fluctuaciones. El parámetro Delta define cuánto debe recorrer px antes de que se reconozca un giro, evitando las señales falsas en mercados planos.

Detalles

  • Criterios de entrada:
    • Largo: px > hi establece trade = 1 y abre un largo cuando no existe posición.
    • Corto: px < lo establece trade = -1 y abre un corto cuando está plano.
  • Lógica de reversión:
    • Señal larga mientras está corto cierra el corto con una compra de mercado antes de entrar largo.
    • Señal corta mientras está largo cierra el largo con una venta de mercado antes de entrar corto.
  • Indicadores:
    • Media móvil rápida (SMA) con período FastMaPeriod.
    • Media móvil lenta (EMA) con período SlowMaPeriod.
    • Oscilador: px = ((Multiplier * 0.1) * (FastMA - SlowMA))^3.
  • Parámetros:
    • Delta – tamaño del canal alto/bajo en pips.
    • Multiplier – escala la diferencia de MA antes de elevar al cubo.
    • FastMaPeriod – longitud de la SMA rápida.
    • SlowMaPeriod – longitud de la EMA lenta.
    • Volume – volumen de la orden en las entradas.
    • CandleType – marco temporal de las velas procesadas.
  • Otras notas:
    • Solo funciona con velas completadas.
    • Sin stop-loss o take-profit explícitos; las posiciones se revierten con señales opuestas.
    • Usa la API de alto nivel con vinculación de indicadores y gráficos automáticos.
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>
/// Moving Average Delta strategy. Trades when the cubed amplified difference
/// between fast and slow moving averages crosses dynamic thresholds.
/// </summary>
public class MaDeltaStrategy : Strategy
{
	private readonly StrategyParam<int> _delta;
	private readonly StrategyParam<int> _multiplier;
	private readonly StrategyParam<int> _fastMaPeriod;
	private readonly StrategyParam<int> _slowMaPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _hi;
	private decimal _lo;
	private bool _isInit;
	private int _trade;
	private decimal _deltaStep;
	private decimal _multiplierFactor;

	public int Delta { get => _delta.Value; set => _delta.Value = value; }
	public int Multiplier { get => _multiplier.Value; set => _multiplier.Value = value; }
	public int FastMaPeriod { get => _fastMaPeriod.Value; set => _fastMaPeriod.Value = value; }
	public int SlowMaPeriod { get => _slowMaPeriod.Value; set => _slowMaPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public MaDeltaStrategy()
	{
		_delta = Param(nameof(Delta), 195)
			.SetDisplay("Delta (pips)", "Hi-Lo threshold in pips", "General")
			.SetOptimize(50, 300, 5);

		_multiplier = Param(nameof(Multiplier), 392)
			.SetDisplay("Multiplier", "Amplifier for MA difference", "General")
			.SetOptimize(100, 500, 10);

		_fastMaPeriod = Param(nameof(FastMaPeriod), 26)
			.SetDisplay("Fast MA Period", "Period for fast moving average", "Indicators")
			.SetOptimize(5, 50, 1);

		_slowMaPeriod = Param(nameof(SlowMaPeriod), 51)
			.SetDisplay("Slow MA Period", "Period for slow moving average", "Indicators")
			.SetOptimize(10, 100, 1);

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles", "General");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_hi = 0m;
		_lo = 0m;
		_isInit = false;
		_trade = 0;
		_deltaStep = 0m;
		_multiplierFactor = 0m;
	}

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

		_hi = 0m;
		_lo = 0m;
		_isInit = false;
		_trade = 0;

		_deltaStep = Delta * 0.00001m;
		_multiplierFactor = Multiplier * 0.1m;

		var fastMa = new ExponentialMovingAverage { Length = FastMaPeriod };
		var slowMa = new ExponentialMovingAverage { Length = SlowMaPeriod };

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

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var diff = _multiplierFactor * (fastMaValue - slowMaValue);
		var px = (decimal)Math.Pow((double)diff, 3);

		if (!_isInit)
		{
			_hi = 0m;
			_lo = 0m;
			_trade = 0;
			_isInit = true;
		}

		if (px > _hi)
		{
			_hi = px;
			_lo = _hi - _deltaStep;
			_trade = 1;
		}
		else if (px < _lo)
		{
			_lo = px;
			_hi = _lo + _deltaStep;
			_trade = -1;
		}

		if (_trade == 1 && Position <= 0)
			BuyMarket();
		else if (_trade == -1 && Position >= 0)
			SellMarket();
	}
}