Ver en GitHub

Estrategia Martini Martingale

Esta estrategia implementa una cuadrícula de martingala con cobertura. Comienza colocando órdenes stop en ambos lados del precio actual y duplica el tamaño de la posición en la dirección opuesta siempre que el mercado se mueva contra la exposición actual en un paso especificado. Todas las operaciones se cierran una vez que el beneficio acumulado supera el objetivo.

Detalles

  • Criterios de entrada:
    • Colocar un buy stop por encima y un sell stop por debajo del mercado a distancia Step.
    • Cuando se activa una orden, cancelar el stop opuesto.
  • Gestión de la posición:
    • Rastrear el precio de la última orden ejecutada.
    • Si el precio se mueve contra la posición abierta en Step * orderCount, enviar una orden de mercado en la dirección opuesta con el doble del volumen anterior.
  • Criterios de salida:
    • Cerrar todas las posiciones cuando el beneficio no realizado alcanza ProfitClose.
  • Largo/Corto: Ambos.
  • Stops: Usa órdenes stop para entradas iniciales; sin stop-loss.
  • Indicadores: Ninguno.
  • Filtros: Ninguno.

Parámetros

  • Step – paso de precio en unidades absolutas.
  • ProfitClose – umbral de beneficio para cerrar todas las operaciones.
  • InitialVolume – volumen inicial para la primera orden.
  • CandleType – serie de velas usada para actualizaciones de precio.
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>
/// Mean reversion strategy inspired by martingale.
/// Enters on RSI extremes, exits when price returns to SMA.
/// </summary>
public class MartiniMartingaleStrategy : Strategy
{
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<int> _smaPeriod;
	private readonly StrategyParam<DataType> _candleType;

	public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
	public int SmaPeriod { get => _smaPeriod.Value; set => _smaPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public MartiniMartingaleStrategy()
	{
		_rsiPeriod = Param(nameof(RsiPeriod), 7)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI period", "Indicators");
		_smaPeriod = Param(nameof(SmaPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("SMA Period", "SMA for mean reversion target", "Indicators");
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles", "General");
	}

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

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

		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		var sma = new SimpleMovingAverage { Length = SmaPeriod };

		SubscribeCandles(CandleType).Bind(rsi, sma, ProcessCandle).Start();
	}

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

		var close = candle.ClosePrice;

		// RSI oversold => buy
		if (rsi < 30 && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
		}
		// RSI overbought => sell
		else if (rsi > 70 && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
		}
		// Exit long at SMA
		else if (Position > 0 && close >= sma && rsi > 50)
		{
			SellMarket();
		}
		// Exit short at SMA
		else if (Position < 0 && close <= sma && rsi < 50)
		{
			BuyMarket();
		}
	}
}