Eröffnungsbereich-Ausbruch-Strategie
Die Eröffnungsbereich-Ausbruch-Strategie verfolgt die höchsten und niedrigsten Preise während der ersten Minuten einer Handelssitzung. Nach dem Ende des Bereichs werden Ausbruchsorders jenseits des Bereichs mit einem konfigurierbaren Puffer platziert. Ziele werden aus einem Gewinn-Risiko-Verhältnis abgeleitet, während Stops auf der gegenüberliegenden Seite des Bereichs gesetzt werden.
Details
- Einstiegskriterien:
- Nach dem Eröffnungsbereich Long gehen, wenn der Preis über dem Hoch plus Puffer schließt.
- Short gehen, wenn der Preis unter dem Tief minus Puffer schließt.
- Long/Short: Beide
- Ausstiegskriterien:
- Stop und Ziel basierend auf Bereich und Gewinn-Risiko-Verhältnis.
- Stops: Ja
- Standardwerte:
RangeMinutes= 15RewardRisk= 2.0EntryBuffer= 0.0001SessionStart= 08:00
- Filter:
- Kategorie: Ausbruch
- Richtung: Beide
- Indikatoren: Keine
- Stops: Ja
- Komplexität: Niedrig
- Zeitrahmen: Beliebig
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Mittel
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>
/// Opening Range Breakout Strategy.
/// Tracks recent high/low range using BB and trades breakouts.
/// Uses EMA as trend filter to determine direction.
/// </summary>
public class OpeningRangeBreakoutStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _bbLength;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<int> _cooldownBars;
private BollingerBands _bb;
private ExponentialMovingAverage _ema;
private int _cooldownRemaining;
private decimal _entryPrice;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int BbLength
{
get => _bbLength.Value;
set => _bbLength.Value = value;
}
public int EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
public OpeningRangeBreakoutStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_bbLength = Param(nameof(BbLength), 20)
.SetGreaterThanZero()
.SetDisplay("BB Length", "Bollinger Bands period", "Indicators");
_emaLength = Param(nameof(EmaLength), 50)
.SetGreaterThanZero()
.SetDisplay("EMA Length", "EMA trend filter period", "Indicators");
_cooldownBars = Param(nameof(CooldownBars), 10)
.SetDisplay("Cooldown Bars", "Bars between trades", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_bb = null;
_ema = null;
_cooldownRemaining = 0;
_entryPrice = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_bb = new BollingerBands { Length = BbLength, Width = 2m };
_ema = new ExponentialMovingAverage { Length = EmaLength };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(_bb, _ema, OnProcess)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _bb);
DrawIndicator(area, _ema);
DrawOwnTrades(area);
}
}
private void OnProcess(ICandleMessage candle, IIndicatorValue bbValue, IIndicatorValue emaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_bb.IsFormed || !_ema.IsFormed)
return;
if (bbValue.IsEmpty || emaValue.IsEmpty)
return;
var bb = (BollingerBandsValue)bbValue;
if (bb.UpBand is not decimal upper || bb.LowBand is not decimal lower || bb.MovingAverage is not decimal mid)
return;
var emaVal = emaValue.ToDecimal();
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
return;
}
var price = candle.ClosePrice;
// Buy: price breaks above upper BB and above EMA (uptrend)
if (price > upper && price > emaVal && Position <= 0)
{
if (Position < 0)
BuyMarket(Math.Abs(Position));
BuyMarket(Volume);
_entryPrice = price;
_cooldownRemaining = CooldownBars;
}
// Sell: price breaks below lower BB and below EMA (downtrend)
else if (price < lower && price < emaVal && Position >= 0)
{
if (Position > 0)
SellMarket(Math.Abs(Position));
SellMarket(Volume);
_entryPrice = price;
_cooldownRemaining = CooldownBars;
}
// Exit long: price returns to mid BB
else if (Position > 0 && price < mid)
{
SellMarket(Math.Abs(Position));
_entryPrice = 0;
_cooldownRemaining = CooldownBars;
}
// Exit short: price returns to mid BB
else if (Position < 0 && price > mid)
{
BuyMarket(Math.Abs(Position));
_entryPrice = 0;
_cooldownRemaining = CooldownBars;
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import BollingerBands, ExponentialMovingAverage, IndicatorHelper
from StockSharp.Algo.Strategies import Strategy
class opening_range_breakout_strategy(Strategy):
"""Opening Range Breakout Strategy."""
def __init__(self):
super(opening_range_breakout_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._bb_length = self.Param("BbLength", 20) \
.SetDisplay("BB Length", "Bollinger Bands period", "Indicators")
self._ema_length = self.Param("EmaLength", 50) \
.SetDisplay("EMA Length", "EMA trend filter period", "Indicators")
self._cooldown_bars = self.Param("CooldownBars", 10) \
.SetDisplay("Cooldown Bars", "Bars between trades", "Risk")
self._bb = None
self._ema = None
self._cooldown_remaining = 0
self._entry_price = 0.0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(opening_range_breakout_strategy, self).OnReseted()
self._bb = None
self._ema = None
self._cooldown_remaining = 0
self._entry_price = 0.0
def OnStarted2(self, time):
super(opening_range_breakout_strategy, self).OnStarted2(time)
self._bb = BollingerBands()
self._bb.Length = int(self._bb_length.Value)
self._bb.Width = 2.0
self._ema = ExponentialMovingAverage()
self._ema.Length = int(self._ema_length.Value)
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(self._bb, self._ema, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._bb)
self.DrawIndicator(area, self._ema)
self.DrawOwnTrades(area)
def _on_process(self, candle, bb_value, ema_value):
if candle.State != CandleStates.Finished:
return
if not self._bb.IsFormed or not self._ema.IsFormed:
return
if bb_value.IsEmpty or ema_value.IsEmpty:
return
if bb_value.UpBand is None or bb_value.LowBand is None or bb_value.MovingAverage is None:
return
upper = float(bb_value.UpBand)
lower = float(bb_value.LowBand)
mid = float(bb_value.MovingAverage)
ema_val = float(IndicatorHelper.ToDecimal(ema_value))
if not self.IsFormedAndOnlineAndAllowTrading():
return
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
return
price = float(candle.ClosePrice)
cooldown = int(self._cooldown_bars.Value)
if price > upper and price > ema_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket(Math.Abs(self.Position))
self.BuyMarket(self.Volume)
self._entry_price = price
self._cooldown_remaining = cooldown
elif price < lower and price < ema_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket(Math.Abs(self.Position))
self.SellMarket(self.Volume)
self._entry_price = price
self._cooldown_remaining = cooldown
elif self.Position > 0 and price < mid:
self.SellMarket(Math.Abs(self.Position))
self._entry_price = 0.0
self._cooldown_remaining = cooldown
elif self.Position < 0 and price > mid:
self.BuyMarket(Math.Abs(self.Position))
self._entry_price = 0.0
self._cooldown_remaining = cooldown
def CreateClone(self):
return opening_range_breakout_strategy()