Открыть на GitHub

Стратегия 5MIN Scalping

Адаптация советника MT4 "5MIN SCALPING" (MQL ID 22828) на инфраструктуру StockSharp с использованием высокоуровневого API. Стратегия ищет быстрые пробойные сетапы на базовом таймфрейме, подтверждает их импульсом старшего горизонта и направлением месячного MACD, а затем открывает сделку.

  • Категория: Скальпинг / пробой с подтверждением импульсом
  • Оригинальная платформа: MetaTrader 4
  • Требования к данным: Поток тиков или свечей для всех используемых таймфреймов (по умолчанию 5 минут, 30 минут, 1 месяц)

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

  1. Фильтр тренда. Две линейно-взвешенные скользящие средние (LWMA) с настраиваемыми периодами (по умолчанию 6 и 85) определяют направление тренда. Для покупок требуется, чтобы быстрая LWMA была выше медленной, для продаж — наоборот.
  2. Паттерн из нескольких свечей. Внутренний набор LWMA с периодами 8, 13 и 21 анализирует последние 20 завершённых свечей, повторяя логику функции scalper() из MQL:
    • Для лонга каждая свеча в окне должна удовлетворять условиям LWMA8 > LWMA13 > LWMA21, минимум свечи откатывается в область средних, а текущая цена закрытия пробивает максимум предыдущих 5 свечей.
    • Для шорта используется зеркальная проверка: максимум свечи касается диапазона средних, а текущее закрытие опускается ниже минимума предыдущих 5 свечей.
  3. Защита от ложных всплесков. Дополнительное условие перекрытия (Low[2] < High[1] для покупок, Low[1] < High[2] для продаж) исключает одиночные шпильки без структуры.
  4. Импульсное подтверждение. Индикатор Momentum на старшем таймфрейме (по умолчанию 30-минутные свечи, период 14) должен показать, что хотя бы одно из трёх последних значений отклоняется от базового уровня 100 больше, чем заданный порог (0.3 по умолчанию).
  5. Месячный MACD. Рассчитывается MACD(12, 26, 9) на месячных свечах. Для входа в лонг линия MACD должна находиться выше сигнальной, для шорта — ниже.
  6. Агрегация позиции. Переход из одной стороны в другую автоматически закрывает текущую позицию и открывает новую с указанным объёмом.

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

  • Фиксированные цели. Необязательные уровни тейк-профита и стоп-лосса, задаваемые в пунктах (конвертируются через PriceStep).
  • Переход в безубыток. При включении стоп переносится на уровень входа ± смещение, как только цена проходит заданное расстояние.
  • Трейлинг-стоп. Необязательный трейлинг, следующий за ценой на фиксированное число пунктов.
  • Ручные выходы. Все закрытия выполняются внутри стратегии без постановки защитных заявок, что повторяет поведение оригинального эксперта.

Параметры

Параметр Значение по умолчанию Описание
CandleType Таймфрейм 5 минут Основной таймфрейм, на котором ищется пробой.
MomentumCandleType Таймфрейм 30 минут Свечи для импульсного подтверждения.
MacroMacdCandleType Таймфрейм 1 месяц Свечи для расчёта долгосрочного MACD.
FastMaLength 6 Период быстрой LWMA.
SlowMaLength 85 Период медленной LWMA.
MomentumLength 14 Длина окна индикатора Momentum.
MomentumBuyThreshold 0.3 Минимальное отклонение Momentum-100 для подтверждения покупок.
MomentumSellThreshold 0.3 Минимальное отклонение Momentum-100 для подтверждения продаж.
TakeProfitPips 50 Дистанция тейк-профита в пунктах (0 — отключить).
StopLossPips 20 Дистанция стоп-лосса в пунктах (0 — отключить).
TrailingStopPips 40 Дистанция трейлинг-стопа в пунктах (работает при включённом EnableTrailing).
EnableTrailing true Включает или отключает трейлинг-стоп.
EnableBreakEven true Включает автоматический переход в безубыток.
BreakEvenTriggerPips 30 Прибыль в пунктах, после которой активируется безубыток.
BreakEvenOffsetPips 30 Дополнительный буфер (в пунктах) при переносе стопа в безубыток.
TradeVolume 1 Объём заявки при входе.

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

  1. Добавьте стратегию в проект StockSharp и выберите нужный инструмент.
  2. Убедитесь, что история по всем требуемым таймфреймам загружена до запуска.
  3. Настройте объём, таймфреймы и пороги под волатильность выбранного инструмента.
  4. Запустите стратегию: она подпишется на нужные серии свечей, построит индикаторы (при наличии графика) и будет автоматически управлять сделками.

