This strategy attempts to trade breakouts from short-term consolidation zones. It searches for compact price ranges on the 15‑minute chart and opens trades when the price breaks away from these ranges by a specified distance.
Strategy Logic
For every finished 15‑minute candle the highest high and lowest low of the last 40 candles are calculated.
If the distance between these extremes is below the Range parameter a consolidation zone is assumed.
After the Delay Open period passes without new trades, a breakout above the upper boundary plus Distance points triggers a long position, while a breakout below the lower boundary minus Distance points triggers a short position.
A fixed Stop Loss and a trailing stop of Trail points are applied once a position is opened.
Consolidation boundaries are reset after the Period hours elapse.
Parameters
DelayOpen – Hours to wait before opening a new trade.
Distance – Breakout distance from the consolidation boundary in points.
Period – Hours after which consolidation levels are recalculated.
Range – Maximum size of the consolidation zone in points.
StopLoss – Initial stop loss in points.
Trail – Trailing stop distance in points.
Notes
The strategy uses only the high-level API: candles are received through SubscribeCandles, and indicator values are bound using Bind. Orders are sent with BuyMarket and SellMarket methods. Comments in the source code are written in English.
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()