EurUsd Sitzungs-Ausbruch-Strategie
Diese Strategie repliziert die klassische EUR/USD-Ausbruchsidee, bei der eine enge europäische Morgensession als Sprungbrett für die US-Session genutzt wird. Sie überwacht ein rollendes 24-Kerzen-Fenster (standardmäßig 15-Minuten-Kerzen), um die Pre-US-Handelsspanne zu messen, filtert Tage heraus, an denen die Spanne einen konfigurierbaren Pip-Schwellenwert überschreitet, und handelt dann Ausbrüche, die vollständig außerhalb dieser Spanne auftreten. Pro Handelstag ist nur ein Long- und ein Short-Versuch erlaubt.
Funktionsweise
- Sitzungsverfolgung – zu Beginn der konfigurierten US-Sitzungsstunde sperrt die Strategie die von den 24 letzten abgeschlossenen Kerzen (ohne den aktuellen Balken) erfasste EU-Spanne. Die Spanne wird für 3- oder 5-stellige Forex-Kurse automatisch auf Pip-Werte angepasst.
- Spannenfilter – der Handel wird nur aktiviert, wenn die erfasste EU-Spanne kleiner ist als der Schwellenwert Kleine EU-Sitzung (Pips).
- Ausbruchsvalidierung – während der erlaubten US-Sitzungsstunden, und nur zwischen
(EU-Startstunde + 5) und (EU-Startstunde + 10), sucht die Strategie nach Kerzen, deren gesamter Körper außerhalb der gespeicherten Spanne mit einem zusätzlichen in Punkten gemessenen Puffer gehandelt hat.
- Orderausführung – eine Market-Kauf-Order wird gesendet, wenn das Tief des Balkens über dem oberen Ende der Spanne plus Puffer bleibt. Eine Market-Verkauf-Order wird gesendet, wenn das Hoch des Balkens unter dem unteren Ende der Spanne minus Puffer bleibt. Long- und Short-Trades sind unabhängige Flags, sodass jede Richtung einmal pro Tag versucht werden kann.
- Risikomanagement – Stop-Loss- und Take-Profit-Niveaus werden in Pips definiert, in absolute Preisabstände umgerechnet und auf jeder abgeschlossenen Kerze mithilfe von Hoch/Tief-Extremen verfolgt.
Parameter
- EU-Sitzungsstart / US-Sitzungsstart / US-Sitzungsende – Stunden (0–23), die definieren, wann das EU-Monitoring beginnt und wann das US-Ausbruchsfenster geöffnet ist.
- Kleine EU-Sitzung (Pips) – maximale Größe der EU-Spanne, die noch den Handel erlaubt.
- Handel am Montag – aktiviert oder deaktiviert den Montags-Handel bei gleichzeitiger Blockierung von Wochenenden.
- Stop-Loss (Pips) – Abstand zwischen Einstiegspreis und Schutz-Stop, automatisch nach Tick-Größe und Stellen skaliert.
- Take-Profit (Pips) – Gewinnziel-Abstand, auf dieselbe Weise wie der Stop behandelt.
- Ausbruchspuffer (Punkte) – Anzahl der Preisschritte, die zum Ausbruchsauslöser hinzugefügt werden, sodass der bestätigende Balken vollständig jenseits der gespeicherten Spanne liegen muss.
- Kerzentyp – Datentyp für das Kerzenabonnement; standardmäßig 15-Minuten-Zeitrahmen, da das ursprüngliche Skript für M15-Charts konzipiert wurde.
Zusätzliche Hinweise
- Die Strategie setzt Netting-Konten voraus: Schutzlevel glätten die gesamte Position mithilfe von Market-Orders.
- Der Tagesstatus wird um Mitternacht zurückgesetzt, sodass Spanne und Ausbruchs-Flags nicht zwischen Sitzungen überlaufen, während offene Positionen ihre Preisziele behalten.
- Da Stop-Loss- und Take-Profit-Niveaus mit Kerzenextremen simuliert werden, werden Intrabar-Spitzen, die nicht in historischen Balken erscheinen, nicht erkannt.
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;
/// <summary>
/// Breakout strategy that trades after a tight consolidation range.
/// Captures the range from a "quiet" session, then trades breakouts in the following session.
/// </summary>
public class EurUsdSessionBreakoutStrategy : Strategy
{
private readonly StrategyParam<int> _euSessionLengthBars;
private readonly StrategyParam<int> _startHourRangeSession;
private readonly StrategyParam<int> _startHourTradeSession;
private readonly StrategyParam<int> _endHourTradeSession;
private readonly StrategyParam<decimal> _smallSessionThreshold;
private readonly StrategyParam<decimal> _stopLossDistance;
private readonly StrategyParam<decimal> _takeProfitDistance;
private readonly StrategyParam<decimal> _breakoutBuffer;
private readonly StrategyParam<DataType> _candleType;
private Highest _highest = null!;
private Lowest _lowest = null!;
private decimal _currentHighest;
private decimal _currentLowest;
private decimal _entryPrice;
private decimal _stopPrice;
private decimal _takePrice;
private DateTime _currentDate;
public EurUsdSessionBreakoutStrategy()
{
_startHourRangeSession = Param(nameof(StartHourRangeSession), 0)
.SetDisplay("Range Session Start", "Start hour of the consolidation range session", "Schedule");
_startHourTradeSession = Param(nameof(StartHourTradeSession), 8)
.SetDisplay("Trade Session Start", "Start hour of the trading session", "Schedule");
_endHourTradeSession = Param(nameof(EndHourTradeSession), 20)
.SetDisplay("Trade Session End", "End hour of the trading session", "Schedule");
_smallSessionThreshold = Param(nameof(SmallSessionThreshold), 200m)
.SetDisplay("Small Session Threshold", "Maximum range session price range to trigger trading", "Risk");
_stopLossDistance = Param(nameof(StopLossDistance), 5m)
.SetDisplay("Stop Loss Distance", "Stop loss distance in price units", "Risk");
_takeProfitDistance = Param(nameof(TakeProfitDistance), 8m)
.SetDisplay("Take Profit Distance", "Take profit distance in price units", "Risk");
_breakoutBuffer = Param(nameof(BreakoutBuffer), 0m)
.SetDisplay("Breakout Buffer", "Extra price buffer added to breakout trigger", "Entries");
_euSessionLengthBars = Param(nameof(EuSessionLengthBars), 10)
.SetRange(1, 72)
.SetDisplay("Range Session Length (bars)", "Number of bars representing the range session", "Schedule");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle type used for calculations", "General");
}
public int StartHourRangeSession
{
get => _startHourRangeSession.Value;
set => _startHourRangeSession.Value = value;
}
public int StartHourTradeSession
{
get => _startHourTradeSession.Value;
set => _startHourTradeSession.Value = value;
}
public int EndHourTradeSession
{
get => _endHourTradeSession.Value;
set => _endHourTradeSession.Value = value;
}
public decimal SmallSessionThreshold
{
get => _smallSessionThreshold.Value;
set => _smallSessionThreshold.Value = value;
}
public decimal StopLossDistance
{
get => _stopLossDistance.Value;
set => _stopLossDistance.Value = value;
}
public decimal TakeProfitDistance
{
get => _takeProfitDistance.Value;
set => _takeProfitDistance.Value = value;
}
public decimal BreakoutBuffer
{
get => _breakoutBuffer.Value;
set => _breakoutBuffer.Value = value;
}
public int EuSessionLengthBars
{
get => _euSessionLengthBars.Value;
set => _euSessionLengthBars.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_highest = null!;
_lowest = null!;
_currentHighest = 0;
_currentLowest = 0;
_entryPrice = 0;
_stopPrice = 0;
_takePrice = 0;
_currentDate = default;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_highest = new Highest { Length = EuSessionLengthBars };
_lowest = new Lowest { Length = EuSessionLengthBars };
_currentDate = time.Date;
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
// Manage protective exits first
ManageActivePosition(candle);
// Update rolling highest/lowest
var previousHighest = _currentHighest;
var previousLowest = _currentLowest;
_currentHighest = _highest.Process(candle).ToDecimal();
_currentLowest = _lowest.Process(candle).ToDecimal();
if (!_highest.IsFormed || !_lowest.IsFormed)
return;
if (previousHighest <= 0 || previousLowest <= 0)
return;
if (Position != 0)
return;
// Breakout above previous rolling highest
if (candle.ClosePrice > previousHighest + BreakoutBuffer)
{
BuyMarket();
SetLongTargets(candle.ClosePrice);
}
// Breakout below previous rolling lowest
else if (candle.ClosePrice < previousLowest - BreakoutBuffer)
{
SellMarket();
SetShortTargets(candle.ClosePrice);
}
}
private void ManageActivePosition(ICandleMessage candle)
{
if (Position == 0)
return;
if (Position > 0)
{
var exitByStop = StopLossDistance > 0m && candle.LowPrice <= _stopPrice;
var exitByTake = TakeProfitDistance > 0m && candle.HighPrice >= _takePrice;
if (exitByStop || exitByTake)
{
SellMarket();
ClearTargets();
}
}
else if (Position < 0)
{
var exitByStop = StopLossDistance > 0m && candle.HighPrice >= _stopPrice;
var exitByTake = TakeProfitDistance > 0m && candle.LowPrice <= _takePrice;
if (exitByStop || exitByTake)
{
BuyMarket();
ClearTargets();
}
}
}
private void SetLongTargets(decimal entryPrice)
{
_entryPrice = entryPrice;
_stopPrice = entryPrice - StopLossDistance;
_takePrice = entryPrice + TakeProfitDistance;
}
private void SetShortTargets(decimal entryPrice)
{
_entryPrice = entryPrice;
_stopPrice = entryPrice + StopLossDistance;
_takePrice = entryPrice - TakeProfitDistance;
}
private void ClearTargets()
{
_entryPrice = 0m;
_stopPrice = 0m;
_takePrice = 0m;
}
private void ResetDailyState(DateTime date)
{
_currentDate = date;
if (Position == 0)
ClearTargets();
}
}
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, CandleIndicatorValue
from StockSharp.Algo.Strategies import Strategy
class eur_usd_session_breakout_strategy(Strategy):
"""
Session breakout strategy using rolling highest/lowest channels.
Buys on breakout above rolling highest, sells on breakout below rolling lowest.
Manual SL/TP management.
"""
def __init__(self):
super(eur_usd_session_breakout_strategy, self).__init__()
self._eu_session_length = self.Param("EuSessionLengthBars", 10) \
.SetDisplay("Range Session Length", "Number of bars for range", "Schedule")
self._stop_loss_dist = self.Param("StopLossDistance", 5.0) \
.SetDisplay("Stop Loss Distance", "Stop loss in price units", "Risk")
self._take_profit_dist = self.Param("TakeProfitDistance", 8.0) \
.SetDisplay("Take Profit Distance", "Take profit in price units", "Risk")
self._breakout_buffer = self.Param("BreakoutBuffer", 0.0) \
.SetDisplay("Breakout Buffer", "Extra buffer for breakout trigger", "Entries")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle type", "General")
self._highest = None
self._lowest = None
self._current_highest = 0.0
self._current_lowest = 0.0
self._entry_price = 0.0
self._stop_price = 0.0
self._take_price = 0.0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(eur_usd_session_breakout_strategy, self).OnReseted()
self._highest = None
self._lowest = None
self._current_highest = 0.0
self._current_lowest = 0.0
self._entry_price = 0.0
self._stop_price = 0.0
self._take_price = 0.0
def OnStarted2(self, time):
super(eur_usd_session_breakout_strategy, self).OnStarted2(time)
self._highest = Highest()
self._highest.Length = self._eu_session_length.Value
self._lowest = Lowest()
self._lowest.Length = self._eu_session_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
self._manage_position(candle)
prev_highest = self._current_highest
prev_lowest = self._current_lowest
h_result = self._highest.Process(CandleIndicatorValue(self._highest, candle))
l_result = self._lowest.Process(CandleIndicatorValue(self._lowest, candle))
self._current_highest = float(h_result) if not h_result.IsEmpty else self._current_highest
self._current_lowest = float(l_result) if not l_result.IsEmpty else self._current_lowest
if not self._highest.IsFormed or not self._lowest.IsFormed:
return
if prev_highest <= 0 or prev_lowest <= 0:
return
if self.Position != 0:
return
close = float(candle.ClosePrice)
buf = float(self._breakout_buffer.Value)
if close > prev_highest + buf:
self.BuyMarket()
self._set_long_targets(close)
elif close < prev_lowest - buf:
self.SellMarket()
self._set_short_targets(close)
def _manage_position(self, candle):
if self.Position == 0:
return
low = float(candle.LowPrice)
high = float(candle.HighPrice)
sl_dist = float(self._stop_loss_dist.Value)
tp_dist = float(self._take_profit_dist.Value)
if self.Position > 0:
exit_stop = sl_dist > 0 and low <= self._stop_price
exit_take = tp_dist > 0 and high >= self._take_price
if exit_stop or exit_take:
self.SellMarket()
self._clear_targets()
elif self.Position < 0:
exit_stop = sl_dist > 0 and high >= self._stop_price
exit_take = tp_dist > 0 and low <= self._take_price
if exit_stop or exit_take:
self.BuyMarket()
self._clear_targets()
def _set_long_targets(self, price):
self._entry_price = price
self._stop_price = price - float(self._stop_loss_dist.Value)
self._take_price = price + float(self._take_profit_dist.Value)
def _set_short_targets(self, price):
self._entry_price = price
self._stop_price = price + float(self._stop_loss_dist.Value)
self._take_price = price - float(self._take_profit_dist.Value)
def _clear_targets(self):
self._entry_price = 0.0
self._stop_price = 0.0
self._take_price = 0.0
def CreateClone(self):
return eur_usd_session_breakout_strategy()