How to Call a Function in MQL5?

Introduction to Functions in MQL5

What are Functions and Why Use Them?

In MQL5, functions are self-contained blocks of code that perform specific tasks. They are essential for creating modular, reusable, and maintainable code. Using functions enhances code readability, reduces redundancy, and simplifies debugging. Think of them as mini-programs within your main program.

Types of Functions: Standard and Custom

MQL5 provides two main types of functions:

  1. Standard (Predefined) Functions: These are built-in functions provided by the MQL5 language itself, such as OrderSend(), iMA(), TimeCurrent(), etc. They handle common tasks like order management, technical indicator calculations, and time retrieval. These are immediately available for use, once the MQL5 program begins execution.
  2. Custom (User-Defined) Functions: These are functions that you define yourself to perform specific tasks tailored to your program’s needs. This allows for modular code and reusability.

Basic Structure of a Function in MQL5

A typical MQL5 function consists of the following elements:

  • Return Type: Specifies the data type of the value returned by the function (e.g., int, double, void). Use void if the function does not return any value.
  • Function Name: A unique identifier for the function.
  • Parameter List: A comma-separated list of input parameters, each with its data type and name. If no parameters are needed, leave the parenthesis empty.
  • Function Body: The block of code enclosed in curly braces {} that contains the function’s logic.
// Example of a custom function structure
double CalculateAverage(double value1, double value2)
{
    double average = (value1 + value2) / 2.0;
    return average;
}

Calling User-Defined Functions

Declaring and Defining Functions

Before calling a custom function, it must be declared and defined. The declaration informs the compiler about the function’s existence, while the definition provides the actual implementation.

// Function Declaration (Prototype)
double CalculateAverage(double value1, double value2);

// Function Definition
double CalculateAverage(double value1, double value2)
{
    double average = (value1 + value2) / 2.0;
    return average;
}

In simple scripts, declarations are optional if definitions come before the first call of the function. In Expert Advisors, using function prototypes for organized code is a good practice.

Calling Functions with No Arguments

To call a function that doesn’t require any input, simply use its name followed by parentheses ().

void PrintMessage()
{
    Print("Hello, World!");
}

void OnStart()
{
    PrintMessage(); // Calling the function
}

Calling Functions with Arguments: Passing by Value and Reference

When calling a function with arguments, you need to provide the required values in the correct order. MQL5 supports two ways of passing arguments:

  • By Value: A copy of the argument’s value is passed to the function. Any changes made to the parameter within the function do not affect the original variable.
  • By Reference: The memory address of the argument is passed to the function. Any changes made to the parameter will affect the original variable. Use the & symbol before the parameter name in the function definition to pass by reference.
void ModifyValue(int value, int &referenceValue)
{
    value = value * 2;           // Modifies the copy
    referenceValue = referenceValue * 2; // Modifies the original
}

void OnStart()
{
    int myValue = 5;
    int myReferenceValue = 10;
    ModifyValue(myValue, myReferenceValue);
    Print("myValue: ", myValue);             // Output: myValue: 5
    Print("myReferenceValue: ", myReferenceValue); // Output: myReferenceValue: 20
}

Returning Values from Functions

Functions can return a value to the calling code using the return keyword. The return type of the function must match the data type of the returned value.

double CalculateProfit(double buyPrice, double sellPrice)
{
    double profit = sellPrice - buyPrice;
    return profit;
}

void OnStart()
{
    double profit = CalculateProfit(1.2345, 1.2355);
    Print("Profit: ", profit);
}

Calling Predefined (Standard) Functions

Overview of Common MQL5 Standard Functions

MQL5 offers a rich set of built-in functions for various purposes, including:

  • Order Management: OrderSend(), OrderClose(), OrderModify(), OrderDelete()
  • Technical Indicators: iMA(), iRSI(), iMACD()
  • Time Functions: TimeCurrent(), TimeToStr(), TimeLocal()
  • String Functions: StringLen(), StringSubstr(), StringConcatenate()
  • Math Functions: MathAbs(), MathSqrt(), MathRand()

Examples of Calling Standard Functions (e.g., OrderSend, iMA)

