Открыть на GitHub

Стратегия ATR Normalize Histogram

Обзор

Стратегия ATR Normalize Histogram переносит логику советника MetaTrader Exp_ATR_Normalize_Histogram в StockSharp. Система анализирует отношение сглаженной разницы «закрытие − минимум» к сглаженному истинному диапазону. Смена цвета гистограммы формирует сигналы входа и выхода, полностью повторяя многобуферный подход оригинала.

Расчёт индикатора

  1. Для каждой завершённой свечи рассчитываются:

    • diff = Close − Low;
    • range = max(High, предыдущий Close) − min(Low, предыдущий Close).
  2. Оба ряда сглаживаются выбранными методами и периодами. Доступны пять вариантов: Simple, Exponential, Smoothed (RMA), Weighted, Jurik. Если в параметрах выбран другой MQL-метод (JurX, Parabolic, T3, VIDYA, AMA), используется простое скользящее среднее с заданной длиной.

  3. Нормализованная гистограмма вычисляется по формуле

    normalized = 100 × smoothedDiff / max(|smoothedRange|, PriceStep).

  4. Пороговые уровни делят гистограмму на пять зон, что позволяет воспроизвести буфер цветов индикатора.

Логика торговли

  • Входы. Параметр SignalBar задаёт, какую историческую свечу нужно анализировать (по умолчанию 1 — последняя закрытая). Стратегия сравнивает её цвет с предыдущей:
    • переход из бычьей экстремальной зоны (цвет 0) в любую другую зону открывает длинную позицию, если разрешена работа в лонг;
    • переход из медвежьей экстремальной зоны (цвет 4) в любую другую зону открывает короткую позицию, если разрешена работа в шорт.
  • Выходы. Для закрытия позиции достаточно цвета предыдущей свечи:
    • цвет 0 закрывает короткие позиции при включённом флаге EnableSellExits;
    • цвет 4 закрывает длинные позиции при включённом EnableBuyExits.
  • Сначала выполняются выходы, затем рассматриваются возможные входы, что исключает наложение встречных сделок.

Управление рисками

Стратегия запоминает цену входа и может применять стоп-лосс и тейк-профит в пунктах инструмента. Пересчёт выполняется через Security.PriceStep, то есть полностью соответствует понятию «points» в оригинале. При достижении стопа или цели внутри бара позиция закрывается немедленно, и следующая свеча уже может сформировать новый сигнал.

Параметры

  • CandleType — таймфрейм расчётов.
  • FirstSmoothingMethod / SecondSmoothingMethod — методы сглаживания рядов diff и range.
  • FirstLength / SecondLength — длины сглаживания.
  • HighLevel, MiddleLevel, LowLevel — пороговые уровни (по умолчанию 60/50/40).
  • SignalBar — смещение по буферу (минимум 1).
  • EnableBuyEntries, EnableSellEntries, EnableBuyExits, EnableSellExits — отдельные переключатели входов/выходов для каждой стороны.
  • TradeVolume — базовый объём заявки; при развороте стратегия автоматически добавляет объём для закрытия текущей позиции.
  • StopLossPoints, TakeProfitPoints — стоп и цель в пунктах, ноль отключает защиту.

Отличия от версии MQL

  • Оба этапа сглаживания настраиваются отдельно, но доступны только пять реализаций StockSharp. При выборе нестандартного метода используется простое скользящее среднее с прежним периодом.
  • Реализация SignalBar соответствует смещению CopyBuffer: независимо от величины смещения сравниваются выбранная свеча и её непосредственный предшественник.
  • Параметры управления капиталом оригинального советника (MM, MMMode, Deviation) заменены единым параметром TradeVolume. Заявки отправляются по рынку, стоп/тейк выполняются силами стратегии.
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>
/// Strategy based on normalized ATR histogram transitions (simplified).
/// Uses ATR to measure volatility and trades on regime changes.
/// </summary>
public class AtrNormalizeHistogramStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _atrLength;
	private readonly StrategyParam<int> _emaLength;

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

	public int AtrLength
	{
		get => _atrLength.Value;
		set => _atrLength.Value = value;
	}

	public int EmaLength
	{
		get => _emaLength.Value;
		set => _emaLength.Value = value;
	}

	public AtrNormalizeHistogramStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe", "General");

		_atrLength = Param(nameof(AtrLength), 14)
			.SetGreaterThanZero()
			.SetDisplay("ATR Length", "ATR period", "Indicators");

		_emaLength = Param(nameof(EmaLength), 20)
			.SetGreaterThanZero()
			.SetDisplay("EMA Length", "EMA period for trend", "Indicators");
	}

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

		var atr = new AverageTrueRange { Length = AtrLength };
		var ema = new ExponentialMovingAverage { Length = EmaLength };

		decimal prevAtr = 0;
		bool hasPrev = false;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(atr, ema, (ICandleMessage candle, decimal atrValue, decimal emaValue) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!hasPrev)
				{
					prevAtr = atrValue;
					hasPrev = true;
					return;
				}

				if (!IsFormedAndOnlineAndAllowTrading())
				{
					prevAtr = atrValue;
					return;
				}

				var price = candle.ClosePrice;

				// ATR expanding + price above EMA = bullish breakout
				if (atrValue > prevAtr * 1.1m && price > emaValue && Position <= 0)
				{
					BuyMarket();
				}
				// ATR expanding + price below EMA = bearish breakout
				else if (atrValue > prevAtr * 1.1m && price < emaValue && Position >= 0)
				{
					SellMarket();
				}

				prevAtr = atrValue;
			})
			.Start();

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