Открыть на GitHub

Стратегия The Predator

Обзор

Стратегия представляет собой конвертацию советника MQL "The Predator" на высокоуровневый API StockSharp. Оригинальная версия совмещает трендовые фильтры с импульсными показателями, полосами Боллинджера и стохастиком. В распоряжении остаются два шаблона входа (Strategy 1 и Strategy 2), полностью повторяющие режимы из MQL.

Все вычисления выполняются на одной настраиваемой серии свечей. Подписки и индикаторы подключаются через механизмы SubscribeCandles и Bind/BindEx, что позволяет обойтись без ручного хранения историй.

Используемые индикаторы

  • Линейные взвешенные скользящие средние (LWMA) — быстрый и медленный фильтр тенденции.
  • DMI + ADX — сила и направление тренда.
  • Momentum (по умолчанию период 14) — оценивает удалённость от нейтрального уровня 100.
  • Полосы Боллинджера — две оболочки (узкая и широкая) для анализа контекста предыдущей свечи.
  • Стохастический осциллятор — дополнительный фильтр для Strategy 2.
  • MACD — подтверждение импульса через сравнение основной и сигнальной линий.

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

Общие условия

  1. Обрабатываются только завершённые свечи.
  2. Перед торгами проверяется готовность индикаторов (IsFormedAndOnlineAndAllowTrading).
  3. ADX должен превышать заданный порог.
  4. Сохраняются три последних отклонения Momentum от уровня 100 (без обращения к GetValue).

Strategy 1

  • Покупка:
    • ADX выше порога и +DI превышает −DI.
    • Быстрая LWMA выше медленной.
    • Отклонение Momentum за один из последних трёх отсчётов превышает порог на покупку.
    • MACD выше сигнальной линии.
  • Продажа — зеркальные условия.

Strategy 2

  • Покупка дополнительно требует:
    • Закрытие предыдущей свечи не ниже узкой нижней полосы Боллинджера.
    • Стохастик: и основная, и сигнальная линии выше верхнего порога.
    • Отклонение Momentum ниже порога покупки хотя бы в одном из трёх значений (поиск откатов в тренде).
  • Продажа дополнительно требует:
    • Закрытие предыдущей свечи не выше узкой верхней полосы.
    • Стохастик: сигнальная линия выше верхнего порога, основная ниже нижнего порога.
    • Отклонение Momentum ниже порога продажи хотя бы раз за три отсчёта.

Управление позицией

  • Перед открытием нового ордера отменяются все активные заявки.
  • При смене направления существующая позиция закрывается и открывается новая противоположная одним маркет-ордером соответствующего объёма.

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

  • StartProtection задаёт:
    • Стоп-лосс в пунктах.
    • Тейк-профит в пунктах.
    • При необходимости — трейлинг-стоп в фиксированном размере.
  • Все расстояния пересчитываются в абсолютные цены через минимальный шаг инструмента.
  • Денежные тралы, безубыток и уведомления из MQL-версии не перенесены, вместо них применены пунктовые параметры.

Параметры

Параметр Описание
Mode Выбор шаблона Strategy 1 или Strategy 2.
FastMaLength, SlowMaLength Периоды быстрый/медленной LWMA.
DmiPeriod, AdxSmoothing Настройки DMI/ADX.
MomentumPeriod Период расчёта Momentum.
MomentumBuyThreshold, MomentumSellThreshold Минимальное отклонение от 100 для сигналов.
AdxThreshold Минимальный уровень ADX для работы.
BollingerPeriod, TightBandWidth, WideBandWidth Параметры полос Боллинджера.
StochasticLength, StochasticSmooth, StochasticUpper, StochasticLower Настройки стохастика для Strategy 2.
TradeVolume Торговый объём.
StopLossPips, TakeProfitPips, TrailingStopPips Расстояния стопов/тейков/трейлинга в пунктах.
CandleType Тип свечей для анализа.

Отличия от оригинала

  • Денежные стопы и тейк-профиты преобразованы в пунктовые значения и обрабатываются через StartProtection.
  • Логика безубытка, а также email/notification-сервисы отсутствуют.
  • В MQL некоторые индикаторы вызывались на старших таймфреймах. В StockSharp версия работает на выбранной серии; при необходимости можно добавить дополнительные подписки.
  • Мартингейл и адаптивный объём заменены на фиксированный параметр TradeVolume.

Использование

  1. Подготовьте соединение и портфель, как в других примерах StockSharp.
  2. Создайте экземпляр ThePredatorStrategy, назначьте Security, Portfolio и параметры.
  3. Запустите стратегию. При наличии окна графика индикаторы и сделки отобразятся автоматически.

Перевод сохраняет ключевые условия оригинала, но использует рекомендованные подходы StockSharp с привязкой индикаторов и стандартным блоком защиты позиций.

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;

public class ThePredatorStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private ExponentialMovingAverage _fast;
	private ExponentialMovingAverage _slow;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }

	public ThePredatorStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
		_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

	protected override void OnReseted()
	{
		base.OnReseted();
		_fast = null; _slow = null;
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_fast = new ExponentialMovingAverage { Length = FastPeriod };
		_slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, ProcessCandle);
		subscription.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
		if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}

		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }

		_prevFast = fastValue; _prevSlow = slowValue;
	}
}