Открыть на GitHub

Стратегия Average Change Candle

Конвертация советника MetaTrader Exp_AverageChangeCandle в среду StockSharp. Алгоритм сглаживает отношения цен свечи к базовой скользящей средней, присваивает свечам цвета и торгует при смене цвета.

Идея

  1. Рассчитать базовую скользящую среднюю (MaMethod1, Length1) по выбранной цене.
  2. Выразить цену открытия и закрытия как отношение к базовой средней и возвести в степень Power.
  3. Сгладить преобразованные значения второй средней (MaMethod2, Length2).
  4. Определить цвет: бычий, если сглаженное закрытие выше открытия, медвежий — если ниже.
  5. Отрабатывать смену цвета после задержки SignalBar.

Обрабатываются только завершённые свечи. Стратегия открывает позиции по направлению нового цвета и при необходимости закрывает противоположные.

Параметры

Параметр Значение по умолчанию Описание
OrderVolume 1 Объём сделки при открытии новой позиции.
MaMethod1 Lwma Метод сглаживания базовой средней (поддержка SMA/EMA/SMMA/LWMA/JJMA/AMA, остальные переходят в EMA).
Length1 12 Период базовой средней.
Phase1 15 Параметр фазы для вариантов Jurik.
PriceSource Median Используемая цена перед вычислением базовой средней.
MaMethod2 Jjma Метод сглаживания преобразованных отношений.
Length2 5 Период второй средней.
Phase2 100 Параметр фазы для второй средней.
Power 5 Степень для отношений открытия/закрытия.
SignalBar 1 Сколько закрытых баров ждать перед реакцией.
BuyOpenEnabled true Разрешить открытие длинных позиций.
SellOpenEnabled true Разрешить открытие коротких позиций.
BuyCloseEnabled true Закрывать лонги при сигнале на шорт.
SellCloseEnabled true Закрывать шорты при сигнале на лонг.
StopLossPoints 0 Абсолютный размер стоп-лосса, 0 отключает.
TakeProfitPoints 0 Абсолютный тейк-профит, 0 отключает.
CandleType Таймфрейм H4 Тип свечей, которые обрабатываются стратегией.

Правила торговли

  • Бычья смена (color = 2): закрываем шорты (если разрешено) и открываем лонг при Position <= 0 и включённом BuyOpenEnabled.
  • Медвежья смена (color = 0): закрываем лонги (если разрешено) и открываем шорт при Position >= 0 и включённом SellOpenEnabled.
  • Цвет 1 (нейтральный) не вызывает сделок.
  • Для имитации оригинального кода сигнал оценивается по свече, отстоящей на SignalBar баров от последней завершённой.

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

StopLossPoints и TakeProfitPoints передаются в StartProtection как абсолютные расстояния. Нулевые значения отключают соответствующую защиту.

Примечания

  • Поддерживаются только те методы сглаживания, которые есть в StockSharp. JurX, ParMA, T3 и VIDYA заменены на EMA.
  • Параметры фаз сохранены ради совместимости и работают только для Jurik/Kaufman сглаживания.
  • Сделки исполняются рыночными ордерами, как в оригинальном советнике. Настройка проскальзывания из версии MQL не переносилась.
namespace StockSharp.Samples.Strategies;

using System;

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

/// <summary>
/// Average Change Candle strategy (simplified).
/// Compares smoothed open vs close ratios to detect bullish/bearish candle patterns.
/// Uses EMA of open and close to determine trend direction.
/// </summary>
public class AverageChangeCandleStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _emaPeriod;

	private decimal _prevSmoothedOpen;
	private decimal _prevSmoothedClose;
	private bool _initialized;

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

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

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

		_emaPeriod = Param(nameof(EmaPeriod), 12)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA smoothing period", "Indicators");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevSmoothedOpen = 0m;
		_prevSmoothedClose = 0m;
		_initialized = false;
	}

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

		_prevSmoothedOpen = 0;
		_prevSmoothedClose = 0;
		_initialized = false;

		var ema = new ExponentialMovingAverage { Length = EmaPeriod };

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

				// Simple exponential smoothing of open and close
				var alpha = 2m / (EmaPeriod + 1m);

				if (!_initialized)
				{
					_prevSmoothedOpen = candle.OpenPrice;
					_prevSmoothedClose = candle.ClosePrice;
					_initialized = true;
					return;
				}

				var smoothedOpen = alpha * candle.OpenPrice + (1m - alpha) * _prevSmoothedOpen;
				var smoothedClose = alpha * candle.ClosePrice + (1m - alpha) * _prevSmoothedClose;

				var prevBullish = _prevSmoothedClose > _prevSmoothedOpen;
				var currBullish = smoothedClose > smoothedOpen;

				if (!IsFormedAndOnlineAndAllowTrading())
				{
					_prevSmoothedOpen = smoothedOpen;
					_prevSmoothedClose = smoothedClose;
					return;
				}

				// Buy on transition to bullish smoothed candle
				if (currBullish && !prevBullish && candle.ClosePrice > emaValue && Position <= 0)
				{
					BuyMarket();
				}
				// Sell on transition to bearish smoothed candle
				else if (!currBullish && prevBullish && candle.ClosePrice < emaValue && Position >= 0)
				{
					SellMarket();
				}

				_prevSmoothedOpen = smoothedOpen;
				_prevSmoothedClose = smoothedClose;
			})
			.Start();

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