Esta estrategia intenta operar rupturas de zonas de consolidación a corto plazo. Busca rangos de precios compactos en el gráfico de 15 minutos y abre operaciones cuando el precio se aleja de estos rangos una distancia especificada.
Lógica de la estrategia
Para cada vela de 15 minutos finalizada, se calculan el máximo más alto y el mínimo más bajo de las últimas 40 velas.
Si la distancia entre estos extremos es inferior al parámetro Range, se asume una zona de consolidación.
Tras esperar el período Delay Open sin nuevas operaciones, una ruptura por encima del límite superior más Distance puntos activa una posición larga, mientras que una ruptura por debajo del límite inferior menos Distance puntos activa una posición corta.
Se aplica un Stop Loss fijo y un trailing stop de Trail puntos una vez abierta la posición.
Los límites de consolidación se reinician tras transcurrir las horas de Period.
Parámetros
DelayOpen – Horas de espera antes de abrir una nueva operación.
Distance – Distancia de ruptura desde el límite de consolidación en puntos.
Period – Horas tras las cuales se recalculan los niveles de consolidación.
Range – Tamaño máximo de la zona de consolidación en puntos.
StopLoss – Stop loss inicial en puntos.
Trail – Distancia del trailing stop en puntos.
Notas
La estrategia usa solo la API de alto nivel: las velas se reciben mediante SubscribeCandles y los valores de indicadores se vinculan con Bind. Las órdenes se envían con los métodos BuyMarket y SellMarket. Los comentarios en el código fuente están escritos en inglés.
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 based on consolidation zones.
/// </summary>
public class MaximusVxLiteStrategy : Strategy
{
private readonly StrategyParam<int> _lookback;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevHigh;
private decimal _prevLow;
private bool _hasPrev;
public int Lookback { get => _lookback.Value; set => _lookback.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public MaximusVxLiteStrategy()
{
_lookback = Param(nameof(Lookback), 20)
.SetDisplay("Lookback", "Highest/Lowest lookback period", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Time frame for candles", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_prevHigh = 0;
_prevLow = 0;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var highest = new Highest { Length = Lookback };
var lowest = new Lowest { Length = Lookback };
SubscribeCandles(CandleType).Bind(highest, lowest, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal highest, decimal lowest)
{
if (candle.State != CandleStates.Finished) return;
if (!_hasPrev)
{
_prevHigh = highest;
_prevLow = lowest;
_hasPrev = true;
return;
}
var close = candle.ClosePrice;
// Breakout above previous highest
if (close > _prevHigh && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
// Breakout below previous lowest
else if (close < _prevLow && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prevHigh = highest;
_prevLow = lowest;
}
}
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
from StockSharp.Algo.Strategies import Strategy
class maximus_vx_lite_strategy(Strategy):
def __init__(self):
super(maximus_vx_lite_strategy, self).__init__()
self._lookback = self.Param("Lookback", 20) \
.SetDisplay("Lookback", "Highest/Lowest lookback period", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Time frame for candles", "General")
self._prev_high = 0.0
self._prev_low = 0.0
self._has_prev = False
@property
def lookback(self):
return self._lookback.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(maximus_vx_lite_strategy, self).OnReseted()
self._prev_high = 0.0
self._prev_low = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(maximus_vx_lite_strategy, self).OnStarted2(time)
highest = Highest()
highest.Length = self.lookback
lowest = Lowest()
lowest.Length = self.lookback
self.SubscribeCandles(self.candle_type).Bind(highest, lowest, self.process_candle).Start()
def process_candle(self, candle, highest, lowest):
if candle.State != CandleStates.Finished:
return
hv = float(highest)
lv = float(lowest)
if not self._has_prev:
self._prev_high = hv
self._prev_low = lv
self._has_prev = True
return
close = float(candle.ClosePrice)
if close > self._prev_high and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif close < self._prev_low and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_high = hv
self._prev_low = lv
def CreateClone(self):
return maximus_vx_lite_strategy()