The strategy measures the highest and lowest prices within the last RangePeriod candles. When the candle closes outside of this range and the total width of the range is narrower than MaxRangePoints, the strategy enters in the breakout direction.
Entry Rules
Long: Candle close >= highest high of the lookback range AND range in points <= MaxRangePoints AND no open position.
Short: Candle close <= lowest low of the lookback range AND range in points <= MaxRangePoints AND no open position.
Exit Rules
Protective stop loss and take profit are applied immediately after the position is opened.
No additional exit rules are used; the position stays open until protection closes it.
Parameters
RangePeriod – number of candles for highest/lowest calculation.
MaxRangePoints – maximum width of the range in points to allow trading.
CandleType – timeframe of candles used for analysis and trading.
Volume – market order volume.
StopLossPoints – stop loss distance in points.
TakeProfitPoints – take profit distance in points.
Indicators
Highest
Lowest
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Range Breakout strategy: Highest/Lowest channel breakout.
/// Buys when close >= highest. Sells when close <= lowest.
/// </summary>
public class RangeBreakoutStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _channelPeriod;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int ChannelPeriod
{
get => _channelPeriod.Value;
set => _channelPeriod.Value = value;
}
public RangeBreakoutStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_channelPeriod = Param(nameof(ChannelPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("Channel Period", "Lookback period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var high = new Highest { Length = ChannelPeriod };
var low = new Lowest { Length = ChannelPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(high, low, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal high, decimal low)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (candle.ClosePrice >= high && Position <= 0)
BuyMarket();
else if (candle.ClosePrice <= low && Position >= 0)
SellMarket();
}
}
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 range_breakout_strategy(Strategy):
def __init__(self):
super(range_breakout_strategy, self).__init__()
self._channel_period = self.Param("ChannelPeriod", 14) \
.SetDisplay("Channel Period", "Highest/Lowest lookback", "Indicators")
self._highest = None
self._lowest = None
@property
def channel_period(self):
return self._channel_period.Value
def OnReseted(self):
super(range_breakout_strategy, self).OnReseted()
self._highest = None
self._lowest = None
def OnStarted2(self, time):
super(range_breakout_strategy, self).OnStarted2(time)
self._highest = Highest()
self._highest.Length = self.channel_period
self._lowest = Lowest()
self._lowest.Length = self.channel_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._highest, self._lowest, self._process_candle)
subscription.Start()
def _process_candle(self, candle, high_val, low_val):
if candle.State != CandleStates.Finished:
return
if not self._highest.IsFormed or not self._lowest.IsFormed:
return
close = float(candle.ClosePrice)
h = float(high_val)
l = float(low_val)
if close >= h and self.Position <= 0:
self.BuyMarket()
elif close <= l and self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return range_breakout_strategy()