Auf GitHub ansehen

SR Rate Indicator-Strategie

Übersicht

Diese Strategie ist ein C#-Port des MetaTrader 5-Experten Exp_SR-RateIndicator. Sie reproduziert die ursprüngliche Handelslogik mit der High-Level-API von StockSharp und einer benutzerdefinierten Implementierung des SR Rate Oszillators. Der Indikator misst, wie weit der gewichtete Kerzenpris innerhalb eines geglätteten Unterstützungs-/Widerstands-Kanals liegt, und malt einen Farbcode, der extreme Lesungen hervorhebt.

Der Algorithmus verarbeitet abgeschlossene Kerzen aus einem konfigurierbaren Zeitrahmen. Wenn die Oszillatorfarbe zum bullischen oder bearischen Extrem springt, schließt die Strategie jede entgegengesetzte Position und eröffnet einen neuen Trade in Signalrichtung. Schutzende Stop-Loss- und Take-Profit-Niveaus werden mit denselben Punktabständen angewendet, die in der MetaTrader-Version verwendet werden.

SR Rate Oszillator

Der Indikator berechnet ein Gaußsches geglättetes Band um den Preis unter Verwendung einer konfigurierbaren Fensterlänge:

  1. Für jede Kerze werden das Hoch, Tief und der gewichtete Schlusskurs mit einseitigen Gaußschen Gewichten der Länge sechs geglättet.
  2. Das höchste geglättete Hoch und das niedrigste geglättete Tief über dem Fenster definieren einen dynamischen Bereich.
  3. Der aktuelle geglättete gewichtete Schlusskurs wird innerhalb dieses Bereichs normiert und auf das Intervall [-100, 100] abgebildet.
  4. Der finale Oszillatorwert wird in fünf Farbzustände konvertiert: 0 (stark bearisch), 1 (leicht bearisch), 2 (neutral), 3 (leicht bullisch) und 4 (stark bullisch).

Eine stark bullische Farbe (4) zeigt an, dass der Preis das obere Extrem des Bereichs erreicht hat, während eine stark bearische Farbe (0) einen Besuch am unteren Extrem signalisiert.

Handelsregeln

  1. Kerzen des konfigurierten Typs abonnieren und den SR Rate Oszillator auf jeder abgeschlossenen Kerze berechnen.
  2. Die Signalauswertung um SignalBar geschlossene Kerzen verschieben (Standard: eine Kerze zurück), um das Expert-Advisor-Verhalten nachzuahmen.
  3. Wenn die verschobene Farbe 4 wird und die vorherige Farbe unter 4 liegt:
    • Jede bestehende Short-Position schließen, wenn Long-Exits aktiviert sind.
    • Eine neue Long-Position eröffnen, wenn Long-Einträge aktiviert sind und keine andere Position aktiv ist.
  4. Wenn die verschobene Farbe 0 wird und die vorherige Farbe über 0 liegt:
    • Jede bestehende Long-Position schließen, wenn Short-Exits aktiviert sind.
    • Eine neue Short-Position eröffnen, wenn Short-Einträge aktiviert sind und keine andere Position aktiv ist.
  5. Nur eine Position kann jederzeit geöffnet sein. Neue Signale werden ignoriert, bis der vorherige Trade geschlossen ist.
  6. Optionale Stop-Loss- und Take-Profit-Niveaus werden in Preispunkten ausgedrückt und automatisch unter Verwendung des Instrument-Kursschritts in absolute Preise umgerechnet.

Parameter

Name Beschreibung
OrderVolume Trade-Volumen für jede Marktorder.
EnableLongEntries Öffnen von Long-Positionen aktivieren/deaktivieren.
EnableShortEntries Öffnen von Short-Positionen aktivieren/deaktivieren.
EnableLongExits Long-Positionen schließen wenn eine stark bearische Farbe erscheint.
EnableShortExits Short-Positionen schließen wenn eine stark bullische Farbe erscheint.
StopLossPoints Stop-Loss-Abstand in Instrument-Punkten (konvertiert mit dem Kursschritt).
TakeProfitPoints Take-Profit-Abstand in Instrument-Punkten (konvertiert mit dem Kursschritt).
SlippagePoints Maximal tolerierter Slippage beim Schließen von Positionen. Für Kompatibilität beibehalten; kein explizites Slippage-Control wird von der High-Level-API angewendet.
CandleType Kerzentyp und Zeitrahmen zur Berechnung des Indikators.
SignalBar Anzahl der übersprungenen geschlossenen Kerzen vor der Histogrammanalyse (Standard 1).
WindowSize Länge des rollenden Fensters für die SR Rate Normierung.
HighLevel Oszillatorlevel der das bullische Extrem definiert (Standard +20).
LowLevel Oszillatorlevel der das bearische Extrem definiert (Standard -20).

Hinweise

  • Die Strategie funktioniert mit jedem Instrument, das Standard-OHLC-Kerzen liefert.
  • Signale werden nur auf abgeschlossenen Kerzen verarbeitet; Intrabar-Neuberechnungen werden ignoriert, genauso wie in der MetaTrader-Implementierung.
  • Die Slippage-Behandlung im ursprünglichen Experten hing von Ausführungseinstellungen ab. StockSharp-Marktorders respektieren bereits Exchange-Regeln, daher wird der SlippagePoints-Parameter nur für Dokumentationszwecke beibehalten.
  • Der Indikator speichert nur die minimale Menge an Verlauf, die zur Auswertung des Fensters benötigt wird, um unnötigen Speicherverbrauch zu vermeiden.
  • Die Python-Version wird gemäß den Projektrichtlinien absichtlich weggelassen.
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 SrRateIndicatorStrategy : 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 SrRateIndicatorStrategy()
	{
		_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;
	}
}