Открыть на GitHub

Стратегия Ichimoku Retracement

Стратегия представляет собой конвертацию MetaTrader-советника «ICHMOKU RETRACEMENT» на платформу StockSharp. Основная идея заключается в поиске откатов к линиям Ichimoku внутри устойчивого тренда более высокого таймфрейма, подтверждённого импульсом и месячным MACD. Реализация использует высокоуровневый API StockSharp, поэтому стратегию легко запускать в Designer или в собственных проектах.

Торговая концепция

  1. Фильтр тренда. Пара линейно-взвешенных скользящих средних (LWMA) задаёт направление: бычий тренд – когда быстрая LWMA выше медленной, медвежий – наоборот.
  2. Откат к Ichimoku. После подтверждения тренда предыдущая свеча должна коснуться одной из линий Ichimoku (Tenkan, Kijun или ведущих спанов). Текущая свеча должна открыться по направлению тренда относительно этой линии – так определяется окончание отката.
  3. Импульс. Используется отношение закрытия (текущее закрытие к закрытию N свечей назад ×100). Требуется, чтобы отклонение от уровня 100 достигло заданного порога.
  4. Макро-фильтр. На старшем таймфрейме (по умолчанию 30 дней) рассчитывается MACD 12/26/9. Для лонгов нужна ситуация, когда линия MACD выше сигнальной, для шортов – наоборот.
  5. Управление позицией. Допускается только одна чистая позиция. Риск контролируется фиксированными стопом и тейк-профитом в пунктах, которые проверяются по закрытым свечам.

Параметры

Имя Описание Значение по умолчанию
Signal Candle Type Таймфрейм для расчёта LWMA, Ichimoku и импульса. Свечи 1 часа
Macro Candle Type Старший таймфрейм для фильтра MACD. Свечи 30 дней
Fast LWMA Период быстрой LWMA. 6
Slow LWMA Период медленной LWMA. 85
Tenkan Period Период линии Tenkan. 9
Kijun Period Период линии Kijun. 26
Span B Period Период ведущего спана B. 52
Momentum Period Длина окна для импульсного отношения. 14
Momentum Threshold Минимальное отклонение от 100 для импульса. 0.3
Take Profit (pips) Расстояние тейк-профита в пунктах. 50
Stop Loss (pips) Расстояние стоп-лосса в пунктах. 20

Базовый параметр Volume определяет объём новых сделок. При смене направления стратегия закрывает текущую позицию и открывает новую в противоположную сторону объёмом Volume + |Position|.

Правила торговли

Вход в длинную позицию

  • Быстрая LWMA выше медленной.
  • На макро-таймфрейме линия MACD выше сигнальной.
  • Импульсное отклонение ≥ заданного порога.
  • Минимум предыдущей свечи касается одной из линий Ichimoku, а текущая свеча открывается выше той же линии.
  • Нет длинной позиции или имеется короткая.

Вход в короткую позицию

  • Быстрая LWMA ниже медленной.
  • На макро-таймфрейме линия MACD ниже сигнальной.
  • Импульсное отклонение ≥ порога.
  • Максимум предыдущей свечи касается одной из линий Ichimoku, а текущая свеча открывается ниже этой линии.
  • Нет короткой позиции или имеется длинная.

Выход

  • Лонг закрывается, если минимум свечи достигает стопа или максимум достигает тейк-профита.
  • Шорт закрывается, если максимум свечи достигает стопа или минимум достигает тейк-профита.

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

  • Не реализованы мартингейл, наращивание лота, перевод в безубыток и другие сервисные функции – остаются только фиксированные стоп и тейк.
  • StockSharp работает с чистой позицией, поэтому вместо каскада ордеров всегда используется один вход в каждую сторону.
  • Убраны уведомления, письма и алерты MetaTrader.

Рекомендации по использованию

  1. Добавьте стратегию в StockSharp Designer или Shell и выберите инструмент.
  2. Подберите значение Signal Candle Type в соответствии с желаемым рабочим таймфреймом.
  3. Убедитесь, что Macro Candle Type может быть построен из доступных данных (allowBuildFromSmallerTimeFrame включён).
  4. Настройте уровни стопа, тейка и порог импульса под волатильность инструмента.

Исходный код снабжён комментариями на английском языке, что облегчает его модификацию и интеграцию с другими фильтрами.

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 IchimokuRetracementStrategy : 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 IchimokuRetracementStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
		_fastPeriod = Param(nameof(FastPeriod), 9).SetGreaterThanZero().SetDisplay("Fast DEMA", "Fast DEMA period", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 26).SetGreaterThanZero().SetDisplay("Slow DEMA", "Slow DEMA 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 DoubleExponentialMovingAverage { Length = FastPeriod };
		var slow = new DoubleExponentialMovingAverage { 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(); }
	}
}