Открыть на GitHub

Стратегия Williams Percent Directional Index

Общее описание

Williams Percent Directional Index Strategy — это порт StockSharp для эксперта MetaTrader 5 «Mt5 Williams % Directional Index EA». Логика построена на сочетании Williams %R и направленного движения ADX для поиска смены импульса, а закрытие позиций контролируется индикаторами Money Flow Index (MFI) и Stochastic Oscillator. Реализация работает только с полностью сформированными свечами и использует механизмы BindEx, поэтому решения принимаются на основе окончательных значений индикаторов.

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

  1. Подтверждение тренда
    • Для покупок Williams %R на двух предыдущих свечах должен расти (значение две свечи назад выше, чем одну свечу назад). Для продаж условие зеркальное.
    • Разница между линиями +DI и -DI (часть ADX) на последней закрывшейся свече обязана пересечь ноль: переход из отрицательной области в положительную подтверждает бычий импульс, переход из положительной в отрицательную — медвежий.
  2. Условия входа
    • Если оба бычьих фильтра выполнены и стратегия не имеет длинной позиции, открывается покупка по рынку.
    • Если оба медвежьих фильтра выполнены и нет короткой позиции, открывается продажа по рынку.
    • В редком случае одновременных сигналов направление пропускается, чтобы избежать конфликтов.
  3. Условия выхода
    • Длинная позиция закрывается, когда MFI двух свечей назад превышает уровень перекупленности либо когда %K стохастика формирует локальный «V-образный» разворот (K[-2] > K[-1] < K[0]).
    • Короткая позиция закрывается, когда MFI двух свечей назад падает ниже зеркального уровня перепроданности (100 - уровень) либо когда стохастик образует локальный максимум (K[-2] < K[-1] > K[0]).
  4. Управление рисками
    • В рамках конвертации сохранены только правила входа/выхода. Стоп-лоссы, трейлинг и временные фильтры из MQL-версии не реализованы и при необходимости должны быть добавлены отдельно средствами StockSharp.

Параметры

Имя Описание Значение по умолчанию
Candle Type Тип/таймфрейм свечей для расчётов. 15-минутные свечи
Williams %R Period Период расчёта индикатора Williams %R. 42
Directional Period Период ADX (влияет на +DI и -DI). 20
MFI Period Период индикатора Money Flow Index. 19
MFI Level Уровень перекупленности для закрытия. Уровень перепроданности вычисляется как 100 - значение. 79
Stochastic %K Период %K стохастика. 22
Stochastic %D Период %D стохастика. 16
Stochastic Smoothing Дополнительное сглаживание (slowing) стохастика. 21

Все параметры представлены через StrategyParam, поэтому их можно изменять и оптимизировать в интерфейсе StockSharp без правки кода.

Рекомендации по использованию

  • Перед запуском назначьте инструмент и объём, с которым стратегия будет работать.
  • Обработка выполняется только по свечам в состоянии CandleStates.Finished, что исключает пересчёт незавершённых баров.
  • При наличии графика стратегия отображает цену, Williams %R, ADX, MFI, стохастик и сделки для визуального контроля.
  • Если необходимо повторить поведение оригинального эксперта по стоп-менеджменту, добавьте StartProtection или собственный модуль управления рисками.

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

  • Используются встроенные индикаторы StockSharp и их привязка через BindEx, но математическая логика (пересечения нуля и трёхсвечные паттерны) полностью соответствует MQL-реализации.
  • Код сессий, повторных попыток отправки ордеров и трейлинг-стопа опущен, чтобы сосредоточиться на ключевых сигналах, как и требовалось в задаче.
namespace StockSharp.Samples.Strategies;

using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

/// <summary>
/// Williams %R Directional Index strategy: Williams %R crossover.
/// Buys when Williams %R crosses above -80, sells when crosses below -20.
/// </summary>
public class WilliamsPercentDirectionalIndexStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _period;
	private readonly StrategyParam<int> _signalCooldownCandles;

	private decimal _prevWr;
	private int _candlesSinceTrade;
	private bool _hasPrev;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int Period { get => _period.Value; set => _period.Value = value; }
	public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }

	public WilliamsPercentDirectionalIndexStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_period = Param(nameof(Period), 14)
			.SetGreaterThanZero()
			.SetDisplay("Period", "Williams %R period", "Indicators");
		_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 4)
			.SetGreaterThanZero()
			.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevWr = 0;
		_candlesSinceTrade = SignalCooldownCandles;
		_hasPrev = false;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevWr = 0;
		_candlesSinceTrade = SignalCooldownCandles;
		_hasPrev = false;
		var wr = new RelativeStrengthIndex { Length = Period };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(wr, ProcessCandle).Start();
	}

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

		if (_candlesSinceTrade < SignalCooldownCandles)
			_candlesSinceTrade++;

		if (_hasPrev)
		{
			if (_prevWr < 35 && wrValue >= 35 && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
			{
				BuyMarket();
				_candlesSinceTrade = 0;
			}
			else if (_prevWr > 65 && wrValue <= 65 && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
			{
				SellMarket();
				_candlesSinceTrade = 0;
			}
		}

		_prevWr = wrValue;
		_hasPrev = true;
	}
}