IU Eröffnungsbereichs-Ausbruch-Strategie
Die IU Opening Range Breakout Strategie überwacht das Hoch und Tief der ersten Bar jeder Session und handelt Ausbrüche in beide Richtungen. Stops verwenden das Extremum der vorherigen Bar und Ziele werden aus einem konfigurierbaren Risiko-Ertrags-Verhältnis abgeleitet. Alle Positionen werden zur benutzerdefinierten Endzeit geschlossen.
Details
- Einstiegskriterien:
- Long, wenn der Schluss über das Hoch der ersten Bar kreuzt.
- Short, wenn der Schluss unter das Tief der ersten Bar kreuzt.
- Long/Short: Beide
- Ausstiegskriterien:
- Stop am Tief/Hoch der vorherigen Bar.
- Ziel basierend auf dem Risiko-Ertrags-Verhältnis.
- Alle Positionen bei
EndTimeschließen.
- Stops: Ja
- Standardwerte:
RiskReward= 2.0MaxTrades= 2EndTime= 15:00CandleType= 1 Minute
- Filter:
- Kategorie: Ausbruch
- Richtung: Beide
- Indikatoren: Keine
- Stops: Ja
- Komplexität: Niedrig
- Zeitrahmen: Beliebig
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Mittel
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>
/// IU Opening Range Breakout Strategy.
/// Trades breakouts of the first session bar with risk to reward management and daily trade limit.
/// </summary>
public class IUOpeningRangeBreakoutStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<decimal> _riskReward;
private readonly StrategyParam<int> _maxTrades;
private readonly StrategyParam<int> _cooldownDays;
private readonly StrategyParam<TimeSpan> _endTime;
private decimal _orHigh;
private decimal _orLow;
private bool _rangeSet;
private decimal _stopPrice;
private decimal _targetPrice;
private int _tradesToday;
private DateTime _currentDay;
private DateTime _nextTradeDate;
private decimal _prevHigh;
private decimal _prevLow;
private int _orBarCount;
/// <summary>
/// Candle type for processing.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Risk to reward ratio.
/// </summary>
public decimal RiskReward
{
get => _riskReward.Value;
set => _riskReward.Value = value;
}
/// <summary>
/// Maximum number of trades per day.
/// </summary>
public int MaxTrades
{
get => _maxTrades.Value;
set => _maxTrades.Value = value;
}
/// <summary>
/// Minimum days between entries.
/// </summary>
public int CooldownDays
{
get => _cooldownDays.Value;
set => _cooldownDays.Value = value;
}
/// <summary>
/// Time to close all positions.
/// </summary>
public TimeSpan EndTime
{
get => _endTime.Value;
set => _endTime.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public IUOpeningRangeBreakoutStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
_riskReward = Param(nameof(RiskReward), 2m)
.SetGreaterThanZero()
.SetDisplay("Risk/Reward", "Risk to reward ratio", "General")
.SetOptimize(1m, 3m, 0.5m);
_maxTrades = Param(nameof(MaxTrades), 3)
.SetGreaterThanZero()
.SetDisplay("Max Trades", "Maximum trades per day", "General");
_cooldownDays = Param(nameof(CooldownDays), 3)
.SetDisplay("Cooldown Days", "Minimum days between entries", "General");
_endTime = Param(nameof(EndTime), new TimeSpan(15, 0, 0))
.SetDisplay("End Time", "Daily close time (UTC)", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_orHigh = 0m;
_orLow = 0m;
_rangeSet = false;
_stopPrice = 0m;
_targetPrice = 0m;
_tradesToday = 0;
_currentDay = default;
_nextTradeDate = DateTime.MinValue;
_prevHigh = 0m;
_prevLow = 0m;
_orBarCount = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_currentDay = time.Date;
_nextTradeDate = DateTime.MinValue;
var dummyEma1 = new ExponentialMovingAverage { Length = 10 };
var dummyEma2 = new ExponentialMovingAverage { Length = 20 };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(dummyEma1, dummyEma2, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal d1, decimal d2)
{
if (candle.State != CandleStates.Finished)
return;
var openTime = candle.OpenTime;
// Reset for new day
if (openTime.Date != _currentDay)
{
_currentDay = openTime.Date;
_rangeSet = false;
_tradesToday = 0;
_orBarCount = 0;
_orHigh = 0m;
_orLow = decimal.MaxValue;
}
_orBarCount++;
if (!_rangeSet)
{
_orHigh = Math.Max(_orHigh, candle.HighPrice);
_orLow = Math.Min(_orLow, candle.LowPrice);
if (_orBarCount >= 2)
_rangeSet = true;
_prevHigh = candle.HighPrice;
_prevLow = candle.LowPrice;
return;
}
// Close positions at end of day
if (openTime.TimeOfDay >= EndTime && Position != 0)
{
if (Position > 0)
SellMarket();
else if (Position < 0)
BuyMarket();
}
if (Position == 0 && _tradesToday < MaxTrades && openTime.Date >= _nextTradeDate)
{
if (candle.HighPrice > _orHigh)
{
BuyMarket();
_tradesToday++;
_nextTradeDate = openTime.Date.AddDays(CooldownDays);
_stopPrice = _prevLow;
_targetPrice = candle.ClosePrice + (candle.ClosePrice - _stopPrice) * RiskReward;
}
else if (candle.LowPrice < _orLow)
{
SellMarket();
_tradesToday++;
_nextTradeDate = openTime.Date.AddDays(CooldownDays);
_stopPrice = _prevHigh;
_targetPrice = candle.ClosePrice - (_stopPrice - candle.ClosePrice) * RiskReward;
}
}
else if (Position > 0)
{
if (candle.LowPrice <= _stopPrice || candle.HighPrice >= _targetPrice)
SellMarket();
}
else if (Position < 0)
{
if (candle.HighPrice >= _stopPrice || candle.LowPrice <= _targetPrice)
BuyMarket();
}
_prevHigh = candle.HighPrice;
_prevLow = candle.LowPrice;
}
}
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.Strategies import Strategy
class iu_opening_range_breakout_strategy(Strategy):
"""
IU Opening Range Breakout: trades breakouts of the first session bars
with risk/reward management and daily trade limit.
"""
def __init__(self):
super(iu_opening_range_breakout_strategy, self).__init__()
self._risk_reward = self.Param("RiskReward", 2.0) \
.SetDisplay("Risk/Reward", "Risk to reward ratio", "General")
self._max_trades = self.Param("MaxTrades", 3) \
.SetDisplay("Max Trades", "Maximum trades per day", "General")
self._cooldown_days = self.Param("CooldownDays", 3) \
.SetDisplay("Cooldown Days", "Minimum days between entries", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._or_high = 0.0
self._or_low = 0.0
self._range_set = False
self._stop_price = 0.0
self._target_price = 0.0
self._trades_today = 0
self._current_day = None
self._prev_high = 0.0
self._prev_low = 0.0
self._or_bar_count = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(iu_opening_range_breakout_strategy, self).OnReseted()
self._or_high = 0.0
self._or_low = 0.0
self._range_set = False
self._stop_price = 0.0
self._target_price = 0.0
self._trades_today = 0
self._current_day = None
self._prev_high = 0.0
self._prev_low = 0.0
self._or_bar_count = 0
def OnStarted2(self, time):
super(iu_opening_range_breakout_strategy, self).OnStarted2(time)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._process_candle).Start()
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
high = float(candle.HighPrice)
low = float(candle.LowPrice)
close = float(candle.ClosePrice)
open_time = candle.OpenTime
day = open_time.Date
if self._current_day is None or self._current_day != day:
self._current_day = day
self._range_set = False
self._trades_today = 0
self._or_bar_count = 0
self._or_high = 0.0
self._or_low = float('inf')
self._or_bar_count += 1
if not self._range_set:
self._or_high = max(self._or_high, high)
self._or_low = min(self._or_low, low)
if self._or_bar_count >= 2:
self._range_set = True
self._prev_high = high
self._prev_low = low
return
if self.Position == 0 and self._trades_today < self._max_trades.Value:
if high > self._or_high:
self.BuyMarket()
self._trades_today += 1
self._stop_price = self._prev_low
self._target_price = close + (close - self._stop_price) * self._risk_reward.Value
elif low < self._or_low:
self.SellMarket()
self._trades_today += 1
self._stop_price = self._prev_high
self._target_price = close - (self._stop_price - close) * self._risk_reward.Value
elif self.Position > 0:
if low <= self._stop_price or high >= self._target_price:
self.SellMarket()
elif self.Position < 0:
if high >= self._stop_price or low <= self._target_price:
self.BuyMarket()
self._prev_high = high
self._prev_low = low
def CreateClone(self):
return iu_opening_range_breakout_strategy()