Ver en GitHub

Estrategia de cuadrícula Turbo Scaler

Descripción general

La estrategia Turbo Scaler Grid es una implementación StockSharp de alto nivel del asesor experto MQL5 "Turbo Scaler Grid Pending". La estrategia se centra en gestionar las rejillas de parada pendientes en torno a niveles de precios predefinidos, proteger dinámicamente las posiciones abiertas con lógica de equilibrio y seguimiento, y supervisar el capital de la cuenta para cerrar posiciones cuando se alcanzan los umbrales de ganancias o pérdidas.

La lógica funciona en múltiples períodos de tiempo simultáneamente:

  • Un período de tiempo de activación configurable observa las señales de proximidad de precios que activan la cuadrícula pendiente.
  • Las velas adicionales de 30 minutos, 2 horas y diarias brindan confirmación para activadores condicionales opcionales.
  • Los datos de Level1 proporcionan los últimos valores de oferta/demanda utilizados para posicionar órdenes pendientes y gestionar los trailingstops.

Reglas de trading

  1. Cuadrícula pendiente
    • Las órdenes de compra y venta se colocan a partir de precios ancla configurables (BuyStopEntry y SellStopEntry).
    • Los pedidos están espaciados por PendingStepPoints y limitados por PendingQuantity.
    • El precio de activación verifica las velas recientes en el período de activación para confirmar que el precio se acercó al nivel de anclaje con suficiente impulso.
    • El activador de condición valida filtros adicionales de múltiples períodos de tiempo (rangos de bloques diarios, dirección de velas H2 y M30 y nivel de rango medio) antes de colocar órdenes pendientes.
  2. Protección de posición
    • El stop loss inicial se calcula a partir de StopLossPoints (o anulaciones de precio fijo).
    • Cuando el precio avanza BreakevenTriggerPoints, el stop se mueve al precio de entrada más BreakevenOffsetPoints (para posiciones largas) o menos la compensación (para posiciones cortas).
    • Un trailing stop se activa solo después de alcanzar el punto de equilibrio y se actualiza una vez que el precio supera el stop anterior en TrailMultiplier * TrailPoints.
  3. Supervisión de patrimonio
    • La estrategia monitorea el PnL flotante y fuerza la liquidación de posiciones si la reducción excede MaxFloatLoss (escalado al volumen de orden seleccionado).
    • Un activador de ganancias flotantes bloquea las ganancias al colocar una línea de capital interna en EquityBreakeven y seguirla en EquityTrail una vez que las ganancias superan EquityTrigger.

Parámetros

Nombre Descripción
StopLossPoints Distancia inicial de stop-loss en puntos.
BreakevenTriggerPoints Puntos necesarios para activar el movimiento de equilibrio.
BreakevenOffsetPoints Compensación agregada al precio de entrada cuando el stop se mueve al punto de equilibrio.
TrailPoints Distancia utilizada para seguir después del punto de equilibrio.
TrailMultiplier Multiplicador aplicado antes de que se establezca un nuevo trailing stop.
BuyStopLossPrice / SellStopLossPrice Precios de parada fijos opcionales para posiciones largas/cortas.
BuyStopEntry / SellStopEntry Precios base para las parrillas de parada pendientes.
OrderVolume Volumen por orden pendiente.
PendingQuantity Número máximo de órdenes pendientes activas.
PendingStepPoints Distancia entre órdenes pendientes consecutivas.
TriggerCandleType Serie de velas utilizada para la lógica de activación del precio.
PendingPriceTrigger Habilita el disparador de proximidad de precio.
PendingConditionTrigger Habilita el activador de confirmación de múltiples períodos de tiempo.
OrderBuyBlockStart / OrderBuyBlockEnd Bloque bajo diario utilizado para validar configuraciones largas.
OrderSellBlockStart / OrderSellBlockEnd Bloque alto diario utilizado para validar configuraciones cortas.
MaxFloatLoss Pérdida flotante máxima permitida (escalada por volumen).
EquityBreakeven Nivel de capital mantenido después de que se activa el activador de ganancias.
EquityTrigger Se requiere beneficio flotante para crear el bloqueo de capital.
EquityTrail Distancia de seguimiento aplicada al bloqueo de equidad.

