Auf GitHub ansehen

Einfache OzFx-Strategie

Überblick

  • 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

  1. 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.
  2. Abonnieren Sie den stochastischen Oszillator (%K-Länge = StochasticLength, Glättung 3/3) und lesen Sie die Hauptlinie bei Kerzenschluss ab.
  3. 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).
  4. Kurzaufbau spiegelt die Regeln in die entgegengesetzte Richtung.
  5. 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.
  6. 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;
	}
}