Открыть на GitHub

Стратегия XAng Zad C TM MM Rec

Обзор

Стратегия является C#-портом советника MetaTrader Exp_XAng_Zad_C_Tm_MMRec. Она использует адаптивные каналы индикатора XAng Zad C, ограничение по торговой сессии и блок управления капиталом, который уменьшает объем сделок после серии убыточных трейдов. Цель — отлавливать пробои в момент пересечения верхней и нижней линий канала и снижать риск при неблагоприятной серии сделок.

Основные элементы

  • Индикатор. XAng Zad C строит адаптивные верхнюю и нижнюю границы. В C#-версии воспроизведены расчеты канала и реализованы сглаживания SMA, EMA, SMMA и LWMA. Экзотические методы, отсутствующие в StockSharp, автоматически заменяются на EMA.
  • Входы. Если на предыдущей свече верхняя линия была выше нижней, а на текущей закрывшейся свече опустилась ниже, формируется сигнал на покупку. Обратная ситуация — сигнал на продажу. Параметр SignalShift задает, сколько закрытых свечей участвует в сравнении.
  • Выходы. Дополнительные флаги позволяют закрывать длинные позиции при повторном падении верхней линии и закрывать короткие позиции при росте нижней. Выход также выполняется сразу, когда цена выходит за рамки разрешенного торгового окна.
  • Управление капиталом. Стратегия хранит историю результатов. Если среди последних BuyTotalTrigger (или SellTotalTrigger) сделок обнаруживается не менее BuyLossTrigger (или SellLossTrigger) убыточных, следующий вход выполняется уменьшенным объемом. При отсутствии серии убытков возвращается стандартный объем.
  • Риск. Фиксированные стоп-лосс и тейк-профит задаются в шагах цены (Security.PriceStep). При достижении уровня внутри свечи позиция закрывается по соответствующей цене.

Параметры

Имя Описание
NormalVolume Базовый объем сделки при отсутствии серии убытков.
ReducedVolume Объем сделки после серии убыточных трейдов.
BuyTotalTrigger / SellTotalTrigger Количество последних сделок, которые анализируются при оценке серии.
BuyLossTrigger / SellLossTrigger Число убыточных сделок в анализируемом окне, необходимое для уменьшения объема.
EnableBuyEntries / EnableSellEntries Разрешение на открытие длинных / коротких позиций.
EnableBuyExit / EnableSellExit Разрешение на автоматическое закрытие позиций по сигналам индикатора.
UseTradingWindow Включение ограничения по времени торговли.
WindowStart / WindowEnd Начало и конец торгового окна (UTC). Окно может пересекать полуночь.
StopLoss Расстояние стоп-лосса в шагах цены (0 — отключено).
TakeProfit Расстояние тейк-профита в шагах цены (0 — отключено).
SignalShift Количество закрытых свечей, участвующих в сравнении линий.
CandleType Тип свечей для расчета индикатора (по умолчанию 4 часа).
SmoothMethods Метод сглаживания внутри индикатора. Не поддерживаемые методы автоматически заменяются на EMA.
MaLength Длина сглаживания.
MaPhase Дополнительный параметр фазы (сохранен для совместимости).
Ki Коэффициент, определяющий скорость реакции канала на цену.
AppliedPrices Тип цены, подаваемой на вход индикатора (Close, Open, Median и т.д.).

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

  • В оригинале использовались глобальные функции работы с историей сделок. В C#-версии результаты фиксируются внутри стратегии, но логика триггеров сохранена.
  • Объем сделок задается напрямую через параметры NormalVolume и ReducedVolume и должен соответствовать инфраструктуре брокера.
  • Торговое окно задается через TimeSpan. Если WindowStart совпадает с WindowEnd, торговля отключается (поведение нулевого окна в оригинале).
  • Стратегия предполагает полный разворот позиции — частичное удержание старых позиций не реализовано.
  • Для отсутствующих в StockSharp сглаживаний (JJMA, JurX, ParMA, T3, VIDYA, AMA) используется EMA по умолчанию. При необходимости можно расширить метод CreateMovingAverage.

Рекомендации по применению

  1. Подбирайте тип свечей, соответствующий таймфрейму оригинального советника (по умолчанию H4).
  2. Настраивайте стоп-лосс и тейк-профит в шагах цены так, чтобы приблизительно соответствовать точкам из MQL5.
  3. Оптимизируйте параметры управления капиталом под волатильность инструмента и допустимый риск.
  4. Перед запуском сравните линии индикатора на графике, чтобы убедиться, что портированная версия ведет себя так же, как оригинал.
using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// XAng Zad strategy using SMA crossover with momentum recovery.
/// </summary>
public class XAngZadCTmMmRecStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;

	private decimal? _prevFast;
	private decimal? _prevSlow;

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

	public int FastPeriod
	{
		get => _fastPeriod.Value;
		set => _fastPeriod.Value = value;
	}

	public int SlowPeriod
	{
		get => _slowPeriod.Value;
		set => _slowPeriod.Value = value;
	}

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

		_fastPeriod = Param(nameof(FastPeriod), 10)
			.SetGreaterThanZero()
			.SetDisplay("Fast Period", "Fast SMA period", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 30)
			.SetGreaterThanZero()
			.SetDisplay("Slow Period", "Slow SMA period", "Indicators");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = null;
		_prevSlow = null;
	}

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

		_prevFast = null;
		_prevSlow = null;

		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fast, slow, ProcessCandle)
			.Start();

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

	private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!IsFormedAndOnlineAndAllowTrading())
		{
			_prevFast = fastVal;
			_prevSlow = slowVal;
			return;
		}

		if (_prevFast == null || _prevSlow == null)
		{
			_prevFast = fastVal;
			_prevSlow = slowVal;
			return;
		}

		var prevAbove = _prevFast.Value > _prevSlow.Value;
		var currAbove = fastVal > slowVal;

		_prevFast = fastVal;
		_prevSlow = slowVal;

		if (!prevAbove && currAbove)
		{
			if (Position < 0)
				BuyMarket();
			if (Position <= 0)
				BuyMarket();
		}
		else if (prevAbove && !currAbove)
		{
			if (Position > 0)
				SellMarket();
			if (Position >= 0)
				SellMarket();
		}
	}
}