Открыть на GitHub

Стратегия ROC

Обзор

Стратегия ROC представляет собой порт советника MetaTrader из файла MQL/26938/ROC.mq4, реализованный на высокоуровневом API StockSharp. Она работает с одним инструментом и анализирует рынок при помощи цепочки линейно-взвешенных скользящих средних (LWMA), собственного индикатора изменения скорости (ROC), старшего таймфрейма для осциллятора Momentum и месячного MACD. Сохранены оригинальные блоки управления капиталом: перевод в безубыток, трейлинг-стоп в пунктах, защита по капиталу и фиксация прибыли в деньгах.

Логика входа

  1. Стратегия подписывается на три потока данных: торговый таймфрейм, повышенный таймфрейм для 14-периодного Momentum и месячные свечи для MACD.
  2. На каждой завершённой свече торгового таймфрейма проверяются условия:
    • Модель ROC должна показывать восходящий тренд (Line4 < Line5) для покупок или нисходящий тренд (Line4 > Line5) для продаж.
    • Быстрая LWMA по типичной цене должна быть выше медленной LWMA для покупок и ниже для продаж.
    • Любое из трёх последних значений Momentum старшего таймфрейма должно превышать соответствующий порог по модулю отклонения от 100.
    • Месячный MACD: основная линия находится выше сигнальной для покупок и ниже для продаж.
    • Количество добавочных позиций не превышает MaxTrades, а объём может увеличиваться после серии убыточных сделок при ненулевом IncreaseFactor.

Логика выхода

  • При изменении позиции рассчитываются уровни стоп-лосса и тейк-профита в пунктах MetaTrader.
  • Модуль безубытка переносит стоп в точку входа с заданным смещением после достижения целевой прибыли в пунктах.
  • Классический трейлинг-стоп подтягивает защитный уровень на каждом закрытии свечи.
  • Деньговая логика закрывает позицию при достижении целевой прибыли в валюте или процента от капитала и может сопровождать плавающую прибыль, фиксируя откат больше StopLossMoney после пробоя TakeProfitMoney.
  • Защита по капиталу сравнивает просадку с историческим максимумом equity и закрывает позицию при превышении разрешённого процента.
  • Параметр ExitStrategy немедленно закрывает позицию по рынку.

Параметры

Параметр Назначение
LotSize Базовый объём сделки.
IncreaseFactor Пересчёт объёма после серии убыточных сделок.
FastMaPeriod / SlowMaPeriod Длины LWMA для трендового фильтра.
PeriodMa0, PeriodMa1, BarsV, AverBars, KCoefficient Настройка кастомной модели ROC.
MomentumBuyThreshold, MomentumSellThreshold Минимальное отклонение Momentum от 100 для фильтра.
StopLossSteps, TakeProfitSteps Исходные уровни SL и TP в пунктах.
TrailingStopSteps Трейлинг-стоп в пунктах.
UseBreakEven, BreakEvenTriggerSteps, BreakEvenOffsetSteps Параметры модуля безубытка.
UseTpInMoney, TpInMoney, UseTpInPercent, TpInPercent Цели фиксации прибыли в деньгах и процентах.
EnableMoneyTrailing, TakeProfitMoney, StopLossMoney Параметры денежного трейлинга.
UseEquityStop, TotalEquityRisk Настройки защиты капитала.
MaxTrades Максимальное количество доливок в одном направлении.
ExitStrategy Принудительный выход из позиции.

Дополнительно

  • Таймфрейм для Momentum автоматически выбирается по аналогии с оригинальным switch из MQL.
  • Все индикаторы работают через Bind, поэтому не нужны ручные запросы исторических данных.
  • Стратегия использует неттинг: при появлении сигнала на покупку закрывает короткую позицию перед открытием лонга, что соответствует работе советника на счетах без хеджирования.
namespace StockSharp.Samples.Strategies;

using System;

using Ecng.Common;

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

/// <summary>
/// Rate of Change strategy: uses ROC indicator with WMA trend filter.
/// Buys when ROC crosses above zero and fast WMA > slow WMA.
/// Sells when ROC crosses below zero and fast WMA less than slow WMA.
/// </summary>
public class RocStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _rocPeriod;
	private readonly StrategyParam<int> _fastMaPeriod;
	private readonly StrategyParam<int> _slowMaPeriod;

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

	public int RocPeriod
	{
		get => _rocPeriod.Value;
		set => _rocPeriod.Value = value;
	}

	public int FastMaPeriod
	{
		get => _fastMaPeriod.Value;
		set => _fastMaPeriod.Value = value;
	}

	public int SlowMaPeriod
	{
		get => _slowMaPeriod.Value;
		set => _slowMaPeriod.Value = value;
	}

	public RocStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");

		_rocPeriod = Param(nameof(RocPeriod), 12)
			.SetGreaterThanZero()
			.SetDisplay("ROC Period", "Rate of Change period", "Indicators");

		_fastMaPeriod = Param(nameof(FastMaPeriod), 5)
			.SetGreaterThanZero()
			.SetDisplay("Fast WMA", "Fast WMA period", "Indicators");

		_slowMaPeriod = Param(nameof(SlowMaPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("Slow WMA", "Slow WMA period", "Indicators");
	}

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

		var roc = new RateOfChange { Length = RocPeriod };
		var fastMa = new WeightedMovingAverage { Length = FastMaPeriod };
		var slowMa = new WeightedMovingAverage { Length = SlowMaPeriod };

		decimal? prevRoc = null;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(roc, fastMa, slowMa, (candle, rocVal, fastMaVal, slowMaVal) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!IsFormedAndOnlineAndAllowTrading())
					return;

				if (prevRoc.HasValue)
				{
					if (prevRoc.Value <= 0 && rocVal > 0 && fastMaVal > slowMaVal && Position <= 0)
						BuyMarket();
					else if (prevRoc.Value >= 0 && rocVal < 0 && fastMaVal < slowMaVal && Position >= 0)
						SellMarket();
				}

				prevRoc = rocVal;
			})
			.Start();

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