MQL4 BASICS COURSE

🧱 Program Structure & Reusable Logic (MQL4)

Lesson: Global vs Local Scope

Lesson Goal

By the end of this lesson you will understand:


1) What “Scope” Means

Scope means:

Where in your code something exists, and who can use it.

MQL4 has two main scopes you’ll use constantly:


2) Global Scope (Global Variables)

Before we write any real trading logic, we need to understand where variables live and who is allowed to use them. This is called scope.

A global variable is a variable that is declared outside of any function.

Because it is outside all functions, it can be accessed from:

Think of global variables as shared memory for your EA. All parts of the EA can see and use them.

Example: Global Variables

Global variables are placed at the top of the EA file, before OnInit() or OnTick().

// ===== GLOBAL SCOPE (top of file) =====
double RiskPercent     = 1.0;
int    MagicNumber     = 12345;
bool   TradingEnabled  = true;

Once declared here, these variables exist for the entire lifetime of the EA. They do not reset on every tick.

What Each Global Variable Represents

When Should You Use Global Variables?

Use global variables only for values that must be:

Common examples include:

Very Important Beginner Warning

Do NOT make everything global.

If you make every variable global, your EA becomes:

Temporary values — like calculations, loop counters, or one-time checks — should be local variables inside functions.

A simple rule to remember:

If a value is only needed inside one function, it should NOT be global.

In the next section, we will look at local scope and see how it keeps your EA clean, safe, and easy to understand.


3) Local Scope (Local Variables)

Local variables are declared inside a function.

They exist only while the function runs, then disappear.

Example: Local Variable

void CheckSpread()
{
   double spreadPoints = MarketInfo(Symbol(), MODE_SPREAD); // LOCAL
   Print("Spread: ", spreadPoints);
}

Use local variables for:

Think of local variables as a “workbench” for the current function only.

4) Why Beginners Struggle: OnTick Gets Huge

Many beginners put everything in OnTick():

void OnTick()
{
   // Spread check
   double spread = MarketInfo(Symbol(), MODE_SPREAD);
   if(spread > 20) return;

   // Lot size logic
   double lotSize = 0.10; // pretend

   // Entry logic
   if(OrdersTotal() == 0)
   {
      // OrderSend...
   }

   // Trade management logic
   if(OrdersTotal() > 0)
   {
      // OrderModify, trailing, etc...
   }
}

Problem: This works at first, but quickly becomes messy, hard to debug, and easy to break.


5) The Fix: Use void Functions as “Action Blocks”

A void function means:

Do this task — it performs actions but returns nothing.

Example: A reusable action block

// Updates a global flag based on spread
void UpdateTradingEnabledBySpread()
{
   double spreadPoints = MarketInfo(Symbol(), MODE_SPREAD); // LOCAL

   if(spreadPoints > 20)
      TradingEnabled = false;  // GLOBAL
   else
      TradingEnabled = true;   // GLOBAL
}

Now you can call this from anywhere without repeating logic.

You would simply use UpdateTradingEnabledBySpread(); to call this function.


6) The “Full EA View” (See the Whole Layout)

This complete EA skeleton shows the order of everything, from top to bottom.

Note: This is a teaching structure (not a full strategy). It shows clean structure, global vs local scope, and reusable void logic.

//+------------------------------------------------------------------+
//|                 EA_Structure_Demo.mq4                             |
//|     Demonstrates Global vs Local Scope + Reusable void functions  |
//+------------------------------------------------------------------+
#property strict

//==============================
// 1) INPUTS (settings user can change)
//==============================
input double InpRiskPercent   = 1.0;
input int    InpMagicNumber   = 12345;
input int    InpMaxSpreadPts  = 20;

//==============================
// 2) GLOBAL VARIABLES (EA "state")
//   - Used across multiple functions
//   - Persist between ticks
//==============================
bool     gTradingEnabled = true;
double   gTodayProfit    = 0.0;     // example state (pretend this is percent)
datetime gLastBarTime    = 0;       // used for New Bar detection

