Auf GitHub ansehen

Umkehr-Reaktions-Strategie

Überblick

Die Umkehr-Reaktions-Strategie ist ein Mean-Reversion-System, inspiriert vom ursprünglichen MetaTrader-Expertenberater "IREA". Sie reagiert auf ungewöhnlich große Einzelbar-Bewegungen und antizipiert eine inverse Reaktion in der nächsten Bar. Die Strategie berechnet ein dynamisches Konfidenzlevel aus jüngsten Kerzenbereichen und handelt nur, wenn Kursschwankungen dieses Level überschreiten, aber innerhalb benutzerdefinierter Grenzen bleiben. Es kann jeweils nur eine Position offen sein.

Handelsstrategie

  1. Umkehr-Reaktions-Indikator – Für jede abgeschlossene Kerze misst die Strategie die Eröffnungs-/Schlusskursänderung und speist ihren Absolutwert in einen einfachen gleitenden Durchschnitt der Länge MaPeriod ein. Die gemittelte Änderung wird mit Coefficient multipliziert, um eine dynamische Schwelle ähnlich dem Dynamic Confidence Level (DCL) des ursprünglichen Indikators zu bilden.
  2. Signalvalidierung – Die absolute Eröffnungs-/Schlusskursänderung der letzten Kerze muss größer als die dynamische Schwelle, größer als MinCriteriaPoints * PriceStep und kleiner als MaxCriteriaPoints * PriceStep sein. Signale werden ignoriert, wenn die vorherige Kerze bereits dieselbe Bedingung erfüllte, was den ursprünglichen Expertenberater widerspiegelt.
  3. Richtung – Eine negative Änderung (bärische Kerze) deutet auf einen Rebound nach oben hin, daher wird eine Long-Position eröffnet. Eine positive Änderung impliziert eine Erwartung einer bärischen Umkehr und löst eine Short-Position aus. Neue Trades werden nur gesendet, wenn keine bestehende Position vorhanden ist.
  4. Risikomanagement – Nach dem Einstieg überwacht die Strategie die folgenden Kerzen. Wenn der Preis die vordefinierten Stop-Loss- oder Take-Profit-Levels berührt (von Punkten in absolute Preise unter Verwendung des PriceStep des Instruments umgerechnet), schließt sie die offene Position sofort mit Marktorders. StartProtection() wird ebenfalls aktiviert, um die integrierten StockSharp-Schutzfunktionen zu unterstützen.

Parameter

Parameter Beschreibung
StopLossPoints Stop-Loss-Abstand in Punkten (multipliziert mit PriceStep).
TakeProfitPoints Take-Profit-Abstand in Punkten.
TradeVolume Für jede Marktorder verwendetes Volumen.
SlippagePoints Informationseinstellung, die die MQL-Version widerspiegelt; derzeit nicht auf Orders angewendet.
MinCriteriaPoints Minimale Eröffnungs-/Schlusskursdistanz (in Punkten) für ein gültiges Signal.
MaxCriteriaPoints Maximal zulässige Eröffnungs-/Schlusskursdistanz (in Punkten).
Coefficient Multiplikator zum Aufbau der dynamischen Konfidenzschwelle.
MaPeriod Länge des im Indikator verwendeten gleitenden Durchschnitts. Muss mindestens 3 sein.
CandleType Zeitrahmen der verarbeiteten Kerzen (Standard: 1 Stunde).

Verwendungsrichtlinien

  • Stellen Sie sicher, dass das ausgewählte Instrument einen gültigen PriceStep hat. Wenn nicht verfügbar, fällt die Strategie auf einen Schritt von 1.0 zurück, was Schwellen verzerren kann.
  • Passen Sie MinCriteriaPoints und MaxCriteriaPoints an die Volatilität des gewählten Zeitrahmens an. Ein zu enges Fenster filtert die meisten Signale heraus, während ein zu weites Fenster extrem große Bewegungen zulässt, die möglicherweise nicht umkehren.
  • Der Standard-Coefficient von 1.618 repliziert die Goldene-Ratio-Skalierung des ursprünglichen Indikators. Höhere Werte erfordern größere Ausreißerkerzen vor dem Handel.
  • Da Positionen durch Marktorders beim nächsten Kerzenschluss geschlossen werden, der die Stop- oder Ziellevels verletzt, kann die tatsächliche Ausführung von den genauen Limitlevels abweichen. Erwägen Sie Tests mit Intraday-Daten für präzisere Kontrolle, wenn nötig.
  • Es wird jeweils nur eine Position gehalten. Die Strategie wartet, bis der aktuelle Trade geschlossen ist, bevor sie auf ein neues Signal reagiert.

