Die Forex Sky Strategy ist eine direkte Portierung des MetaTrader-Expertenberaters Forex_SKY.mq4. Es handelt mit MACD Momentumschwankungen und beschränkt sich strikt auf eine einzige Position pro Handelstag. Die StockSharp-Implementierung behält die ursprünglichen MACD-Schwellenwerte und die Sicherheitsprüfung bei, die mehr als eine Bestellung pro Kerze verhindert.
Die Strategie abonniert den durch CandleType definierten Zeitrahmen (standardmäßig 15-Minuten-Kerzen) und wertet den klassischen MACD (26.12.9) am Ende jeder abgeschlossenen Kerze aus.
Handelslogik
Langer Einstieg – Platzieren Sie einen Marktkauf, wenn:
Die aktuelle MACD-Hauptzeile liegt über Null;
Es überschreitet auch +0.00009, um die Dynamik zu bestätigen;
Mindestens einer der vorherigen drei MACD-Werte war kleiner oder gleich Null (was einen Aufwärtstrend aus dem negativen Bereich darstellt).
Short-Einstieg – Platzieren Sie einen Marktverkauf, wenn eine der folgenden Bedingungen zutrifft:
Die Hauptlinie MACD liegt unter Null, fällt unter -0.0004, mindestens einer der letzten drei Messwerte war nicht negativ und der Wert vor vier Balken betrug mindestens +0.001.
Oder der Wert von vor vier Balken war ≥ +0.003, was einen Short-Trade sofort autorisiert, genau wie im ursprünglichen MetaTrader-Code.
Positionsverwaltung – Der Algorithmus öffnet nie mehr als eine Order pro Kerze (Time0 Guard) und handelt nie mehr als einmal pro Kalendertag (CheckTodaysOrders Guard). Schutzausstiegsbefehle werden vom Helfer StockSharp StartProtection verarbeitet, sodass alle Stopps und Ziele mit dem aktuellen Volumen synchronisiert bleiben.
Über die Schutzanordnungen hinaus gibt es keine autonome Flatting-Logik – es wird erwartet, dass Positionen durch Take-Profit, Stop-Loss oder manuelle Intervention geschlossen werden, was das Verhalten des ursprünglichen Expertenberaters widerspiegelt.
Parameter
Name
Standard
Beschreibung
FastPeriod
12
Schnelle EMA-Länge des MACD-Indikators.
SlowPeriod
26
Langsame EMA-Länge des MACD-Indikators.
SignalPeriod
9
Signallänge EMA des Indikators MACD.
TakeProfitPoints
100
Abstand zur Take-Profit-Order, ausgedrückt in Instrumentenpunkten. Durch Multiplikation mit der Wertpapierpreisstufe in einen Preis umgerechnet.
StopLossPoints
3000
Abstand zur Stop-Loss-Order in Instrumentenpunkten.
TradeVolume
0,1
Basis-Market-Order-Größe (Lots).
CandleType
15-minütiger Zeitrahmen
Zeitrahmen, der in die Berechnungen und Handelsentscheidungen von MACD einfließt.
Berechnung des Instrumentenpunkts
TakeProfitPoints und StopLossPoints werden genau wie die Version MetaTrader angegeben – Point in MQL4 entspricht Security.PriceStep in StockSharp. Für ein fünfstelliges Forex-Paar (PriceStep = 0.00001) lauten die Standardeinstellungen wie folgt:
StartProtection installiert automatisch die Take-Profit- und Stop-Loss-Orders, nachdem ein Eintrag ausgeführt wurde. Sie sind mit der Handelsrichtung verknüpft und verwenden bei Auslösung Marktaufträge, die dem MetaTrader-Verhalten entsprechen. Setzen Sie einen der Parameter auf 0, um die entsprechende Schutzanordnung zu deaktivieren.
Migrationshinweise
Der Verlaufspuffer MACD speichert die letzten vier abgeschlossenen Werte in Klassenfeldern, sodass keine Indikatoraufrufe mit verschobenen Indizes erforderlich sind.
Die tägliche Handelsdrosselung und die Beschränkung auf einen einzelnen Handel pro Balken replizieren CheckTodaysOrders() und Time0 aus der Originalquelle.
Alle Kommentare wurden in Englisch umgeschrieben und die Logik basiert auf StockSharp High-Level-Bindungen (Bind) für die Indikatorverarbeitung.
Nutzungstipps
Passen Sie CandleType an den Diagrammzeitraum an, den Sie emulieren möchten. Das ursprüngliche Skript übernimmt den Zeitrahmen des Diagramms automatisch.
Da pro Tag nur ein Handel zulässig ist, wählen Sie Märkte mit bedeutenden Intraday-Schwankungen aus oder erwägen Sie eine Anhebung der MACD-Schwellenwerte, wenn Sie Instrumente mit höherer Volatilität verwenden.
Überwachen Sie die Uhr/Zeitzone der Plattform, um sicherzustellen, dass die Tagesgrenze mit Ihrer Handelssitzung übereinstimmt, da der Limitzähler basierend auf dem Öffnungsdatum der Kerze zurückgesetzt wird.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Forex Sky: MACD zero-line cross with EMA trend filter.
/// </summary>
public class ForexSkyStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastLength;
private readonly StrategyParam<int> _slowLength;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<int> _atrLength;
private decimal _prevMacd;
private decimal _entryPrice;
public ForexSkyStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_fastLength = Param(nameof(FastLength), 12)
.SetDisplay("Fast EMA", "MACD fast period.", "Indicators");
_slowLength = Param(nameof(SlowLength), 26)
.SetDisplay("Slow EMA", "MACD slow period.", "Indicators");
_emaLength = Param(nameof(EmaLength), 50)
.SetDisplay("EMA Length", "Trend filter.", "Indicators");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Length", "ATR period.", "Indicators");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastLength
{
get => _fastLength.Value;
set => _fastLength.Value = value;
}
public int SlowLength
{
get => _slowLength.Value;
set => _slowLength.Value = value;
}
public int EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
public int AtrLength
{
get => _atrLength.Value;
set => _atrLength.Value = value;
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevMacd = 0;
_entryPrice = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevMacd = 0;
_entryPrice = 0;
var fastEma = new ExponentialMovingAverage { Length = FastLength };
var slowEma = new ExponentialMovingAverage { Length = SlowLength };
var ema = new ExponentialMovingAverage { Length = EmaLength };
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastEma, slowEma, ema, atr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal, decimal emaVal, decimal atrVal)
{
if (candle.State != CandleStates.Finished)
return;
if (atrVal <= 0)
return;
var macd = fastVal - slowVal;
var close = candle.ClosePrice;
if (_prevMacd == 0)
{
_prevMacd = macd;
return;
}
if (Position > 0)
{
if (close >= _entryPrice + atrVal * 3m || close <= _entryPrice - atrVal * 2m || (macd < 0 && _prevMacd >= 0))
{
SellMarket();
_entryPrice = 0;
}
}
else if (Position < 0)
{
if (close <= _entryPrice - atrVal * 3m || close >= _entryPrice + atrVal * 2m || (macd > 0 && _prevMacd <= 0))
{
BuyMarket();
_entryPrice = 0;
}
}
if (Position == 0)
{
if (macd > 0 && _prevMacd <= 0 && close > emaVal)
{
_entryPrice = close;
BuyMarket();
}
else if (macd < 0 && _prevMacd >= 0 && close < emaVal)
{
_entryPrice = close;
SellMarket();
}
}
_prevMacd = macd;
}
}
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 ExponentialMovingAverage, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class forex_sky_strategy(Strategy):
"""
Forex Sky: MACD zero-line cross with EMA trend filter and ATR-based exits.
"""
def __init__(self):
super(forex_sky_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._fast_length = self.Param("FastLength", 12) \
.SetDisplay("Fast EMA", "MACD fast period", "Indicators")
self._slow_length = self.Param("SlowLength", 26) \
.SetDisplay("Slow EMA", "MACD slow period", "Indicators")
self._ema_length = self.Param("EmaLength", 50) \
.SetDisplay("EMA Length", "Trend filter", "Indicators")
self._atr_length = self.Param("AtrLength", 14) \
.SetDisplay("ATR Length", "ATR period", "Indicators")
self._prev_macd = 0.0
self._entry_price = 0.0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(forex_sky_strategy, self).OnReseted()
self._prev_macd = 0.0
self._entry_price = 0.0
def OnStarted2(self, time):
super(forex_sky_strategy, self).OnStarted2(time)
self._prev_macd = 0.0
self._entry_price = 0.0
fast_ema = ExponentialMovingAverage()
fast_ema.Length = self._fast_length.Value
slow_ema = ExponentialMovingAverage()
slow_ema.Length = self._slow_length.Value
ema = ExponentialMovingAverage()
ema.Length = self._ema_length.Value
atr = AverageTrueRange()
atr.Length = self._atr_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast_ema, slow_ema, ema, atr, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def _process_candle(self, candle, fast_val, slow_val, ema_val, atr_val):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_val)
slow_val = float(slow_val)
ema_val = float(ema_val)
atr_val = float(atr_val)
if atr_val <= 0:
return
macd = fast_val - slow_val
close = float(candle.ClosePrice)
if self._prev_macd == 0:
self._prev_macd = macd
return
if self.Position > 0:
if (close >= self._entry_price + atr_val * 3.0 or
close <= self._entry_price - atr_val * 2.0 or
(macd < 0 and self._prev_macd >= 0)):
self.SellMarket()
self._entry_price = 0.0
elif self.Position < 0:
if (close <= self._entry_price - atr_val * 3.0 or
close >= self._entry_price + atr_val * 2.0 or
(macd > 0 and self._prev_macd <= 0)):
self.BuyMarket()
self._entry_price = 0.0
if self.Position == 0:
if macd > 0 and self._prev_macd <= 0 and close > ema_val:
self._entry_price = close
self.BuyMarket()
elif macd < 0 and self._prev_macd >= 0 and close < ema_val:
self._entry_price = close
self.SellMarket()
self._prev_macd = macd
def CreateClone(self):
return forex_sky_strategy()