Complete MQL5 guide & code

MQL5 Classes, Structs & Inheritance: OOP Architecture Guide

Master MQL5 object-oriented programming with classes, structs, and inheritance. Learn memory management, access specifiers, virtual methods, and modular EA design.

What this MQL5 guide covers

MQL5 supports object-oriented programming based on C++, including class encapsulation, inheritance, and polymorphism.

Structs in MQL5 default to public member access and serve as lightweight value types for signals, ticks, and configuration parameters.

Classes default to private access, support single inheritance (class Derived : public Base), virtual methods, and heap allocation via new and delete.

Structs in MQL5 cannot inherit or declare virtual functions; polymorphic strategy components require classes.

Struct vs Class in MQL5: Core Differences

Both structs and classes in MQL5 can contain data members, constructor and destructor methods, and member functions. The key structural differences govern default access rights, inheritance capabilities, and allocation patterns.

A struct defaults to public access for its members and methods. A class defaults to private access, enforcing data encapsulation unless public or protected specifiers are declared.

FeatureMQL5 StructMQL5 Class
Default Accesspublicprivate
InheritanceNot supportedSingle inheritance supported
Virtual MethodsNot supportedSupported (polymorphism)
Memory ModelValue type (stack copy)Reference or pointer type
Typical Use CaseData records (MqlTick, signals)Trading engines, indicator wrappers

Inheritance and Virtual Methods in MQL5

MQL5 implements single class inheritance using the colon syntax: class CDerived : public CBase. Multiple inheritance is not supported in MQL5.

Declaring methods with the virtual keyword enables runtime polymorphism. A base pointer can store derived class instances and invoke the correct overridden implementation dynamically.

  • virtual void OnTick() = 0; defines a pure virtual method, making the class abstract.
  • Derived classes override methods without altering the calling code interface.
  • Constructors execute from base to derived; destructors execute in reverse order.

Dynamic Allocation and Pointer Safety: CheckPointer

Objects in MQL5 can be declared statically on the stack or dynamically allocated on the heap using the new operator. Dynamic objects return a pointer (CStrategyBase*).

Every dynamic object created with new must be explicitly freed with delete in OnDeinit(). To prevent null pointer exceptions, always verify pointers with CheckPointer(ptr) != POINTER_INVALID before calling methods.

CheckPointer ReturnMeaningRecommended Action
POINTER_INVALIDPointer does not reference valid memoryDo not dereference; reinitialize or abort
POINTER_DYNAMICAllocated with new on the heapValid to call methods; must delete in OnDeinit
POINTER_AUTOMATICAllocated on the stack (local variable)Valid to call methods; cleans up automatically

OOP Patterns in the MT5 Standard Library

The MetaTrader 5 Standard Library relies heavily on OOP architecture. Classes such as CTrade, CPositionInfo, COrderInfo, and CAccountInfo encapsulate low-level trade structures into clean methods.

Extending or composing standard library classes inside your custom strategy classes produces modular Expert Advisors that are easy to test, maintain, and adapt to different market regimes.

Implementation details & mechanics

Core implementation pattern

In OnInit(), dynamically instantiate a strategy class: g_strategy = new CRsiStrategy(_Symbol, _Period, InpPeriod, InpThreshold). Verify pointer validity with CheckPointer(g_strategy) == POINTER_DYNAMIC. In OnTick(), delegate evaluation to g_strategy.Update() and g_strategy.CheckSignal(). If the returned TradeSignal struct signals a buy, execute via a shared CTrade instance.

Error handling & safety rules

In OnDeinit(const int reason), safely deallocate the strategy instance: if(CheckPointer(g_strategy) == POINTER_DYNAMIC) delete g_strategy; g_strategy = NULL. Position close checks call g_strategy.CheckExit() to keep exit condition evaluation decoupled from EA event handlers.

MQL5 Code Implementation Code

//+------------------------------------------------------------------+
//|                                  ClassesStructsInheritanceEA.mq5 |
//|                             Copyright 2026, Pineify Guides Series |
//|                                              https://pineify.app |
//+------------------------------------------------------------------+
#property copyright "Pineify Guides Series"
#property link      "https://pineify.app/mql5/classes-structs-inheritance-guide"
#property version   "1.00"
#property strict

#include <Trade\Trade.mqh>

