Ver en GitHub

Estrategia experta en martingala

Descripción general

Martingail Expert es una estrategia de martingala que sigue tendencias y se basa en el oscilador Stochastic para cronometrar nuevas secuencias de operaciones. Una vez que el indicador genera una dirección, la estrategia inicia una escalera de órdenes de mercado y gestiona la exposición utilizando un objetivo de ganancias dinámico y un esquema de tamaño de posición geométrico.

Lógica de trading

  • Calcule un oscilador Stochastic en la serie de velas configurada. Los valores finales más recientes de %K y %D se almacenan en caché para la toma de decisiones.
  • Inicie una nueva secuencia larga cuando %K (previous) > %D (previous) y %D (previous) estén por encima del umbral BuyLevel.
  • Inicie una nueva secuencia corta cuando %K (previous) < %D (previous) y %D (previous) estén por debajo del umbral SellLevel.
  • Después de ingresar una secuencia, cada movimiento de precio favorable igual a ProfitFactor × openOrders pips agrega una nueva posición con el volumen base.
  • Cada movimiento adverso de StepPoints pips multiplica el último volumen llenado por Multiplier y envía una orden promedio en la misma dirección.

Reglas de salida

  • Cierre toda la posición tan pronto como el último precio de ejecución alcance un objetivo de beneficio dinámico de ProfitFactor × openOrders pips en la dirección favorable.
  • Restablezca el estado de martingala cada vez que el tamaño de la posición agregada vuelva a cero.

Gestión del riesgo

La progresión de martingala aumenta la exposición rápidamente cuando el precio se mueve en contra de la posición. Ajuste Multiplier, StepPoints y ProfitFactor cuidadosamente para que coincidan con el tamaño de la cuenta y la volatilidad del instrumento.

Parámetros

Nombre Descripción
Volume Volumen de orden de mercado base utilizado para la primera operación y cada complemento favorable.
Multiplier Factor aplicado al último volumen ejecutado al promediar durante movimientos adversos.
StepPoints Distancia en puntos que desencadena un orden de promediación de martingala.
ProfitFactor Objetivo de beneficio por orden abierta expresado en puntos. La distancia real es ProfitFactor × number_of_orders.
KPeriod Longitud retrospectiva para la línea %K.
DPeriod Longitud de suavizado para la línea %D.
Slowing Suavizado adicional aplicado a %K antes de comparar con %D.
BuyLevel Valor mínimo de %D requerido para permitir una nueva secuencia larga.
SellLevel Valor máximo de %D requerido para permitir una nueva secuencia corta.
CandleType Serie de velas utilizadas para los cálculos (predeterminado: período de 5 minutos).

Notas

  • Funciona mejor en pares de divisas líquidos donde el tamaño del pip y el paso de volumen permiten un escalado granular.
  • Requiere margen suficiente para soportar varios pasos de martingala.
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>
/// Martingale strategy driven by stochastic oscillator crossovers.
/// Buy when K crosses above D, sell when K crosses below D.
/// Doubles down on adverse moves with martingale averaging.
/// </summary>
public class MartingailExpertSequenceStrategy : Strategy
{
	private readonly StrategyParam<int> _kPeriod;
	private readonly StrategyParam<int> _dPeriod;
	private readonly StrategyParam<decimal> _stepPoints;
	private readonly StrategyParam<decimal> _takeProfitPoints;
	private readonly StrategyParam<DataType> _candleType;

	private decimal? _prevK;
	private decimal? _prevD;
	private decimal _entryPrice;

	public int KPeriod { get => _kPeriod.Value; set => _kPeriod.Value = value; }
	public int DPeriod { get => _dPeriod.Value; set => _dPeriod.Value = value; }
	public decimal StepPoints { get => _stepPoints.Value; set => _stepPoints.Value = value; }
	public decimal TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public MartingailExpertSequenceStrategy()
	{
		_kPeriod = Param(nameof(KPeriod), 14)
			.SetDisplay("K Period", "Stochastic K period", "Indicators");

		_dPeriod = Param(nameof(DPeriod), 3)
			.SetDisplay("D Period", "Stochastic D period", "Indicators");

		_stepPoints = Param(nameof(StepPoints), 500m)
			.SetDisplay("Step Points", "Distance for martingale averaging", "Risk");

		_takeProfitPoints = Param(nameof(TakeProfitPoints), 200m)
			.SetDisplay("Take Profit", "Take profit in price steps", "Risk");

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

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_prevK = null;
		_prevD = null;
		_entryPrice = 0m;
	}

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

		_prevK = null;
		_prevD = null;

		var stoch = new StochasticOscillator
		{
			K = { Length = KPeriod },
			D = { Length = DPeriod }
		};

		var subscription = SubscribeCandles(CandleType);
		subscription
			.BindEx(stoch, ProcessCandle)
			.Start();
	}

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

		if (!stochValue.IsFinal)
			return;

		if (stochValue is not StochasticOscillatorValue stoch)
			return;

		if (stoch.K is not decimal k || stoch.D is not decimal d)
			return;

		var step = Security?.PriceStep ?? 1m;
		if (step <= 0) step = 1m;

		// Check take profit
		if (Position > 0 && candle.ClosePrice >= _entryPrice + TakeProfitPoints * step)
		{
			SellMarket();
			_prevK = k;
			_prevD = d;
			return;
		}
		else if (Position < 0 && candle.ClosePrice <= _entryPrice - TakeProfitPoints * step)
		{
			BuyMarket();
			_prevK = k;
			_prevD = d;
			return;
		}

		if (_prevK is not decimal prevK || _prevD is not decimal prevD)
		{
			_prevK = k;
			_prevD = d;
			return;
		}

		// Stochastic crossover signals
		var bullCross = prevK <= prevD && k > d;
		var bearCross = prevK >= prevD && k < d;

		if (Position == 0)
		{
			if (bullCross)
			{
				BuyMarket();
				_entryPrice = candle.ClosePrice;
			}
			else if (bearCross)
			{
				SellMarket();
				_entryPrice = candle.ClosePrice;
			}
		}
		else if (Position > 0 && bearCross)
		{
			SellMarket(); // Close long
			SellMarket(); // Open short
			_entryPrice = candle.ClosePrice;
		}
		else if (Position < 0 && bullCross)
		{
			BuyMarket(); // Close short
			BuyMarket(); // Open long
			_entryPrice = candle.ClosePrice;
		}

		_prevK = k;
		_prevD = d;
	}
}