Complete .mq5 source code

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

52.8%
Win Rate
19.3%
Max Drawdown
1.15
Sharpe Ratio
2020–2025
Test Period

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

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 accessVia TradingView broker 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 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.