Открыть на GitHub

Стратегия Get trend Stochastic

Стратегия представляет собой реализацию на высокоуровневом API StockSharp оригинального советника MetaTrader 4 Get trend.mq4. Основная работа ведётся на таймфрейме M15, при этом направление тренда подтверждается по H1. Используются две сглаженные скользящие средние (SMMA) и два стохастика для поиска откатных входов поблизости от медленной средней. Управление позицией сохраняет механику оригинала: фиксированные значения тейк-профита, стоп-лосса и трейлинг-стопа задаются в пунктах.

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

  1. Источник данных и индикаторы
    • Свечи M15 рассчитывают SMMA по медианной цене с периодом M15MaPeriod, а также два стохастика (быстрый и медленный).
    • Свечи H1 питают вторую SMMA по медианной цене с периодом H1MaPeriod.
    • Быстрый стохастик (FastStochasticPeriod, 3, 3) предоставляет текущее значение линии %K и его предыдущее значение. Медленный стохастик (SlowStochasticPeriod, 3, 3) используется ради сигнальной линии %D.
  2. Условия для покупок
    • Закрытие текущей свечи M15 находится ниже своей SMMA, а закрытие H1 — ниже своей SMMA.
    • Расстояние между M15-SMMA и закрытием не превышает ThresholdPoints пунктов.
    • Оба стохастика расположены ниже 20. Линия %K пересекает %D снизу вверх (текущее значение > %D при том, что предыдущее было ниже %D).
    • При наличии короткой позиции стратегия сначала докупает объём для её закрытия и только затем открывает новый лонг объёмом TradeVolume.
  3. Условия для продаж симметричны:
    • Оба закрытия находятся выше своих SММА, расстояние не превосходит ThresholdPoints, стохастики выше 80, а линия %K пересекает %D сверху вниз. При необходимости длинная позиция закрывается перед открытием шорта.
  4. Риск-менеджмент
    • После входа выставляются защитные ордера на расстояниях StopLossPoints и TakeProfitPoints, умноженных на шаг цены инструмента.
    • Трейлинг-стоп переставляет стоп-ордер, как только прибыль по сделке превышает TrailingStopPoints пунктов: стоп располагается на текущем закрытии минус/плюс трейлинг-дистанция для лонгов/шортов соответственно.
    • При выходе в ноль все защитные ордера снимаются.

Отличия от оригинального советника

  • В MT4 SMMA применяется с положительным сдвигом на восемь баров. В StockSharp отсутствует прямой параметр сдвига, поэтому используется значение индикатора на последней завершённой свече. Это сохраняет ключевую логику кроссоверов без внедрения дополнительных буферов.
  • В MQL трейлинг рассчитывался по Bid/Ask. В порте используется цена закрытия сформированной свечи, инициировавшей пересчёт трейлинга, что является ближайшим аналогом в высокоуровневом API.
  • Управление ордерами построено на стандартных методах StockSharp (BuyMarket, SellMarket, SellStop и т. д.) вместо вызовов OrderSend и OrderModify.

Параметры

Группа Имя Описание Значение по умолчанию
Data M15 Candle Type Таймфрейм/тип свечей для расчёта сигналов. Свечи M15
Data H1 Candle Type Таймфрейм/тип свечей для фильтра тренда. Свечи H1
Indicators M15 SMMA Period Период SMMA на серии M15. 200
Indicators H1 SMMA Period Период SMMA на серии H1. 200
Indicators Slow Stochastic Period Период %K медленного стохастика, формирующего линию %D. 14
Indicators Fast Stochastic Period Период %K быстрого стохастика. 14
Signals Threshold (points) Максимально допустимое расстояние от цены до M15-SMMA для входа. 50
Risk Take Profit (points) Дистанция тейк-профита в шагах цены. 570
Risk Stop Loss (points) Дистанция стоп-лосса в шагах цены. 30
Risk Trailing Stop (points) Дистанция трейлинг-стопа в шагах цены. 200
Trading Trade Volume Объём, отправляемый рыночными ордерами. 0.1

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

  • Убедитесь, что у инструмента задан PriceStep. При его отсутствии расстояния в пунктах будут интерпретированы как абсолютное значение 1, что может привести к слишком широким защитным ордерам.
  • Трейлинг реализован через снятие и повторную регистрацию стоп-ордера. Если брокер ограничивает количество модификаций, стоит добавить собственное ограничение частоты.
  • Стратегия работает с завершёнными свечами. Для онлайна необходимо синхронизировать правила построения свечей между терминалом и сервером StockSharp.
using System;

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

namespace StockSharp.Samples.Strategies;

public class GetTrendStochasticStrategy : Strategy
{
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<decimal> _oversold;
	private readonly StrategyParam<decimal> _overbought;
	private readonly StrategyParam<int> _cooldownCandles;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevRsi;
	private bool _hasPrev;
	private int _cooldownRemaining;

	public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
	public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
	public decimal Oversold { get => _oversold.Value; set => _oversold.Value = value; }
	public decimal Overbought { get => _overbought.Value; set => _overbought.Value = value; }
	public int CooldownCandles { get => _cooldownCandles.Value; set => _cooldownCandles.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public GetTrendStochasticStrategy()
	{
		_rsiPeriod = Param(nameof(RsiPeriod), 14).SetDisplay("RSI Period", "RSI lookback", "Indicators");
		_emaPeriod = Param(nameof(EmaPeriod), 20).SetDisplay("EMA Period", "EMA filter", "Indicators");
		_oversold = Param(nameof(Oversold), 35m).SetDisplay("Oversold", "RSI oversold level", "Levels");
		_overbought = Param(nameof(Overbought), 65m).SetDisplay("Overbought", "RSI overbought level", "Levels");
		_cooldownCandles = Param(nameof(CooldownCandles), 30).SetDisplay("Cooldown", "Candles between signals", "General");
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevRsi = default;
		_hasPrev = default;
		_cooldownRemaining = default;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevRsi = 0;
		_hasPrev = false;
		_cooldownRemaining = 0;

		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		var ema = new ExponentialMovingAverage { Length = EmaPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(rsi, ema, ProcessCandle).Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal rsi, decimal ema)
	{
		if (candle.State != CandleStates.Finished) return;
		var close = candle.ClosePrice;
		if (!_hasPrev) { _prevRsi = rsi; _hasPrev = true; return; }

		if (_cooldownRemaining > 0)
		{
			_cooldownRemaining--;
			_prevRsi = rsi;
			return;
		}

		if (_prevRsi <= Oversold && rsi > Oversold && close > ema && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
			_cooldownRemaining = CooldownCandles;
		}
		else if (_prevRsi >= Overbought && rsi < Overbought && close < ema && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
			_cooldownRemaining = CooldownCandles;
		}
		_prevRsi = rsi;
	}
}