H4L4 Breakout
Daily breakout strategy that calculates H4 and L4 levels from the previous day's high, low, and close. A sell limit is placed at H4 and a buy limit at L4 at the start of each day. All open positions and pending orders are cleared before new orders are submitted. Protective stop loss and take profit are applied using tick-based distances.
Details
- Entry Criteria: Sell limit at H4 and buy limit at L4 derived from the previous day's candle.
- Long/Short: Both directions.
- Exit Criteria: Stop loss or take profit.
- Stops: Yes.
- Default Values:
TakeProfit= 57StopLoss= 7CandleType= TimeSpan.FromDays(1)
- Filters:
- Category: Breakout
- Direction: Both
- Indicators: None
- Stops: Yes
- Complexity: Basic
- Timeframe: Daily
- Seasonality: No
- Neural Networks: No
- Divergence: No
- Risk Level: Medium
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Breakout strategy based on calculated H4 and L4 levels.
/// When price range expands, places limit orders above and below to catch breakouts.
/// </summary>
public class H4L4BreakoutStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private decimal _prevHigh;
private decimal _prevLow;
private int _lastSignal;
private bool _hasPrev;
/// <summary>
/// Candle type for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initialize <see cref="H4L4BreakoutStrategy"/>.
/// </summary>
public H4L4BreakoutStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Working candle timeframe", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevHigh = 0m;
_prevLow = 0m;
_lastSignal = 0;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var sma = new SimpleMovingAverage { Length = 10 };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sma, (candle, ma) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!_hasPrev)
{
_prevHigh = candle.HighPrice;
_prevLow = candle.LowPrice;
_hasPrev = true;
return;
}
if (candle.ClosePrice > _prevHigh && candle.ClosePrice > ma && _lastSignal != 1 && Position <= 0)
{
BuyMarket();
_lastSignal = 1;
}
else if (candle.ClosePrice < _prevLow && candle.ClosePrice < ma && _lastSignal != -1 && Position >= 0)
{
SellMarket();
_lastSignal = -1;
}
_prevHigh = candle.HighPrice;
_prevLow = candle.LowPrice;
})
.Start();
StartProtection(
new Unit(2000m, UnitTypes.Absolute),
new Unit(1000m, UnitTypes.Absolute));
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Indicators import SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class h4_l4_breakout_strategy(Strategy):
def __init__(self):
super(h4_l4_breakout_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4)))
self._prev_high = 0.0
self._prev_low = 0.0
self._last_signal = 0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(h4_l4_breakout_strategy, self).OnStarted2(time)
self._prev_high = 0.0
self._prev_low = 0.0
self._last_signal = 0
self._has_prev = False
sma = SimpleMovingAverage()
sma.Length = 10
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(sma, self.ProcessCandle).Start()
self.StartProtection(
Unit(2000.0, UnitTypes.Absolute),
Unit(1000.0, UnitTypes.Absolute))
def ProcessCandle(self, candle, ma_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
ma = float(ma_value)
if not self._has_prev:
self._prev_high = float(candle.HighPrice)
self._prev_low = float(candle.LowPrice)
self._has_prev = True
return
if close > self._prev_high and close > ma and self._last_signal != 1 and self.Position <= 0:
self.BuyMarket()
self._last_signal = 1
elif close < self._prev_low and close < ma and self._last_signal != -1 and self.Position >= 0:
self.SellMarket()
self._last_signal = -1
self._prev_high = float(candle.HighPrice)
self._prev_low = float(candle.LowPrice)
def OnReseted(self):
super(h4_l4_breakout_strategy, self).OnReseted()
self._prev_high = 0.0
self._prev_low = 0.0
self._last_signal = 0
self._has_prev = False
def CreateClone(self):
return h4_l4_breakout_strategy()