Ver en GitHub

Stochastic Martingale Estrategia de cuadrícula

Descripción general

Esta estrategia es un StockSharp puerto del MetaTrader asesor experto rmkp_9yj4qp1gn8fucubyqnvb. Combina un filtro de entrada de oscilador estocástico con una cuadrícula de promedio estilo martingala. El algoritmo monitorea las velas terminadas, espera a que la línea de señal estocástica salga de las zonas predefinidas de sobrecompra o sobreventa y luego abre una posición en la dirección de la reversión. Cuando el precio se mueve en contra de la operación, agrega órdenes promedio con volumen duplicado a distancias de pips fijas. Cada tramo tiene su propio objetivo de obtención de beneficios y gestión de trailing stop, lo que permite que las posiciones se amplíen de forma independiente una vez que el precio se recupere.

Lógica de trading

  • Detección de señal:
    • Las líneas %K y %D de un oscilador estocástico configurable se evalúan en velas completadas.
    • Una configuración larga se activa cuando, en la vela anterior, %K estaba por encima de %D y %D estaba por debajo del umbral ZoneBuy.
    • Una configuración corta se activa cuando, en la vela anterior, %K estaba por debajo de %D y %D estaba por encima del umbral ZoneSell.
  • Ejecución inicial:
    • Con una señal válida y mientras la cuenta está plana, la estrategia envía una orden de mercado con el BaseVolume.
    • El precio de entrada se almacena para gestionar los trailingstops y las órdenes promediadas posteriores.
  • Martingale promedio:
    • Mientras una posición permanece abierta, el algoritmo detecta movimientos adversos del precio de StepPips con respecto a la última orden ejecutada.
    • Cada nueva orden promedio duplica el volumen del tramo anterior (progresión de martingala clásica) y solo se coloca si el número total de tramos abiertos es inferior a MaxOrders y el comercio permanece permitido.
  • Gestión de salidas:
    • Cada tramo define un nivel de toma de ganancias individual ubicado a TakeProfitPips de su precio de entrada.
    • Los trailingstops se activan una vez que las ganancias no realizadas alcanzan TrailingStopPips; el ancla posterior se aprieta cada vez que las ganancias se extienden más.
    • Si el precio retrocede hasta el nivel final o alcanza el nivel de toma de ganancias, el tramo correspondiente se cierra mientras el resto del grupo permanece activo.
    • Cuando todos los tramos salen, la estrategia restablece su estado interno y espera la siguiente señal estocástica.

Gestión del riesgo

  • La expansión de martingala está limitada por MaxOrders y los límites de volumen de seguridad.
  • Los volúmenes se normalizan según el VolumeStep del instrumento y se respetan las restricciones de volumen mínimo/máximo.
  • Los trailingstops ayudan a proteger las ganancias flotantes de reversiones totales.

Parámetros

Nombre Descripción Predeterminado
CandleType Suscripción de vela utilizada para los cálculos de indicadores. plazo de 15 minutos
BaseVolume Volumen de pedido inicial realizado en la primera señal. 0.1
TakeProfitPips Distancia de pip entre cada precio de entrada y su objetivo de obtención de beneficios. 50
TrailingStopPips Distancia de pip utilizada para la activación y el seguimiento del trailing stop por tramo. 20
MaxOrders Número máximo de tramos promediadores simultáneos (incluida la entrada inicial). 7
StepPips Movimiento adverso mínimo, en pips, requerido antes de agregar otra orden promedio. 7
KPeriod Longitud retrospectiva de la línea estocástica %K. 5
DPeriod Longitud de suavizado para la línea estocástica %D. 3
Slowing Suavizado adicional aplicado al cálculo de %K. 3
ZoneBuy Límite superior que permite configuraciones largas cuando %K está por encima de %D. 30
ZoneSell Límite inferior que permite configuraciones breves cuando %K está por debajo de %D. 70

Notas

  • La estrategia utiliza StockSharp API de alto nivel con suscripciones de velas y vinculaciones de indicadores, manteniendo la implementación cerca de la lógica MetaTrader original mientras aprovecha las herramientas de visualización y riesgo de StockSharp.
  • Debido a que las operaciones promedio duplican el volumen, asegúrese de que el volumen máximo permitido del instrumento pueda acomodar la escalera de martingala.
  • Al igual que con cualquier sistema martingala, se recomienda encarecidamente una gestión adecuada del capital y restricciones de riesgo adicionales antes de implementarlo en una cuenta real.
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>
/// Stochastic based martingale averaging strategy translated from the MetaTrader expert "rmkp_9yj4qp1gn8fucubyqnvb".
/// Adds averaging orders when price moves against the latest entry and manages each leg with trailing stops and individual take profits.
/// </summary>
public class StochasticMartingaleGridStrategy : Strategy
{
	private sealed class Entry
	{
		public decimal Price { get; set; }
		public decimal Volume { get; set; }
		public decimal? TrailingPrice { get; set; }
	}

	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<decimal> _baseVolume;
	private readonly StrategyParam<decimal> _takeProfitPips;
	private readonly StrategyParam<decimal> _trailingStopPips;
	private readonly StrategyParam<int> _maxOrders;
	private readonly StrategyParam<decimal> _stepPips;
	private readonly StrategyParam<int> _kPeriod;
	private readonly StrategyParam<int> _dPeriod;
	private readonly StrategyParam<int> _slowing;
	private readonly StrategyParam<decimal> _zoneBuy;
	private readonly StrategyParam<decimal> _zoneSell;

	private List<Entry> _entries;

	private StochasticOscillator _stochastic;
	private decimal? _previousMain;
	private decimal? _previousSignal;
	private decimal _pipSize;

