An inside bar forms when a candle's range is fully contained within the previous bar's high and low. It signals short-term indecision that can lead to a breakout once price clears the pattern. This strategy waits for that break and then trades in the direction of the expansion.
Testing indicates an average annual return of about 118%. It performs best in the stocks market.
Each new candle is compared with the one before it. If an inside bar appears, the system marks its high and low and watches for a close outside those levels. A bullish breakout opens a long position with a stop below the pattern low, while a bearish breakout triggers a short with a stop above the pattern high.
Should price fail to break out immediately, the strategy manages existing positions by exiting if the next candle moves against the trade beyond the prior bar's extremes.
Details
Entry Criteria: Breakout of an inside bar's high or low.
Long/Short: Both.
Exit Criteria: Price crossing previous candle extreme or stop-loss.
Stops: Yes, placed beyond the pattern.
Default Values:
CandleType = 5 minute
StopLossPercent = 1
The stop lies this many percent beyond the opposite side of the inside bar; both it and the previous-candle exit are checked on candle closes.
Filters:
Category: Breakout
Direction: Both
Indicators: Candlestick
Stops: Yes
Complexity: Intermediate
Timeframe: Intraday
Seasonality: No
Neural networks: No
Divergence: No
Risk level: Medium
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>
/// Inside Bar Breakout strategy.
/// An inside bar's range lies within the previous candle's high and low. While flat, a close above the latest inside bar's
/// high buys and a close below its low sells. The stop lies StopLossPercent percent beyond the opposite side of the pattern,
/// and a close beyond the previous candle's extreme against the position also exits.
/// </summary>
public class InsideBarBreakoutStrategy : Strategy
{
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
private (decimal High, decimal Low)? _prevCandle;
private (decimal High, decimal Low)? _insideBar;
private decimal _stopPrice;
/// <summary>
/// Distance of the stop beyond the pattern, in percent.
/// </summary>
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
/// <summary>
/// Candle type and timeframe.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public InsideBarBreakoutStrategy()
{
_stopLossPercent = Param(nameof(StopLossPercent), 1m)
.SetNotNegative()
.SetDisplay("Stop Loss %", "Distance of the stop beyond the pattern, in percent", "Risk");
_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();
_prevCandle = null;
_insideBar = null;
_stopPrice = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevCandle = null;
_insideBar = null;
_stopPrice = default;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var previous = _prevCandle;
var pattern = _insideBar;
_prevCandle = (candle.HighPrice, candle.LowPrice);
var isInside = previous is { } prev && candle.HighPrice <= prev.High && candle.LowPrice >= prev.Low;
var close = candle.ClosePrice;
// A close outside the pattern uses it up; a new inside bar replaces it.
if (pattern is { } bar && (close > bar.High || close < bar.Low))
_insideBar = null;
if (isInside)
_insideBar = (candle.HighPrice, candle.LowPrice);
if (previous is not { } prior || !IsFormedAndOnlineAndAllowTrading())
return;
if (Position > 0)
{
if (close <= _stopPrice || close < prior.Low)
SellMarket(Position);
}
else if (Position < 0)
{
if (close >= _stopPrice || close > prior.High)
BuyMarket(-Position);
}
else if (pattern is { } inside)
{
if (close > inside.High)
{
BuyMarket(Volume);
_stopPrice = inside.Low * (1 - StopLossPercent / 100m);
}
else if (close < inside.Low)
{
SellMarket(Volume);
_stopPrice = inside.High * (1 + StopLossPercent / 100m);
}
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
class inside_bar_breakout_strategy(Strategy):
"""
Inside Bar Breakout strategy.
An inside bar's range lies within the previous candle's high and low. While flat, a close above the latest inside bar's
high buys and a close below its low sells. The stop lies StopLossPercent percent beyond the opposite side of the pattern,
and a close beyond the previous candle's extreme against the position also exits.
"""
def __init__(self):
super(inside_bar_breakout_strategy, self).__init__()
self._stop_loss_percent = self.Param("StopLossPercent", 1.0).SetNotNegative().SetDisplay("Stop Loss %", "Distance of the stop beyond the pattern, in percent", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_candle = None
self._inside_bar = None
self._stop_price = Decimal(0)
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(inside_bar_breakout_strategy, self).OnReseted()
self._prev_candle = None
self._inside_bar = None
self._stop_price = Decimal(0)
def OnStarted2(self, time):
super(inside_bar_breakout_strategy, self).OnStarted2(time)
self._prev_candle = None
self._inside_bar = None
self._stop_price = Decimal(0)
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 _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
previous = self._prev_candle
pattern = self._inside_bar
self._prev_candle = (candle.HighPrice, candle.LowPrice)
is_inside = previous is not None and candle.HighPrice <= previous[0] and candle.LowPrice >= previous[1]
close = candle.ClosePrice
# A close outside the pattern uses it up; a new inside bar replaces it.
if pattern is not None and (close > pattern[0] or close < pattern[1]):
self._inside_bar = None
if is_inside:
self._inside_bar = (candle.HighPrice, candle.LowPrice)
if previous is None or not self.IsFormedAndOnlineAndAllowTrading():
return
percent = Decimal(self._stop_loss_percent.Value) / Decimal(100)
if self.Position > 0:
if close <= self._stop_price or close < previous[1]:
self.SellMarket(self.Position)
elif self.Position < 0:
if close >= self._stop_price or close > previous[0]:
self.BuyMarket(-self.Position)
elif pattern is not None:
if close > pattern[0]:
self.BuyMarket(self.Volume)
self._stop_price = pattern[1] * (Decimal(1) - percent)
elif close < pattern[1]:
self.SellMarket(self.Volume)
self._stop_price = pattern[0] * (Decimal(1) + percent)
def CreateClone(self):
return inside_bar_breakout_strategy()