Открыть на GitHub

Стратегия Pull Back

Обзор

Стратегия Pull Back переносит логику оригинального советника MetaTrader "PULL BACK" в инфраструктуру StockSharp. Алгоритм ищет откаты к быстрой взвешенной скользящей средней на старшем таймфрейме, проверяет силу импульса за несколько свечей и торгует в сторону тренда по индикатору MACD на длинном горизонте. После входа в позицию включаются правила управления риском: стоп-лосс, тейк-профит, перевод в безубыток и трейлинг-стоп.

Данные и индикаторы

  • Торговый таймфрейм: настраиваемый тип свечей (CandleType, по умолчанию 15 минут).
  • Подтверждающий таймфрейм: отдельная подписка (HigherCandleType, по умолчанию 1 час) для:
    • Быстрой и медленной WMA.
    • Индикатора Momentum с расчётом модуля отклонения от нейтрального уровня 100.
    • Обнаружения отката, когда свеча касается быстрой WMA.
  • Таймфрейм MACD: отдельная подписка (MacdCandleType, по умолчанию 30 дней) для оценки направления линии сигнала MACD.
  • Используемые индикаторы:
    • Взвешенная скользящая средняя (WMA) на рабочем и старшем таймфреймах.
    • Momentum с заданным периодом на старшем таймфрейме.
    • Moving Average Convergence Divergence (MACD) на длинном таймфрейме.

Логика входа

Длинные позиции

  1. На старшем таймфрейме быстрая WMA выше медленной.
  2. Последняя завершённая свеча открылась выше быстрой WMA и касалась её минимумом.
  3. Как минимум одно из трёх последних значений |Momentum-100| превышает MomentumBuyThreshold.
  4. Основная линия MACD выше сигнальной на выбранном таймфрейме MACD.
  5. На торговом таймфрейме быстрая WMA выше медленной.

При выполнении всех условий отправляется рыночная заявка на покупку, а цена входа сохраняется для контроля рисков.

Короткие позиции

  1. На старшем таймфрейме быстрая WMA ниже медленной.
  2. Последняя свеча открылась ниже быстрой WMA и касалась её максимумом.
  3. Одно из последних трёх значений |Momentum-100| превышает MomentumSellThreshold.
  4. Основная линия MACD ниже сигнальной.
  5. На торговом таймфрейме быстрая WMA ниже медленной.

При выполнении условий стратегия продаёт по рынку.

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

  • Стоп-лосс: расстояние StopLossTicks от цены входа (пересчёт в абсолютное значение через Security.PriceStep).
  • Тейк-профит: расстояние TakeProfitTicks от цены входа.
  • Безубыток: при продвижении цены на BreakEvenTriggerTicks стоп переносится на уровень входа плюс BreakEvenOffsetTicks в сторону сделки (если UseBreakEven = true).
  • Трейлинг-стоп: при UseTrailingStop = true стоп следует за ценой с отступом TrailingStopTicks.
  • Проверка выхода: выполняется на каждой завершённой свече торгового таймфрейма; при достижении стопа или цели позиция закрывается рыночной заявкой.

Параметры

Параметр Описание
FastMaLength Период быстрой WMA на торговом таймфрейме (по умолчанию 6).
SlowMaLength Период медленной WMA на торговом таймфрейме (по умолчанию 85).
BounceSlowLength Период медленной WMA на подтверждающем таймфрейме (по умолчанию 200).
MomentumLength Период Momentum на старшем таймфрейме (по умолчанию 14).
MomentumBuyThreshold Минимальное Momentum-100 для входа в лонг (по умолчанию 0.3).
MomentumSellThreshold Минимальное Momentum-100 для входа в шорт (по умолчанию 0.3).
StopLossTicks Стоп-лосс в тиках (по умолчанию 200).
TakeProfitTicks Тейк-профит в тиках (по умолчанию 500).
UseTrailingStop Включение трейлинг-стопа (по умолчанию true).
TrailingStopTicks Отступ трейлинг-стопа в тиках (по умолчанию 400).
UseBreakEven Включение перевода в безубыток (по умолчанию true).
BreakEvenTriggerTicks Триггер перевода в безубыток в тиках (по умолчанию 300).
BreakEvenOffsetTicks Смещение стопа после перевода в безубыток в тиках (по умолчанию 300).
MacdFastLength Быстрый период EMA для MACD (по умолчанию 12).
MacdSlowLength Медленный период EMA для MACD (по умолчанию 26).
MacdSignalLength Период сигнальной EMA MACD (по умолчанию 9).
CandleType Тип свечей торгового таймфрейма.
HigherCandleType Тип свечей подтверждающего таймфрейма.
MacdCandleType Тип свечей для расчёта MACD.

Примечания

  • Для корректного пересчёта тиковых расстояний необходимо, чтобы Security.PriceStep был задан поставщиком данных.
  • Стратегия удерживает только одну суммарную позицию; сигналы в противоположную сторону игнорируются до закрытия текущей.
  • Обработка выполняется только по завершённым свечам, чтобы исключить реакцию на неполные данные.
using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

public class PullBackStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private decimal? _prevFast, _prevSlow;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }

	public PullBackStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
		_fastPeriod = Param(nameof(FastPeriod), 5).SetGreaterThanZero().SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 15).SetGreaterThanZero().SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = null;
		_prevSlow = null;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevFast = null; _prevSlow = null;
		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, ProcessCandle).Start();
		var area = CreateChartArea();
		if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, fast); DrawIndicator(area, slow); DrawOwnTrades(area); }
	}

	private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!IsFormedAndOnlineAndAllowTrading()) { _prevFast = fast; _prevSlow = slow; return; }
		if (_prevFast == null || _prevSlow == null) { _prevFast = fast; _prevSlow = slow; return; }
		var prevAbove = _prevFast.Value > _prevSlow.Value;
		var currAbove = fast > slow;
		_prevFast = fast; _prevSlow = slow;
		if (!prevAbove && currAbove && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
		else if (prevAbove && !currAbove && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
	}
}