Открыть на GitHub

Стратегия Profit Hunter HSI with Fibonacci

Обзор

Эта стратегия представляет собой перенос на C# советника MetaTrader 4 Profit_Hunter_HSI_with_fibonacci.mq4. Оригинальный код совмещал фильтр на основе экспоненциальной скользящей средней (EMA) с Fibonacci-уровнями, рассчитанными по дневным свечам. Версия для StockSharp использует высокоуровневый API: подписывается на поток внутридневных свечей, параллельно получает дневные данные, по последним максимумам и минимумам строит сетку Fibonacci и по взаимодействию цены с ключевыми уровнями формирует торговые сигналы. Управление позицией реализует начальную защиту и ступенчатый трейлинг стоп по тому же алгоритму, что и в MT4.

Потоки данных

  1. Внутридневные свечи – параметр TimeFrame задаёт рабочий таймфрейм (по умолчанию 1 минута). Каждая завершённая свеча подаётся на вход EMA, обновляет ссылочные уровни поддержки/сопротивления (значения NumBars свечей назад) и запускает торговую логику.
  2. Дневные свечи – отдельная подписка собирает старший таймфрейм. Два индекса определяют, какие дневные свечи используются в качестве опорного максимума и минимума. При появлении новой дневной свечи сетка Fibonacci пересчитывается целиком, включая расширения 161.8%, 261.8% и 423.6%.

Формирование сигналов

В оригинальном советнике сохранялись цены последнего максимума и минимума, а переменная highFirst указывала, какая экстремальная точка встретилась раньше. Перенос сохраняет идею, сравнивая индексы выбранных дневных свечей:

  • Если индекс максимума меньше индекса минимума (highFirst = true), считается, что рынок сначала сделал максимум, а затем минимум, и сетка строится от минимума вверх.
  • В противном случае предполагается, что минимум появился раньше, и уровни откладываются от максимума вниз.

На каждой завершённой внутридневной свече выполняется последовательность, повторяющая MT4-скрипт:

  1. Трендовый фильтр – EMA с периодом MaPeriod. Если цена закрытия (используется как аналог Bid/Ask) выше EMA, тренд считается восходящим ("Naik"), если ниже – нисходящим ("Turun"). При нейтральном положении относительно EMA входы блокируются.
  2. Сигналы Fibonacci – в зависимости от highFirst сравниваются уровни 23.6%, 76.4%, 91% и 14.6%. Результатом становится одна из строк Reverse-Buy, Reverse-Sell, Trading-Area или Continuation. Три первые участвуют в правилах входа, Continuation служит для информационного вывода.
  3. Правила входа – реализованы все шесть веток исходного советника:
    • Восходящий тренд + "Trading-Area" + пробой сопротивления → покупка со стопом на уровне поддержки.
    • Восходящий тренд + "Reverse-Sell" + highFirst == false + цена ниже сопротивления → продажа со стопом на уровне 14.6%.
    • Восходящий тренд + "Reverse-Buy" + highFirst == false + цена ниже сопротивления → покупка со стопом на уровне 91%.
    • Нисходящий тренд + "Trading-Area" + пробой поддержки → продажа со стопом на сопротивлении.
    • Нисходящий тренд + "Reverse-Sell" + highFirst == true + цена ниже сопротивления → продажа со стопом на 91%.
    • Нисходящий тренд + "Reverse-Buy" + highFirst == true + цена ниже сопротивления → покупка со стопом на 14.6%. В стратегии одновременно может быть только одна позиция; новые заявки не подаются, пока есть открытые ордера.

Управление позицией

  • Выход по уровням – как и в MT4, длинная позиция закрывается при возврате цены к поддержке, короткая – при росте до сопротивления, независимо от текущего результата.
  • Исходный стоп – цена стоп-лосса, выбранная при входе, сохраняется внутри стратегии и проверяется на каждой свече. StockSharp- версия не модифицирует ордера брокера напрямую, а контролирует условие самостоятельно.
  • Ступенчатый трейлинг – в оригинале стоп сдвигался при достижении прибыли 60 пунктов, далее каждые 20 пунктов переносился ещё на 5 пунктов в сторону прибыли (до барьера 260 пунктов). Перенос выполняет ту же лестницу, умножая значения на PriceStep инструмента. Для коротких позиций стоп опускается, тем самым фиксируя прибыль.

Параметры

