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:
- 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. - 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). Usevoidif 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);
}