Blog Details

thumb
13 Jul 2026

Understanding MQL4 Code After Decompilation: How to Read and Interpret Your Recovered Source

Understanding MQL4 Code After Decompilation: How to Read and Interpret Your Recovered Source



Table of Contents

  • The Structure of an MQL4 Expert Advisor
  • Understanding the Mandatory Functions
  • Recognizing Common Trading Logic Patterns
  • Reading Indicator Calls in Detail
  • Understanding Order Management Code
  • Decoding Generic Variable Names
  • An Efficient Annotation Workflow
  • Testing Your Understanding
  • Further Learning Resources

Professional decompilation has done its job: you have a recovered MQL4 .mq4 file. It compiles without errors in MetaEditor. Now you open it and stare at pages of code some parts recognizable, others confusing, and in some cases, decorated with generic variable names like a0b1, and c3 rather than descriptive ones.

This guide teaches you how to navigate and understand recovered MQL4 source code systematically. Whether you are a developer who wants to verify the recovery, a trader who wants to understand the strategy logic, or an auditor checking for security issues, this walkthrough provides the framework you need to extract meaning from the code you have received.

The Structure of an MQL4 Expert Advisor

Every MQL4 Expert Advisor follows a predictable structure regardless of its trading strategy. This structure is always preserved in decompiled code because it is an inherent requirement of the MQL4 language. Understanding it gives you an immediate orientation in any recovered code file:

Section 1: File Properties and Copyright

#property copyright "Developer Name"

#property link   property version   "1.00"

#property strict

Always at the top. The #property strict directive enables strict type checking its presence or absence tells you something about when the EA was written (newer EAs typically use it). The copyright and link fields, if present and not generic, can provide clues about the EA's origin.

Section 2: Input Parameters

input double LotSize       = 0.1;

input int    TakeProfit    = 50;

input int    StopLoss      = 30;

input int    FastMAPeriod  = 20;

input int    SlowMAPeriod  = 50;

input int    MagicNumber   = 12345;

Input parameters are always clearly readable after decompilation they are stored in the EX4's properties section which survives compilation cleanly, including the original parameter names. These tell you immediately: what the user can configure, what units are used (points? pips?), and what the default strategy settings are. This section alone gives you significant insight into the EA's design philosophy.

Section 3: Global Variables

After inputs, global variables are declared. In decompiled code these often have generic names, but their types reveal their purpose:

int    a0;      // int = counter, state flag, order ticket, or time comparison

double b1;      // double = price level, indicator value, or calculation

bool   c2;      // bool = condition flag (true/false signal)

datetime d3;    // datetime = time tracking for bar detection

string e4;      // string = symbol name, message, or text value

Before reading any function code, scan the global variable declarations and use their types to form initial hypotheses about each variable's purpose. You will refine these hypotheses as you trace each variable through the code.

Understanding the Mandatory Functions

Every MQL4 EA must implement certain mandatory event handler functions. Identifying and reading these in order gives you the complete operational picture of the EA:

OnInit() Initialization

Runs once when the EA is attached to a chart or MetaTrader is restarted. Read this function to find:

  • Indicator handle creation (what indicators the EA will use)
  • Input validation logic (what ranges are considered valid)
  • Initial state setup (starting values for tracking variables)
  • License validation code (account number checks, broker name checks)
  • Any external service connections initialized at startup

OnInit() returns an integer returning 0 means success, any non-zero value causes the EA to fail to start. Any non-zero return based on a condition tells you what the EA considers invalid configuration.

OnDeinit() Cleanup

Runs when the EA is removed or MetaTrader closes. Typically brief deleting chart objects, releasing indicator handles, closing any external connections. The presence of ObjectDelete() calls here tells you the EA draws objects on the chart during operation. Otherwise minimal strategic significance.

OnTick() The Heart of the EA

The most important function. Runs on every incoming price update (tick). All trading decisions happen here. Read this function top to bottom to understand the complete trading logic:

  1. New bar detection Many EAs only act once per bar open, not on every tick. Look for a datetime comparison at the top of OnTick() that checks whether a new bar has opened.
  2. Indicator value reading After bar detection, indicator values for the current bar are retrieved.
  3. Position counting Most EAs check how many of their own positions are currently open before deciding whether to open new ones.
  4. Exit logic Some EAs implement manual exits (trailing stops, time-based exits) that run before checking for new entries.
  5. Entry logic The core trading signal evaluation and order placement.

Recognizing Common Trading Logic Patterns

MQL4 trading logic follows a small number of highly recognizable patterns. Identifying these patterns lets you understand any EA's strategy quickly:

New Bar Detection Pattern

// Always at the top of OnTick() for bar-based EAs:

static datetime lastBar = 0;

if(Time[0] == lastBar) return;  // Not a new bar yet - exit immediately

lastBar = Time[0];              // Record the current bar time

What it means: The EA only acts once per bar (at bar open), not on every tick. This makes it a "bar-based" strategy it uses bar closing prices to make decisions, not tick-by-tick price movements. This is important for understanding the strategy's time characteristics.

