iJam StudioiJam Studio
🤖 Chapter 7: Trading Bot & Automation

MQL5 EA Development Basics

EA structure, key functions, and building your first EA

30 minLesson 19

Introduction to MQL5

MQL5 (MetaQuotes Language 5) is the programming language used to create trading robots, custom indicators, scripts, and libraries for the MetaTrader 5 platform. If you want to automate your trading strategies, MQL5 is your gateway.

MQL5 is a C++-like language specifically designed for financial trading. It provides built-in functions for market data access, order management, technical indicators, and more. The language is compiled (not interpreted), which means your Expert Advisors run extremely fast.

Why Learn MQL5? Automated trading removes emotional decision-making, executes trades 24/5 without fatigue, and can monitor dozens of instruments simultaneously. MQL5 is the industry standard for retail algorithmic trading on MetaTrader 5.


Expert Advisor Structure

Every Expert Advisor (EA) in MQL5 follows a standard structure built around three core event handler functions. Understanding these is essential before writing any code.

OnInit()

This function runs once when the EA is first attached to a chart or when parameters change. Use it for initialization tasks.

int OnInit()
{
   // Set up indicator handles
   // Initialize variables
   // Validate input parameters

Print("EA initialized successfully");
return(INIT_SUCCEEDED);
}

Common uses:

  • Creating indicator handles with functions like iMA(), iRSI()

  • Validating that input parameters are within acceptable ranges

  • Setting up arrays and data structures


OnDeinit()

This function runs once when the EA is removed from the chart or the terminal closes. Use it for cleanup.

void OnDeinit(const int reason)
{
   // Release indicator handles
   // Clean up objects from the chart
   // Save state if needed

Print("EA removed. Reason: ", reason);
}

OnTick()

This is the heart of your EA. It runs every time a new price tick arrives for the symbol the EA is attached to. All your trading logic goes here.

void OnTick()
{
   // Check market conditions
   // Evaluate entry/exit signals
   // Manage open positions
   // Place or modify orders
}

Important: OnTick() can fire hundreds of times per minute on liquid pairs. Keep your logic efficient and avoid unnecessary computations on every tick.


Input Parameters

Input parameters allow you to customize your EA without editing the code. They appear in the EA settings dialog when you attach it to a chart.

input int      MAPeriodFast   = 10;       // Fast MA Period
input int      MAPeriodSlow   = 50;       // Slow MA Period
input double   LotSize        = 0.01;     // Trading Lot Size
input int      StopLoss       = 100;      // Stop Loss in Points
input int      TakeProfit     = 200;      // Take Profit in Points
input int      MagicNumber    = 12345;    // Unique EA Identifier

The input keyword makes these values editable from the MT5 interface. The comment at the end of each line becomes the label displayed in the settings panel.

Best practices for inputs:

  • Always include a MagicNumber to distinguish your EA's trades from others

  • Use sensible default values that work on common pairs

  • Add comments that clearly describe what each parameter controls



Key MQL5 Functions

Indicator Functions

MQL5 provides built-in functions to create indicator handles and retrieve values.

// Create a Moving Average handle
int maHandle = iMA(_Symbol, PERIOD_CURRENT, 20, 0, MODE_SMA, PRICE_CLOSE);

// Create an RSI handle
int rsiHandle = iRSI(_Symbol, PERIOD_CURRENT, 14, PRICE_CLOSE);

// Read indicator values into an array
double maValues[];
ArraySetAsSeries(maValues, true);
CopyBuffer(maHandle, 0, 0, 3, maValues);
// maValues[0] = current bar, maValues[1] = previous bar

The CTrade Class

The CTrade class simplifies order operations. Include it at the top of your EA.

#include <Trade/Trade.mqh>

CTrade trade;

// Open a buy position
trade.Buy(0.01, _Symbol, 0, stopLossPrice, takeProfitPrice, "My EA Buy");

// Open a sell position
trade.Sell(0.01, _Symbol, 0, stopLossPrice, takeProfitPrice, "My EA Sell");

// Close a specific position
trade.PositionClose(ticket);

Position Management

// Check if we already have an open position
bool HasOpenPosition(int magic)
{
   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
      if(PositionSelectByTicket(PositionGetTicket(i)))
      {
         if(PositionGetInteger(POSITION_MAGIC) == magic &&
            PositionGetString(POSITION_SYMBOL) == _Symbol)
            return true;
      }
   }
   return false;
}

Market Data Functions

// Get current bid/ask prices
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

// Get the point value (smallest price change)
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);

// Calculate stop loss price for a buy
double slPrice = ask - StopLoss * point;
double tpPrice = ask + TakeProfit * point;


Complete Example: MA Crossover EA

Here is a full working Expert Advisor that trades based on a Moving Average crossover strategy. When the fast MA crosses above the slow MA, it buys. When the fast MA crosses below, it sells.

#property copyright "iJam Studio"
#property version   "1.00"
#property strict

#include <Trade/Trade.mqh>

// --- Input Parameters ---
input int FastMAPeriod = 10; // Fast MA Period
input int SlowMAPeriod = 50; // Slow MA Period
input double LotSize = 0.01; // Lot Size
input int StopLoss = 150; // Stop Loss (points)
input int TakeProfit = 300; // Take Profit (points)
input int MagicNumber = 101010; // Magic Number

// --- Global Variables ---
int fastMAHandle;
int slowMAHandle;
CTrade trade;

