Complete MQL5 guide & code

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

AspectPine Script (TradingView)MQL5 (MetaTrader 5)
ExecutionSeries evaluated on chart updatesEvent handlers with explicit buffers
DeploymentRuns in TradingView with alertsRuns in the MT5 terminal or on a VPS
Broker accessStrategy orders are simulated; live automation needs a separate integrationDirect broker connectivity
BacktestingStrategy Tester for strategy scriptsStrategy Tester for Expert Advisors
Code complexitySimpler, functional syntaxC++-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.