AlgoPro UniversityCourse home
Part 9 · Lesson

MQL5 language basics & the three event handlers

Types, functions, #property directives and input parameters, then the lifecycle every EA is built on: OnInit, OnTick and OnDeinit — with a minimal EA you can compile and run.

MQL5 reads like C++ with the sharp edges filed off: statically typed, compiled, curly-brace blocks, every statement ending in a semicolon. If you have written Python, the ideas transfer — you just have to *declare your types* and get used to the compiler refusing to run until everything lines up.

Types you will actually use

Functions and the shape of a program

A function declares its return type, a name, and typed parameters. void means it returns nothing. Here is an ordinary helper — nothing special, just to fix the syntax in your mind:

mql5A plain MQL5 function
class="c">// Returns the pip value distance as a price offset.
class="c">// _Point and _Digits are built-in variables for the current symbol.
double PipsToPrice(int pips)
{
   class="c">// On class="n">5-digit and class="n">3-digit brokers, one class="s">"pip" is class="n">10 points.
   double factor = (_Digits == class="n">3 || _Digits == class="n">5) ? class="n">10.0 : class="n">1.0;
   return(pips * _Point * factor);
}

Note the details: the type before the name, the semicolons, the // comments, and the ternary ?: operator. return wraps its value in parentheses by convention. _Point and _Digits are built-in globals the terminal fills in for the chart's symbol — you will use dozens of these.

#property: metadata for the compiler

Every EA starts with #property directives — preprocessor lines that tell MetaEditor and the terminal about your program. They are not code that runs; they are labels baked into the compiled file.

mql5Standard EA header
class="c">#property copyright class="s">"AlgoPro University"
class="c">#property link      class="s">"https:class="c">//algopro-university.netlify.app"
class="c">#property version   class="s">"class="n">1.00"
class="c">#property description class="s">"Teaching EA — demo accounts only, not financial advice."

input: the parameters the user can change

The single most useful keyword in MQL5 is input. An input variable becomes a field in the EA's settings dialog — the box that pops up when you attach the EA to a chart or launch the Strategy Tester. This is how you expose a strategy's knobs (periods, lot size, stop distance) without editing code, and — crucially — it is what the optimiser sweeps in the final lesson.

mql5Inputs become dialog fields — and optimiser variables
input int    FastPeriod = class="n">12;      class="c">// Fast MA period
input int    SlowPeriod = class="n">26;      class="c">// Slow MA period
input double Lots       = class="n">0.10;    class="c">// Trade size in lots
input double StopLossPips   = class="n">40;  class="c">// Stop-loss distance (pips)
input double TakeProfitPips = class="n">80;  class="c">// Take-profit distance (pips)
input ulong  MagicNumber = class="n">8080;   class="c">// Unique EA id for its own orders

The three handlers: an EA's whole life

An EA has a lifecycle, and MQL5 gives you exactly three functions to hook into it. The terminal calls them for you at the right moments — you never call them yourself.

  1. OnInit() — called once, when the EA is attached to the chart (or a test run starts, or inputs change). Set things up here: create indicator handles, validate inputs, allocate state. Returns INIT_SUCCEEDED if all is well, or an error code to abort.
  2. OnTick() — called on every incoming tick. This is where the strategy lives: read data, decide, trade. It runs constantly, so it must be fast and defensive.
  3. OnDeinit() — called once, when the EA is removed, the chart closes, the timeframe changes, or the terminal shuts down. Clean up here: release indicator handles, tidy state. It receives a reason code telling you *why* it is stopping.
ticksAttach EAOnInit()OnTick() × NOnDeinit()Removed
The EA lifecycle. OnInit runs once at the start, OnTick runs on every tick for as long as the EA is attached, OnDeinit runs once at the end.

A minimal EA you can compile right now

Here is the smallest complete Expert Advisor. It does not trade — it just prints, so you can watch the lifecycle in the terminal's Experts log tab and *feel* how ticks arrive.

mql5MinimalEA.mq5 — the whole lifecycle, no trading
class="c">#property copyright class="s">"AlgoPro University"
class="c">#property version   class="s">"class="n">1.00"

input string Greeting = class="s">"Hello from MQL5";  class="c">// Message to print on start

int tickCount = class="n">0;   class="c">// Global state persists across OnTick calls

class="c">// Called once when the EA starts.
int OnInit()
{
   Print(Greeting, class="s">" — attached to ", _Symbol, class="s">" ", EnumToString(_Period));
   tickCount = class="n">0;
   return(INIT_SUCCEEDED);
}

class="c">// Called on every incoming tick.
void OnTick()
{
   tickCount++;
   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   class="c">// Print only every 50th tick so the log stays readable.
   if(tickCount % class="n">50 == class="n">0)
      Print(class="s">"Tick class="c">#", tickCount, class="s">"  bid=", DoubleToString(bid, _Digits));
}

class="c">// Called once when the EA is removed.
void OnDeinit(const int reason)
{
   Print(class="s">"EA stopped after ", tickCount, class="s">" ticks. Reason code: ", reason);
}

Compile it (F7), drag it onto a demo EURUSD chart, and watch the Experts tab. You now understand the skeleton every EA in the world is built on. Next we make it *read the market*.