Ver en GitHub

Estrategia Exp Skyscraper Fix Duplex

Descripción general

Exp Skyscraper Fix Duplex es un port del asesor experto MQL5 Exp_Skyscraper_Fix_Duplex. La estrategia ejecuta el canal Skyscraper Fix en los lados largo y corto de forma independiente, permitiendo que cada lado use su propio marco temporal, ventana ATR y sensibilidad. Las operaciones largas y cortas pueden por lo tanto reaccionar a diferentes regímenes de mercado mientras comparten la misma lógica de ejecución dentro de StockSharp.

Lógica del indicador

El indicador personalizado Skyscraper Fix reproduce el script original:

  • Se calcula un ATR con un período interno fijo de 15 para cada vela finalizada.
  • Los valores más altos y más bajos de ATR a través de la ventana Length configurable determinan el paso de precio adaptativo.
  • Dependiendo del Mode seleccionado, se usa el High/Low del bar o el precio de cierre para proyectar niveles de canal superior e inferior a el doble de la distancia del paso.
  • El breakout más reciente por encima del nivel superior o por debajo del nivel inferior voltea la tendencia interna y fija el nivel de trailing para que nunca se mueva contra el sesgo actual.
  • El cruce de la línea de trailing opuesta produce disparadores discretos de compra o venta (reflejando los buffers de flechas del indicador en MQL).

El indicador expone el nivel superior de trailing, el nivel inferior de trailing, disparadores de entrada y una línea media que se puede representar si se desea.

Reglas de trading

Las operaciones largas y cortas se evalúan por separado para cada vela finalizada de la suscripción respectiva:

  • Entrada larga – activada cuando el indicador largo reporta un nuevo nivel de compra. Cualquier exposición corta existente se cubre primero, luego se envía una nueva orden larga de mercado con el volumen configurado.
  • Salida larga – activada cuando el indicador largo reporta la línea de trailing opuesta. Cualquier posición larga existente se cierra con una venta de mercado.
  • Entrada corta – activada cuando el indicador corto reporta un nuevo nivel de venta. La exposición larga existente se cierra primero, luego se envía una nueva orden corta de mercado.
  • Salida corta – activada cuando el indicador corto reporta la línea de trailing opuesta. Cualquier posición corta activa se cubre con una compra de mercado.

Las señales pueden retrasarse con los parámetros SignalBar para que la estrategia actúe sobre la vela cerrada más recientemente (0) o sobre velas más atrás en la historia (1 imita la configuración MQL predeterminada).

Parámetros

  • TradeVolume – tamaño de la orden para entradas de mercado.
  • EnableLongEntries / EnableLongExits – interruptores para el trading del lado largo.
  • LongCandleType – serie de velas usada para el indicador largo.
  • LongLength, LongKv, LongPercentage, LongMode, LongSignalBar – configuraciones de Skyscraper Fix para el lado largo.
  • EnableShortEntries / EnableShortExits – interruptores para el trading del lado corto.
  • ShortCandleType – serie de velas usada para el indicador corto.
  • ShortLength, ShortKv, ShortPercentage, ShortMode, ShortSignalBar – configuraciones de Skyscraper Fix para el lado corto.

Notas de uso

  • La estrategia establece la propiedad global Volume desde TradeVolume, por lo que las llamadas estándar BuyMarket() y SellMarket() usan ese tamaño automáticamente.
  • Ambas instancias del indicador leen el PriceStep del instrumento. Si es cero, el indicador espera silenciosamente hasta que un paso de precio válido esté disponible.
  • StartProtection() se invoca al inicio para que las protecciones a nivel de plataforma estén activas antes de que se envíe la primera orden.
  • No hay una implementación de Python separada; el directorio PY se omite intencionalmente según lo solicitado.
using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

public class ExpSkyscraperFixDuplexStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private decimal? _prevFast, _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 ExpSkyscraperFixDuplexStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
		_fastPeriod = Param(nameof(FastPeriod), 9).SetGreaterThanZero().SetDisplay("Fast DEMA", "Fast DEMA period", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 25).SetGreaterThanZero().SetDisplay("Slow DEMA", "Slow DEMA period", "Indicators");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = null;
		_prevSlow = null;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevFast = null; _prevSlow = null;
		var fast = new DoubleExponentialMovingAverage { Length = FastPeriod };
		var slow = new DoubleExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, ProcessCandle).Start();
		var area = CreateChartArea();
		if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, fast); DrawIndicator(area, slow); DrawOwnTrades(area); }
	}

	private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!IsFormedAndOnlineAndAllowTrading()) { _prevFast = fast; _prevSlow = slow; return; }
		if (_prevFast == null || _prevSlow == null) { _prevFast = fast; _prevSlow = slow; return; }
		var prevAbove = _prevFast.Value > _prevSlow.Value;
		var currAbove = fast > slow;
		_prevFast = fast; _prevSlow = slow;
		if (!prevAbove && currAbove && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
		else if (prevAbove && !currAbove && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
	}
}