Understanding EA Execution Mechanism
When you attach an Expert Advisor to a chart in MetaTrader, a specific sequence of events occurs. Understanding this execution mechanism is essential for writing reliable EA code.
Three Core Phases of EA Lifecycle
| Phase | Function | Trigger | Runs |
|-------|----------|---------|------|
| Initialization | OnInit() | EA attached to chart | Once |
| Execution | OnTick() / OnTimer() | Each price tick / timer interval | Repeatedly |
| Deinitialization | OnDeinit() | EA removed or chart closed | Once |
Phase 1: Initialization - What Happens When EA Loads
When you drag an EA onto a chart or restart MT4/MT5, the following sequence occurs:
1. Platform loads the EX4/EX5 compiled file
2. Memory is allocated for global variables
3. Input parameters are read from chart settings
4. OnInit() function is called
5. If OnInit() returns INIT_SUCCEEDED, EA starts normally
6. If OnInit() returns INIT_FAILED, EA stops automatically
Complete Initialization Code Example
```mql4
// Input parameters with validation ranges
input double InpLotSize = 0.1; // Lot size (0.01 to 10)
input int InpStopLoss = 50; // Stop loss in points
input int InpTakeProfit = 100; // Take profit in points
input int InpMagicNumber = 12345; // EA magic number
// Global variables
double g_spread;
int g_totalOrders;
bool g_initSuccess = false;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit() {
Print("========== EA INITIALIZATION START ==========");
// Step 1: Validate input parameters
if(InpLotSize < 0.01 || InpLotSize > 10) {
Print("ERROR: Lot size must be between 0.01 and 10");
return(INIT_FAILED);
}
if(InpStopLoss < 10) {
Print("ERROR: Stop loss must be at least 10 points");
return(INIT_FAILED);
}
// Step 2: Check trading conditions
if(IsTradeAllowed() == false) {
Print("ERROR: Auto-trading is disabled");
return(INIT_FAILED);
}
// Step 3: Get market information
g_spread = MarketInfo(Symbol(), MODE_SPREAD);
Print("Current spread: ", g_spread);
// Step 4: Create chart objects (optional)
CreateInfoPanel();
// Step 5: Set timer if needed (1 second interval)
EventSetTimer(1);
g_initSuccess = true;
Print("========== EA INITIALIZATION SUCCESS ==========");
Print("Symbol: ", Symbol(), " | Period: ", Period());
Print("Lot size: ", InpLotSize, " | Magic: ", InpMagicNumber);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Create information panel on chart |
//+------------------------------------------------------------------+
void CreateInfoPanel() {
string objName = "InfoPanel";
if(ObjectFind(0, objName) < 0) {
ObjectCreate(0, objName, OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_TOP_LEFT);
ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, 10);
ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, 10);
ObjectSetString(0, objName, OBJPROP_TEXT, "EA Ready");
ObjectSetInteger(0, objName, OBJPROP_COLOR, clrWhite);
}
}
```
Phase 2: Tick Execution - How OnTick Processes Each Price Change
Every time the market price changes (bid or ask updates), MT4/MT5 triggers the OnTick() function. Understanding this execution frequency is critical:
| Symbol | Average Ticks Per Minute | EA Execution Per Minute |
|--------|-------------------------|------------------------|
| EURUSD (Normal) | 30-60 | 30-60 OnTick calls |
| EURUSD (News) | 200-500 | 200-500 OnTick calls |
| XAUUSD (Gold) | 20-40 | 20-40 OnTick calls |
| BTCUSD (Crypto) | 10-20 | 10-20 OnTick calls |
Optimized OnTick Structure with Bar Control
```mql4
//+------------------------------------------------------------------+
//| Expert tick function - Optimized version |
//+------------------------------------------------------------------+
void OnTick() {
// CRITICAL: Control execution frequency to avoid over-processing
static datetime lastBarTime = 0;
static datetime lastTradeTime = 0;
// Option 1: Execute only on new bar (recommended for most strategies)
if(Time[0] == lastBarTime) return;
lastBarTime = Time[0];
// Option 2: Execute every N seconds (for timer-based strategies)
if(TimeCurrent() - lastTradeTime < 5) return;
lastTradeTime = TimeCurrent();
// Check if EA is allowed to trade
if(!IsTradeAllowed()) {
Comment("Trading disabled. Check Auto-Trading button.");
return;
}
// Main trading logic goes here
double maFast = iMA(NULL, 0, 10, 0, MODE_SMA, PRICE_CLOSE, 1);
double maSlow = iMA(NULL, 0, 30, 0, MODE_SMA, PRICE_CLOSE, 1);
if(maFast > maSlow && CountOrders(InpMagicNumber) == 0) {
OpenBuyOrder();
}
else if(maFast < maSlow && CountOrders(InpMagicNumber) == 0) {
OpenSellOrder();
}
// Update chart display
UpdateInfoPanel(maFast, maSlow);
}
//+------------------------------------------------------------------+
//| Count orders by magic number |
//+------------------------------------------------------------------+
int CountOrders(int magic) {
int count = 0;
for(int i = 0; i < OrdersTotal(); i++) {
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
if(OrderSymbol() == Symbol() && OrderMagicNumber() == magic) {
count++;
}
}
}
return count;
}
```
Timer Events - Alternative to OnTick
Timer events are ideal for strategies that don't need every tick:
```mql4
// Set timer in OnInit()
EventSetTimer(5); // Trigger OnTimer() every 5 seconds
// Timer event handler
void OnTimer() {
static datetime lastCheck = 0;
if(TimeCurrent() - lastCheck < 60) return; // Check once per minute
lastCheck = TimeCurrent();
// Execute strategy at controlled intervals
CheckMarketConditions();
}
// Kill timer in OnDeinit()
EventKillTimer();
```
Phase 3: Deinitialization - Proper Cleanup Process
When EA is removed, OnDeinit() executes. Proper cleanup prevents memory leaks and chart clutter:
```mql4
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
Print("========== EA DEINITIALIZATION ==========");
Print("Reason code: ", reason);
Print("Reason: ", GetDeinitReason(reason));
// Step 1: Kill timer if used
EventKillTimer();
// Step 2: Delete all objects created by EA
DeleteAllEAObjects();
// Step 3: Close any open file handles
if(FileHandle != INVALID_HANDLE) {
FileClose(FileHandle);
}
// Step 4: Clear chart comment
Comment("");
// Step 5: Print final statistics
Print("Final balance: ", AccountBalance());
Print("Total ticks processed: ", g_tickCounter);
Print("=========================================");
}
//+------------------------------------------------------------------+
//| Delete all objects with EA prefix |
//+------------------------------------------------------------------+
void DeleteAllEAObjects() {
int total = ObjectsTotal(0);
for(int i = total - 1; i >= 0; i--) {
string objName = ObjectName(0, i);
if(StringFind(objName, "EA_") == 0) {
ObjectDelete(0, objName);
}
}
}
//+------------------------------------------------------------------+
//| Get readable deinitialization reason |
//+------------------------------------------------------------------+
string GetDeinitReason(int reason) {
switch(reason) {
case REASON_REMOVE: return "Removed by user";
case REASON_RECOMPILE: return "Recompiled";
case REASON_CHARTCLOSE: return "Chart closed";
case REASON_PARAMETERS: return "Parameters changed";
case REASON_ACCOUNT: return "Account changed";
default: return "Unknown reason";
}
}
```
EA State Diagram
```
[EA Dragged to Chart]
↓
[OnInit()]
↓
[INIT_SUCCEEDED?]
/ \
YES NO
↓ ↓
[OnTick Loop] [EA Stops]
↓
[Price Change?] → YES → [Execute Trading Logic]
↓ NO
[Timer Event?] → YES → [Execute Timer Logic]
↓
[EA Removed?] → YES → [OnDeinit()] → [Cleanup]
```
Common Execution Issues and Solutions
| Issue | Cause | Solution |
|-------|-------|----------|
| EA executes too many trades | No bar control in OnTick() | Add new bar detection before trading logic |
| Chart freezes during news | OnTick() too slow | Move heavy calculations to OnTimer() |
| EA doesn't start | OnInit() returns INIT_FAILED | Check validation conditions and error logs |
| Object persists after removal | Missing cleanup in OnDeinit() | Add ObjectDelete() for all EA-created objects |
| Timer not triggering | EventSetTimer() missing or killed | Check EventSetTimer() call in OnInit() |
Best Practices Summary
Reference:
9. Next Step
Part 6 will explain MQL4 Programming Quick Start - Variables and Data Types – Understanding all MQL4 data types, variable declaration, scope rules, and type conversion.