Отличия от исходного советника

  • Денежные модули (Take_Profit_In_Money, TRAIL_PROFIT_IN_MONEY2) и блок стопа по эквити не перенесены — управление рисками выполняется через пунктовые расстояния.
  • Мартингейл-увеличение лота (Lots * MathPow(LotExponent, CountTrades())) не реализовано. При необходимости корректируйте TradeVolume вручную.
  • Почтовые и push-уведомления из оригинального кода опущены. При необходимости используйте уведомления StockSharp.
  • Конвертация пунктов опирается на PriceStep инструмента. Проверьте корректность параметров инструмента в вашем соединении.
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>
/// 5-minute scalping strategy using fast/slow WMA crossover with momentum confirmation.
/// Buys on bullish crossover, sells on bearish crossover.
/// </summary>
public class FiveMinScalpingStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private WeightedMovingAverage _fast;
	private WeightedMovingAverage _slow;

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

	/// <summary>
	/// Fast WMA period.
	/// </summary>
	public int FastPeriod
	{
		get => _fastPeriod.Value;
		set => _fastPeriod.Value = value;
	}

	/// <summary>
	/// Slow WMA period.
	/// </summary>
	public int SlowPeriod
	{
		get => _slowPeriod.Value;
		set => _slowPeriod.Value = value;
	}

	/// <summary>
	/// Stop-loss distance in price steps.
	/// </summary>
	public int StopLossPoints
	{
		get => _stopLossPoints.Value;
		set => _stopLossPoints.Value = value;
	}

	/// <summary>
	/// Take-profit distance in price steps.
	/// </summary>
	public int TakeProfitPoints
	{
		get => _takeProfitPoints.Value;
		set => _takeProfitPoints.Value = value;
	}

	/// <summary>
	/// Initializes a new instance of the <see cref="FiveMinScalpingStrategy"/> class.
	/// </summary>
	public FiveMinScalpingStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("Fast Period", "Fast WMA period", "Indicator");

		_slowPeriod = Param(nameof(SlowPeriod), 85)
			.SetGreaterThanZero()
			.SetDisplay("Slow Period", "Slow WMA period", "Indicator");

		_stopLossPoints = Param(nameof(StopLossPoints), 200)
			.SetNotNegative()
			.SetDisplay("Stop Loss", "Stop-loss distance in price steps", "Risk");

		_takeProfitPoints = Param(nameof(TakeProfitPoints), 500)
			.SetNotNegative()
			.SetDisplay("Take Profit", "Take-profit distance in price steps", "Risk");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_fast = null;
		_slow = null;
		_prevFast = 0;
		_prevSlow = 0;
		_entryPrice = 0;
		_cooldown = 0;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_fast = new WeightedMovingAverage { Length = FastPeriod };
		_slow = new WeightedMovingAverage { 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;

		// Check SL/TP
		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step)
			{
				SellMarket();
				_entryPrice = 0;
				_cooldown = 60;
				_prevFast = fastValue;
				_prevSlow = slowValue;
				return;
			}

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

			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step)
			{
				BuyMarket();
				_entryPrice = 0;
				_cooldown = 60;
				_prevFast = fastValue;
				_prevSlow = slowValue;
				return;
			}
		}

		// WMA crossover buy
		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();

			BuyMarket();
			_entryPrice = close;
			_cooldown = 60;
		}
		// WMA crossover sell
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{
			if (Position > 0)
				SellMarket();

			SellMarket();
			_entryPrice = close;
			_cooldown = 60;
		}

		_prevFast = fastValue;
		_prevSlow = slowValue;
	}
}