MQL4 BASICS COURSE

Organizing EA Logic Outside OnTick() (MQL4)

Lesson Goal

In this lesson, you will learn:


1) What OnTick() Is (And What It Is NOT)

OnTick() runs every time a new price tick arrives. That can be many times per second.

Because of this, OnTick() should:

OnTick() should NOT:

Think of OnTick() as a traffic controller, not a worker.


2) The Common Beginner Problem

Most beginners start with something like this:

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

   // Time filter
   if(Hour() < 8 || Hour() > 16) return;

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

   // Trade management
   if(OrdersTotal() > 0)
   {
      // trailing stop, exits, etc.
   }
}

This code works, but it quickly becomes:


3) The Core Rule: OnTick() Should Read Like English

A well-structured OnTick() should be short and readable.

You should be able to understand it without scrolling.

Example: Clean OnTick()

void OnTick()
{
   UpdateTradingRules();
   if(!TradingAllowed) return;

   ManageOpenTrades();
   LookForEntries();
}

If you can read OnTick() like a checklist, you are doing it right.


4) Step 1: Move Rule Checks Out of OnTick()

Rule checks include:

Instead of checking these directly in OnTick(), move them into a single function.

Example: Rule Update Function

// Global state
bool TradingAllowed = true;

void UpdateTradingRules()
{
   TradingAllowed = true;

   if(MarketInfo(Symbol(), MODE_SPREAD) > 20)
      TradingAllowed = false;

   if(Hour() < 8 || Hour() > 16)
      TradingAllowed = false;
}

Now OnTick() simply asks:

if(!TradingAllowed) return; 
//Meaning if TradingAllowed==False go back to the start and try again... YOU SHALL NOT PASS!

5) Step 2: Separate Trade Management from Entries

Managing open trades and opening new trades are two very different jobs.

They should NEVER be mixed in the same block of code.

Example: Two Separate Functions

void ManageOpenTrades()
{
   // trailing stops, exits, breakeven logic
}

void LookForEntries()
{
   if(OrdersTotal() > 0) return;

   // entry logic here
}

This prevents:


6) Optional but Powerful: Run Logic Once Per Bar

Many EA calculations do not need to run on every tick.

A common professional technique is to run logic once per candle.

Example: New Bar Detection

datetime LastBarTime = 0;

bool IsNewBar()
{
   if(Time[0] != LastBarTime)
   {
      LastBarTime = Time[0];
      return(true);
   }
   return(false);
}

Now OnTick() becomes even cleaner:

void OnTick()
{
   UpdateTradingRules();
   if(!TradingAllowed) return;

   if(IsNewBar())
   {
      ManageOpenTrades();
      LookForEntries();
   }
}

7) Full EA Skeleton (Everything in One Place)

This shows the recommended structure for a beginner-friendly, professional-quality EA.

//==============================
// GLOBAL VARIABLES
//==============================
bool TradingAllowed = true;
datetime LastBarTime = 0;

//==============================
// ONTICK (traffic controller)
//==============================
void OnTick()
{
   UpdateTradingRules();
   if(!TradingAllowed) return;

   if(IsNewBar())
   {
      ManageOpenTrades();
      LookForEntries();
   }
}

//==============================
// LOGIC FUNCTIONS
//==============================

void UpdateTradingRules()
{
   TradingAllowed = true;

   if(MarketInfo(Symbol(), MODE_SPREAD) > 20)
      TradingAllowed = false;

   if(Hour() < 8 || Hour() > 16)
      TradingAllowed = false;
}

void ManageOpenTrades()
{
   // trade management logic
}

void LookForEntries()
{
   if(OrdersTotal() > 0) return;

   // entry logic
}

//==============================
// HELPER FUNCTIONS
//==============================

bool IsNewBar()
{
   if(Time[0] != LastBarTime)
   {
      LastBarTime = Time[0];
      return(true);
   }
   return(false);
}

8) Common Beginner Mistakes


Lesson Summary


Next Lesson

Writing Clean, Readable EA Code

We will focus on naming, spacing, comments, and structure so your EA is easy to understand months later.