Открыть на GitHub

Стратегия Ichimoku 2005

Эта стратегия представляет собой порт эксперта MetaTrader ichimok2005, адаптированный под высокоуровневый API StockSharp. Алгоритм ищет уверенные пробои выше или ниже линии Senkou Span B индикатора Ichimoku и подтверждает импульс серией направленных свечей.

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

Условия для покупки

  1. Анализируются последние Shift + 2 завершённых свечей (при значении Shift = 1 это три предыдущих бара).
  2. Необходимо, чтобы:
    • Самая дальняя свеча (Shift + 2) открылась ниже Senkou Span B.
    • Средняя свеча (Shift + 1) открылась и закрылась выше Senkou Span B.
    • Последняя свеча (Shift) открылась и закрылась выше Senkou Span B.
    • Две последние свечи были бычьими (цена закрытия выше цены открытия).
  3. Запаздывающая линия Chinkou не должна находиться внутри облака, когда Senkou Span A расположена ниже Senkou Span B. Это повторяет фильтр исходного эксперта, который избегает боковых фаз.
  4. При наличии короткой позиции она закрывается. Если предыдущий сигнал не был покупкой, открывается новая длинная позиция.

Условия для продажи

  1. Симметричные критерии в противоположном направлении:
    • Свеча Shift + 2 открывается выше Senkou Span B.
    • Свеча Shift + 1 открывается и закрывается ниже Senkou Span B.
    • Свеча Shift открывается и закрывается ниже Senkou Span B.
    • Две последние свечи являются медвежьими (цена закрытия ниже цены открытия).
  2. Линия Chinkou должна оставаться вне облака, если Senkou Span A ниже Senkou Span B.
  3. При наличии длинной позиции она закрывается. Если предыдущий сигнал не был продажей, открывается новая короткая позиция.

Стоп-лосс и тейк-профит задаются в шагах цены и автоматически преобразуются в абсолютные расстояния через PriceStep. Для имитации поведения MetaTrader используются защитные рыночные заявки.

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

Оригинальный советник поддерживал два режима:

  • Фиксированный объём (UseMoneyManagement = false): сделки исполняются объёмом OrderVolume (по умолчанию 0.1 лота).
  • Управление риском (UseMoneyManagement = true): размер позиции рассчитывается от текущей стоимости портфеля и процента MaximumRisk. Результат округляется к шагу лота инструмента и не опускается ниже одного шага.

Параметры

Параметр Описание Значение по умолчанию
StopLossPoints Расстояние стоп-лосса в шагах цены. 30
TakeProfitPoints Расстояние тейк-профита в шагах цены. 60
Shift Смещение по барам при проверке структуры пробоя. 1
OrderVolume Фиксированный объём при отключённом управлении риском. 0.1
MaximumRisk Процент портфеля, используемый при расчёте объёма. 10
UseMoneyManagement Включает управление риском. false
TenkanPeriod Период линии Tenkan-sen индикатора Ichimoku. 9
KijunPeriod Период линии Kijun-sen индикатора Ichimoku. 26
SenkouBPeriod Период линии Senkou Span B индикатора Ichimoku. 52
CandleType Таймфрейм расчётов (по умолчанию часовые свечи). 1 час

Примечания

  • Обрабатываются только завершённые свечи, поэтому значения Ichimoku всегда окончательные.
  • Переменная _lastSignal предотвращает повторное открытие сделки в том же направлении подряд, как и в оригинальном советнике.
  • Если инструмент не задаёт PriceStep, расстояния стоп-лосса и тейк-профита трактуются как абсолютные значения цены.
using System;

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

namespace StockSharp.Samples.Strategies;

public class Ichimoku2005Strategy : Strategy
{
	private readonly StrategyParam<int> _channelPeriod;
	private readonly StrategyParam<int> _cooldownCandles;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevClose;
	private decimal _prevMid;
	private bool _hasPrev;
	private int _cooldownRemaining;

	public int ChannelPeriod { get => _channelPeriod.Value; set => _channelPeriod.Value = value; }
	public int CooldownCandles { get => _cooldownCandles.Value; set => _cooldownCandles.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public Ichimoku2005Strategy()
	{
		_channelPeriod = Param(nameof(ChannelPeriod), 52).SetDisplay("Channel Period", "Channel lookback", "Indicators");
		_cooldownCandles = Param(nameof(CooldownCandles), 150).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();
		_prevClose = default;
		_prevMid = default;
		_hasPrev = default;
		_cooldownRemaining = default;
	}

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

		var highest = new Highest { Length = ChannelPeriod };
		var lowest = new Lowest { Length = ChannelPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(highest, lowest, ProcessCandle).Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal highest, decimal lowest)
	{
		if (candle.State != CandleStates.Finished) return;
		var close = candle.ClosePrice;
		var mid = (highest + lowest) / 2;
		if (!_hasPrev) { _prevClose = close; _prevMid = mid; _hasPrev = true; return; }

		if (_cooldownRemaining > 0)
		{
			_cooldownRemaining--;
			_prevClose = close;
			_prevMid = mid;
			return;
		}

		if (_prevClose <= _prevMid && close > mid && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
			_cooldownRemaining = CooldownCandles;
		}
		else if (_prevClose >= _prevMid && close < mid && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
			_cooldownRemaining = CooldownCandles;
		}
		_prevClose = close;
		_prevMid = mid;
	}
}