Auf GitHub ansehen

Otkat Sys-Strategie

Die Strategie reproduziert den Expertenberater MetaTrader 1_Otkat_Sys. Es überwacht den Eröffnungs-, Schluss- und Höchststand des vorherigen Handelstages. und niedrig, um zu entscheiden, ob in den ersten drei Minuten nach Mitternacht (Brokerzeit) von Dienstag bis eine Position eingegeben werden soll Donnerstag.

Handelslogik

  1. Tägliche Statistiken – die letzte abgeschlossene tägliche Kerze wird zwischengespeichert, um Folgendes zu berechnen:
    • Open - Close und Close - Open, um festzustellen, ob die vorherige Sitzung bärisch oder bullisch war.
    • Close - Low und High - Close, um zu messen, wie stark sich der Preis von den Extremen zurückgezogen hat.
  2. Einstiegsfenster – neue Trades werden ausgewertet, wenn die Einstiegskerze zwischen 00:00 und 00:03 Uhr geöffnet wird. Montag und Freitag sind übersprungen, passend zu den DayOfWeek-Filtern des ursprünglichen Roboters.
  3. Richtungsfilter – vier sich gegenseitig ausschließende Bedingungen spiegeln die MQL-Regeln wider:
    • Bärischer Vortag (Open - Close über der Korridorschwelle) kombiniert mit einem flachen Retracement (Close - Low unter Pullback - Tolerance) öffnet eine lange.
    • Der bullische Vortag mit einem ausgedehnten Aufwärts-Retracement (High - Close über Pullback + Tolerance) eröffnet ebenfalls eine Long-Position.
    • Der bullische Vortag mit einem schwachen Aufwärts-Retracement (High - Close unter Pullback - Tolerance) eröffnet einen Short.
    • Der rückläufige Vortag mit einem ausgedehnten Abwärts-Retracement (Close - Low über Pullback + Tolerance) eröffnet einen Short.
  4. Orders – Eingaben sind Market Orders, die mit der konfigurierten Losgröße platziert werden. Kaufgeschäfte verwenden eine Take-Profit-Distanz von TakeProfit + 3 Punkte (wie im Original EA); Shorts verwenden genau TakeProfit Punkte. Beide Seiten wenden den gleichen Stop-Loss an Entfernung.
  5. Zeitbasierter Ausstieg – jede offene Position wird nach 22:45 Uhr reduziert, wodurch die nächtliche Bereinigung nachgebildet wird, die im MetaTrader implementiert wurde. Skript.

Alle Schwellenwertparameter werden in Punkten ausgedrückt und mit dem PriceStep des Instruments in Preisabstände übersetzt.

Parameter

Name Beschreibung
EntryCandleType Zeitrahmen für das Handelsfenster (Standard: 1 Minute).
DailyCandleType Zeitrahmen zur Bereitstellung der täglichen Statistiken (Standard: 1 Tag).
TakeProfit Gewinnziel in Punkten. Long-Trades fügen einen 3-Punkte-Puffer hinzu.
StopLoss Schutzstoppabstand in Punkten.
PullbackThreshold Basis-Pullback-Schwellenwert („Otkat“) in Punkten.
CorridorThreshold Schwellenwert für den Richtungskorridor (KoridorOC).
ToleranceThreshold Rückzugstoleranz (KoridorOt).
TradeVolume Losgröße für jeden Eintrag.

Die Strategie setzt ihre zwischengespeicherten Werte am Reset automatisch zurück, abonniert sowohl Eintritts- als auch tägliche Kerzenströme und Ziehungen Kerzen plus Handelsmarkierungen, wenn ein Chartbereich verfügbar ist.

using System;

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

namespace StockSharp.Samples.Strategies;

public class OtkatSysStrategy : Strategy
{
	private readonly StrategyParam<int> _channelPeriod;
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<int> _cooldownCandles;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevClose;
	private decimal _prevMid;
	private bool _hasPrev;
	private int _cooldownRemaining;

	public int ChannelPeriod { get => _channelPeriod.Value; set => _channelPeriod.Value = value; }
	public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
	public int CooldownCandles { get => _cooldownCandles.Value; set => _cooldownCandles.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public OtkatSysStrategy()
	{
		_channelPeriod = Param(nameof(ChannelPeriod), 48).SetDisplay("Channel Period", "Channel lookback", "Indicators");
		_emaPeriod = Param(nameof(EmaPeriod), 20).SetDisplay("EMA Period", "EMA filter", "Indicators");
		_cooldownCandles = Param(nameof(CooldownCandles), 150).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();
		_prevClose = default;
		_prevMid = default;
		_hasPrev = default;
		_cooldownRemaining = default;
	}

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

		var highest = new Highest { Length = ChannelPeriod };
		var lowest = new Lowest { Length = ChannelPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(highest, lowest, ProcessCandle).Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal highest, decimal lowest)
	{
		if (candle.State != CandleStates.Finished) return;
		var close = candle.ClosePrice;
		var mid = (highest + lowest) / 2;
		if (!_hasPrev) { _prevClose = close; _prevMid = mid; _hasPrev = true; return; }

		if (_cooldownRemaining > 0)
		{
			_cooldownRemaining--;
			_prevClose = close;
			_prevMid = mid;
			return;
		}

		if (_prevClose <= _prevMid && close > mid && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
			_cooldownRemaining = CooldownCandles;
		}
		else if (_prevClose >= _prevMid && close < mid && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
			_cooldownRemaining = CooldownCandles;
		}
		_prevClose = close;
		_prevMid = mid;
	}
}