View on GitHub

Ichimoku 2005 Strategy

This strategy is a direct port of the MetaTrader expert advisor ichimok2005 tailored for the StockSharp high-level API. It focuses on identifying decisive breakouts above or below the Ichimoku Senkou Span B line and confirms momentum through consecutive candle bodies.

Trading Logic

Long setup

  1. Evaluate the last Shift + 2 completed candles (the default Shift is 1, so the algorithm observes the previous three bars).
  2. Require that:
    • The oldest reference candle (Shift + 2) opened below Senkou Span B.
    • The middle reference candle (Shift + 1) opened above Senkou Span B and closed above it.
    • The most recent reference candle (Shift) opened and closed above Senkou Span B.
    • The last two reference candles are bullish (close price is greater than open price).
  3. Ensure that the Ichimoku Chinkou Span is not trapped inside the cloud when Senkou Span A is below Senkou Span B. This mimics the original expert advisor filter that avoids congested market phases.
  4. If the strategy currently holds a short position, it is closed. Otherwise a new long trade is opened provided the previous signal was not already long.

Short setup

  1. Mirror the long conditions in the opposite direction:
    • Candle Shift + 2 must open above Senkou Span B.
    • Candle Shift + 1 must open and close below Senkou Span B.
    • Candle Shift must open and close below Senkou Span B.
    • The last two reference candles are bearish (close price is less than open price).
  2. The Chinkou Span must stay outside the cloud when Senkou Span A is below Senkou Span B.
  3. Close any existing long position, then open a new short position if the previous signal was not short.

Positions are managed with StockSharp's protective orders. Stop loss and take profit are measured in price steps and converted to absolute distances using the instrument's PriceStep. Protective orders are registered with market exits to replicate the MetaTrader behaviour of using market stops.

Position Sizing

The original advisor supported two sizing modes:

  • Fixed volume (UseMoneyManagement = false): trades are executed with the OrderVolume parameter (default 0.1 lots).
  • Money management (UseMoneyManagement = true): the strategy uses the portfolio's current value and the MaximumRisk percentage to derive the order size. The result is snapped to the security's lot step and never falls below a single step.

Parameters

Parameter Description Default
StopLossPoints Stop-loss distance in price steps. 30
TakeProfitPoints Take-profit distance in price steps. 60
Shift Number of bars used as an offset when validating the breakout structure. 1
OrderVolume Fixed trade size when money management is disabled. 0.1
MaximumRisk Portfolio percentage used to size orders when money management is enabled. 10
UseMoneyManagement Enables risk-based position sizing. false
TenkanPeriod Tenkan-sen period of the Ichimoku indicator. 9
KijunPeriod Kijun-sen period of the Ichimoku indicator. 26
SenkouBPeriod Senkou Span B period of the Ichimoku indicator. 52
CandleType Timeframe for all calculations (defaults to hourly candles). 1 hour

Notes

  • Only completed candles are processed, guaranteeing that the Ichimoku values are final.
  • The strategy keeps track of the last executed direction (_lastSignal) to avoid repeating identical orders on consecutive signals, matching the MetaTrader expert behaviour.
  • If the instrument does not publish PriceStep, the stop-loss and take-profit distances are treated as absolute price values.
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;
	}
}