Auf GitHub ansehen

Stochastic Momentum Filter-Strategie

Übersicht

Die Stochastic Momentum Filter-Strategie ist ein StockSharp-Port des MetaTrader Expert Advisors Stochastic.mq4 (Ordner MQL/23473). Der originale Roboter kombiniert zwei stochastische Oszillatoren, linear gewichtete Moving Averages (LWMA), einen Momentum-Abweichungsfilter und einen höheren Zeitrahmen-MACD-Trendcheck. Diese C#-Version re­kreiert dieselben Bausteine auf der StockSharp High-Level-API und behält den mehrschichtigen Bestätigungsworkflow:

  1. Trendfilter – ein schneller LWMA muss über (oder unter) einem langsamen LWMA liegen, bevor Long-Trades (oder Short-Trades) erlaubt werden.
  2. Oszillatorbestätigung – sowohl ein schneller Stochastik (5/2/2) als auch ein langsamer Stochastik (21/4/10) müssen in überverkauften/überkauften Zonen übereinstimmen.
  3. Momentum-Abweichung – mindestens eine der drei neuesten Momentum-Ablesungen muss um mehr als einen konfigurierbaren Schwellenwert von der 100-Basislinie abweichen und entspricht der Verwendung der MT4-iMomentum-Funktion durch den Experten.
  4. Höherer Zeitrahmen-MACD – die MACD-Hauptlinie auf einem konfigurierbaren höheren Zeitrahmen muss für Longs über der Signallinie bleiben (und für Shorts darunter). Der standardmäßige 30-Tage-Zeitrahmen approximiert den ursprünglichen monatlichen Filter.
  5. RisikoLogik – Stop-Loss, Take-Profit und optionaler Trailing werden durch StartProtection gehandhabt und spiegeln die Schutzparameter des EA wider. Positions-Flips schließen entgegengesetzte Exposition automatisch, bevor die neue Nettoposition aufgebaut wird.

Die Strategie abonniert zwei Kerzenstreams: den Handelszeitrahmen und den höheren Zeitrahmen, der den MACD-Filter speist. Alle Berechnungen werden mit StockSharp-Indikatoren durchgeführt und durch die High-Level-Bind-Helfer verarbeitet.

Parameter

