Esta estrategia define un rango de apertura y opera las rupturas por encima o por debajo de él. Tras el cierre de la ventana del rango de apertura, si la amplitud supera un porcentaje del precio de cierre, se preparan órdenes stop en los límites del rango. Las posiciones utilizan un stop loss y un objetivo de beneficio basados en el tamaño del rango. Opcionalmente solo se realiza una operación por día, y las operaciones perdedoras pueden revertirse. Todas las posiciones se cierran al final de la sesión.
Detalles
Criterios de entrada:
Largo: el precio rompe por encima del máximo del rango de apertura.
Corto: el precio rompe por debajo del mínimo del rango de apertura.
Largo/Corto: Ambos.
Criterios de salida:
Stop loss o take profit basado en el rango.
Cierre al final del día.
Stops: Sí.
Valores predeterminados:
Rango de apertura = 09:30–10:15.
Fin del día = 15:45.
MinRangePercent = 0.35.
RewardRisk = 1.1.
Retrace = 0.5.
Filtros:
Categoría: Ruptura
Dirección: Ambos
Indicadores: Precio
Stops: Sí
Complejidad: Moderado
Marco temporal: Intradía
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class OpeningRangeBreakout2Strategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private decimal _orHigh;
private decimal _orLow;
private bool _tradeTakenToday;
private bool _wasInOr;
private DateTime _currentDay;
private bool _orEstablished;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public OpeningRangeBreakout2Strategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame());
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_orHigh = 0;
_orLow = 0;
_tradeTakenToday = false;
_wasInOr = false;
_currentDay = default;
_orEstablished = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_orHigh = 0;
_orLow = 0;
_tradeTakenToday = false;
_wasInOr = false;
_currentDay = default;
_orEstablished = false;
var sma = new SimpleMovingAverage { Length = 20 };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sma, (candle, smaVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!sma.IsFormed)
return;
var day = candle.OpenTime.Date;
if (_currentDay != day)
{
_currentDay = day;
_orHigh = 0;
_orLow = 0;
_tradeTakenToday = false;
_orEstablished = false;
}
var hour = candle.OpenTime.TimeOfDay.TotalHours;
var inOr = hour >= 0 && hour < 1;
if (inOr)
{
_orHigh = _orHigh > 0 ? Math.Max(_orHigh, candle.HighPrice) : candle.HighPrice;
_orLow = _orLow > 0 ? Math.Min(_orLow, candle.LowPrice) : candle.LowPrice;
}
if (_wasInOr && !inOr && _orHigh > 0 && _orLow > 0)
{
var range = _orHigh - _orLow;
if (range > 0)
_orEstablished = true;
}
// Only one entry per day, no exit logic (just entry)
if (!_tradeTakenToday && _orEstablished && !inOr)
{
if (candle.ClosePrice > _orHigh && candle.ClosePrice > smaVal && Position <= 0)
{
BuyMarket();
_tradeTakenToday = true;
}
else if (candle.ClosePrice < _orLow && candle.ClosePrice < smaVal && Position >= 0)
{
SellMarket();
_tradeTakenToday = true;
}
}
_wasInOr = inOr;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sma);
DrawOwnTrades(area);
}
}
}
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 SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class opening_range_breakout2_strategy(Strategy):
def __init__(self):
super(opening_range_breakout2_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5)))
self._or_high = 0.0
self._or_low = 0.0
self._trade_taken_today = False
self._was_in_or = False
self._current_day = None
self._or_established = False
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
def OnReseted(self):
super(opening_range_breakout2_strategy, self).OnReseted()
self._or_high = 0.0
self._or_low = 0.0
self._trade_taken_today = False
self._was_in_or = False
self._current_day = None
self._or_established = False
def OnStarted2(self, time):
super(opening_range_breakout2_strategy, self).OnStarted2(time)
self._or_high = 0.0
self._or_low = 0.0
self._trade_taken_today = False
self._was_in_or = False
self._current_day = None
self._or_established = False
self._sma = SimpleMovingAverage()
self._sma.Length = 20
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._sma, self.OnProcess).Start()
def OnProcess(self, candle, sma_val):
if candle.State != CandleStates.Finished:
return
if not self._sma.IsFormed:
return
sv = float(sma_val)
close = float(candle.ClosePrice)
high = float(candle.HighPrice)
low = float(candle.LowPrice)
day = candle.OpenTime.Date
if self._current_day is None or self._current_day != day:
self._current_day = day
self._or_high = 0.0
self._or_low = 0.0
self._trade_taken_today = False
self._or_established = False
hour = candle.OpenTime.TimeOfDay.TotalHours
in_or = hour >= 0 and hour < 1
if in_or:
self._or_high = max(self._or_high, high) if self._or_high > 0 else high
self._or_low = min(self._or_low, low) if self._or_low > 0 else low
if self._was_in_or and not in_or and self._or_high > 0 and self._or_low > 0:
rng = self._or_high - self._or_low
if rng > 0:
self._or_established = True
if not self._trade_taken_today and self._or_established and not in_or:
if close > self._or_high and close > sv and self.Position <= 0:
self.BuyMarket()
self._trade_taken_today = True
elif close < self._or_low and close < sv and self.Position >= 0:
self.SellMarket()
self._trade_taken_today = True
self._was_in_or = in_or
def CreateClone(self):
return opening_range_breakout2_strategy()