View on GitHub

Breakout 04 Strategy

Strategy that trades breakouts of the previous day's range. Buys when price moves above the prior daily high and sells when price falls below the prior daily low. Uses a trailing stop and fixed take profit with optional position sizing based on account balance. Trading is disabled before a configured Monday start hour and after a Friday cutoff hour.

Details

  • Entry Criteria:
    • Long: Price > Previous High
    • Short: Price < Previous Low
  • Long/Short: Both
  • Exit Criteria: Trailing stop or take profit
  • Stops: Trailing and fixed stop loss
  • Default Values:
    • MondayHour = 18
    • FridayHour = 14
    • TrailingStop = 21
    • TakeProfit = 550
    • StopLoss = 124
    • UseMoneyManagement = false
    • PercentMM = 8m
    • Volume = 0.1m
  • Filters:
    • Category: Breakout
    • Direction: Both
    • Indicators: None
    • Stops: Yes
    • Complexity: Basic
    • 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 using Highest/Lowest channels.
/// </summary>
public class Breakout04Strategy : 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 Breakout04Strategy()
	{
		_lookback = Param(nameof(Lookback), 30)
			.SetDisplay("Lookback", "Channel lookback period", "General");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candle type", "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;

		if (close > _prevHigh && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
		}
		else if (close < _prevLow && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
		}

		_prevHigh = highest;
		_prevLow = lowest;
	}
}