Name Standard Beschreibung
StochasticBuyLevel 30 Überverkauftes Niveau, das beide stochastischen Oszillatoren für Long-Setups unterschreiten müssen.
StochasticSellLevel 80 Überkauftes Niveau, das beide stochastischen Oszillatoren für Short-Setups erreichen müssen.
FastMaPeriod 6 Länge des schnellen LWMA-Trendfilters.
SlowMaPeriod 85 Länge des langsamen LWMA-Trendfilters.
FastStochasticPeriod 5 %K-Periode des schnellen stochastischen Oszillators.
FastStochasticSignal 2 %D-Glättungsperiode des schnellen Stochastik.
FastStochasticSmoothing 2 Zusätzliche Glättung des schnellen Stochastik (entspricht MT4-„slowing").
SlowStochasticPeriod 21 %K-Periode des langsamen stochastischen Oszillators.
SlowStochasticSignal 4 %D-Glättungsperiode des langsamen Stochastik.
SlowStochasticSmoothing 10 Zusätzliche Glättung des langsamen Stochastik.
MomentumPeriod 14 Lookback des Momentum-Oszillators (wie MT4-iMomentum).
MomentumThreshold 0.3 Minimale absolute Abweichung von der 100-Basislinie innerhalb der letzten drei Momentum-Werte.
MacdFastPeriod 12 Schnelle EMA-Periode für den höheren Zeitrahmen-MACD.
MacdSlowPeriod 26 Langsame EMA-Periode für den höheren Zeitrahmen-MACD.
MacdSignalPeriod 9 Signal-EMA-Periode für den höheren Zeitrahmen-MACD.
TakeProfitPoints 50 Take-Profit-Abstand (in Preispunkten). Auf 0 setzen zum Deaktivieren.
StopLossPoints 20 Stop-Loss-Abstand (in Preispunkten). Auf 0 setzen zum Deaktivieren.
EnableTrailing true Aktiviert StockSharp-Trailing des Schutz-Stops.
TradeVolume 1 Netto-Positionsgröße bei jedem Signal.
MaxNetPositions 1 Begrenzt die gestapelte Netto-Exposition (multipliziert TradeVolume).
CandleType 15m Zeitrahmen Haupt-Handelszeitrahmen.
HigherTimeframe 30d Zeitrahmen Zeitrahmen für MACD-Bestätigung.

Handelslogik

  1. Indikatorvorbereitung – die Strategie bindet beide LWMAs, beide stochastischen Oszillatoren, den Momentum-Indikator und den MACD an ihre jeweiligen Kerzenstreams.
  2. Momentum-Historie – die absolute Distanz des Momentum-Oszillators von 100 wird für die letzten drei abgeschlossenen Balken gespeichert. Dies repliziert die MomLevelB/MomLevelS-Arrays des EA.
  3. Einstiegsregeln
    • Long: schneller LWMA über langsamem LWMA, %K- und %D-Werte beider Stochastiken unter StochasticBuyLevel, Momentum-Abweichung über MomentumThreshold, und MACD-Hauptlinie über der Signallinie.
    • Short: schneller LWMA unter langsamem LWMA, %K- und %D-Werte beider Stochastiken über StochasticSellLevel, Momentum-Abweichung über dem Schwellenwert, und MACD-Hauptlinie unter der Signallinie.
  4. Positions-Handling – Orders werden mit BuyMarket/SellMarket gesendet. Wenn ein Umkehrsignal erscheint, schließt die Strategie automatisch jede entgegengesetzte Netto-Exposition, bevor die neue Richtung etabliert wird.
  5. SchutzStartProtection wendet die konfigurierten Take-Profit- und Stop-Loss-Abstände (in Punkten) an. Wenn EnableTrailing true ist, verwaltet StockSharp das Stop-Trailing ähnlich wie die Trailing-Routine des EA.

Unterschiede zur MQL-Version

  • Volumenskalierung: der EA skaliert Lotgrößen mit LotExponent und erlaubt mehrere gleichzeitige Tickets. Der StockSharp-Port konzentriert sich auf Netto-Exposition und zielt auf ein einzelnes TradeVolume pro Richtung ab (begrenzt durch MaxNetPositions).
  • Margin-Verwaltung: Margin-Checks, Equity-Stops und Benachrichtigungsfunktionen aus dem Originalskript werden nicht reproduziert, da sie auf MT4-Konto-APIs angewiesen sind.
  • Freeze-Niveaus: Broker-spezifische Niedrig-Level-Freeze-Niveau-Prüfungen werden weggelassen; StockSharp-Order-Routing verarbeitet Exchange-Einschränkungen.
  • Break-Even-Toggle: der MT4-„Move to Breakeven"-Helfer wird durch StockSharp's Trailing-Schutz ersetzt.

Verwendungshinweise

  1. Instrument und Connector zuweisen, dann die Strategie starten. Sie abonniert automatisch sowohl den Handelszeitrahmen als auch den höheren Zeitrahmen für den MACD-Filter.
  2. Wenn Ihre Datenquelle keinen 30-Tage-Kerzentyp unterstützt, HigherTimeframe auf ein unterstütztes Intervall anpassen (z.B. wöchentlich oder täglich).
  3. TradeVolume auf Ihre Portfolioeinheiten einstellen.
  4. TakeProfitPoints/StopLossPoints auf null setzen, wenn Schutzorders deaktiviert sein sollen.
  5. Alle Kommentare im Code sind auf Englisch geschrieben, und die Einrückung verwendet Tabs.

Dateien

  • CS/StochasticMomentumFilterStrategy.cs – StockSharp-Implementierung der Strategielogik.
  • README.md – englische Dokumentation (diese Datei).
  • README_ru.md – russische Dokumentation.
  • README_zh.md – chinesische Dokumentation.
using System;
using System.Collections.Generic;

using Ecng.Common;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

public class StochasticMomentumFilterStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private ExponentialMovingAverage _fast;
	private ExponentialMovingAverage _slow;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }

	public StochasticMomentumFilterStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
		_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

	protected override void OnReseted()
	{
		base.OnReseted();
		_fast = null; _slow = null;
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_fast = new ExponentialMovingAverage { Length = FastPeriod };
		_slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, ProcessCandle);
		subscription.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
		if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}

		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }

		_prevFast = fastValue; _prevSlow = slowValue;
	}
}