	/// <summary>
	/// Initializes a new instance of the <see cref="StochasticMartingaleGridStrategy"/> class.
	/// </summary>
	public StochasticMartingaleGridStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe used to evaluate stochastic values", "General");

		_baseVolume = Param(nameof(BaseVolume), 0.1m)
			.SetGreaterThanZero()
			.SetDisplay("Base Volume", "Initial order volume", "Trading")
			;

		_takeProfitPips = Param(nameof(TakeProfitPips), 50m)
			.SetGreaterThanZero()
			.SetDisplay("Take Profit (pips)", "Distance to the take profit target for each entry", "Risk")
			;

		_trailingStopPips = Param(nameof(TrailingStopPips), 20m)
			.SetGreaterThanZero()
			.SetDisplay("Trailing Stop (pips)", "Trailing stop distance applied per entry", "Risk")
			;

		_maxOrders = Param(nameof(MaxOrders), 2)
			.SetGreaterThanZero()
			.SetDisplay("Max Orders", "Maximum number of simultaneous averaging entries", "Martingale");

		_stepPips = Param(nameof(StepPips), 7m)
			.SetGreaterThanZero()
			.SetDisplay("Step (pips)", "Adverse move required before adding a new entry", "Martingale")
			;

		_kPeriod = Param(nameof(KPeriod), 5)
			.SetGreaterThanZero()
			.SetDisplay("%K Period", "Stochastic %K lookback length", "Indicators")
			;

		_dPeriod = Param(nameof(DPeriod), 3)
			.SetGreaterThanZero()
			.SetDisplay("%D Period", "Stochastic %D smoothing length", "Indicators")
			;

		_slowing = Param(nameof(Slowing), 3)
			.SetGreaterThanZero()
			.SetDisplay("Slowing", "Additional smoothing applied to %K", "Indicators")
			;

		_zoneBuy = Param(nameof(ZoneBuy), 50m)
			.SetDisplay("Buy Zone", "Upper limit that allows long setups when %K is above %D", "Indicators")
			;

		_zoneSell = Param(nameof(ZoneSell), 50m)
			.SetDisplay("Sell Zone", "Lower limit that allows short setups when %K is below %D", "Indicators")
			;
	}

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

	/// <summary>
	/// Initial trade volume.
	/// </summary>
	public decimal BaseVolume
	{
		get => _baseVolume.Value;
		set => _baseVolume.Value = value;
	}

	/// <summary>
	/// Take profit distance in pips applied to every entry.
	/// </summary>
	public decimal TakeProfitPips
	{
		get => _takeProfitPips.Value;
		set => _takeProfitPips.Value = value;
	}

	/// <summary>
	/// Trailing stop distance in pips applied to every entry.
	/// </summary>
	public decimal TrailingStopPips
	{
		get => _trailingStopPips.Value;
		set => _trailingStopPips.Value = value;
	}

	/// <summary>
	/// Maximum number of averaging entries.
	/// </summary>
	public int MaxOrders
	{
		get => _maxOrders.Value;
		set => _maxOrders.Value = value;
	}

	/// <summary>
	/// Step in pips required to trigger a new averaging entry.
	/// </summary>
	public decimal StepPips
	{
		get => _stepPips.Value;
		set => _stepPips.Value = value;
	}

	/// <summary>
	/// Stochastic %K period.
	/// </summary>
	public int KPeriod
	{
		get => _kPeriod.Value;
		set => _kPeriod.Value = value;
	}

	/// <summary>
	/// Stochastic %D period.
	/// </summary>
	public int DPeriod
	{
		get => _dPeriod.Value;
		set => _dPeriod.Value = value;
	}

	/// <summary>
	/// Stochastic slowing period.
	/// </summary>
	public int Slowing
	{
		get => _slowing.Value;
		set => _slowing.Value = value;
	}

	/// <summary>
	/// Maximum signal level that allows long entries.
	/// </summary>
	public decimal ZoneBuy
	{
		get => _zoneBuy.Value;
		set => _zoneBuy.Value = value;
	}

	/// <summary>
	/// Minimum signal level that allows short entries.
	/// </summary>
	public decimal ZoneSell
	{
		get => _zoneSell.Value;
		set => _zoneSell.Value = value;
	}

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

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

		_entries = null;
		_stochastic = null;
		_previousMain = null;
		_previousSignal = null;
		_pipSize = 0m;
	}

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

		_entries = new List<Entry>();
		_pipSize = Security?.PriceStep ?? 1m;

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

		Indicators.Add(_stochastic);

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

		StartProtection(
			takeProfit: new Unit(2, UnitTypes.Percent),
			stopLoss: new Unit(1, UnitTypes.Percent));

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

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

		var stochResult = _stochastic.Process(candle);
		if (!_stochastic.IsFormed)
			return;

		if (stochResult is not StochasticOscillatorValue stoch)
			return;

		if (stoch.K is not decimal currentMain || stoch.D is not decimal currentSignal)
			return;

		if (Position != 0)
		{
			_previousMain = currentMain;
			_previousSignal = currentSignal;
			return;
		}

		if (_previousMain is decimal prevMain && _previousSignal is decimal prevSignal)
		{
			// Buy: K crosses above D in oversold zone
			if (prevMain <= prevSignal && currentMain > currentSignal && currentSignal < ZoneBuy)
				BuyMarket();
			// Sell: K crosses below D in overbought zone
			else if (prevMain >= prevSignal && currentMain < currentSignal && currentSignal > ZoneSell)
				SellMarket();
		}

		_previousMain = currentMain;
		_previousSignal = currentSignal;
	}
}