Konvertierung des MetaTrader 4 Expert Advisors OzFx (Ordner MQL/7994) in den StockSharp High-Level API.
Verwendet den Accelerator/Decelerator-Oszillator (AC) zusammen mit der %K-Linie des stochastischen Oszillators, um Impulsumkehrungen um die Nulllinie zu erkennen.
Reproduziert das Verhalten des Experten, fünf Marktaufträge mit gestaffelten Take-Profits und Breakeven-Schutz zu stapeln, nachdem das erste Ziel erreicht wurde.
Handelslogik
Bauen Sie den Awesome Oscillator (5/34) und subtrahieren Sie dessen 5-Perioden SMA, um den Accelerator Oscillator-Wert der vorherigen und aktuellen abgeschlossenen Kerze zu erhalten.
Abonnieren Sie den stochastischen Oszillator (%K-Länge = StochasticLength, Glättung 3/3) und lesen Sie die Hauptlinie bei Kerzenschluss ab.
Lange Einrichtung erfordert:
%K über dem konfigurierten Mittelwert (Standard 50).
Aktueller AC-Wert positiv und höher als der vorherige.
Vorheriger AC-Wert immer noch unter Null (Impuls überschreitet die Basislinie).
Kurzaufbau spiegelt die Regeln in die entgegengesetzte Richtung.
Wenn ein Signal auf einem neuen Balken erscheint, eröffnet die Strategie fünf gleiche Marktaufträge:
Die Schichten 1–4 erhalten Take-Profits im Abstand von TakeProfitPips-Vielfachen.
Schicht 5 hat kein Gewinnziel und bleibt der Entwicklung hinterher.
Tritt das gegenteilige Setup auf, während ein Stapel offen ist, werden die verbleibenden Aufträge zum Marktwert geschlossen, sodass die Strategie vor neuen Einträgen unverändert bleibt.
Positionsmanagement
Jede Ebene hat die gleiche Stop-Loss-Distanz, die durch StopLossPips definiert ist.
Nachdem der erste Take-Profit ausgeführt wurde, verschärfen die verbleibenden Orders ihre Stops auf den Breakeven-Preis (Einstiegspreis), was der ursprünglichen „Modok“-Logik entspricht.
Schutzausgänge werden ausgeführt, wenn die Extremwerte der Kerze die gespeicherten Stopp- oder Zielniveaus durchbrechen; Brokerseitige Pending Orders werden nicht genutzt.
Die Strategie lässt jeweils nur eine Richtung zu und wartet, bis alle Aufträge geschlossen sind, bevor die Eingabeblock-Flags zurückgesetzt werden.
Parameter
Name
Beschreibung
Standard
OrderVolume
Losgröße für jede der fünf Marktaufträge.
0.1
StopLossPips
Abstand zwischen Einstieg und Stop-Loss, ausgedrückt in Pips.
100
TakeProfitPips
Inkrement zwischen aufeinanderfolgenden Take-Profit-Ebenen (Ebenen 1–4).
50
StochasticLevel
Auf den stochastischen %K-Wert angewendeter Schwellenwert.
50
StochasticLength
Lookback-Zeitraum der stochastischen %K-Berechnung.
5
CandleType
Von der Strategie verwendete Quellkerzenserie (standardmäßig 4-Stunden-Kerzen).
4h time-frame
Implementierungshinweise
Signale werden nur bei fertigen Kerzen ausgewertet, um im Einklang mit dem MT4-Experten zu bleiben, der an neuen Balken arbeitet.
Die Pip-Konvertierung passt sich automatisch an 3/5-stellige Forex-Symbole an, indem der minimale Preisschritt bei Bedarf mit 10 multipliziert wird.
Gestaffelte Ein- und Ausstiege werden im Speicher über geschichtete Objekte abgewickelt, sodass die Strategie Teile der Position ordnungsgemäß schließen kann.
Alle Kommentare im C#-Code sind gemäß den Repository-Richtlinien in Englisch verfasst.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class OzFxSimpleStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _cooldownCandles;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
private int _cooldownRemaining;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int CooldownCandles { get => _cooldownCandles.Value; set => _cooldownCandles.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public OzFxSimpleStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 20).SetDisplay("Fast WMA", "Fast WMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 80).SetDisplay("Slow WMA", "Slow WMA period", "Indicators");
_cooldownCandles = Param(nameof(CooldownCandles), 100).SetDisplay("Cooldown", "Candles between signals", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = default;
_prevSlow = default;
_hasPrev = default;
_cooldownRemaining = default;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = 0;
_prevSlow = 0;
_hasPrev = false;
_cooldownRemaining = 0;
var fast = new WeightedMovingAverage { Length = FastPeriod };
var slow = new WeightedMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(fast, slow, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished) return;
if (!_hasPrev) { _prevFast = fast; _prevSlow = slow; _hasPrev = true; return; }
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
_prevFast = fast;
_prevSlow = slow;
return;
}
if (_prevFast <= _prevSlow && fast > slow && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
_cooldownRemaining = CooldownCandles;
}
else if (_prevFast >= _prevSlow && fast < slow && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
_cooldownRemaining = CooldownCandles;
}
_prevFast = fast;
_prevSlow = slow;
}
}
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 WeightedMovingAverage
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
from indicator_extensions import *
class oz_fx_simple_strategy(Strategy):
def __init__(self):
super(oz_fx_simple_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 20).SetDisplay("Fast WMA", "Fast WMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 80).SetDisplay("Slow WMA", "Slow WMA period", "Indicators")
self._cooldown_candles = self.Param("CooldownCandles", 100).SetDisplay("Cooldown", "Candles between signals", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Candle timeframe", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(oz_fx_simple_strategy, self).OnReseted()
self._prev_fast = 0
self._prev_slow = 0
self._has_prev = False
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(oz_fx_simple_strategy, self).OnStarted2(time)
self._prev_fast = 0
self._prev_slow = 0
self._has_prev = False
self._cooldown_remaining = 0
fast = WeightedMovingAverage()
fast.Length = self._fast_period.Value
slow = WeightedMovingAverage()
slow.Length = self._slow_period.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(fast, slow, self.OnProcess).Start()
def OnProcess(self, candle, fast, slow):
if candle.State != CandleStates.Finished:
return
if not self._has_prev:
self._prev_fast = fast
self._prev_slow = slow
self._has_prev = True
return
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
self._prev_fast = fast
self._prev_slow = slow
return
if self._prev_fast <= self._prev_slow and fast > slow and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._cooldown_remaining = self._cooldown_candles.Value
elif self._prev_fast >= self._prev_slow and fast < slow and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._cooldown_remaining = self._cooldown_candles.Value
self._prev_fast = fast
self._prev_slow = slow
def CreateClone(self):
return oz_fx_simple_strategy()