Hinweise

  • Backtesten Sie die Konfiguration auf historischen Daten, bevor Sie sie live verwenden. Der ursprüngliche EA wurde für FX-Märkte konzipiert; Parameteranpassungen können für andere Assets erforderlich sein.
  • Der SlippagePoints-Parameter wird aus Vollständigkeitsgründen beibehalten, aber absichtlich nicht verwendet, weil StockSharp Slippage anders als MetaTrader handhabt.
  • Stellen Sie sicher, dass MaPeriod bei oder über 3 bleibt; kleinere Werte waren in der ursprünglichen Implementierung verboten und können zu instabilen Schwellen führen.
using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Strategy that reacts to large single-bar moves expecting a mean reversion.
/// </summary>
public class InverseReactionStrategy : Strategy
{
	private readonly StrategyParam<decimal> _stopLossPoints;
	private readonly StrategyParam<decimal> _takeProfitPoints;
	private readonly StrategyParam<decimal> _coefficient;
	private readonly StrategyParam<int> _maPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private readonly List<decimal> _absChanges = new();

	public decimal StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public decimal TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
	public decimal Coefficient { get => _coefficient.Value; set => _coefficient.Value = value; }
	public int MaPeriod { get => _maPeriod.Value; set => _maPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public InverseReactionStrategy()
	{
		_stopLossPoints = Param(nameof(StopLossPoints), 1000m)
			.SetGreaterThanZero()
			.SetDisplay("Stop Loss", "Stop-loss distance in points", "Risk");

		_takeProfitPoints = Param(nameof(TakeProfitPoints), 250m)
			.SetGreaterThanZero()
			.SetDisplay("Take Profit", "Take-profit distance in points", "Risk");

		_coefficient = Param(nameof(Coefficient), 1.618m)
			.SetGreaterThanZero()
			.SetDisplay("Coefficient", "Confidence coefficient", "Signal");

		_maPeriod = Param(nameof(MaPeriod), 3)
			.SetGreaterThanZero()
			.SetDisplay("MA Period", "Moving average length", "Signal");

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
			.SetDisplay("Candle Type", "Primary timeframe", "General");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	protected override void OnReseted()
	{
		base.OnReseted();
		_absChanges.Clear();
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var step = Security?.PriceStep ?? 1m;
		if (step <= 0m) step = 1m;

		StartProtection(
			takeProfit: new Unit(TakeProfitPoints * step, UnitTypes.Absolute),
			stopLoss: new Unit(StopLossPoints * step, UnitTypes.Absolute),
			useMarketOrders: true);

		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(ProcessCandle).Start();
	}

	private void ProcessCandle(ICandleMessage candle)
	{
		if (candle.State != CandleStates.Finished)
			return;

		var change = candle.ClosePrice - candle.OpenPrice;
		var absChange = Math.Abs(change);

		_absChanges.Add(absChange);
		if (_absChanges.Count > MaPeriod)
			_absChanges.RemoveAt(0);

		if (_absChanges.Count < MaPeriod)
			return;

		var avg = 0m;
		for (int i = 0; i < _absChanges.Count; i++)
			avg += _absChanges[i];
		avg /= _absChanges.Count;

		var threshold = avg * Coefficient;

		if (Position != 0)
			return;

		if (absChange > threshold && absChange > 0m)
		{
			if (change < 0m)
			{
				// Large bearish bar => expect reversion upward
				BuyMarket();
			}
			else
			{
				// Large bullish bar => expect reversion downward
				SellMarket();
			}
		}
	}
}