Moving Average Crossover Pattern

double a0 = iMA(NULL, 0, input_1, 0, 1, 0, 0);  // Fast EMA, current bar

double a1 = iMA(NULL, 0, input_1, 0, 1, 0, 1);  // Fast EMA, previous bar

double a2 = iMA(NULL, 0, input_2, 0, 1, 0, 0);  // Slow EMA, current bar

double a3 = iMA(NULL, 0, input_2, 0, 1, 0, 1);  // Slow EMA, previous bar


// Crossover: fast was below slow, now is above

bool buySignal = (a0 > a2) && (a1 <= a3);

This pattern is unambiguous even with generic names. The iMA calls with the arguments 0, 1, 0, 0 decode as: MODE_EMA, applied to PRICE_CLOSE. The crossover logic compares current values to previous bar values this is the standard MA crossover implementation.

RSI Threshold Pattern

double b0 = iRSI(NULL, 0, 14, 0, 0);  // RSI(14) on current bar

bool oversold   = (b0 < 30);           // Classic oversold threshold

bool overbought = (b0 > 70);           // Classic overbought threshold

RSI function calls always expose the period (14), the price type (0=Close), and which bar (0=current). The thresholds (30 and 70) immediately identify the classic oversold/overbought interpretation even with a generic variable name for the RSI value itself.

Position Counting Pattern

int openBuys = 0, openSells = 0;

for(int i = OrdersTotal() - 1; i >= 0; i--)

{

    if(!OrderSelect(i, SELECT_BY_POS)) continue;

    if(OrderMagicNumber() != MagicNumber) continue;  // Only count our own orders

    if(OrderSymbol() != Symbol()) continue;            // Only on current symbol

    if(OrderType() == OP_BUY)  openBuys++;

    if(OrderType() == OP_SELL) openSells++;

}

This standard loop counts the EA's own open positions. The magic number filter ensures the EA only counts positions it opened itself, not manual trades. The result tells you how many open positions of each type the EA currently manages.

Reading Indicator Calls in Detail

MQL4 indicator function calls are always fully readable after decompilation they are built-in function calls whose syntax is completely preserved. Learning to read them unlocks the complete picture of what market data the EA uses.

The general format for iMA():

iMA(symbol, timeframe, period, shift, method, price, bar_index)

//   NULL=current  0=current  e.g.14  0=no shift  0=SMA,1=EMA,2=SMMA,3=LWMA  0=Close,1=Open  0=current bar

Complete indicator reference for common calls:

Function

Key Parameters

What to Look For

iMA()

period, method(0-3), price, bar

MA type, period, timeframe

iRSI()

period, price, bar

Period (usually 14), thresholds used

iMACD()

fast, slow, signal, price, mode, bar

Standard (12,26,9) or custom params

iBands()

period, deviation, price, mode, bar

Band width (deviation), which band (upper/lower/mid)

iStochastic()

K-period, D-period, slowing, price, mode, bar

Standard (5,3,3) or custom

iATR()

period, bar

Period, whether used for stop sizing

Understanding Order Management Code

Order management code is highly readable in decompiled MQL4 the built-in functions are always preserved exactly. Here is what the key calls tell you:

OrderSend() Trade Execution

int ticket = OrderSend(

    Symbol(),                    // Currency pair (always current symbol unless hardcoded)

    OP_BUY,                      // Direction: OP_BUY or OP_SELL

    lots,                        // Volume trace this variable to find lot sizing formula

    Ask,                         // Entry price: Ask for buys, Bid for sells

    3,                           // Slippage tolerance in points

    Ask - StopLoss * Point,      // Stop loss level

    Ask + TakeProfit * Point,    // Take profit level

    "EA Comment",                // Text comment (often reveals EA name or version)

    MagicNumber,                 // EA's unique identifier

    0,                           // Expiry (0 = no expiry for market orders)

    clrBlue                      // Chart arrow color

);

This single function call tells you: entry direction, exact stop loss and take profit calculation methods, slippage tolerance, and the magic number used to identify orders. Trace the lots variable back to its definition to find the complete lot sizing formula this is one of the most revealing elements of any code review.

Trailing Stop Implementation

// Standard trailing stop pattern

for(int i = OrdersTotal() - 1; i >= 0; i--)

{

    if(!OrderSelect(i, SELECT_BY_POS)) continue;

    if(OrderMagicNumber() != MagicNumber) continue;

    if(OrderType() == OP_BUY)

    {

        double newSL = Bid - TrailPoints * Point;  // New stop level

        if(newSL > OrderStopLoss() + Point)        // Only move stop forward, never back

            OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrNone);

    }

}

This pattern implements a standard trailing stop that moves the stop loss forward as price advances. The logic is clear and unambiguous regardless of variable name genericness.

Decoding Generic Variable Names

