Ichimoku Cloud MT5 Indicator: MQL5 Code, Trading Rules & EA
Use the built-in iIchimoku handle from an educational Expert Advisor. This guide explains buffer numbering, chart-aligned cloud values, completed-bar Tenkan/Kijun crosses and a historical-close comparison. The code belongs in MQL5/Experts; it does not draw a custom indicator. Compile with the standard Trade library and test the rules independently; no verified performance record is supplied.
Implementation details & mechanics
Core implementation pattern
On the chart timeframe, compare Tenkan and Kijun for completed bars 2 and 1. A buy requires an upward cross, close[1] above both cloud boundaries aligned with chart bar 1, and close[1] above close[1 + InpKijun]. Shorts reverse those tests. The historical comparison defines a simple Chikou-style filter without reading future or unavailable shifted Chikou values. Span A versus B ordering is not an additional condition; above the cloud is not inside it.
Error handling & safety rules
At a new bar, a long exits when Tenkan is below Kijun or close is at/below the cloud top; a short exits when Tenkan is above Kijun or close is at/above the cloud bottom. This includes an adverse jump across the cloud. Initial stop requests sit five broker points beyond the lower/upper cloud boundary. Optional Kijun trailing tightens only on the valid side of the current quote, once per bar. No take-profit or guaranteed protection is included; fixed lots, costs, tick/stop grids and account-mode ownership must be tested.
MQL5 Code Implementation
//+------------------------------------------------------------------+
//| 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()
{
if(InpTenkan<1 || InpKijun<1 || InpSenkouB<1 || InpLotSize<=0 || InpMagicNumber<0 || InpSlippage<0)
return INIT_PARAMETERS_INCORRECT;
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);
if(!g_trade.SetTypeFillingBySymbol(_Symbol)) return INIT_FAILED;
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<=0 || currentBar == s_lastBar) return;
// Static two-value arrays store older bar 2 at index 0, bar 1 at index 1.
double tenkan[2],kijun[2],spanA[1],spanB[1],closePrice[1],pastClose[1];
if(CopyBuffer(g_ichiHandle,0,1,2,tenkan)!=2 ||
CopyBuffer(g_ichiHandle,1,1,2,kijun)!=2 ||
CopyBuffer(g_ichiHandle,2,1,1,spanA)!=1 ||
CopyBuffer(g_ichiHandle,3,1,1,spanB)!=1 ||
CopyClose(_Symbol,PERIOD_CURRENT,1,1,closePrice)!=1 ||
CopyClose(_Symbol,PERIOD_CURRENT,1+InpKijun,1,pastClose)!=1) return;
if(tenkan[0]==EMPTY_VALUE || tenkan[1]==EMPTY_VALUE || kijun[0]==EMPTY_VALUE ||
kijun[1]==EMPTY_VALUE || spanA[0]==EMPTY_VALUE || spanB[0]==EMPTY_VALUE ||
closePrice[0]<=0 || pastClose[0]<=0) return;
s_lastBar=currentBar;
double close=closePrice[0];
// CopyBuffer offsets include plot displacement: these spans align with chart bar 1.
double cloudTop=MathMax(spanA[0],spanB[0]),cloudBottom=MathMin(spanA[0],spanB[0]);
bool tkCrossUp=tenkan[1]>kijun[1] && tenkan[0]<=kijun[0];
bool tkCrossDown=tenkan[1]<kijun[1] && tenkan[0]>=kijun[0];
bool aboveCloud=close>cloudTop, belowCloud=close<cloudBottom;
bool chikouBull=close>pastClose[0], chikouBear=close<pastClose[0];
bool longSignal = tkCrossUp && aboveCloud && chikouBull;
bool shortSignal = tkCrossDown && belowCloud && chikouBear;
//--- Manage trailing stop on existing positions
if(InpUseTrailing)
ManageTrailing(kijun[1]);
//--- Check existing positions before opening new ones
if(HasPosition(POSITION_TYPE_BUY) || HasPosition(POSITION_TYPE_SELL))
{
CheckExit(tenkan[1], kijun[1], 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 = NormalizeDouble(cloudBottom - 5 * pt,_Digits);
if(sl>=bid) return;
if(!g_trade.Buy(InpLotSize,_Symbol,ask,sl,0,"Ichimoku Long") ||
(g_trade.ResultRetcode()!=TRADE_RETCODE_DONE && g_trade.ResultRetcode()!=TRADE_RETCODE_DONE_PARTIAL))
Print("Buy failed: ",g_trade.ResultRetcode()," ",g_trade.ResultRetcodeDescription());
}
else if(shortSignal)
{
double sl = NormalizeDouble(cloudTop + 5 * pt,_Digits);
if(sl<=ask) return;
if(!g_trade.Sell(InpLotSize,_Symbol,bid,sl,0,"Ichimoku Short") ||
(g_trade.ResultRetcode()!=TRADE_RETCODE_DONE && g_trade.ResultRetcode()!=TRADE_RETCODE_DONE_PARTIAL))
Print("Sell failed: ",g_trade.ResultRetcode()," ",g_trade.ResultRetcodeDescription());
}
}
//+------------------------------------------------------------------+
//| 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);
bool exitShort = (type == POSITION_TYPE_SELL) &&
(tenkan > kijun ||
close>=cloudBottom);
if(exitLong || exitShort)
{
if(!g_trade.PositionClose(ticket) ||
(g_trade.ResultRetcode()!=TRADE_RETCODE_DONE && g_trade.ResultRetcode()!=TRADE_RETCODE_DONE_PARTIAL))
Print("Close failed: ",g_trade.ResultRetcode()," ",g_trade.ResultRetcodeDescription());
}
}
}
//+------------------------------------------------------------------+
//| 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 = NormalizeDouble(kijun - 5 * pt,_Digits);
if(newSL > currentSL && newSL<SymbolInfoDouble(_Symbol,SYMBOL_BID))
if(!g_trade.PositionModify(ticket,newSL,PositionGetDouble(POSITION_TP)) || g_trade.ResultRetcode()!=TRADE_RETCODE_DONE)
Print("Trailing failed: ",g_trade.ResultRetcode()," ",g_trade.ResultRetcodeDescription());
}
else if(type == POSITION_TYPE_SELL)
{
double newSL = NormalizeDouble(kijun + 5 * pt,_Digits);
if((newSL < currentSL || currentSL == 0) && newSL>SymbolInfoDouble(_Symbol,SYMBOL_ASK))
if(!g_trade.PositionModify(ticket,newSL,PositionGetDouble(POSITION_TP)) || g_trade.ResultRetcode()!=TRADE_RETCODE_DONE)
Print("Trailing failed: ",g_trade.ResultRetcode()," ",g_trade.ResultRetcodeDescription());
}
}
}
//+------------------------------------------------------------------+
//| 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 your MQL5 folder (Experts, Scripts, or Include), and compile with F7.
Generate custom MQL5 code with Pineify AI
Describe the trade execution, indicator calculations, risk management, or data processing logic you need. Pineify generates editable MQL5 source code. Review its logic, request a syntax check, and compile and test the final file 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 | Strategy orders are simulated; live automation needs a separate 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 reference guide before porting logic between them.
Frequently Asked Questions
Related MQL5 pages
Technical references
Risk and testing note
These educational examples require independent compilation and testing. A compile pass or an illustrative setting does not establish execution correctness or profitability. Any reported performance must be supported by reproducible data and test settings; past results do not predict future returns. Trading involves significant risk of loss. This content is not financial advice.