void OnStart()
{
    // Example using OrderSend
    MqlTradeRequest request;
    MqlTradeResult  result;
    ZeroMemory(request);
    request.action   = TRADE_ACTION_DEAL;
    request.symbol   = _Symbol;
    request.volume   = 0.01;
    request.type     = ORDER_TYPE_BUY;
    request.price    = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
    request.sl       = request.price - 500 * _Point; // 50 pips SL
    request.tp       = request.price + 1000 * _Point; // 100 pips TP
    request.magic    = 123456;                       // Magic number
    request.deviation= 10;
    OrderSend(request, result);

    // Example using iMA
    int maHandle = iMA(_Symbol, PERIOD_H1, 20, 0, MODE_SMA, PRICE_CLOSE);
    double maValue;
    CopyBuffer(maHandle, 0, 0, 1, maValue);
    Print("20 period SMA on H1: ", maValue);
    IndicatorRelease(maHandle);
}

Understanding Function Parameters and Return Types

It is crucial to understand the required parameters and return type of each standard function. Refer to the MQL5 documentation for detailed information. Incorrect parameters or return type handling can lead to errors and unexpected behavior. For example, OrderSend() requires a properly structured MqlTradeRequest and populates an MqlTradeResult structure.

Function Scope and Lifetime

Global vs. Local Variables

  • Global Variables: Declared outside any function. They are accessible from anywhere in the program and their lifetime spans the entire program execution.
  • Local Variables: Declared inside a function. They are only accessible within that function, and their lifetime is limited to the function’s execution.

Scope of Functions: Calling Functions from Different Parts of the Program

Functions declared in the global scope can be called from any part of the program, including other functions. Local functions (nested functions) are not supported in MQL5.

Static Variables in Functions

A static variable declared inside a function retains its value between function calls. It is initialized only once, during the first call to the function.

void Counter()
{
    static int count = 0; // Initialized only once
    count++;
    Print("Count: ", count);
}

void OnStart()
{
    Counter(); // Output: Count: 1
    Counter(); // Output: Count: 2
    Counter(); // Output: Count: 3
}

Advanced Function Calling Techniques

Calling Functions Recursively

A recursive function is a function that calls itself. Recursion is useful for solving problems that can be broken down into smaller, self-similar subproblems. However, it’s important to ensure that the recursion has a base case to prevent infinite loops.

int Factorial(int n)
{
    if (n == 0)
        return 1; // Base case
    else
        return n * Factorial(n - 1); // Recursive call
}

void OnStart()
{
    int result = Factorial(5);
    Print("Factorial of 5: ", result); // Output: Factorial of 5: 120
}

Function Pointers (if applicable – check MQL5 support)

MQL5 does not directly support function pointers in the same way as C or C++. However, you can achieve similar functionality using object-oriented programming techniques and interfaces. This allows you to pass objects that implement a specific interface, where the interface defines a method that effectively acts like a function pointer.

// Example demonstrating the concept of function pointers using OOP
interface IFunction
{
    int Execute(int x, int y);
};

class Addition : public IFunction
{
public:
    int Execute(int x, int y) override
    {
        return x + y;
    }
};

class Subtraction : public IFunction
{
public:
    int Execute(int x, int y) override
    {
        return x - y;
    }
};

void PerformOperation(IFunction* function, int a, int b)
{
    int result = function.Execute(a, b);
    Print("Result: ", result);
}

void OnStart()
{
    Addition* add = new Addition();
    Subtraction* sub = new Subtraction();

    PerformOperation(add, 5, 3); // Result: 8
    PerformOperation(sub, 5, 3); // Result: 2

    delete add;
    delete sub;
}

Error Handling and Function Return Codes

When calling functions, it’s essential to check for errors. Many standard functions return specific values to indicate success or failure. For example, OrderSend() returns a ticket number on success or -1 on failure. Check the return code and use GetLastError() to get more information about the error.

MqlTradeRequest request;
MqlTradeResult  result;
// ... (Populate request structure) ...
int ticket = OrderSend(request, result);
if (ticket < 0)
{
    Print("OrderSend failed. Error code: ", GetLastError());
}
else
{
    Print("Order placed successfully. Ticket: ", ticket);
}

Leave a Reply