//==============================
// 3) FUNCTION DECLARATIONS (optional, but helps readability)
//==============================
void   UpdateTradingEnabledBySpread();
void   UpdateDailyStopRules();
void   ManageOpenTrades();
void   LookForEntries();
bool   IsNewBar();
int    CountOpenTrades(string sym, int magic);

//+------------------------------------------------------------------+
//| OnInit() - runs once when EA starts                               |
//+------------------------------------------------------------------+
int OnInit()
{
   Print("EA started. Magic=", InpMagicNumber, " Risk%=", InpRiskPercent);
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| OnDeinit() - runs once when EA is removed                         |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   Print("EA stopped.");
}

//+------------------------------------------------------------------+
//| OnTick() - runs every tick                                        |
//| IMPORTANT: keep it short! It's a traffic controller.              |
//+------------------------------------------------------------------+
void OnTick()
{
   // 1) Update rules / environment checks
   UpdateTradingEnabledBySpread();
   UpdateDailyStopRules();

   // If trading is disabled, stop here.
   if(!gTradingEnabled) return;

   // Optional: run heavy logic once per bar instead of every tick
   if(IsNewBar())
   {
      // 2) Manage open trades
      ManageOpenTrades();

      // 3) Look for new entries
      LookForEntries();
   }
}

//==============================
// 4) REUSABLE VOID FUNCTIONS (Action blocks)
//==============================

// Checks spread and updates a global flag
void UpdateTradingEnabledBySpread()
{
   // LOCAL variable: only needed inside this function
   double spreadPts = MarketInfo(Symbol(), MODE_SPREAD);

   if(spreadPts > InpMaxSpreadPts)
      gTradingEnabled = false;
   else
      gTradingEnabled = true;
}

// Example: daily stop rules (profit target / max loss)
void UpdateDailyStopRules()
{
   // In a real EA, you’d calculate today’s closed profit/loss.
   // Here we just demonstrate structure using a pretend % variable.

   if(gTodayProfit >= 6.0)  gTradingEnabled = false; // +6% done
   if(gTodayProfit <= -6.0) gTradingEnabled = false; // -6% done
}

// Example open-trade management block
void ManageOpenTrades()
{
   int total = OrdersTotal(); // LOCAL

   for(int i = total - 1; i >= 0; i--)
   {
      if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
      if(OrderSymbol() != Symbol()) continue;
      if(OrderMagicNumber() != InpMagicNumber) continue;

      // Manage trades here:
      // trailing stop, breakeven, exit rules, etc.
   }
}

// Example entry block
void LookForEntries()
{
   // Only enter if no open trades for this symbol/magic
   if(CountOpenTrades(Symbol(), InpMagicNumber) > 0)
      return;

   // LOCAL variables for setup logic
   double bid = Bid;
   double ask = Ask;

   // Entry conditions would go here (strategy-specific)

   // OrderSend would go here
   // OrderSend(Symbol(), OP_BUY, lots, ask, slippage, sl, tp, "Demo", InpMagicNumber, 0, clrBlue);
}

//==============================
// 5) SMALL HELPER FUNCTIONS (return values)
//==============================

// Detect a new bar (common structure tool)
bool IsNewBar()
{
   datetime currentBarTime = Time[0]; // LOCAL

   if(currentBarTime != gLastBarTime)
   {
      gLastBarTime = currentBarTime; // GLOBAL updated
      return(true);
   }
   return(false);
}

// Helper: count open trades for a given symbol/magic
int CountOpenTrades(string sym, int magic)
{
   int count = 0;              // LOCAL
   int total = OrdersTotal();  // LOCAL

   for(int i = total - 1; i >= 0; i--)
   {
      if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
      if(OrderSymbol() != sym) continue;
      if(OrderMagicNumber() != magic) continue;

      count++;
   }
   return(count);
}

7) Cheat Sheet (Remember This)

Global variables are for:

Local variables are for:

OnTick should be a “traffic controller”:

void OnTick()
{
   UpdateRules();
   if(!Allowed) return;

   ManageTrades();
   FindEntries();
}

Next Lesson

Using void functions for reusable logic

Next we’ll build a reusable “EA toolbox”: spread filter, time filter, risk lot sizing, trade counting, and safe OrderSend wrappers.