Auf GitHub ansehen

Standard Deviation Channel-Strategie

Überblick

Diese Strategie ist ein StockSharp-Port des MetaTrader-Experten Standard Deviation Channel. Sie zeichnet einen Volatilitätskanal auf Basis eines linearen gewichteten gleitenden Durchschnitts (LWMA) und handelt Ausbrüche, die mit dem vorherrschenden Trend übereinstimmen. Einstiege werden durch Momentum-Stärke und eine MACD-Bestätigung gefiltert, während Ausstiege feste Ziele, Break-Even-Sprünge und Trailing-Schutz kombinieren.

Indikatoren und Signale

  • Standard Deviation-Kanal aus einer LWMA-Basislinie und einem konfigurierbaren Abweichungsmultiplikator. Long-Setups erfordern eine steigende obere Bande; Short-Setups erfordern eine fallende untere Bande.
  • Trendfilter: Schnelle und langsame LWMA auf denselben Kerzen. Longs erfordern LWMA_fast > LWMA_slow; Shorts erfordern das Gegenteil.
  • Momentum-Filter: Ein 14-Perioden-Momentum-Indikator. Mindestens eine der letzten drei Messwerte muss vom neutralen Niveau 100 um den konfigurierten Schwellenwert abweichen.
  • MACD-Filter: Klassische 12/26/9-Konfiguration. Long-Einstiege benötigen MACD ≥ signal, während Short-Einstiege MACD ≤ signal erfordern.

Trade-Management

  • Positionsgrößenbestimmung: Verwendet den Parameter TradeVolume. Umkehrungen schließen automatisch das entgegengesetzte Exposure, bevor die neue Seite eröffnet wird.
  • Take-Profit & Stop-Loss: In Pips ausgedrückt und gegen den PriceStep des Instruments bewertet. Die Strategie gibt Marktausstiege aus, sobald die Kerzenspanne das Ziel- oder Stop-Preisniveau berührt.
  • Break-Even-Sprung: Sobald der unrealisierte Gewinn BreakEvenTriggerPips erreicht, wird der Stop auf Einstieg plus BreakEvenOffsetPips verschoben (oder minus bei Shorts).
  • Trailing Stop: Nach Erreichen von TrailingStartPips folgt der Stop dem Preis um TrailingStepPips und sichert Gewinne auf beiden Seiten.
  • Kanalablehnungsausstieg: Wenn der Preis zurück in den Kanal schließt und die Neigung gegen die Position abflacht, wird der Trade frühzeitig geschlossen.

Parameter

Name Beschreibung
CandleType Primärer Zeitrahmen für alle Berechnungen.
TradeVolume Basis-Auftragsgröße.
TrendLength LWMA-Rückblickperiode, die die Kanal-Basislinie definiert.
DeviationMultiplier Standardabweichungsmultiplikator für die Kanalbreite.
FastMaLength / SlowMaLength LWMA-Längen für den Trendfilter.
MomentumPeriod Rückblickperiode für den Momentum-Filter.
MomentumThreshold Mindestabweichung von 100 in einem der letzten drei Momentum-Werte.
TakeProfitPips / StopLossPips Abstände der festen Ausstiegsniveaus (umgerechnet mit PriceStep).
BreakEvenTriggerPips / BreakEvenOffsetPips Steuert wann und wie der Break-Even-Stop aktiviert wird.
TrailingStartPips / TrailingStepPips Aktiviert und dimensioniert den Trailing Stop.
MacdFastPeriod, MacdSlowPeriod, MacdSignalPeriod MACD-Konfiguration.
MaxPositionUnits Maximale absolute Nettoposition; verhindert Überheblung.

Verwendungshinweise

  1. Fügen Sie die Strategie einem Wertpapier hinzu, das einen gültigen PriceStep aufweist. Pips werden durch Multiplikation dieses Schrittwerts umgerechnet.
  2. Verwenden Sie TrendLength und DeviationMultiplier, um den Kanal an verschiedene Märkte anzupassen.
  3. Momentum- und MACD-Filter können gelockert werden (niedrigerer Schwellenwert, kürzere Perioden), um die Handelsfrequenz zu erhöhen.
  4. Die Trailing-Logik funktioniert bei Kerzenschlusskursen; Intrabar-Spitzen, die nicht über die Schwellenwerte hinausgehen, werden ignoriert.

Unterschiede zum originalen Expert Advisor

  • Die MetaTrader-Version verwendet grafische Objekte zur Ablesung der Kanalneigung und nutzt mehrere Money-Management-Zweige (Martingale-Sizing, Eigenkapitalschutz). Dieser Port behält die Neigungsprüfung bei, vereinfacht aber die Risikokontrolle auf Trades fester Größe, begrenzt durch MaxPositionUnits.
  • Alle Ausstiege werden mit Marktorders beim Kerzenabschluss abgewickelt, da StockSharp-Strategien die MT4-Ordermodifikations-APIs nicht direkt spiegeln.
  • E-Mail- und Push-Benachrichtigungen werden durch AddInfoLog-Nachrichten ersetzt, um die Konvertierung eigenständig zu halten.
  • Kapitalbasierte Konto-Stopp-Outs wurden weggelassen; stattdessen liegt der Fokus auf positionsbezogenen Schutzfunktionen.

Haftungsausschluss

Dieses Beispiel ist für Bildungszwecke bestimmt. Führen Sie immer Vorwärtstests durch und validieren Sie die Konfiguration, bevor Sie sie auf einem Live-Konto einsetzen.

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 StandardDeviationChannelStrategy : 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 StandardDeviationChannelStrategy()
	{
		_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;
	}
}