//--- 1. Plain Data Structure (Struct)
struct TradeSignal
  {
   bool     isValid;
   int      direction; // 1 = Buy, -1 = Sell, 0 = Flat
   double   price;
   datetime timestamp;
   string   comment;
  };

//--- 2. Abstract Base Class
class CStrategyBase
  {
protected:
   string            m_symbol;
   ENUM_TIMEFRAMES   m_timeframe;

public:
                     CStrategyBase(const string symbol, const ENUM_TIMEFRAMES tf)
                       : m_symbol(symbol), m_timeframe(tf) {}
   virtual          ~CStrategyBase() {}

   // Pure virtual methods enforcing contract in derived classes
   virtual bool      Init() = 0;
   virtual void      Update() = 0;
   virtual TradeSignal CheckSignal() = 0;
  };

//--- 3. Derived Concrete Strategy Class
class CRsiStrategy : public CStrategyBase
  {
private:
   int               m_period;
   double            m_oversold;
   int               m_handle;
   double            m_buffer[];

public:
                     CRsiStrategy(const string symbol, const ENUM_TIMEFRAMES tf,
                                  const int period, const double oversold)
                       : CStrategyBase(symbol, tf),
                         m_period(period),
                         m_oversold(oversold),
                         m_handle(INVALID_HANDLE) {}

   virtual          ~CRsiStrategy()
     {
      if(m_handle != INVALID_HANDLE)
         IndicatorRelease(m_handle);
     }

   virtual bool Init() override
     {
      m_handle = iRSI(m_symbol, m_timeframe, m_period, PRICE_CLOSE);
      if(m_handle == INVALID_HANDLE)
         return false;

      ArraySetAsSeries(m_buffer, true);
      return true;
     }

   virtual void Update() override
     {
      if(m_handle != INVALID_HANDLE)
         CopyBuffer(m_handle, 0, 0, 2, m_buffer);
     }

   virtual TradeSignal CheckSignal() override
     {
      TradeSignal signal;
      ZeroMemory(signal);

      if(ArraySize(m_buffer) < 2)
         return signal;

      // Detect oversold rebound: previous bar below oversold, latest crossed above
      if(m_buffer[1] < m_oversold && m_buffer[0] >= m_oversold)
        {
         signal.isValid   = true;
         signal.direction = 1; // Long
         signal.price     = SymbolInfoDouble(m_symbol, SYMBOL_ASK);
         signal.timestamp = TimeCurrent();
         signal.comment   = "RSI Oversold Rebound";
        }

      return signal;
     }
  };

//--- Global Variables
CStrategyBase *g_strategy = NULL;
CTrade         g_trade;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   // Instantiate derived class through base pointer
   g_strategy = new CRsiStrategy(_Symbol, _Period, 14, 30.0);

   if(CheckPointer(g_strategy) == POINTER_INVALID)
     {
      Print("Failed to allocate strategy instance.");
      return(INIT_FAILED);
     }

   if(!g_strategy.Init())
     {
      Print("Strategy initialization failed.");
      return(INIT_FAILED);
     }

   Print("OOP EA initialized successfully.");
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   // Safe dynamic memory cleanup
   if(CheckPointer(g_strategy) == POINTER_DYNAMIC)
     {
      delete g_strategy;
      g_strategy = NULL;
     }

   PrintFormat("Strategy instance deleted. Deinit reason: %d", reason);
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(CheckPointer(g_strategy) == POINTER_INVALID)
      return;

   g_strategy.Update();
   TradeSignal sig = g_strategy.CheckSignal();

   if(sig.isValid && sig.direction == 1)
     {
      PrintFormat("Signal triggered: %s at price %.5f", sig.comment, sig.price);
      // Execute order via CTrade
     }
  }

Copy this code into MetaEditor, save it in your MQL5 folder (Experts, Scripts, or Include), and compile with F7.

Generate custom MQL5 code with Pineify AI

Describe the trade execution, indicator calculations, risk management, or data processing logic you need. Pineify produces clean, typed MQL5 source code ready to compile in MetaEditor.

Frequently Asked Questions

Related MQL5 pages

Technical references

Risk and testing note

Past performance is not indicative of future results. Backtest statistics are based on historical data and do not guarantee future profits. Trading involves significant risk of loss. This content is for educational purposes only and does not constitute financial advice.