When decompilation produces generic names (a0, b1, c3), systematic decoding is possible through careful tracing:

  1. Start with the type. int = counter, index, ticket, or state flag. double = price, indicator value, lot size, or monetary value. datetime = time tracking. bool = condition flag. string = symbol name, message, or text.
  2. Find where it is assigned. What value is assigned to this variable? If a0 = iMA(...), it is an MA value. If a0 = OrderSend(...), it is an order ticket. If a0 = OrdersTotal(), it is a position count.
  3. Find how it is used. How is the variable used in conditions and function calls? What functions receive it as a parameter? What values is it compared to?
  4. Rename it in your working copy. Create a renamed version of the recovered source with meaningful names. This turns generic code into readable, maintainable code. This renaming process itself deepens your understanding of the strategy significantly.

Understanding the compilation process that determines whether variable names are preserved or not is covered in detail in the article on practical application of this knowledge using it to evaluate EAs before purchase is covered in the guide on

An Efficient Annotation Workflow

A structured workflow for annotating recovered decompiled code makes the process significantly more efficient:

  1. Create a working copy. Never modify the original recovered file. Work from a copy so you can always reference the original decompilation output.
  2. Read the input parameters first. Document what each parameter controls in a comment above it. This gives you the strategy's vocabulary.
  3. Read and annotate OnInit(). Document what each line initializes. This reveals the EA's startup requirements and any broker-specific logic.
  4. Read OnTick() top to bottom. Add a comment above each logical block describing what it does at a high level before getting into the details.
  5. Rename global variables as you go. Once you understand a variable's purpose, rename it in the working copy. Your IDE or text editor's find-and-replace handles this efficiently.
  6. Produce a strategy summary. After completing the annotation, write a 5–10 sentence plain-English summary of what the EA does. This summary is the most useful artifact of the annotation process for communicating the strategy to others or for your own records.

Testing Your Understanding

The ultimate validation of whether you have correctly understood the recovered code is behavioral equivalence testing:

  1. Run a backtest with the original EX4 on a specific symbol, timeframe, and date range. Note the exact trade count, profit/loss, and equity curve shape.
  2. Compile and run a backtest with your annotated recovered source on identical settings. Results should be very similar not identical to the decimal place due to floating-point arithmetic differences, but the same trade count and broadly similar profit/loss.
  3. Run both versions simultaneously on a demo account. Attach the original EX4 and the compiled recovered source to different charts of the same symbol. They should open and close the same trades at the same times. Any divergence reveals a discrepancy between the original and recovered code that requires investigation.

Close behavioral match between the original and recovered code validates both that the decompilation was successful and that your annotation-based understanding is correct. This verification step is especially important before using the recovered source code to make any modifications intended for live deployment.

Further Learning Resources

To deepen your MQL4 reading skills beyond what this guide covers:

  • MetaQuotes MQL4 Reference: The official documentation at ex4decompiler.com covers every built-in function with full parameter descriptions. Bookmark this for looking up any function call you encounter in recovered code.
  • MQL5 Community Code Base: Thousands of open-source indicators and EAs with full source code, available for reading and learning from. Comparing similar strategies helps calibrate your reading of less familiar code patterns.
  • Forex Factory Developer Section: Experienced MQL4 developers discuss code patterns, debugging approaches, and common implementation questions. A useful resource for specific questions about patterns you encounter in recovered code.

The Ex4decompiler.com  at ForexMQ5 provides the recovered source code you need as the starting point for this entire reading and annotation process. Their professional recovery, combined with the reading methodology in this guide, gives you everything needed to fully understand any Expert Advisor regardless of whether you originally wrote it, purchased it, or inherited it from another developer.

Practical Code Reading Tips From Experienced Reviewers

MQL4 developers who regularly review decompiled code have developed techniques that make the process faster and more effective. These practical tips come from working through hundreds of recovered source files:

Read the EA properties section first, always. The input parameters their names, types, and default values provide the vocabulary for everything that follows. Before reading a single function, understanding what is configurable tells you how the developer designed the strategy's flexibility and what the intended operating range for each parameter is.

Use MetaEditor's Go To Definition feature actively. When you encounter a variable or function whose purpose is unclear, right-click and select "Go to definition." MetaEditor will jump to where it is declared or defined. For global variables in decompiled code, the declaration often includes type information and initial values that help infer purpose.

Print() calls are your secret weapon. Developers leave Print() calls in production EAs to debug and log behavior. Even when all structural comments are gone after decompilation, the strings passed to Print() often contain the developer's own description of what is happening at that point in the code. These developer-authored descriptions provide context that no decompiler can fabricate.

Backtrace variables bottom-up. When you find a variable being compared in a critical condition (entry signal, exit trigger), trace it backwards from that comparison to its origin. Each assignment in the backtrace adds one layer of understanding. Starting from the comparison the outcome and working backwards to the source tends to be more efficient than trying to follow every variable forward from its initial assignmentAOofT3V.png

We may use cookies or any other tracking technologies when you visit our website, including any other media form, mobile website, or mobile application related or connected to help customize the Site and improve your experience. learn more

Allow