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
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.
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.
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.
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.
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;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class otkat_sys_strategy(Strategy):
def __init__(self):
super(otkat_sys_strategy, self).__init__()
self._channel_period = self.Param("ChannelPeriod", 48) \
.SetDisplay("Channel Period", "Channel lookback", "Indicators")
self._cooldown_candles = self.Param("CooldownCandles", 150) \
.SetDisplay("Cooldown", "Candles between signals", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_close = 0.0
self._prev_mid = 0.0
self._has_prev = False
self._cooldown_remaining = 0
@property
def channel_period(self):
return self._channel_period.Value
@property
def cooldown_candles(self):
return self._cooldown_candles.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(otkat_sys_strategy, self).OnReseted()
self._prev_close = 0.0
self._prev_mid = 0.0
self._has_prev = False
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(otkat_sys_strategy, self).OnStarted2(time)
self._prev_close = 0.0
self._prev_mid = 0.0
self._has_prev = False
self._cooldown_remaining = 0
highest = Highest()
highest.Length = self.channel_period
lowest = Lowest()
lowest.Length = self.channel_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(highest, lowest, self.process_candle).Start()
def process_candle(self, candle, highest, lowest):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
mid = (float(highest) + float(lowest)) / 2.0
if not self._has_prev:
self._prev_close = close
self._prev_mid = mid
self._has_prev = True
return
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
self._prev_close = close
self._prev_mid = mid
return
if self._prev_close <= self._prev_mid and close > mid and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._cooldown_remaining = self.cooldown_candles
elif self._prev_close >= self._prev_mid and close < mid and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._cooldown_remaining = self.cooldown_candles
self._prev_close = close
self._prev_mid = mid
def CreateClone(self):
return otkat_sys_strategy()