Estrategia de Ruptura de Máximos y Mínimos con Análisis Estadístico
Opera rupturas de los niveles de máximo o mínimo del marco temporal seleccionado. La estrategia puede entrar en largo o corto según la opción configurada y cierra la posición después de un número fijo de barras.
Detalles
- Criterios de entrada: El cierre cruza el nivel de máximo o mínimo seleccionado.
- Largo/Corto: Ambas direcciones.
- Criterios de salida: Señal opuesta o después de HoldingPeriod barras.
- Stops: No.
- Valores predeterminados:
EntryOption= LongAtHighTimeframeOption= DailyHoldingPeriod= 5CandleType= TimeSpan.FromMinutes(5)
- Filtros:
- Categoría: Ruptura
- Dirección: Ambos
- Indicadores: High, Low
- Stops: No
- Complejidad: Básico
- Marco temporal: Intradía (5m)
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Medio
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// High Low Breakout Statistical Analysis strategy.
/// Tracks the high and low of the previous completed day, week or month (TimeframeOption). Depending on EntryOption it buys or
/// sells when the close crosses above the previous high, or buys or sells when the close crosses below the previous low. The
/// position is closed after HoldingPeriod candles.
/// </summary>
public class HighLowBreakoutStatisticalAnalysisStrategy : Strategy
{
/// <summary>
/// Which level to trade and in which direction.
/// </summary>
public enum EntryOptions
{
/// <summary>
/// Buy when the close crosses above the previous high.
/// </summary>
LongAtHigh,
/// <summary>
/// Sell when the close crosses above the previous high.
/// </summary>
ShortAtHigh,
/// <summary>
/// Buy when the close crosses below the previous low.
/// </summary>
LongAtLow,
/// <summary>
/// Sell when the close crosses below the previous low.
/// </summary>
ShortAtLow,
}
/// <summary>
/// Period the reference high and low are taken from.
/// </summary>
public enum TimeframeOptions
{
/// <summary>
/// Previous day.
/// </summary>
Daily,
/// <summary>
/// Previous week.
/// </summary>
Weekly,
/// <summary>
/// Previous month.
/// </summary>
Monthly,
}
private readonly StrategyParam<EntryOptions> _entryOption;
private readonly StrategyParam<TimeframeOptions> _timeframeOption;
private readonly StrategyParam<int> _holdingPeriod;
private readonly StrategyParam<DataType> _candleType;
private DateTime? _periodStart;
private decimal _periodHigh;
private decimal _periodLow;
private decimal? _prevHigh;
private decimal? _prevLow;
private decimal? _prevClose;
private int _barsInPosition;
/// <summary>
/// Which level to trade and in which direction.
/// </summary>
public EntryOptions EntryOption
{
get => _entryOption.Value;
set => _entryOption.Value = value;
}
/// <summary>
/// Period the reference high and low are taken from.
/// </summary>
public TimeframeOptions TimeframeOption
{
get => _timeframeOption.Value;
set => _timeframeOption.Value = value;
}
/// <summary>
/// Candles to hold a position.
/// </summary>
public int HoldingPeriod
{
get => _holdingPeriod.Value;
set => _holdingPeriod.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public HighLowBreakoutStatisticalAnalysisStrategy()
{
_entryOption = Param(nameof(EntryOption), EntryOptions.LongAtHigh)
.SetDisplay("Entry Option", "Which level to trade and in which direction", "Trading");
_timeframeOption = Param(nameof(TimeframeOption), TimeframeOptions.Daily)
.SetDisplay("Timeframe Option", "Period the reference high and low are taken from", "Trading");
_holdingPeriod = Param(nameof(HoldingPeriod), 5)
.SetGreaterThanZero()
.SetDisplay("Holding Period", "Candles to hold a position", "Trading");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
ResetState();
}
private void ResetState()
{
_periodStart = null;
_periodHigh = 0m;
_periodLow = 0m;
_prevHigh = null;
_prevLow = null;
_prevClose = null;
_barsInPosition = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
ResetState();
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private DateTime GetPeriodStart(DateTime time)
{
var date = time.Date;
return TimeframeOption switch
{
TimeframeOptions.Weekly => date.AddDays(-(((int)date.DayOfWeek + 6) % 7)),
TimeframeOptions.Monthly => new DateTime(date.Year, date.Month, 1, 0, 0, 0, date.Kind),
_ => date,
};
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var periodStart = GetPeriodStart(candle.OpenTime);
if (_periodStart != periodStart)
{
if (_periodStart != null)
{
_prevHigh = _periodHigh;
_prevLow = _periodLow;
}
_periodStart = periodStart;
_periodHigh = candle.HighPrice;
_periodLow = candle.LowPrice;
}
else
{
_periodHigh = Math.Max(_periodHigh, candle.HighPrice);
_periodLow = Math.Min(_periodLow, candle.LowPrice);
}
var close = candle.ClosePrice;
var prevClose = _prevClose;
_prevClose = close;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (Position != 0)
{
_barsInPosition++;
if (_barsInPosition >= HoldingPeriod)
{
if (Position > 0)
SellMarket(Position);
else
BuyMarket(-Position);
}
return;
}
if (prevClose is not decimal lastClose || _prevHigh is not decimal high || _prevLow is not decimal low)
return;
var crossHigh = lastClose <= high && close > high;
var crossLow = lastClose >= low && close < low;
switch (EntryOption)
{
case EntryOptions.LongAtHigh when crossHigh:
case EntryOptions.LongAtLow when crossLow:
BuyMarket(Volume);
_barsInPosition = 0;
break;
case EntryOptions.ShortAtHigh when crossHigh:
case EntryOptions.ShortAtLow when crossLow:
SellMarket(Volume);
_barsInPosition = 0;
break;
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
# EntryOption values, matching the C# EntryOptions enum.
ENTRY_LONG_AT_HIGH = 0
ENTRY_SHORT_AT_HIGH = 1
ENTRY_LONG_AT_LOW = 2
ENTRY_SHORT_AT_LOW = 3
# TimeframeOption values, matching the C# TimeframeOptions enum.
TIMEFRAME_DAILY = 0
TIMEFRAME_WEEKLY = 1
TIMEFRAME_MONTHLY = 2
class high_low_breakout_statistical_analysis_strategy(Strategy):
"""
High Low Breakout Statistical Analysis strategy.
Tracks the high and low of the previous completed day, week or month (TimeframeOption). Depending on EntryOption it buys or
sells when the close crosses above the previous high, or buys or sells when the close crosses below the previous low. The
position is closed after HoldingPeriod candles.
"""
def __init__(self):
super(high_low_breakout_statistical_analysis_strategy, self).__init__()
self._entry_option = self.Param("EntryOption", ENTRY_LONG_AT_HIGH).SetDisplay("Entry Option", "0 LongAtHigh, 1 ShortAtHigh, 2 LongAtLow, 3 ShortAtLow", "Trading")
self._timeframe_option = self.Param("TimeframeOption", TIMEFRAME_DAILY).SetDisplay("Timeframe Option", "0 Daily, 1 Weekly, 2 Monthly", "Trading")
self._holding_period = self.Param("HoldingPeriod", 5).SetGreaterThanZero().SetDisplay("Holding Period", "Candles to hold a position", "Trading")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._reset_state()
@property
def candle_type(self):
return self._candle_type.Value
def _reset_state(self):
self._period_start = None
self._period_high = 0.0
self._period_low = 0.0
self._prev_high = None
self._prev_low = None
self._prev_close = None
self._bars_in_position = 0
def OnReseted(self):
super(high_low_breakout_statistical_analysis_strategy, self).OnReseted()
self._reset_state()
def OnStarted2(self, time):
super(high_low_breakout_statistical_analysis_strategy, self).OnStarted2(time)
self._reset_state()
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 _get_period_start(self, time):
date = time.Date
option = int(self._timeframe_option.Value)
if option == TIMEFRAME_WEEKLY:
return date.AddDays(-((int(date.DayOfWeek) + 6) % 7))
if option == TIMEFRAME_MONTHLY:
return date.AddDays(1 - date.Day)
return date
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
high_price = float(candle.HighPrice)
low_price = float(candle.LowPrice)
period_start = self._get_period_start(candle.OpenTime)
if self._period_start is None or self._period_start != period_start:
if self._period_start is not None:
self._prev_high = self._period_high
self._prev_low = self._period_low
self._period_start = period_start
self._period_high = high_price
self._period_low = low_price
else:
self._period_high = max(self._period_high, high_price)
self._period_low = min(self._period_low, low_price)
close = float(candle.ClosePrice)
prev_close = self._prev_close
self._prev_close = close
if not self.IsFormedAndOnlineAndAllowTrading():
return
if self.Position != 0:
self._bars_in_position += 1
if self._bars_in_position >= self._holding_period.Value:
if self.Position > 0:
self.SellMarket(self.Position)
else:
self.BuyMarket(-self.Position)
return
if prev_close is None or self._prev_high is None or self._prev_low is None:
return
cross_high = prev_close <= self._prev_high and close > self._prev_high
cross_low = prev_close >= self._prev_low and close < self._prev_low
option = int(self._entry_option.Value)
if (option == ENTRY_LONG_AT_HIGH and cross_high) or (option == ENTRY_LONG_AT_LOW and cross_low):
self.BuyMarket(self.Volume)
self._bars_in_position = 0
elif (option == ENTRY_SHORT_AT_HIGH and cross_high) or (option == ENTRY_SHORT_AT_LOW and cross_low):
self.SellMarket(self.Volume)
self._bars_in_position = 0
def CreateClone(self):
return high_low_breakout_statistical_analysis_strategy()