Ver en GitHub

Estrategia de Plan X

Descripción general

La estrategia Plan X es un sistema de breakout convertido desde el asesor experto original de MetaTrader 5. Evalúa el cierre de cada vela finalizada contra una vela de referencia desplazada por un número configurable de barras. Cuando el cierre más reciente supera el cierre de referencia por una altura de canal especificada, la estrategia abre una posición en la dirección del breakout. La reversión de señal opcional permite operar breakouts en la dirección opuesta.

La implementación usa la API de alto nivel de StockSharp. Soporta stop-loss ajustable, take-profit, lógica de trailing stop y un filtro de sesión de trading.

Cómo funciona

  1. Procesamiento de velas – la estrategia se suscribe al tipo de vela configurado y procesa solo las velas finalizadas. Se mantiene un breve historial de cierres para comparar el último valor con una barra de referencia desplazada.
  2. Detección de breakout – si el último cierre es mayor que el cierre de referencia por más que la altura del canal, se produce una señal long. Si es menor por la misma cantidad, se genera una señal short. Cuando el indicador de reversión está habilitado, las señales se invierten.
  3. Ejecución de órdenes – la estrategia usa órdenes de mercado. Al revertir desde una posición opuesta, el volumen de la orden incluye automáticamente el valor absoluto de la posición actual para aplanar y re-entrar en una sola operación.
  4. Gestión de riesgos – los niveles de stop-loss y take-profit se establecen inmediatamente después de la entrada. Un trailing stop puede reemplazar al stop original cuando el precio se mueve favorablemente por más que la distancia de trailing más el paso de trailing.
  5. Filtro de tiempo – el trading puede limitarse a una hora de inicio y fin. Si la hora de inicio es mayor que la hora de fin, la ventana se trata como cruzando la medianoche.

Parámetros

Parámetro Descripción
Stop Loss (pips) Distancia del stop de protección en pips, convertida a unidades de precio basadas en el paso de precio del instrumento.
Take Profit (pips) Distancia del objetivo en pips.
Trailing Stop (pips) Distancia entre el precio y el trailing stop. Establecer en cero para deshabilitar el trailing.
Trailing Step (pips) Beneficio adicional requerido antes de que el trailing stop avance. Debe ser positivo cuando el trailing está habilitado.
Channel Height (pips) Umbral de breakout expresado en pips.
Candle Shift Número de barras entre el último cierre y la vela de referencia.
Use Time Control Habilita o deshabilita el filtro de sesión de trading.
Start Hour Primera hora (0–23) cuando se permite el trading.
End Hour Última hora (0–23) cuando se permite el trading.
Reverse Signals Invierte la dirección del breakout.
Order Volume Tamaño de la orden de mercado expresado en lotes/contratos.
Candle Type Tipo de datos de velas utilizado para el análisis.

Lógica de señales

  • Entrada long – último cierre ≥ cierre de referencia + altura del canal, reversión deshabilitada.
  • Entrada short – último cierre ≤ cierre de referencia − altura del canal, reversión deshabilitada.
  • Cuando la reversión está habilitada, la lógica intercambia las condiciones long y short.

Lógica de trailing stop

  • El trailing stop se activa cuando el movimiento favorable supera Trailing Stop + Trailing Step en términos de precio.
  • Para posiciones long el stop se mueve a high − Trailing Stop si el nuevo valor es mayor que el stop existente.
  • Para posiciones short el stop se mueve a low + Trailing Stop si el nuevo valor es menor que el stop existente.

Notas adicionales

  • El cálculo del tamaño de pip emula la versión MQL multiplicando el paso de precio por 10 para instrumentos de 3 o 5 decimales.
  • El trading fuera de la sesión permitida omite nuevas entradas pero sigue gestionando posiciones abiertas.
  • La estrategia llama a StartProtection() una vez durante el inicio para habilitar los servicios de protección de cartera integrados.
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;

public class PlanXStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private ExponentialMovingAverage _fast;
	private ExponentialMovingAverage _slow;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }

	public PlanXStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
		_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

	protected override void OnReseted()
	{
		base.OnReseted();
		_fast = null; _slow = null;
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_fast = new ExponentialMovingAverage { Length = FastPeriod };
		_slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, ProcessCandle);
		subscription.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
		if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}

		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }

		_prevFast = fastValue; _prevSlow = slowValue;
	}
}