//+------------------------------------------------------------------+
int OnInit()
{
// Create indicator handles
fastMAHandle = iMA(_Symbol, PERIOD_CURRENT, FastMAPeriod, 0, MODE_SMA, PRICE_CLOSE);
slowMAHandle = iMA(_Symbol, PERIOD_CURRENT, SlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE);

if(fastMAHandle == INVALID_HANDLE || slowMAHandle == INVALID_HANDLE)
{
Print("Error creating MA handles");
return(INIT_FAILED);
}

trade.SetExpertMagicNumber(MagicNumber);
Print("MA Crossover EA initialized");
return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
IndicatorRelease(fastMAHandle);
IndicatorRelease(slowMAHandle);
Print("MA Crossover EA removed");
}

//+------------------------------------------------------------------+
void OnTick()
{
// Only trade on new bar
static datetime lastBarTime = 0;
datetime currentBarTime = iTime(_Symbol, PERIOD_CURRENT, 0);
if(currentBarTime == lastBarTime) return;
lastBarTime = currentBarTime;

// Get MA values
double fastMA[], slowMA[];
ArraySetAsSeries(fastMA, true);
ArraySetAsSeries(slowMA, true);

if(CopyBuffer(fastMAHandle, 0, 0, 3, fastMA) < 3) return;
if(CopyBuffer(slowMAHandle, 0, 0, 3, slowMA) < 3) return;

// Detect crossover (using completed bars 1 and 2)
bool bullishCross = fastMA[1] > slowMA[1] && fastMA[2] <= slowMA[2];
bool bearishCross = fastMA[1] < slowMA[1] && fastMA[2] >= slowMA[2];

double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);

// Check for existing position
bool hasPosition = false;
long posType = -1;
ulong posTicket = 0;

for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(PositionSelectByTicket(ticket))
{
if(PositionGetInteger(POSITION_MAGIC) == MagicNumber &&
PositionGetString(POSITION_SYMBOL) == _Symbol)
{
hasPosition = true;
posType = PositionGetInteger(POSITION_TYPE);
posTicket = ticket;
break;
}
}
}

// Trading logic
if(bullishCross)
{
// Close any existing sell
if(hasPosition && posType == POSITION_TYPE_SELL)
trade.PositionClose(posTicket);

// Open buy if no buy exists
if(!hasPosition || posType == POSITION_TYPE_SELL)
{
double sl = ask - StopLoss * point;
double tp = ask + TakeProfit * point;
trade.Buy(LotSize, _Symbol, ask, sl, tp, "MA Cross Buy");
}
}
else if(bearishCross)
{
// Close any existing buy
if(hasPosition && posType == POSITION_TYPE_BUY)
trade.PositionClose(posTicket);

// Open sell if no sell exists
if(!hasPosition || posType == POSITION_TYPE_BUY)
{
double sl = bid + StopLoss * point;
double tp = bid - TakeProfit * point;
trade.Sell(LotSize, _Symbol, bid, sl, tp, "MA Cross Sell");
}
}
}


Compiling and Debugging

Compiling Your EA

1. Open MetaEditor (press F4 from MT5, or use the IDE icon)
2. Write or paste your code in a .mq5 file
3. Press F7 or click Compile
4. Fix any errors shown in the Errors tab at the bottom
5. A successful compile produces an .ex5 file in the MQL5/Experts folder

Common Compilation Errors

| Error | Cause | Fix |
|---|---|---|
| undeclared identifier | Variable or function not defined | Check spelling, ensure variables are declared |
| wrong parameters count | Incorrect number of function arguments | Check the function documentation |
| implicit conversion | Type mismatch (e.g., int to double) | Use explicit casting |
| semicolon expected | Missing ; at end of statement | Add the semicolon |

Debugging Tips

  • Use Print() and Comment() to display values on the chart and in the Experts tab
  • Use Alert() for important notifications during testing
  • The Debugger in MetaEditor allows breakpoints and step-through execution
  • Check the Journal tab in MT5 for runtime errors and trade execution logs

Installing an EA on a Chart

Follow these steps to run your EA in live or demo trading:

1. Compile the EA in MetaEditor (press F7)
2. In MT5, open the Navigator panel (Ctrl+N)
3. Expand Expert Advisors in the Navigator tree
4. Find your EA and drag it onto the desired chart
5. In the settings dialog:
- Common tab: Enable "Allow Algo Trading"
- Inputs tab: Adjust your parameters as needed
6. Click OK to attach the EA
7. Verify the EA is running: look for the smiley face icon in the top-right corner of the chart
8. Ensure Algo Trading is enabled globally (the button in the MT5 toolbar should be green)

Safety Tip: Always test your EA on a demo account first. Run it for at least 2-4 weeks before considering live trading. Start with the smallest possible lot size.


Summary

  • MQL5 Expert Advisors are built around three event handlers: OnInit(), OnDeinit(), and OnTick()
  • Input parameters make your EA configurable without code changes
  • The CTrade class simplifies order management
  • Use iMA(), iRSI(), and similar functions to create indicator handles, then CopyBuffer() to read values
  • Always include a MagicNumber to identify your EA's trades
  • Compile in MetaEditor, fix errors, then attach the .ex5 file to a chart
  • Test thoroughly on a demo account before going live
In the next lesson, we will learn how to backtest and optimize your EA using the MT5 Strategy Tester to evaluate performance before risking real money.