Auf GitHub ansehen

Wöchentliche Rebound-Korridor-Strategie

Überblick

Die Weekly Rebound Corridor-Strategie repliziert das Verhalten des MetaTrader 4 Expert Advisors 2_Otkat_Sys_v1_1. Das System sucht nach einer starken Lücke zwischen dem Schlusskurs der vorherigen Sitzung und dem Eröffnungspreis, der 24 Kerzen zuvor aufgetreten ist. Wenn die erkannte Lücke einen konfigurierbaren Korridorschwellenwert überschreitet und es sich um den angegebenen Handelstag der Woche handelt, kommt die Strategie in den ersten Minuten des neuen Handelstages auf den Markt. Es werden schützende Stop-Loss- und Take-Profit-Level angewendet und alle offenen Positionen werden kurz vor Ende der Handelssitzung zwangsweise geschlossen.

Handelslogik

  1. Datenvorbereitung
    • Verwendet standardmäßig Minutenkerzen. Der Kerzentyp ist für andere Bargrößen konfigurierbar.
    • Verfolgt den Schlusskurs der vorherigen Kerze und unterhält einen Ringpuffer, der den vor 24 Kerzen beobachteten Eröffnungspreis zurückgibt.
  2. Signalerzeugung
    • Am angegebenen Handelstag der Woche (MetaTrader-Format: 0 = Sunday, 6 = Saturday) wertet die Strategie fertige Kerzen aus, deren Ortszeit zwischen 00:00 und 00:03 liegt.
    • Berechnet die Differenz zwischen der historischen Eröffnungskerze (vor 24 Kerzen) und der letzten geschlossenen Kerze. Wenn die Differenz den konfigurierten Korridorschwellenwert überschreitet, wird eine Marktorder gesendet:
      • Long-Setup: Der historische Eröffnungskurs minus der vorherige Schlusskurs liegt über dem Korridorschwellenwert.
      • Short-Setup: Der vorherige Schlusskurs minus der historische Eröffnungskurs liegt über dem Korridorschwellenwert.
    • Jeder Handelstag kann höchstens einen Eintrag auslösen.
  3. Handelsmanagement
    • Stop-Loss- und Take-Profit-Level werden in Punkten ausgedrückt. Die Tick-Größe des Instruments wandelt die Punktwerte in tatsächliche Preisversätze um.
    • Long-Trades addieren den ursprünglichen MT4-Offset von drei Extrapunkten zur Take-Profit-Distanz.
    • Die Strategie überwacht kontinuierlich die Höchst- und Tiefststände der Kerzen, um Stop-Loss- oder Take-Profit-Treffer zu erkennen, und schließt die offene Position bei Auslösung mit einer Marktorder.
    • Alle verbleibenden offenen Positionen werden nach 22:45 Uhr Ortszeit geschlossen, um die End-of-Day-Flat-Regel des ursprünglichen Expert Advisors zu emulieren.

Parameter

Name Beschreibung Standard
TakeProfitPoints Take-Profit-Distanz in Punkten. Long-Trades fügen drei zusätzliche Punkte hinzu, wie im MT4-Skript definiert. 5
StopLossPoints Stop-Loss-Distanz in Punkten. 49
TradeVolume Mit Marktaufträgen übermitteltes Volumen. Der Wert wird automatisch an den Lautstärkeschritt des Instruments angepasst. 1
CorridorPoints Erforderliche Mindestlücke zwischen dem historischen Eröffnungskurs und dem letzten Schlusskurs. 10
TradeDayOfWeek Handelstag in der Nummerierung MetaTrader (0 = Sunday6 = Saturday). 5 (Freitag)
CandleType Für die Analyse verwendeter Kerzendatentyp. 1 minute

Notizen

  • Die Strategie basiert ausschließlich auf fertigen Kerzen, um sie an den Projektrichtlinien auszurichten.
  • Stellen Sie sicher, dass das ausgewählte Instrument genügend historische Daten bereitstellt, um den 24-Kerzen-Puffer aufzubauen, bevor Einträge erwartet werden.
  • Die volumen- und punktbasierten Parameter sollten an die Instrumentenspezifikation (Tickgröße, Lotschritt, Handelsplan) angepasst werden.
using System;

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

namespace StockSharp.Samples.Strategies;

public class WeeklyReboundCorridorStrategy : Strategy
{
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<decimal> _oversold;
	private readonly StrategyParam<decimal> _overbought;
	private readonly StrategyParam<int> _cooldownCandles;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevRsi;
	private bool _hasPrev;
	private int _cooldownRemaining;

	public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
	public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
	public decimal Oversold { get => _oversold.Value; set => _oversold.Value = value; }
	public decimal Overbought { get => _overbought.Value; set => _overbought.Value = value; }
	public int CooldownCandles { get => _cooldownCandles.Value; set => _cooldownCandles.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public WeeklyReboundCorridorStrategy()
	{
		_rsiPeriod = Param(nameof(RsiPeriod), 14).SetDisplay("RSI Period", "RSI lookback", "Indicators");
		_emaPeriod = Param(nameof(EmaPeriod), 50).SetDisplay("EMA Period", "EMA filter", "Indicators");
		_oversold = Param(nameof(Oversold), 25m).SetDisplay("Oversold", "RSI oversold level", "Levels");
		_overbought = Param(nameof(Overbought), 75m).SetDisplay("Overbought", "RSI overbought level", "Levels");
		_cooldownCandles = Param(nameof(CooldownCandles), 50).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();
		_prevRsi = default;
		_hasPrev = default;
		_cooldownRemaining = default;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevRsi = 0;
		_hasPrev = false;
		_cooldownRemaining = 0;

		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		var ema = new ExponentialMovingAverage { Length = EmaPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(rsi, ema, ProcessCandle).Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal rsi, decimal ema)
	{
		if (candle.State != CandleStates.Finished) return;
		var close = candle.ClosePrice;
		if (!_hasPrev) { _prevRsi = rsi; _hasPrev = true; return; }

		if (_cooldownRemaining > 0)
		{
			_cooldownRemaining--;
			_prevRsi = rsi;
			return;
		}

		var oversold = Oversold;
		var overbought = Overbought;

		if (_prevRsi >= oversold && rsi < oversold && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
			_cooldownRemaining = CooldownCandles;
		}
		else if (_prevRsi <= overbought && rsi > overbought && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
			_cooldownRemaining = CooldownCandles;
		}
		_prevRsi = rsi;
	}
}