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(); }
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import DoubleExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class exp_skyscraper_fix_duplex_strategy(Strategy):
def __init__(self):
super(exp_skyscraper_fix_duplex_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._fast_period = self.Param("FastPeriod", 9) \
.SetDisplay("Fast DEMA", "Fast DEMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 25) \
.SetDisplay("Slow DEMA", "Slow DEMA period", "Indicators")
self._prev_fast = None
self._prev_slow = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def FastPeriod(self):
return self._fast_period.Value
@property
def SlowPeriod(self):
return self._slow_period.Value
def OnReseted(self):
super(exp_skyscraper_fix_duplex_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(exp_skyscraper_fix_duplex_strategy, self).OnStarted2(time)
self._prev_fast = None
self._prev_slow = None
fast = DoubleExponentialMovingAverage()
fast.Length = self.FastPeriod
slow = DoubleExponentialMovingAverage()
slow.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast, slow, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def _on_process(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fv = float(fast_value)
sv = float(slow_value)
if self._prev_fast is None or self._prev_slow is None:
self._prev_fast = fv
self._prev_slow = sv
return
prev_above = self._prev_fast > self._prev_slow
curr_above = fv > sv
self._prev_fast = fv
self._prev_slow = sv
if not prev_above and curr_above and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif prev_above and not curr_above and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
def CreateClone(self):
return exp_skyscraper_fix_duplex_strategy()