Открыть на GitHub

Стратегия Eugene Inside Breakout

Стратегия Eugene Inside Breakout представляет собой прямую конвертацию оригинального советника MetaTrader от barabashkakvn. Осн ова лежит исключительно на ценовом действии: серия внутренних свечей с последующим пробоем диапазона. Уровни подтверждения, рас считанные по телу предыдущей свечи, позволяют дождаться развития импульса до входа в позицию.

Обзор

Алгоритм отслеживает формирование нового максимума или минимума относительно предыдущей свечи. Для лонгов требуется, чтобы мини мум предыдущей свечи находился ниже максимума свечи два бара назад — это подчеркивает сжатие перед пробоем. Для шортов стратегия отказывается торговать, если предыдущая свеча является внутренней, полностью повторяя защиту из исходного MQL-кода. Заявки всег да исполняются по рынку фиксированным объемом.

Рыночная логика

  • Делает акцент на пробоях последних экстремумов, чтобы как можно раньше войти в зарождающееся движение.
  • Использует тело предыдущей свечи для расчёта двух уровней отката на одну треть (zigLevelBuy и zigLevelSell). Цена должна к оснуться соответствующего уровня либо торговая сессия должна перейти за настроенный час активации, чтобы вход был разрешён.
  • Блокирует новые позиции, если пробой совпадает с внутренней свечой против направления сделки.
  • Закрывает открытые позиции, когда подтверждается противоположный пробой, поэтому стратегия всегда остаётся вне рынка или в пос леднем сигнале.

Правила входа

Лонг

  1. Текущий максимум выше максимума предыдущей свечи.
  2. Подтверждение получено, когда текущий минимум пробивает уровень отката одной третьей тела предыдущей свечи либо текущий час п ревышает параметр активации.
  3. Текущий минимум должен оставаться выше предыдущего минимума, при этом минимум предыдущей свечи располагается ниже максимума с вечи два бара назад.
  4. Открытых позиций нет.

Шорт

  1. Текущий минимум ниже минимума предыдущей свечи.
  2. Подтверждение получено, когда текущий максимум тестирует верхний уровень отката одной третьей тела предыдущей свечи либо теку щий час превышает параметр активации.
  3. Предыдущая свеча не является внутренней (её максимум не ниже и минимум не выше свечи два бара назад).
  4. Текущий максимум ниже максимума предыдущей свечи.
  5. Открытых позиций нет.

Правила выхода

  • Закрывать лонг, когда формируется подтверждённый шорт-пробой (условия 1–3 логики входа в шорт).
  • Закрывать шорт, когда формируется подтверждённый лонг-пробой (условия 1–3 логики входа в лонг).

Параметры

Имя Описание Значение по умолчанию
CandleType Таймфрейм свечей, обрабатываемых стратегией. 1-часовые свечи
Volume Объём заявки для каждого рыночного ордера. 0.1
ActivationHour Час, после которого подтверждения принимаются автоматически. Повторяет фильтр TimeCurrent() из MQL-кода. 8

Примечания

  • Проверки "white bird" и "black bird" из оригинального скрипта из-за условий всегда ложны; они сохранены для совместимости и н е влияют на торговые решения.
  • Дополнительные индикаторы и трейлинг-стопы не используются — стратегия полностью основана на цене и переворачивается при каждо м противоположном пробое.
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;
	}
}