Открыть на GitHub

Стратегия Exp XPeriod Candle X2

Обзор

Exp XPeriod Candle X2 воспроизводит оригинального эксперта MetaTrader на базе высокоуровневого API StockSharp. Стратегия формирует сглаженные синтетические свечи на двух таймфреймах и сравнивает смещённый открытый ценовой уровень с текущим сглаженным закрытием. Цвет свечи старшего таймфрейма задаёт тренд, а рабочий таймфрейм ждёт смены цветов, чтобы открывать и закрывать позиции. Необязательные стоп-лосс и тейк-профит повторяют настройки money-management из исходного кода.

Логика

  • Фильтр тренда – на старшем таймфрейме цены открытия и закрытия проходят через выбранное сглаживание. Каждая завершённая свеча сравнивает сглаженное закрытие с отложенным сглаженным открытием TrendPeriod баров назад. Закрытие выше смещённого открытия формирует бычий цвет (0), ниже – медвежий (2). Цвет сдвига TrendSignalBar переводится в тренд +1, -1 или 0.
  • Сигналы входа – рабочий таймфрейм выполняет те же вычисления и сохраняет текущий и предыдущий цвета, заданные EntrySignalBar. Для короткой позиции необходим нисходящий тренд, текущий цвет 0 и предыдущий цвет 2; для длинной позиции – восходящий тренд, текущий цвет 2 и предыдущий цвет 0. Это соответствует логике XPeriodCandle.
  • Управление позицией – флаги CloseLongOnTrendFlip, CloseShortOnTrendFlip, CloseLongOnEntrySignal, CloseShortOnEntrySignal закрывают позиции при развороте тренда или смене цвета на рабочем таймфрейме. Новая заявка отправляется объёмом Volume + |Position|, что обеспечивает закрытие и разворот аналогично MQL-реализации.
  • Риск-менеджмент – стоп-лосс и тейк-профит задаются в шагах цены (StopLossTicks, TakeProfitTicks) и активируются только при включённых флагах.
  • Методы сглаживания – используются стандартные индикаторы StockSharp: простая, экспоненциальная, сглаженная (SMMA), взвешенная, Hull, Kaufman Adaptive и Jurik. Параметры TrendPhase и EntryPhase применяются только к Jurik и ограничены диапазоном ±100.

Параметры

Параметр Описание
TrendCandleType Тип свечей старшего таймфрейма для фильтра тренда.
EntryCandleType Тип свечей рабочего таймфрейма для сигналов.
TrendPeriod Количество сглаженных свечей для расчёта смещённого открытия на старшем ТФ.
EntryPeriod Количество сглаженных свечей для смещённого открытия на рабочем ТФ.
TrendLength Длина сглаживания на старшем таймфрейме.
EntryLength Длина сглаживания на рабочем таймфрейме.
TrendPhase Параметр фазы Jurik для старшего таймфрейма (игнорируется другими методами).
EntryPhase Параметр фазы Jurik для рабочего таймфрейма (игнорируется другими методами).
TrendSignalBar Сдвиг цвета тренда (1 соответствует последней закрытой свече).
EntrySignalBar Сдвиг цветов для входа (1 – последняя свеча, 2 – предыдущая).
TrendSmoothing Тип сглаживания на старшем таймфрейме.
EntrySmoothing Тип сглаживания на рабочем таймфрейме.
EnableLongEntries Разрешить входы в лонг.
EnableShortEntries Разрешить входы в шорт.
CloseLongOnTrendFlip Закрывать лонг при смене тренда на медвежий.
CloseShortOnTrendFlip Закрывать шорт при смене тренда на бычий.
CloseLongOnEntrySignal Закрывать лонг при появлении медвежьего цвета на рабочем таймфрейме.
CloseShortOnEntrySignal Закрывать шорт при появлении бычьего цвета на рабочем таймфрейме.
UseStopLoss Включить стоп-лосс в шагах цены.
StopLossTicks Дистанция стоп-лосса в шагах цены.
UseTakeProfit Включить тейк-профит в шагах цены.
TakeProfitTicks Дистанция тейк-профита в шагах цены.

Примечания

  • Алгоритм смещённого открытия хранит самую старую сглаженную цену внутри окна, полностью повторяя циклический буфер оригинального индикатора.
  • Если TrendCandleType совпадает с EntryCandleType, создаётся единственная подписка на свечи, но логика двойного цвета сохраняется.
  • Перед запуском задайте подходящее значение Volume: при развороте стратегия автоматически добавляет модуль текущей позиции, как это делал эксперт в MetaTrader.
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>
/// Exp XPeriodCandle X2 strategy (simplified). Uses candle body analysis
/// with EMA trend filter for breakout entries.
/// </summary>
public class ExpXPeriodCandleX2Strategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _emaLength;

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

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

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

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

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

		var ema = new ExponentialMovingAverage { Length = EmaLength };

		decimal prevClose = 0, prevOpen = 0;
		var hasPrev = false;

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

				if (!hasPrev)
				{
					prevClose = candle.ClosePrice;
					prevOpen = candle.OpenPrice;
					hasPrev = true;
					return;
				}

				if (!IsFormedAndOnlineAndAllowTrading())
				{
					prevClose = candle.ClosePrice;
					prevOpen = candle.OpenPrice;
					return;
				}

				var close = candle.ClosePrice;

				// Two consecutive bullish candles above EMA
				if (prevClose > prevOpen && close > candle.OpenPrice && close > emaValue && Position <= 0)
					BuyMarket();
				// Two consecutive bearish candles below EMA
				else if (prevClose < prevOpen && close < candle.OpenPrice && close < emaValue && Position >= 0)
					SellMarket();

				prevClose = close;
				prevOpen = candle.OpenPrice;
			})
			.Start();

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