Ver no GitHub

Eugene Inside Breakout Strategy

The Eugene Inside Breakout strategy is a direct port of the original MetaTrader expert by barabashkakvn. It focuses on pure price action: an inside candle sequence followed by a range breakout. Confirmation levels derived from the previous candle body ensure that the breakout develops momentum before the strategy takes a position.

Overview

The strategy watches for a fresh high or low relative to the previous candle. Long setups require that the prior candle has a lo w below the high of the candle before it, highlighting compression before the breakout. Short setups refuse to trade if the prev ious candle is an inside bar, mirroring the safeguards in the source MQL logic. Orders are always executed at market with a fixe d volume.

Market Logic

  • Emphasises breakouts of the most recent high/low to catch directional moves early.
  • Uses the prior candle body to compute two one-third retracement levels (zigLevelBuy and zigLevelSell). The price must touch these levels, or the session must be past the configured activation hour, before an entry is allowed.
  • Prevents new positions when a breakout coincides with an inside candle against the trade direction.
  • Closes open positions whenever the opposite breakout signal confirms, ensuring the strategy is always flat or aligned with the latest signal.

Entry Rules

Long

  1. Current candle high is greater than the previous candle high.
  2. Confirmation is received when the current low pierces the one-third retracement of the prior candle body, or the current hour is beyond the activation hour parameter.
  3. The current low must stay above the prior low while the prior low sits below the high from two candles ago.
  4. No existing position is open.

Short

  1. Current candle low is lower than the previous candle low.
  2. Confirmation is received when the current high tests the upper one-third retracement of the prior candle body, or the current hour is beyond the activation hour parameter.
  3. The previous candle must not be an inside bar.
  4. The current high must be below the prior high.
  5. No existing position is open.

Exit Rules

  • Close long positions when a validated short breakout forms (conditions 1–3 of the short entry logic).
  • Close short positions when a validated long breakout forms (conditions 1–3 of the long entry logic).

Parameters

Name Description Default
CandleType Time frame of the candles processed by the strategy. 1-hour candles
Volume Order size sent with each market order. 0.1
ActivationHour Hour of day after which confirmations are automatically accepted, replicating the TimeCurrent() filter fro
m the MQL code. 8

Notes

  • The confirmation checks labelled “white bird” and “black bird” in the original script always evaluate to false because of the source conditions; they are preserved for parity but do not affect trading decisions.
  • No additional indicators or trailing stops are used—the approach is purely price-based and flips positions on each opposite br eakout.
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 derived from the Eugene expert advisor.
/// </summary>
public class EugeneInsideBreakoutStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _activationHour;

	private decimal _prevOpen1;
	private decimal _prevClose1;
	private decimal _prevHigh1;
	private decimal _prevLow1;

	private decimal _prevOpen2;
	private decimal _prevClose2;
	private decimal _prevHigh2;
	private decimal _prevLow2;

	private bool _hasPrev1;
	private bool _hasPrev2;

	/// <summary>
	/// Candle type to process.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}


	/// <summary>
	/// Hour of day after which confirmations are automatically valid.
	/// </summary>
	public int ActivationHour
	{
		get => _activationHour.Value;
		set => _activationHour.Value = value;
	}

	/// <summary>
	/// Initializes <see cref="EugeneInsideBreakoutStrategy"/>.
	/// </summary>
	public EugeneInsideBreakoutStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles to process", "General");


		_activationHour = Param(nameof(ActivationHour), 8)
			.SetRange(0, 23)
			.SetDisplay("Activation Hour", "Hour when confirmations become unconditional", "Filters");

		ResetHistory();
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		ResetHistory();
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		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;

		if (!_hasPrev2)
		{
			UpdateHistory(candle);
			return;
		}

		var open1 = _prevOpen1;
		var close1 = _prevClose1;
		var open2 = _prevOpen2;
		var close2 = _prevClose2;
		var high0 = candle.HighPrice;
		var high1 = _prevHigh1;
		var high2 = _prevHigh2;
		var low0 = candle.LowPrice;
		var low1 = _prevLow1;
		var low2 = _prevLow2;

		// Replicate the original expert advisor checks for inside bars.
		var blackInsider = high1 <= high2 && low1 >= low2 && close1 <= open1;
		var whiteInsider = high1 <= high2 && low1 >= low2 && close1 > open1;
		var whiteBird = whiteInsider && close2 > open2;
		var blackBird = blackInsider && close2 < open2;

		// ZigZag style confirmation levels based on the previous candle body.
		var zigLevelBuy = close1 < open1
			? open1 - (close1 - open1) / 3m
			: open1 - (open1 - low1) / 3m;

		var zigLevelSell = close1 > open1
			? open1 + (close1 - open1) / 3m
			: open1 + (high1 - open1) / 3m;

		var confirmBuy = (low0 <= zigLevelBuy || candle.CloseTime.Hour >= ActivationHour) && !blackBird && !whiteInsider;
		var confirmSell = (high0 >= zigLevelSell || candle.CloseTime.Hour >= ActivationHour) && !whiteBird && !blackInsider;

		var buySignal = high0 > high1;
		var sellSignal = low0 < low1;

		if (Position == 0)
		{
			if (buySignal && confirmBuy && low0 > low1 && low1 < high2)
			{
				BuyMarket();
			}
			else if (sellSignal && confirmSell && high0 < high1)
			{
				SellMarket();
			}
		}
		else if (Position > 0)
		{
			if (sellSignal && confirmSell && high0 < high1)
				SellMarket();
		}
		else if (Position < 0)
		{
			if (buySignal && confirmBuy && low0 > low1 && low1 < high2)
				BuyMarket();
		}

		UpdateHistory(candle);
	}

	private void UpdateHistory(ICandleMessage candle)
	{
		// Keep the two most recent completed candles for decision making.
		_prevOpen2 = _prevOpen1;
		_prevClose2 = _prevClose1;
		_prevHigh2 = _prevHigh1;
		_prevLow2 = _prevLow1;
		_hasPrev2 = _hasPrev1;

		_prevOpen1 = candle.OpenPrice;
		_prevClose1 = candle.ClosePrice;
		_prevHigh1 = candle.HighPrice;
		_prevLow1 = candle.LowPrice;
		_hasPrev1 = true;
	}

	private void ResetHistory()
	{
		_prevOpen1 = default;
		_prevClose1 = default;
		_prevHigh1 = default;
		_prevLow1 = default;
		_prevOpen2 = default;
		_prevClose2 = default;
		_prevHigh2 = default;
		_prevLow2 = default;
		_hasPrev1 = false;
		_hasPrev2 = false;
	}
}