Notas

  • El volumen del pedido se escala para que coincida con el comportamiento original de EA (los lotes 0.01 se tratan como el paso base).
  • Todos los comentarios dentro del código están escritos en inglés, mientras que este documento proporciona una descripción detallada para una rápida incorporación.
  • La estrategia utiliza solo API StockSharp de alto nivel (SubscribeCandles, Bind, BuyStop, SellStop, SellMarket, BuyMarket) de acuerdo con los requisitos del proyecto.
using System;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Simplified from "Turbo Scaler Grid" MetaTrader expert.
/// Uses EMA crossover with RSI confirmation for scalping entries.
/// </summary>
public class TurboScalerGridStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<decimal> _rsiUpper;
	private readonly StrategyParam<decimal> _rsiLower;

	private ExponentialMovingAverage _fastEma;
	private ExponentialMovingAverage _slowEma;
	private RelativeStrengthIndex _rsi;
	private decimal? _prevFast;
	private decimal? _prevSlow;

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

	public int FastPeriod
	{
		get => _fastPeriod.Value;
		set => _fastPeriod.Value = value;
	}

	public int SlowPeriod
	{
		get => _slowPeriod.Value;
		set => _slowPeriod.Value = value;
	}

	public int RsiPeriod
	{
		get => _rsiPeriod.Value;
		set => _rsiPeriod.Value = value;
	}

	public decimal RsiUpper
	{
		get => _rsiUpper.Value;
		set => _rsiUpper.Value = value;
	}

	public decimal RsiLower
	{
		get => _rsiLower.Value;
		set => _rsiLower.Value = value;
	}

	public TurboScalerGridStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for scalping", "General");

		_fastPeriod = Param(nameof(FastPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 34)
			.SetGreaterThanZero()
			.SetDisplay("Slow SMA", "Slow SMA period (computed manually)", "Indicators");

		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI period for confirmation", "Indicators");

		_rsiUpper = Param(nameof(RsiUpper), 60m)
			.SetDisplay("RSI Upper", "RSI level for buy confirmation", "Signals");

		_rsiLower = Param(nameof(RsiLower), 40m)
			.SetDisplay("RSI Lower", "RSI level for sell confirmation", "Signals");
	}

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

		_prevFast = null;
		_prevSlow = null;

		_fastEma = new ExponentialMovingAverage { Length = FastPeriod };
		_slowEma = new ExponentialMovingAverage { Length = SlowPeriod };
		_rsi = new RelativeStrengthIndex { Length = RsiPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(_fastEma, _slowEma, _rsi, ProcessCandle)
			.Start();

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

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue, decimal rsiValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!_fastEma.IsFormed || !_slowEma.IsFormed || !_rsi.IsFormed)
		{
			_prevFast = fastValue;
			_prevSlow = slowValue;
			return;
		}

		if (_prevFast is null || _prevSlow is null)
		{
			_prevFast = fastValue;
			_prevSlow = slowValue;
			return;
		}

		var volume = Volume;
		if (volume <= 0)
			volume = 1;

		var crossUp = _prevFast.Value <= _prevSlow.Value && fastValue > slowValue;
		var crossDown = _prevFast.Value >= _prevSlow.Value && fastValue < slowValue;

		if (crossUp && rsiValue > RsiUpper)
		{
			if (Position <= 0)
				BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
		}
		else if (crossDown && rsiValue < RsiLower)
		{
			if (Position >= 0)
				SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
		}

		_prevFast = fastValue;
		_prevSlow = slowValue;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		_fastEma = null;
		_slowEma = null;
		_rsi = null;
		_prevFast = null;
		_prevSlow = null;

		base.OnReseted();
	}
}