The Expert Ichimoku strategy replicates the logic of the original MQL5 "Expert Ichimoku" expert advisor using StockSharp's high-level API. The system is a directional trend-following model that combines multiple components of the Ichimoku Kinko Hyo indicator with price-action filters and an optional martingale-style position sizing module.
The strategy evaluates signals on completed candles of a configurable timeframe. Long and short trades are mutually exclusive — the strategy maintains a single net position and flips direction only after closing the existing exposure. All indicator values are calculated on the subscribed candle series; no external data is required.
Core Logic
Indicator Configuration
Tenkan-sen (Conversion Line): Fast moving average used for crossover detection.
Kijun-sen (Base Line): Slow moving average forming the crossover partner.
Senkou Span A / Senkou Span B: Cloud boundaries evaluated on the previous bar to confirm bullish or bearish market structure.
Position filter: No long exposure is currently active. If a short position exists, it is closed first; the new long is submitted only after the short has been flattened.
A short position is opened under symmetric conditions:
Momentum trigger: Either
Tenkan-sen crossed below Kijun-sen (Tenkant-1 ≥ Kijunt-1 and Tenkant < Kijunt), or
The Chikou Span broke below historical price (Chikout-1 ≥ Opent-11 and Chikout < Opent-10),
Cloud filter: The current close is below both Senkou spans from the previous bar,
Position filter: Existing long exposure is closed before opening the short.
Position Sizing and Martingale Option
The base order size equals the strategy Volume property.
When Use Martingale is enabled, the next entry size doubles if the previous completed trade closed with a loss. Profitable or breakeven trades reset the multiplier.
The resulting order size is capped by Volume × Max Position Multiplier, mirroring the maximum-number-of-positions safeguard in the original EA.
Risk Management
Static Stop-Loss / Take-Profit: Optional absolute price offsets are applied to each new position. If the close price reaches the stop or target, the position is closed at market.
Trailing Stop: When both Trailing Stop Offset and Trailing Step are positive, the stop level is tightened only after price advances beyond offset + step from the entry, emulating the incremental trailing logic from the MQL5 version.
The strategy trades one net position. Upon exit (via stop, target, trailing, or reversal), the realized PnL is evaluated to update the martingale flag for the next signal.
Parameters
Name
Description
Default
Tenkan Period
Length of the Tenkan-sen line.
9
Kijun Period
Length of the Kijun-sen line.
26
Senkou Span B Period
Length of the Senkou Span B line.
52
Stop Loss Offset
Absolute distance between entry price and protective stop. Set to 0 to disable.
0
Take Profit Offset
Absolute distance between entry price and profit target. Set to 0 to disable.
0
Trailing Stop Offset
Base trailing distance applied after activation.
0
Trailing Step
Additional movement required before tightening the trailing stop.
0
Max Position Multiplier
Upper bound for the effective order size (relative to Volume).
5
Use Martingale
Whether to double the next trade size after a losing trade.
true
Candle Type
Candle series used for calculations.
1-hour time frame
Practical Notes
The strategy requires at least 12 completed candles before all conditions can be evaluated (Chikou comparisons reference prices up to 11 bars back).
Because StockSharp strategies operate on net positions, the Max Position Multiplier parameter caps the maximum contract size instead of managing multiple independent tickets. This keeps the behavior aligned with the exposure limit from the MQL5 implementation.
Trailing-stop logic mirrors the EA: the stop is moved only when the price has progressed by Trailing Stop Offset + Trailing Step. Setting either parameter to zero disables trailing adjustments.
Logging statements report every entry and exit, making it easy to audit decision points when replaying market data.
Usage Workflow
Configure the desired candle type and instrument in a StrategyContainer or designer template.
Set base Volume and adjust risk parameters according to symbol volatility (e.g., convert pip-based distances from the original EA into price units for the selected market).
Start the strategy. Once the indicator has sufficient history, it will evaluate crossovers and lagging-line confirmations on each completed bar, automatically managing exits and martingale sizing.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Ichimoku strategy using Tenkan/Kijun crossover (midline of short/long channels).
/// </summary>
public class ExpertIchimokuStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _tenkanPeriod;
private readonly StrategyParam<int> _kijunPeriod;
private decimal? _prevTenkan;
private decimal? _prevKijun;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int TenkanPeriod
{
get => _tenkanPeriod.Value;
set => _tenkanPeriod.Value = value;
}
public int KijunPeriod
{
get => _kijunPeriod.Value;
set => _kijunPeriod.Value = value;
}
public ExpertIchimokuStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_tenkanPeriod = Param(nameof(TenkanPeriod), 9)
.SetGreaterThanZero()
.SetDisplay("Tenkan Period", "Short channel period", "Indicators");
_kijunPeriod = Param(nameof(KijunPeriod), 26)
.SetGreaterThanZero()
.SetDisplay("Kijun Period", "Long channel period", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevTenkan = null;
_prevKijun = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevTenkan = null;
_prevKijun = null;
// Tenkan: midline of short highest/lowest
var tenkanHigh = new Highest { Length = TenkanPeriod };
var tenkanLow = new Lowest { Length = TenkanPeriod };
// Kijun: midline of long highest/lowest
var kijunHigh = new Highest { Length = KijunPeriod };
var kijunLow = new Lowest { Length = KijunPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(tenkanHigh, tenkanLow, kijunHigh, kijunLow, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal tHigh, decimal tLow, decimal kHigh, decimal kLow)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var tenkan = (tHigh + tLow) / 2;
var kijun = (kHigh + kLow) / 2;
if (_prevTenkan == null || _prevKijun == null)
{
_prevTenkan = tenkan;
_prevKijun = kijun;
return;
}
// Tenkan crosses above Kijun → buy
if (_prevTenkan.Value <= _prevKijun.Value && tenkan > kijun)
{
if (Position < 0)
BuyMarket();
if (Position <= 0)
BuyMarket();
}
// Tenkan crosses below Kijun → sell
else if (_prevTenkan.Value >= _prevKijun.Value && tenkan < kijun)
{
if (Position > 0)
SellMarket();
if (Position >= 0)
SellMarket();
}
_prevTenkan = tenkan;
_prevKijun = kijun;
}
}