Breakout strategy based on daily high and low levels. It looks for price moving beyond the previous day's range with an RSI and EMA trend filter. The strategy calculates the daily high and low, offsets them by a configurable delta, and enters long above the upper level or short below the lower level when trend conditions are confirmed.
Details
Entry Criteria:
Long: Close > DailyHigh + Delta and RSI > 55 and FastEMA > SlowEMA
Short: Close < DailyLow - Delta and RSI < 45 and FastEMA < SlowEMA
Long/Short: Both
Exit Criteria: Opposite signal or protection
Stops: Configurable take profit and stop loss in percent
Default Values:
Delta = 0.0002m
FastPeriod = 18
SlowPeriod = 60
RsiPeriod = 14
TakeProfit = 1m
StopLoss = 0.5m
CandleType = TimeSpan.FromHours(1).TimeFrame()
Filters:
Category: Breakout
Direction: Both
Indicators: EMA, RSI
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>
/// Breakout strategy based on EMA crossover with RSI trend filter.
/// </summary>
public class CharlesBreakoutStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public CharlesBreakoutStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 18)
.SetDisplay("Fast EMA Period", "Fast EMA length", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 60)
.SetDisplay("Slow EMA Period", "Slow EMA length", "Indicators");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetDisplay("RSI Period", "RSI length", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for calculations", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0;
_prevSlow = 0;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fastEma = new ExponentialMovingAverage { Length = FastPeriod };
var slowEma = new ExponentialMovingAverage { Length = SlowPeriod };
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
SubscribeCandles(CandleType).Bind(fastEma, slowEma, rsi, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastEma, decimal slowEma, decimal rsi)
{
if (candle.State != CandleStates.Finished) return;
if (!_hasPrev)
{
_prevFast = fastEma;
_prevSlow = slowEma;
_hasPrev = true;
return;
}
var crossUp = _prevFast <= _prevSlow && fastEma > slowEma;
var crossDown = _prevFast >= _prevSlow && fastEma < slowEma;
if (crossUp && rsi > 50 && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (crossDown && rsi < 50 && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prevFast = fastEma;
_prevSlow = slowEma;
}
}