MQL5 Custom Indicator Handle: How to Use It?

Introduction to MQL5 Custom Indicator Handles

In MQL5, custom indicator handles are essential for accessing and utilizing the data produced by custom indicators within your Expert Advisors (EAs) or other scripts. Understanding how to properly obtain, use, and manage these handles is crucial for building sophisticated trading strategies.

What is a Custom Indicator Handle?

A custom indicator handle is an integer value that serves as a unique identifier for an instance of a custom indicator loaded into a chart. Think of it as a pointer, although it’s not a memory address in the traditional sense. It allows your MQL5 program to communicate with and retrieve data from that specific instance of the custom indicator.

Why Use Handles for Custom Indicators?

Instead of directly embedding the indicator’s code into your EA, using handles promotes modularity and reusability. You can update the indicator without modifying the EA’s code. Furthermore, it avoids code duplication, leading to cleaner and more maintainable codebases.

Benefits of Using Indicator Handles

  • Modularity: Separates indicator logic from EA logic.
  • Reusability: Allows the same indicator to be used by multiple EAs or scripts.
  • Maintainability: Simplifies updates and modifications to indicators.
  • Efficiency: Avoids code duplication and potential performance issues.

Obtaining an Indicator Handle

The iCustom() function is the primary way to obtain an indicator handle.

The iCustom() Function: Syntax and Parameters

The iCustom() function has the following syntax:

int iCustom(
   string symbol,          // Symbol
   ENUM_TIMEFRAMES period, // Timeframe
   string name,            // Indicator name
   ...                     // Indicator input parameters
);
  • symbol: The symbol the indicator is attached to (e.g., Symbol()).
  • period: The timeframe of the chart (e.g., Period()).
  • name: The name of the custom indicator’s .ex5 file (without the extension).
  • ...: Optional input parameters for the indicator, passed in the order they are defined in the indicator’s code.

Specifying Indicator Name and Parameters

Ensure the name parameter matches the filename of your compiled indicator exactly (case-sensitive). The input parameters must match the indicator’s declared inputs in both order and type. Mismatched parameters will lead to an invalid handle.

Error Handling: Checking for Invalid Handles

It is critical to check if the iCustom() function successfully returns a valid handle. An invalid handle is represented by INVALID_HANDLE (typically -1). Always include error handling to prevent unexpected behavior.

int handle = iCustom(Symbol(), Period(), "MyCustomIndicator", param1, param2);
if (handle == INVALID_HANDLE)
  {
   Print("Error creating indicator handle: ", GetLastError());
   return; // or handle the error appropriately
  }

Using the Indicator Handle to Access Indicator Data

Once you have a valid handle, you can use the CopyBuffer() function to retrieve indicator values.

CopyBuffer() Function: Retrieving Indicator Values

The CopyBuffer() function copies data from a specific indicator buffer into an array.

int CopyBuffer(
   int     indicator_handle,   // Indicator handle
   int     buffer_num,         // Buffer number
   int     start_pos,          // Starting index
   int     count,              // Number of elements to copy
   double& dest_array[]       // Destination array
   );
  • indicator_handle: The handle obtained from iCustom().
  • buffer_num: The index of the indicator buffer (0, 1, 2, etc.). This depends on how the indicator is programmed. Check the indicator’s source code to determine the number and purpose of each buffer. You should typically find #property indicator_buffers and #property indicator_plots declarations.
  • start_pos: The starting index in the indicator’s buffer. Usually 0 refers to the most recent bar.
  • count: The number of elements to copy.
  • dest_array[]: The destination array to store the copied data. The array should be declared as double[] or float[].

Specifying the Buffer Number and Data Range

The buffer_num is critical. Custom indicators can have multiple buffers, each representing a different data series (e.g., the main line, signal line, overbought/oversold levels). Refer to the indicator’s source code or documentation to identify the correct buffer number. The data range is determined by start_pos and count. Pay attention to the history available; requesting data beyond the available bars will result in an error.

Handling Data Type Conversions (if necessary)

The CopyBuffer() function copies data as double. If the indicator buffer stores data in a different format (unlikely, but possible), you might need to perform manual data type conversions after copying the data.

Managing and Releasing Indicator Handles

Releasing indicator handles is crucial for preventing resource leaks and ensuring optimal performance.

IndicatorRelease() Function: Why and When to Use It

The IndicatorRelease() function releases the resources associated with an indicator handle.

void IndicatorRelease(int indicator_handle);

Call IndicatorRelease() when you are finished using the indicator handle. This is typically done in the OnDeinit() function of your EA or script.

Best Practices for Handle Management

  • Always check for INVALID_HANDLE after calling iCustom(). If invalid, do not proceed.
  • Release the handle in OnDeinit() to free resources when the EA or script is removed from the chart or when the terminal closes.
  • Avoid creating handles repeatedly in the OnTick() or OnCalculate() functions. Create the handle once in OnInit() and reuse it.

Avoiding Memory Leaks

Failing to release indicator handles can lead to memory leaks, which can degrade performance and eventually crash the terminal. Always pair every call to iCustom() with a corresponding call to IndicatorRelease().

Practical Examples and Use Cases

Example 1: Retrieving Moving Average Values

int ma_handle;

int OnInit()
  {
   ma_handle = iCustom(Symbol(), Period(), "Moving Average", 14, 0, MODE_SMA, PRICE_CLOSE); // Replace "Moving Average" with the correct filename if needed
   if (ma_handle == INVALID_HANDLE)
    {
     Print("Error creating MA handle: ", GetLastError());
     return INIT_FAILED;
    }
   return INIT_SUCCEEDED;
  }

void OnDeinit(const int reason)
  {
   IndicatorRelease(ma_handle);
  }

void OnTick()
  {
   double ma_value[1];
   if (CopyBuffer(ma_handle, 0, 0, 1, ma_value) > 0)
    {
     Print("Moving Average value: ", ma_value[0]);
    }
   else
    {
     Print("Error copying MA buffer: ", GetLastError());
    }
  }

Example 2: Integrating a Custom RSI Indicator

Assume you have a custom RSI indicator named “MyRSIIndicator.ex5” with a single input parameter ‘Period’.

int rsi_handle;

int OnInit()
  {
   rsi_handle = iCustom(Symbol(), Period(), "MyRSIIndicator", 14); // Assuming Period is 14
   if (rsi_handle == INVALID_HANDLE)
    {
     Print("Error creating RSI handle: ", GetLastError());
     return INIT_FAILED;
    }
   return INIT_SUCCEEDED;
  }

void OnDeinit(const int reason)
  {
   IndicatorRelease(rsi_handle);
  }

void OnTick()
  {
   double rsi_value[1];
   if (CopyBuffer(rsi_handle, 0, 0, 1, rsi_value) > 0)
    {
     Print("RSI value: ", rsi_value[0]);
    }
   else
    {
     Print("Error copying RSI buffer: ", GetLastError());
    }
  }

Advanced Scenarios: Using Handles in Expert Advisors

In sophisticated EAs, you can use indicator handles to:

  • Generate trading signals based on indicator values.
  • Implement complex filtering logic using multiple indicators.
  • Dynamically adjust trading parameters based on market conditions (e.g., volatility measured by an ATR indicator).

By mastering the use of MQL5 custom indicator handles, you can unlock the full potential of custom indicators and create powerful and flexible trading systems.


Leave a Reply