Auf GitHub ansehen

Plateau-Strategie

Die Plateau-Strategie ist eine Konvertierung des ursprünglichen MetaTrader 5 Expert Advisors. Sie kombiniert ein Paar linear gewichteter gleitender Durchschnitte mit Bollinger Bands, um potenzielle Umkehrungen zu erkennen, wenn der Preis in der Nähe des unteren Bandes handelt.

Trading-Idee

  • Schnelle und langsame gleitende Durchschnitte mit der ausgewählten Glättungsmethode und Preisquelle berechnen.
  • Bollinger Bands um dieselbe Preisserie aufbauen.
  • Wenn der schnelle Durchschnitt über den langsamen kreuzt, während die vorherige Kerze unter dem unteren Band schloss, eine Long-Position eröffnen.
  • Wenn der schnelle Durchschnitt unter den langsamen kreuzt, während die vorherige Kerze über dem unteren Band schloss, eine Short-Position eröffnen.
  • Optional Signale umkehren, wenn der Reverse-Schalter aktiviert ist.

Orderverwaltung

  • Positionen können entweder mit einem festen Lot oder durch Riskieren eines Prozentsatzes des Portfolio-Wertes pro Trade dimensioniert werden.
  • Stop-Loss- und Take-Profit-Niveaus werden in Pips ausgedrückt und unmittelbar nach dem Füllen der Marktorder angehängt.
  • Ein Trailing-Stop kann aktiviert werden, wenn sowohl die Trailing-Distanz als auch der Schritt positiv sind.
  • Wenn Close Opposite aktiviert ist, schließt die Strategie automatisch die entgegengesetzte Position, bevor ein neuer Trade eingegangen wird.

Parameter

Parameter Beschreibung
Stop Loss Stop-Loss-Abstand in Pips.
Take Profit Take-Profit-Abstand in Pips.
Trailing Stop Trailing-Stop-Abstand in Pips.
Trailing Step Minimaler Schritt (in Pips), der erforderlich ist, um den Trailing-Stop zu bewegen.
Money Mode Wählen zwischen festem Lot und risikoprozentbasierer Dimensionierung.
Lot / Risk Entweder die feste Lot-Größe oder der Risikoanteil je nach ausgewähltem Geldmodus.
Fast MA / Slow MA Perioden für das gleitende Durchschnittspaar.
MA Shift Horizontale Verschiebung, die auf beide gleitenden Durchschnitte angewendet wird.
MA Method Glättungsalgorithmus für gleitende Durchschnitte.
MA Price Preisquelle für die Berechnung der gleitenden Durchschnitte.
Bands Period Mittelungsperiode für Bollinger Bands.
Bands Shift Horizontale Verschiebung der Bollinger-Band-Werte.
Bands Deviation Standardabweichungsmultiplikator für Bollinger Bands.
Bands Price Preisquelle für die Berechnung der Bollinger Bands.
Reverse Long- und Short-Signallogik umkehren.
Close Opposite Eine bestehende Position in der entgegengesetzten Richtung schließen, bevor eine neue eröffnet wird.
Verbose Log Detaillierte Ausführungsinformationen in das Log drucken.
Candle Type Kerzendatenserie für Indikatorberechnungen.

Hinweise

  • Die Pip-Größe wird automatisch an Instrumente mit drei oder fünf Dezimalstellen angepasst, um dem ursprünglichen Expert-Verhalten zu entsprechen.
  • Wenn der Trailing-Stop aktiviert ist, muss der Trailing-Schritt strikt positiv sein; andernfalls wirft die Strategie beim Start einen Fehler.
  • Die risikobasierte Positionsgröße erfordert sowohl eine gültige Stop-Loss-Distanz als auch Portfolio-Bewertungsdaten. Wenn nicht verfügbar, fällt die Strategie auf das Standardvolumen zurück.
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 PlateauStrategy : 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 PlateauStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 15).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 60).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;
	}
}