Exp Skyscraper Fix Duplex ist ein Port des MQL5-Expert Advisors Exp_Skyscraper_Fix_Duplex. Die Strategie führt den Skyscraper Fix-Kanal auf der Long- und Short-Seite unabhängig aus, sodass jede Seite ihren eigenen Zeitrahmen, ATR-Fenster und Sensitivität verwenden kann. Long- und Short-Trades können daher auf unterschiedliche Marktregimes reagieren, während sie dieselbe Ausführungslogik innerhalb von StockSharp teilen.
Indikatorlogik
Der benutzerdefinierte Skyscraper Fix-Indikator reproduziert das ursprüngliche Skript:
Ein ATR mit einer festen internen Periode von 15 wird für jede abgeschlossene Kerze berechnet.
Die höchsten und niedrigsten ATR-Werte über das konfigurierbare Length-Fenster bestimmen den adaptiven Preisschritt.
Abhängig vom ausgewählten Mode werden entweder der Hoch/Tief der Kerze oder der Schlusskurs verwendet, um obere und untere Kanalniveaus im doppelten Schrittabstand zu projizieren.
Der jüngste Ausbruch über das obere Niveau oder unter das untere Niveau kippt den internen Trend und fixiert das Trailing-Niveau so, dass es sich nie gegen den aktuellen Bias bewegt.
Das Kreuzen der entgegengesetzten Trail-Linie erzeugt diskrete Kauf- oder Verkaufsauslöser (spiegelt die Pfeil-Buffer des Indikators in MQL wider).
Der Indikator exponiert das obere Trailing-Niveau, das untere Trailing-Niveau, Einstiegsauslöser und eine Mittellinie, die bei Bedarf geplottet werden kann.
Handelsregeln
Long- und Short-Operationen werden separat für jede abgeschlossene Kerze des jeweiligen Abonnements ausgewertet:
Long-Einstieg – ausgelöst, wenn der Long-Indikator ein frisches Kaufniveau meldet. Bestehende Short-Exponierung wird zuerst gedeckt, dann wird eine neue Long-Marktorder mit dem konfigurierten Volumen eingereicht.
Long-Ausstieg – ausgelöst, wenn der Long-Indikator die entgegengesetzte Trailing-Linie meldet. Jede bestehende Long-Position wird mit einem Marktverkauf geschlossen.
Short-Einstieg – ausgelöst, wenn der Short-Indikator ein frisches Verkaufsniveau meldet. Bestehende Long-Exponierung wird zuerst geschlossen, dann wird eine neue Short-Marktorder gesendet.
Short-Ausstieg – ausgelöst, wenn der Short-Indikator die entgegengesetzte Trailing-Linie meldet. Jede aktive Short-Position wird mit einem Marktkauf gedeckt.
Signale können mit den SignalBar-Parametern verzögert werden, damit die Strategie auf der zuletzt geschlossenen Kerze (0) oder auf weiter zurückliegenden Kerzen (1 ahmt die Standard-MQL-Einrichtung nach) reagiert.
Parameter
TradeVolume – Ordergröße für Markteinstiege.
EnableLongEntries / EnableLongExits – Umschalter für Long-seitigen Handel.
LongCandleType – Kerzenserie für den Long-Indikator.
LongLength, LongKv, LongPercentage, LongMode, LongSignalBar – Skyscraper Fix-Einstellungen für die Long-Seite.
EnableShortEntries / EnableShortExits – Umschalter für Short-seitigen Handel.
ShortCandleType – Kerzenserie für den Short-Indikator.
ShortLength, ShortKv, ShortPercentage, ShortMode, ShortSignalBar – Skyscraper Fix-Einstellungen für die Short-Seite.
Nutzungshinweise
Die Strategie setzt die globale Volume-Eigenschaft aus TradeVolume, sodass Standard-BuyMarket()- und SellMarket()-Aufrufe diese Größe automatisch verwenden.
Beide Indikatorinstanzen lesen den PriceStep des Instruments. Wenn dieser null ist, wartet der Indikator still, bis ein gültiger Preisschritt verfügbar ist.
StartProtection() wird beim Start aufgerufen, damit Schutzmaßnahmen auf Plattformebene aktiv sind, bevor die erste Order eingereicht wird.
Es gibt keine separate Python-Implementierung; das PY-Verzeichnis wird wie angefordert absichtlich weggelassen.
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()