Die Synchronized Hour Breakout Strategy ist eine StockSharp-Portierung des MetaTrader 4-Expertenberaters JK_sinkhro1. Es analysiert das Gleichgewicht bullischer und bärischer Kerzen während des letzten Handelsfensters und handelt nur während zwei sorgfältig ausgewählter Synchronisationsstunden (standardmäßig 19:00 und 22:00 Uhr plus ein Offset). Die Strategie konzentriert sich auf die Erfassung von Richtungsausbrüchen bei gleichzeitiger Durchsetzung konservativer Risikomanagementregeln ähnlich dem ursprünglichen EA.
Handelslogik
Funktioniert mit der durch den Parameter Candle Type ausgewählten Kerzenserie (Standard: 1-Stunden-Kerzen).
Behält ein Schiebefenster der letzten Analysis Period abgeschlossenen Kerzen bei und zählt, wie viele geschlossene bullische vs. bärische Kerzen.
Wenn die bullische Zahl die bärische Zahl übersteigt, bereitet sich die Strategie auf einen langen Ausbruch während der ersten Synchronisationsstunde (22 + Hour Offset) vor.
Wenn die rückläufige Zahl die bullische Zahl übersteigt, bereitet sie sich auf einen kurzen Ausbruch während der zweiten Synchronisationsstunde (19 + Hour Offset) vor.
Signale sind nur innerhalb der ersten fünf Minuten der vollen Stunde gültig, sodass die Bestellung mit der Eröffnung des neuen Balkens synchronisiert wird, wie im Original von MQL.
Neue Trades werden ignoriert, wenn bereits Max Active Orders registriert sind oder eine offene Position vorhanden ist.
Risikomanagement und Handelsmanagement
Positionen werden entweder mit einer festen Losgröße (Fixed Volume) oder einer risikobasierten Größe unter Verwendung der Kontogeld- und Risk %-Parameter eröffnet. Das Risikomodell dividiert das zulässige Cash-Risiko durch die Stop-Distanz in Preisschritten, um das Verhalten der Quelle EA anzunähern.
Jede Position verwendet drei Ebenen der Exit-Logik:
Ein primärer Take-Profit von Take Profit (pts) vom Einstiegspreis.
Ein zweiter, schnellerer Take-Profit bei Secondary TP (pts), um den frühen manuellen Abschluss im Originalcode nachzuahmen.
Ein harter Stop-Loss bei Stop Loss (pts) unter/über dem Einstiegspreis.
Optionaler Trailing-Stop: Sobald der Preis um mehr als Trailing Stop (pts) steigt, folgt der Trailing-Schwellenwert dem günstigen Extremwert und schließt die Position, wenn der Preis über die Trailing-Distanz hinaus zurückgeht.
Der Positionsstatus wird nach jedem vollständigen Verlassen zurückgesetzt, um sich auf das nächste Synchronisierungsfenster vorzubereiten.
Parameter
Parameter
Beschreibung
Take Profit (pts)
Primäre Take-Profit-Distanz bei Wertpapierpreisschritten.
Secondary TP (pts)
Schnellere Take-Profit-Entfernung vor dem Hauptziel.
Stop Loss (pts)
Stop-Loss-Distanz gemessen in Preisschritten.
Trailing Stop (pts)
Trailing-Stop-Distanz; Zum Deaktivieren auf 0 setzen.
Analysis Period
Anzahl der zuletzt überprüften Kerzen bei der Zählung bullischer/bärischer Schlusskurse.
Hour Offset
Versatz zu den ursprünglichen Handelszeiten von 19:00 und 22:00 Uhr hinzugefügt.
Max Active Orders
Maximale Anzahl gleichzeitig aktiver Aufträge, bevor neue Einträge gesperrt werden.
Fixed Volume
Handelsvolumen, das verwendet wird, wenn die risikobasierte Größenbestimmung deaktiviert ist.
Use Risk Volume
Ermöglicht eine dynamische Positionsgrößenbestimmung basierend auf dem Portfolio-Cash und der Stop-Distanz.
Risk %
Prozentsatz des Portfolio-Bargelds, das pro Trade im risikobasierten Modus riskiert wird.
Candle Type
Kerzentyp/Zeitrahmen, der für Berechnungen und Signalgenerierung verwendet wird.
Nutzungshinweise
Die Standardkonfiguration emuliert die MetaTrader-Version, die während der New Yorker Sitzung mit EURUSD gehandelt wurde; Passen Sie den Stundenversatz an die Zeitzone Ihres Brokers/Servers an.
Stellen Sie sicher, dass die Wertpapierdefinition genaue PriceStep-, VolumeStep- und MinVolume-Werte bereitstellt, damit die risikobasierte Positionsgröße die Volumina an die Umtausch-Lot-Inkremente anpassen kann.
Da die Strategie auf Candle-Close-Daten basiert, verknüpfen Sie sie mit einem Verlaufsanbieter oder einem Live-Daten-Feed, der die ausgewählte Candle-Serie mit minimaler Verzögerung liefern kann.
Der Trailing-Exit verwendet Schlusskurse von abgeschlossenen Kerzen, was der Tick-basierten Trailing-Logik der Quelle EA sehr nahe kommt und gleichzeitig mit dem High-Level-API von StockSharp kompatibel bleibt.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class SynchronizedHourBreakoutStrategy : Strategy
{
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<int> _cooldownCandles;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevClose;
private decimal _prevEma;
private bool _hasPrev;
private int _cooldownRemaining;
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
public int CooldownCandles { get => _cooldownCandles.Value; set => _cooldownCandles.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public SynchronizedHourBreakoutStrategy()
{
_emaPeriod = Param(nameof(EmaPeriod), 50).SetDisplay("EMA Period", "EMA lookback", "Indicators");
_atrPeriod = Param(nameof(AtrPeriod), 14).SetDisplay("ATR Period", "ATR lookback", "Indicators");
_cooldownCandles = Param(nameof(CooldownCandles), 200).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;
_prevEma = default;
_hasPrev = default;
_cooldownRemaining = default;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevClose = 0;
_prevEma = 0;
_hasPrev = false;
_cooldownRemaining = 0;
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var atr = new AverageTrueRange { Length = AtrPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ema, atr, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal ema, decimal atr)
{
if (candle.State != CandleStates.Finished) return;
var close = candle.ClosePrice;
if (!_hasPrev) { _prevClose = close; _prevEma = ema; _hasPrev = true; return; }
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
_prevClose = close;
_prevEma = ema;
return;
}
if (_prevClose <= _prevEma && close > ema && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
_cooldownRemaining = CooldownCandles;
}
else if (_prevClose >= _prevEma && close < ema && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
_cooldownRemaining = CooldownCandles;
}
_prevClose = close;
_prevEma = ema;
}
}
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 ExponentialMovingAverage, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class synchronized_hour_breakout_strategy(Strategy):
def __init__(self):
super(synchronized_hour_breakout_strategy, self).__init__()
self._ema_period = self.Param("EmaPeriod", 50) \
.SetDisplay("EMA Period", "EMA lookback", "Indicators")
self._atr_period = self.Param("AtrPeriod", 14) \
.SetDisplay("ATR Period", "ATR lookback", "Indicators")
self._cooldown_candles = self.Param("CooldownCandles", 200) \
.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_ema = 0.0
self._has_prev = False
self._cooldown_remaining = 0
@property
def ema_period(self):
return self._ema_period.Value
@property
def atr_period(self):
return self._atr_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(synchronized_hour_breakout_strategy, self).OnReseted()
self._prev_close = 0.0
self._prev_ema = 0.0
self._has_prev = False
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(synchronized_hour_breakout_strategy, self).OnStarted2(time)
self._prev_close = 0.0
self._prev_ema = 0.0
self._has_prev = False
self._cooldown_remaining = 0
ema = ExponentialMovingAverage()
ema.Length = self.ema_period
atr = AverageTrueRange()
atr.Length = self.atr_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ema, atr, self.process_candle).Start()
def process_candle(self, candle, ema, atr):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
ema_val = float(ema)
if not self._has_prev:
self._prev_close = close
self._prev_ema = ema_val
self._has_prev = True
return
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
self._prev_close = close
self._prev_ema = ema_val
return
if self._prev_close <= self._prev_ema and close > ema_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._cooldown_remaining = self.cooldown_candles
elif self._prev_close >= self._prev_ema and close < ema_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._cooldown_remaining = self.cooldown_candles
self._prev_close = close
self._prev_ema = ema_val
def CreateClone(self):
return synchronized_hour_breakout_strategy()