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);
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class exp_x_period_candle_x2_strategy(Strategy):
def __init__(self):
super(exp_x_period_candle_x2_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candles", "General")
self._ema_length = self.Param("EmaLength", 20) \
.SetDisplay("EMA Length", "Trend EMA period", "Indicators")
self._prev_close = 0.0
self._prev_open = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@property
def EmaLength(self):
return self._ema_length.Value
def OnReseted(self):
super(exp_x_period_candle_x2_strategy, self).OnReseted()
self._prev_close = 0.0
self._prev_open = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(exp_x_period_candle_x2_strategy, self).OnStarted2(time)
self._prev_close = 0.0
self._prev_open = 0.0
self._has_prev = False
ema = ExponentialMovingAverage()
ema.Length = self.EmaLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(ema, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def _on_process(self, candle, ema_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
open_p = float(candle.OpenPrice)
if not self._has_prev:
self._prev_close = close
self._prev_open = open_p
self._has_prev = True
return
ev = float(ema_value)
if (self._prev_close > self._prev_open and close > open_p
and close > ev and self.Position <= 0):
self.BuyMarket()
elif (self._prev_close < self._prev_open and close < open_p
and close < ev and self.Position >= 0):
self.SellMarket()
self._prev_close = close
self._prev_open = open_p
def CreateClone(self):
return exp_x_period_candle_x2_strategy()