Имя Описание Значение по умолчанию Примечания
NumBars Номер свечи в прошлом, чьи High/Low используются как поддержка/сопротивление. 3 Аналог numBars, значение > 0.
MaPeriod Период EMA для фильтрации тренда. 5 Соответствует maPeriod.
TimeFrame Таймфрейм внутридневных свечей. 1 минута Аналог timeFrame, принимает любой TimeSpan.
DaysBackForHigh Индекс дневной свечи с максимумом. 1 Соответствует daysBackForHigh.
DaysBackForLow Индекс дневной свечи с минимумом. 1 Соответствует daysBackForLow.
Volume Объём рыночного ордера. 1 В лотах/контрактах, должен быть положительным.

Особенности реализации

  • Графические объекты из MT4 не переносятся: в StockSharp визуализация выполняется иначе, а подписи носили декоративный характер.
  • Вместо вызовов iLow/iHigh стратегия хранит списки завершённых свечей и считывает необходимые значения напрямую по индексу.
  • Управление стопом реализовано внутри метода ManagePosition, что избавляет от использования OrderModify и делает код независимым от конкретного брокера.
  • При ошибке регистрации ордера внутреннее состояние сбрасывается, чтобы не оставалось "подвешенных" намерений на повторную отправку.

Отличия от версии для MetaTrader

  • В MT4 использовались цены Bid и Ask в реальном времени. Здесь их роль выполняет цена закрытия свечи, что полностью сохраняет логику принятия решений.
  • Проверка "кто был первым" больше не опирается на глобальные массивы High[]/Low[]. Сравнение индексов дневных свечей повторяет исходное поведение для стандартных параметров и даёт ожидаемый результат при иных настройках.
  • Защитные ордера брокера заменены виртуальными условиями выхода, проверяемыми после получения каждой свечи. Это упрощает перенос стратегии на разные соединения и при этом оставляет те же правила выхода, что и в оригинале.
using System;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Profit Hunter strategy with Fibonacci retracement levels.
/// Uses EMA trend filter and enters on pullbacks to Fibonacci levels.
/// </summary>
public class ProfitHunterHsiWithFibonacciStrategy : Strategy
{
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<int> _lookbackPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private int _barCount;

	public ProfitHunterHsiWithFibonacciStrategy()
	{
		_emaPeriod = Param(nameof(EmaPeriod), 20)
			.SetDisplay("EMA Period", "Period for trend filter EMA.", "Indicators");

		_lookbackPeriod = Param(nameof(LookbackPeriod), 50)
			.SetDisplay("Lookback Period", "Bars to look back for range high/low.", "Fibonacci");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(2).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for analysis.", "General");
	}

	public int EmaPeriod
	{
		get => _emaPeriod.Value;
		set => _emaPeriod.Value = value;
	}

	public int LookbackPeriod
	{
		get => _lookbackPeriod.Value;
		set => _lookbackPeriod.Value = value;
	}

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

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

		_barCount = 0;
	}

		protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_barCount = 0;

		var ema = new ExponentialMovingAverage { Length = EmaPeriod };
		var highest = new Highest { Length = LookbackPeriod };
		var lowest = new Lowest { Length = LookbackPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(ema, highest, lowest, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, ema);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, decimal emaValue, decimal highestValue, decimal lowestValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		_barCount++;

		if (_barCount < LookbackPeriod)
			return;

		var range = highestValue - lowestValue;
		if (range <= 0)
			return;

		// Fibonacci levels
		var fib382 = highestValue - range * 0.382m;
		var fib618 = highestValue - range * 0.618m;
		var close = candle.ClosePrice;

		// Manage position
		if (Position > 0)
		{
			// Exit long at 0 fib (range high) or if price drops below 61.8%
			if (close >= highestValue || close < fib618)
			{
				SellMarket();
			}
		}
		else if (Position < 0)
		{
			// Exit short at 100% fib (range low) or if price rises above 38.2%
			if (close <= lowestValue || close > fib382)
			{
				BuyMarket();
			}
		}

		// Entry logic
		if (Position == 0)
		{
			if (close > emaValue && close <= fib382 && close > fib618)
			{
				// Uptrend + pullback to Fib zone -> buy
				BuyMarket();
			}
			else if (close < emaValue && close >= fib618 && close < fib382)
			{
				// Downtrend + pullback to Fib zone -> sell
				SellMarket();
			}
		}
	}
}