MQL5 CopyBuffer Function Guide: Indicator Buffers, Handles & EA Examples
Complete guide to the MQL5 CopyBuffer function. Learn how to create technical indicator handles (iMA, iRSI), index arrays as series, read buffer values into Expert Advisors, and handle asynchronous data loading.
What this MQL5 guide covers
CopyBuffer extracts calculated data from indicator buffers into dynamic arrays for Expert Advisors and custom indicators.
Indicator handles must be created once in OnInit() using functions like iMA() or iRSI() and released in OnDeinit() with IndicatorRelease().
Use ArraySetAsSeries(array, true) so that index 0 represents the newest bar (current candle) and index 1 is the most recently closed bar.
Always verify the return value of CopyBuffer(); it returns the number of copied elements, or -1 if the indicator is still calculating.
CopyBuffer Function Signatures and Overloads
In MQL5, technical indicators run in separate threads and store their outputs in internal buffers. The CopyBuffer function bridges indicator computations and Expert Advisors, copying calculated values into user-defined double arrays.
There are three official overloads of CopyBuffer: copying by starting bar index and count, copying by starting datetime and count, and copying between two specific datetime boundaries.
| Parameter | Type | Description |
|---|---|---|
| indicator_handle | int | Handle returned by iMA, iRSI, iMACD, or iCustom |
| buffer_num | int | Buffer index (0 = main line, 1 = signal line, etc.) |
| start_pos | int | Starting bar position (0 = current bar, 1 = previous closed bar) |
| count | int | Number of elements to copy into the target array |
| buffer_array[] | double[] | Target dynamic array receiving the calculated float values |
Array Indexing Direction: ArraySetAsSeries
By default, standard MQL5 dynamic arrays are indexed in chronological order (index 0 is the oldest bar in the array). In algorithmic trading, you almost always want reverse chronological indexing where index 0 is the current developing bar and index 1 is the last completed bar.
Calling ArraySetAsSeries(buffer, true) switches the array to time-series indexing. When copying count=3 bars starting from index 0: buffer[0] is current bar, buffer[1] is 1 bar ago, and buffer[2] is 2 bars ago.
- ArraySetAsSeries(arr, true): Index 0 = newest copied bar (standard EA convention).
- ArraySetAsSeries(arr, false): Index 0 = oldest copied bar (standard indicator calculation convention).
- ArrayFree(arr) or dynamic resizing: CopyBuffer automatically allocates memory for target dynamic arrays.
Common CopyBuffer Pitfalls and Error Handling
Indicators in MetaTrader 5 calculate asynchronously. When an EA starts or switches timeframes, calling CopyBuffer on the very first tick may return -1 with error 4806 (ERR_INDICATOR_DATA_NOT_FOUND) or 4807.
Check BarsCalculated(handle) before reading, or simply test if CopyBuffer() < count. If not enough bars are ready, log a warning and return early from OnTick() until the indicator cache populates.
Implementation details & mechanics
Core implementation pattern
Initialize indicator handles in OnInit() using iMA(_Symbol, _Period, 14, 0, MODE_EMA, PRICE_CLOSE) and iRSI(_Symbol, _Period, 14, PRICE_CLOSE). Set target arrays as series with ArraySetAsSeries(). In OnTick(), copy 2 bars of MA and RSI. Confirm both CopyBuffer calls return exactly 2 elements before evaluating crossover or threshold logic.
Error handling & safety rules
In OnDeinit(const int reason), release all initialized handles using IndicatorRelease(maHandle) and IndicatorRelease(rsiHandle) to prevent memory leaks in terminal memory. When evaluating exits, read the latest closed bar values (index 1) to avoid repaint or unfinished candle fluctuations.
MQL5 Code Implementation Code
//+------------------------------------------------------------------+
//| CopyBufferGuideEA.mq5 |
//| Copyright 2026, Pineify Guides Series |
//| https://pineify.app |
//+------------------------------------------------------------------+
#property copyright "Pineify Guides Series"
#property link "https://pineify.app/mql5/copybuffer-guide"
#property version "1.00"
#property strict
//--- Input parameters
input group "--- Moving Average ---"
input int InpMAPeriod = 20; // MA Period
input ENUM_MA_METHOD InpMAMethod = MODE_EMA; // MA Method
input ENUM_APPLIED_PRICE InpMAPrice = PRICE_CLOSE; // Applied Price
input group "--- RSI Settings ---"
input int InpRSIPeriod = 14; // RSI Period
input ENUM_APPLIED_PRICE InpRSIPrice = PRICE_CLOSE; // RSI Applied Price
//--- Indicator handles
int g_maHandle = INVALID_HANDLE;
int g_rsiHandle = INVALID_HANDLE;
//--- Data buffers
double g_maBuffer[];
double g_rsiBuffer[];
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// 1. Create Moving Average handle
g_maHandle = iMA(_Symbol, _Period, InpMAPeriod, 0, InpMAMethod, InpMAPrice);
if(g_maHandle == INVALID_HANDLE)
{
Print("Error creating iMA handle: ", GetLastError());
return(INIT_FAILED);
}
// 2. Create RSI handle
g_rsiHandle = iRSI(_Symbol, _Period, InpRSIPeriod, InpRSIPrice);
if(g_rsiHandle == INVALID_HANDLE)
{
Print("Error creating iRSI handle: ", GetLastError());
return(INIT_FAILED);
}
// 3. Configure arrays as time series (Index 0 = current bar, Index 1 = bar 1)
ArraySetAsSeries(g_maBuffer, true);
ArraySetAsSeries(g_rsiBuffer, true);
Print("CopyBufferGuideEA initialized successfully.");
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// Release indicator handles
if(g_maHandle != INVALID_HANDLE)
IndicatorRelease(g_maHandle);
if(g_rsiHandle != INVALID_HANDLE)
IndicatorRelease(g_rsiHandle);
Print("Indicator handles released. Reason: ", reason);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// Verify indicators have calculated enough bars
if(BarsCalculated(g_maHandle) < InpMAPeriod || BarsCalculated(g_rsiHandle) < InpRSIPeriod)
{
Print("Indicator calculation pending...");
return;
}
// Copy 3 bars of MA: buffer 0 (main line), starting from bar 0
int copiedMA = CopyBuffer(g_maHandle, 0, 0, 3, g_maBuffer);
if(copiedMA < 3)
{
PrintFormat("CopyBuffer failed for MA! Copied %d elements, Error: %d",
copiedMA, GetLastError());
return;
}
// Copy 3 bars of RSI: buffer 0 (main line), starting from bar 0
int copiedRSI = CopyBuffer(g_rsiHandle, 0, 0, 3, g_rsiBuffer);
if(copiedRSI < 3)
{
PrintFormat("CopyBuffer failed for RSI! Copied %d elements, Error: %d",
copiedRSI, GetLastError());
return;
}
// Read completed bar values (index 1 = previous closed bar)
double closedMA = g_maBuffer[1];
double closedRSI = g_rsiBuffer[1];
double closedPrice = iClose(_Symbol, _Period, 1);
// Print values to Experts log
PrintFormat("Bar [1] -> Close: %.5f | EMA(%d): %.5f | RSI(%d): %.2f",
closedPrice, InpMAPeriod, closedMA, InpRSIPeriod, closedRSI);
// Signal generation example:
bool isBullish = (closedPrice > closedMA) && (closedRSI > 50.0);
bool isBearish = (closedPrice < closedMA) && (closedRSI < 50.0);
if(isBullish)
{
// Long entry trigger condition met
}
}
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.