Why Ichimoku Kinko Hyo Deserves a Place in Your EA Toolkit
Most traders either love Ichimoku Kinko Hyo or dismiss it as too complex. I’ve been on both sides. After a decade of building EAs in MQL4, I’ve come to respect this system precisely because it forces you to think in terms of time, price, and momentum simultaneously. Unlike a simple moving average crossover or RSI divergence, Ichimoku embeds multiple layers of market structure into one chart. When you automate it correctly, you get a strategy that adapts to trends, ranges, and reversals without needing a dozen separate indicators.
In this post, I’ll walk through exactly how to translate the five Ichimoku lines into a robust MQL4 Expert Advisor. We’ll cover signal generation, cloud filtering, risk management, and the critical pitfalls that destroy most Ichimoku EAs. By the end, you’ll have a working framework you can adapt to your own trading style.
The beauty of Ichimoku automation lies in its discipline. Most traders struggle with discretionary cloud reading—they see a crossover and jump in without checking the cloud color or Chikou alignment. An EA eliminates these emotional errors. But it also introduces new challenges: repainting concerns, shift handling, and parameter sensitivity. I’ll address each of these with battle-tested solutions from my own live trading.
Understanding the Five Components of Ichimoku Kinko Hyo
Before we write a single line of MQL4, you need a clear mental model of what each line tells you. Ichimoku is not a single indicator; it’s a complete system. Here’s the breakdown:
- Tenkan-sen (Conversion Line): (9-period high + 9-period low) / 2. Measures short-term momentum. When price moves above it, buyers are in control; below it, sellers.
- Kijun-sen (Base Line): (26-period high + 26-period low) / 2. Acts as a trend confirmation line and trailing stop level in strong trends.
- Senkou Span A (Leading Span A): (Tenkan-sen + Kijun-sen) / 2, plotted 26 periods ahead. Forms one edge of the cloud.
- Senkou Span B (Leading Span B): (52-period high + 52-period low) / 2, plotted 26 periods ahead. Forms the other edge of the cloud.
- Chikou Span (Lagging Span): Current closing price plotted 26 periods behind. Used for confirmation — it should be above or below price 26 bars ago to confirm trend.
The cloud (Kumo) is the area between Senkou Span A and B. A thick cloud indicates strong support/resistance; a thin cloud signals potential breakout. Price above the cloud is bullish, below is bearish, and inside is sideways/no-trade zone. The cloud color matters: when Span A > Span B, the cloud is green (bullish); when Span A < Span B, it’s red (bearish). This color coding reveals the prevailing market sentiment.
One nuance many traders miss: the cloud is forward-shifted by 26 bars. This means the support/resistance levels you see today are actually based on data from 26 bars ago. This forward projection gives Ichimoku its predictive quality—it anticipates where support and resistance will form, rather than just reacting to past price.
Another critical detail is the time displacement built into the system. The standard settings (9, 26, 52) originate from Goichi Hosoda’s observations of Japanese candlestick patterns on daily charts, where 26 days approximates one month of trading. If you trade on lower timeframes like M15 or H1, consider scaling these periods proportionally. For example, on H1, use (9*4, 26*4, 52*4) = (36, 104, 208) to maintain the same time horizon. This scaling preserves the predictive power of the cloud across different chart timeframes.
Building the Ichimoku EA in MQL4: Core Logic
Let’s get practical. I’ll assume you’re comfortable with MQL4 basics — OnInit, OnTick, order management. We’ll focus on the Ichimoku-specific logic. I’ll also share some debugging techniques that saved me hours of frustration.
Step 1: Calculate Ichimoku Values
MQL4 provides the iIchimoku() function, but you need to understand its buffer indices. Here’s my preferred approach using custom arrays for clarity:
// Calculate Ichimoku values
double tenkan = iIchimoku(NULL, 0, 9, 26, 52, MODE_TENKANSEN, 0);
double kijun = iIchimoku(NULL, 0, 9, 26, 52, MODE_KIJUNSEN, 0);
double spanA = iIchimoku(NULL, 0, 9, 26, 52, MODE_SENKOUSPANA, 26); // shift 26 bars ahead
double spanB = iIchimoku(NULL, 0, 9, 26, 52, MODE_SENKOUSPANB, 26);
double chikou = iIchimoku(NULL, 0, 9, 26, 52, MODE_CHIKOUSPAN, -26); // shift 26 bars behind
Note the shift values: Span A and B are plotted 26 bars ahead, so we shift them forward by 26 to align with current price. Chikou is plotted 26 bars behind, so we shift it backward by 26. If you forget these shifts, your EA will compare current price against future or past cloud edges—a common bug that produces false signals. I’ve seen EAs that take trades based on cloud levels that haven’t formed yet, leading to catastrophic losses when price reverses.
I also recommend fetching the previous bar’s values for crossover detection. Here’s how I store them:
double prevTenkan = iIchimoku(NULL, 0, 9, 26, 52, MODE_TENKANSEN, 1);
double prevKijun = iIchimoku(NULL, 0, 9, 26, 52, MODE_KIJUNSEN, 1);
double prevSpanA = iIchimoku(NULL, 0, 9, 26, 52, MODE_SENKOUSPANA, 27);
double prevSpanB = iIchimoku(NULL, 0, 9, 26, 52, MODE_SENKOUSPANB, 27);
Notice the shift for prevSpanA is 27 (current shift 26 + 1 bar back). This ensures you’re comparing the same cloud projection across consecutive bars. A common mistake is using shift 26 for both current and previous values, which compares different cloud projections and generates false crossovers.
For debugging, always print these values to the Experts tab during development:
Print("Bar ", Bars, " Tenkan: ", tenkan, " Kijun: ", kijun, " SpanA: ", spanA, " SpanB: ", spanB, " Chikou: ", chikou);
Print("Price: ", Bid, " Cloud diff: ", spanA - spanB);
This helps you verify that shifts are correct and values align with what you see on the chart.
Step 2: Define Signal Conditions
I use a combination of three confirmations to filter false signals:
- Tenkan/Kijun Crossover: The classic signal. Buy when Tenkan crosses above Kijun, sell when it crosses below. But this alone is weak — it generates many whipsaws in ranging markets.
- Cloud Filter: Only take long signals when price is above the cloud (above both Span A and Span B) and the cloud is green (Span A > Span B). For shorts, price below cloud and red cloud (Span A < Span B).
- Chikou Confirmation: The Chikou Span should be above its corresponding price 26 bars ago for buys, below for sells.
Here’s the buy condition in code:
bool buySignal = false;
double currentPrice = Ask;
double prevTenkan = iIchimoku(NULL, 0, 9, 26, 52, MODE_TENKANSEN, 1);
double prevKijun = iIchimoku(NULL, 0, 9, 26, 52, MODE_KIJUNSEN, 1);
// Tenkan/Kijun crossover
if(tenkan > kijun && prevTenkan <= prevKijun)
{
// Cloud filter: price above cloud AND cloud is green
if(currentPrice > spanA && currentPrice > spanB && spanA > spanB)
{
// Chikou confirmation: Chikou above price 26 bars ago
double price26Ago = iClose(NULL, 0, 26);
if(chikou > price26Ago)
{
buySignal = true;
}
}
}
The sell condition is the mirror image. I also add a check for the cloud thickness — if the difference between Span A and Span B is less than a configurable threshold (say 10 pips on EURUSD), I skip the trade because the cloud is too thin to provide meaningful support/resistance. Here’s the thickness filter:
double cloudThickness = MathAbs(spanA - spanB);
double minThickness = CloudMinThickness * Point; // CloudMinThickness in pips
if(cloudThickness < minThickness)
{
return; // Skip trade
}
I also recommend adding a trend strength filter using the distance from price to the cloud. If price is too far from the cloud (e.g., more than 2 ATR), the trend may be overextended and due for a pullback. This prevents entering at blow-off tops or capitulation bottoms. Calculate ATR like this:
double atr = iATR(NULL, 0, 14, 0);
double priceToCloud = MathAbs(Bid - (spanA + spanB) / 2);
if(priceToCloud > atr * MaxATRMultiplier)
{
return; // Skip trade, trend overextended
}
I set MaxATRMultiplier to 2.0 as default, but this should be optimized per instrument. On volatile pairs like GBPJPY, a multiplier of 3.0 might be more appropriate to avoid missing strong trends.
Step 3: Entry and Exit Rules
I enter on the next bar after the signal to avoid repainting issues (Ichimoku does not repaint, but using close of current bar is safer). My stop loss is placed below the nearest swing low (for buys) or above the nearest swing high (for sells), but I also use the Kijun-sen as a dynamic stop. Take profit is a multiple of the risk — typically 2:1 or 3:1 risk-reward.
Here’s the entry logic with a check to avoid multiple entries on the same signal:
static datetime lastSignalTime = 0;
if(buySignal && Time[0] != lastSignalTime)
{
double stopLoss = MathMin(spanA, spanB) - (ATRValue * 1.5);
double takeProfit = Ask + (Ask - stopLoss) * TakeProfitMultiplier;
int ticket = OrderSend(Symbol(), OP_BUY, lotSize, Ask, 3, stopLoss, takeProfit, "Ichimoku EA", MagicNumber, 0, clrGreen);
if(ticket > 0)
{
lastSignalTime = Time[0];
Print("Buy order placed at ", Ask, " SL: ", stopLoss, " TP: ", takeProfit);
}
}
For exits, I also implement a trailing stop based on Kijun-sen. In strong trends, Kijun-sen acts as dynamic support/resistance. I update the stop loss to follow Kijun-sen if price moves favorably by more than 1 ATR:
if(OrderType() == OP_BUY)
{
double newSL = kijun;
if(newSL > OrderStopLoss() && (Bid - newSL) > ATRValue)
{
if(OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrNONE))
{
Print("Trailing stop moved to ", newSL);
}
}
}
One edge case to handle: when Kijun-sen is below the current stop loss, don’t modify the order. Also, avoid modifying on every tick — check only on new bars to reduce broker API calls and slippage. Use if(Volume[0] != lastVolume) to trigger bar-level checks.
Here’s a parameter table for the EA inputs:
| Parameter | Type | Default | Description |
|---|---|---|---|
| Tenkan Period | int | 9 | Period for Conversion Line. |
| Kijun Period | int | 26 | Period for Base Line. |
| Senkou B Period | int | 52 |

