Ichimoku Cloud MT5 Indicator: MQL5 Code, Trading Rules & EA
This page provides a complete MQL5 implementation of the Ichimoku Cloud indicator for MetaTrader 5, including the five core components: Tenkan-sen, Kijun-sen, Senkou Span A, Senkou Span B, and Chikou Span. It covers trading rules for bullish and bearish cloud setups across forex, indices, and commodities, along with a ready-to-compile Expert Advisor that automates cloud-based entries and exits.
Historical test results
Past performance is not indicative of future results. Backtest statistics are based on historical data and do not guarantee future profits. Trading involves significant risk of loss. This content is for educational purposes only and does not constitute financial advice.
How the Supertrend signal works
Bullish flip
A long trade is triggered when the price closes above both Senkou Span A and Senkou Span B (inside a bullish cloud), the Tenkan-sen crosses above the Kijun-sen, and the Chikou Span is above the price from 26 periods ago. A short trade is triggered by the mirror conditions: price below a bearish cloud, Tenkan-sen crossing below Kijun-sen, and Chikou Span below historical price.
Bearish flip
Long positions are closed when the Tenkan-sen crosses back below the Kijun-sen, or when price re-enters and closes inside the cloud, signalling trend exhaustion. A fixed stop-loss is placed below Senkou Span B at trade entry, and a trailing mechanism tightens the stop as the Kijun-sen advances in the direction of the trade.
MQL5 Custom Indicator Code
//+------------------------------------------------------------------+
//| IchimokuCloudEA.mq5 |
//| Ichimoku Cloud Expert Advisor for MetaTrader 5 |
//| Pineify.app — AI-powered MQL5 & Pine Script code generation |
//+------------------------------------------------------------------+
#property copyright "Pineify.app"
#property version "1.00"
#property strict
#include <Trade\Trade.mqh>
//--- Input parameters
input int InpTenkan = 9; // Tenkan-sen period
input int InpKijun = 26; // Kijun-sen period
input int InpSenkouB = 52; // Senkou Span B period
input double InpLotSize = 0.1; // Trade lot size
input int InpMagicNumber = 202600; // Magic number
input int InpSlippage = 10; // Max slippage (points)
input bool InpUseTrailing = true; // Enable Kijun trailing stop
//--- Global handles and objects
int g_ichiHandle = INVALID_HANDLE;
CTrade g_trade;
//+------------------------------------------------------------------+
//| Expert initialisation |
//+------------------------------------------------------------------+
int OnInit()
{
g_ichiHandle = iIchimoku(_Symbol, PERIOD_CURRENT,
InpTenkan, InpKijun, InpSenkouB);
if(g_ichiHandle == INVALID_HANDLE)
{
Print("ERROR: Failed to create Ichimoku handle — ", GetLastError());
return INIT_FAILED;
}
g_trade.SetExpertMagicNumber(InpMagicNumber);
g_trade.SetDeviationInPoints(InpSlippage);
g_trade.SetTypeFilling(ORDER_FILLING_FOK);
Print("IchimokuCloudEA initialised on ", _Symbol,
" [Tenkan=", InpTenkan,
" Kijun=", InpKijun,
" SenkouB=", InpSenkouB, "]");
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| Expert tick handler |
//+------------------------------------------------------------------+
void OnTick()
{
//--- Only act on a new completed bar
static datetime s_lastBar = 0;
datetime currentBar = (datetime)SeriesInfoInteger(_Symbol, PERIOD_CURRENT,
SERIES_LASTBAR_DATE);
if(currentBar == s_lastBar)
return;
s_lastBar = currentBar;
//--- Fetch Ichimoku buffers (index 1 = previous closed bar)
double tenkan[3], kijun[3], spanA[3], spanB[3], chikou[3];
if(CopyBuffer(g_ichiHandle, 0, 1, 3, tenkan) < 3) return;
if(CopyBuffer(g_ichiHandle, 1, 1, 3, kijun) < 3) return;
if(CopyBuffer(g_ichiHandle, 2, 1, 3, spanA) < 3) return;
if(CopyBuffer(g_ichiHandle, 3, 1, 3, spanB) < 3) return;
if(CopyBuffer(g_ichiHandle, 4, 1, 3, chikou) < 3) return;
double closePrice[1];
if(CopyClose(_Symbol, PERIOD_CURRENT, 1, 1, closePrice) < 1) return;
double close = closePrice[0];
double cloudTop = MathMax(spanA[0], spanB[0]);
double cloudBottom = MathMin(spanA[0], spanB[0]);
//--- Signal detection (index 0 = bar-1, index 1 = bar-2 for crossover)
bool tkCrossUp = tenkan[0] > kijun[0] && tenkan[1] <= kijun[1];
bool tkCrossDown = tenkan[0] < kijun[0] && tenkan[1] >= kijun[1];
bool aboveCloud = close > cloudTop;
bool belowCloud = close < cloudBottom;
bool chikouBull = chikou[0] > close; // simplified: chikou vs current
bool chikouBear = chikou[0] < close;
bool longSignal = tkCrossUp && aboveCloud && chikouBull;
bool shortSignal = tkCrossDown && belowCloud && chikouBear;
//--- Manage trailing stop on existing positions
if(InpUseTrailing)
ManageTrailing(kijun[0]);
//--- Check existing positions before opening new ones
if(HasPosition(POSITION_TYPE_BUY) || HasPosition(POSITION_TYPE_SELL))
{
CheckExit(tenkan[0], kijun[0], cloudTop, cloudBottom, close);
return;
}
//--- Open new positions
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double pt = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
if(longSignal)
{
double sl = cloudBottom - 5 * pt;
g_trade.Buy(InpLotSize, _Symbol, ask, sl, 0,
"Ichimoku Long");
PrintFormat("LONG opened | Close=%.5f CloudBot=%.5f SL=%.5f",
close, cloudBottom, sl);
}
else if(shortSignal)
{
double sl = cloudTop + 5 * pt;
g_trade.Sell(InpLotSize, _Symbol, bid, sl, 0,
"Ichimoku Short");
PrintFormat("SHORT opened | Close=%.5f CloudTop=%.5f SL=%.5f",
close, cloudTop, sl);
}
}
//+------------------------------------------------------------------+
//| Check exit conditions for open positions |
//+------------------------------------------------------------------+
void CheckExit(double tenkan, double kijun,
double cloudTop, double cloudBottom, double close)
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket == 0) continue;
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if(PositionGetInteger(POSITION_MAGIC) != InpMagicNumber) continue;
ENUM_POSITION_TYPE type =
(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
bool exitLong = (type == POSITION_TYPE_BUY) &&
(tenkan < kijun ||
(close < cloudTop && close > cloudBottom));
bool exitShort = (type == POSITION_TYPE_SELL) &&
(tenkan > kijun ||
(close > cloudBottom && close < cloudTop));
if(exitLong || exitShort)
{
g_trade.PositionClose(ticket);
PrintFormat("Position %d closed — exit signal", (int)ticket);
}
}
}
//+------------------------------------------------------------------+
//| Trailing stop along Kijun-sen |
//+------------------------------------------------------------------+
void ManageTrailing(double kijun)
{
double pt = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket == 0) continue;
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if(PositionGetInteger(POSITION_MAGIC) != InpMagicNumber) continue;
ENUM_POSITION_TYPE type =
(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
double currentSL = PositionGetDouble(POSITION_SL);
if(type == POSITION_TYPE_BUY)
{
double newSL = kijun - 5 * pt;
if(newSL > currentSL)
g_trade.PositionModify(ticket, newSL,
PositionGetDouble(POSITION_TP));
}
else if(type == POSITION_TYPE_SELL)
{
double newSL = kijun + 5 * pt;
if(newSL < currentSL || currentSL == 0)
g_trade.PositionModify(ticket, newSL,
PositionGetDouble(POSITION_TP));
}
}
}
//+------------------------------------------------------------------+
//| Check whether a position of given type is open |
//+------------------------------------------------------------------+
bool HasPosition(ENUM_POSITION_TYPE posType)
{
for(int i = 0; i < PositionsTotal(); i++)
{
ulong ticket = PositionGetTicket(i);
if(ticket == 0) continue;
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if(PositionGetInteger(POSITION_MAGIC) != InpMagicNumber) continue;
if((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == posType)
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Expert deinitialization |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if(g_ichiHandle != INVALID_HANDLE)
IndicatorRelease(g_ichiHandle);
PrintFormat("IchimokuCloudEA deinitialized — reason %d", reason);
}
//+------------------------------------------------------------------+Copy this code into MetaEditor, save it in the MQL5/Indicators folder, and compile with F7.
Change the settings or add your own signal filter
Describe the ATR inputs, alert rules, visual style, or confirmation filter you want. Pineify generates editable MQL5 source code that you can inspect and compile in MetaEditor.
Pine Script vs MQL5: Same Strategy, Different Platforms
| Aspect | Pine Script (TradingView) | MQL5 (MetaTrader 5) |
|---|---|---|
| Execution | Series evaluated on chart updates | Event handlers with explicit buffers |
| Deployment | Runs in TradingView with alerts | Runs in the MT5 terminal or on a VPS |
| Broker access | Via TradingView broker integration | Direct broker connectivity |
| Backtesting | Strategy Tester for strategy scripts | Strategy Tester for Expert Advisors |
| Code complexity | Simpler, functional syntax | C++-like, more powerful |
The calculation can be implemented on either platform, but the runtime model and buffer APIs differ. Read the Pine Script Supertrend reference before porting logic between them.
Frequently Asked Questions
Related MQL5 pages
Risk and testing note
Past performance is not indicative of future results. Backtest statistics are based on historical data and do not guarantee future profits. Trading involves significant risk of loss. This content is for educational purposes only and does not constitute financial advice.