Ver en GitHub

Estrategia Avalanche AV

Avalanche AV es una estrategia de martingala aleatorizada que alterna entre entradas largas y cortas con igual probabilidad. Las operaciones se abren solo después de un número configurable de velas terminadas, y cada posición hereda niveles fijos de stop-loss y take-profit definidos en pips. Cuando una operación cierra con pérdida, el tamaño de posición se multiplica por el coeficiente de martingala para perseguir la recuperación; las operaciones rentables restablecen el tamaño al volumen inicial una vez que el saldo de la cuenta registra un nuevo máximo de capital. La estrategia también aplica una caída flotante máxima como porcentaje del saldo de la cuenta y cerrará cualquier posición que supere este umbral.

La versión original MQL abría operaciones en ticks. El port de StockSharp mantiene el mismo comportamiento probabilístico pero trabaja en actualizaciones de velas, haciéndola adecuada tanto para backtesting como para trading en vivo con datos de barras.

Reglas de trading

  • Intervalo de decisión: esperar el número especificado de velas terminadas antes de evaluar una nueva señal. Si una posición aún está abierta, el intervalo continúa contando pero no se toma ninguna nueva operación.
  • Dirección de entrada: generar un número aleatorio; valores por encima de 16384 desencadenan una entrada larga, de lo contrario una entrada corta. Las posiciones se abren solo cuando no hay operación activa.
  • Tamaño de orden: empezar con InitialVolume. Después de cada operación perdedora, el próximo tamaño de orden se convierte en PreviousVolume * MartingaleMultiplier (normalizado al paso de volumen del instrumento). Las operaciones ganadoras restablecen el tamaño a InitialVolume una vez que el saldo realizado registra un nuevo máximo; de lo contrario la expansión de martingala continúa.
  • Stops y objetivos: el stop-loss y take-profit se calculan en pips desde el precio de entrada. Un pip es igual al paso de precio del instrumento.
  • Caída flotante: mientras una posición está activa, la estrategia monitorea el PnL no realizado. Si la pérdida excede MaxDrawdownPercent del saldo realizado de la cuenta (saldo inicial + PnL realizado), la posición se cierra inmediatamente.

Parámetros

Parámetro Predeterminado Descripción
InitialVolume 0.1 Volumen inicial de operación.
StopLossPips 15 Distancia de stop en pips (0 deshabilita el stop).
TakeProfitPips 30 Distancia de take profit en pips (0 deshabilita el objetivo).
MaxDrawdownPercent 75 Pérdida flotante máxima tolerada como porcentaje del saldo.
MartingaleMultiplier 1.6 Multiplicador de volumen aplicado después de una pérdida.
DecisionInterval 9 Número de velas terminadas entre nuevas decisiones de operación.
CandleType Marco temporal de 1 minuto Tipo de vela que impulsa la estrategia.

Notas

  • El volumen se normaliza automáticamente a los límites VolumeStep, MinVolume y MaxVolume del instrumento. Si la normalización falla, el tamaño se restablece al volumen inicial.
  • Los niveles de stop-loss y take-profit se basan en el PriceStep del instrumento como un pip; verifique el paso para símbolos exóticos.
  • La protección de caída requiere que tanto PriceStep como StepPrice estén definidos; de lo contrario, la verificación de seguridad se omite.
  • Dado que la estrategia depende de la aleatoriedad, los resultados varían entre ejecuciones incluso con datos de mercado idénticos a menos que la semilla aleatoria se controle externamente.
using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Avalanche strategy using channel breakout with Highest/Lowest.
/// </summary>
public class AvalancheAvStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _period;

	private decimal? _prevHigh;
	private decimal? _prevLow;

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

	public int Period
	{
		get => _period.Value;
		set => _period.Value = value;
	}

	public AvalancheAvStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe", "General");

		_period = Param(nameof(Period), 14)
			.SetGreaterThanZero()
			.SetDisplay("Period", "Channel period", "Indicators");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevHigh = null;
		_prevLow = null;
	}

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

		_prevHigh = null;
		_prevLow = null;

		var highest = new Highest { Length = Period };
		var lowest = new Lowest { Length = Period };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(highest, lowest, ProcessCandle)
			.Start();

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
		{
			_prevHigh = high;
			_prevLow = low;
			return;
		}

		var close = candle.ClosePrice;

		if (_prevHigh == null || _prevLow == null)
		{
			_prevHigh = high;
			_prevLow = low;
			return;
		}

		if (close > _prevHigh.Value && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		else if (close < _prevLow.Value && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevHigh = high;
		_prevLow = low;
	}
}