MQL5 CopyBuffer Returns -1: Fix Error 4806 and Read Closed Bars
MQL5 CopyBuffer returning -1 means the copy failed; error 4806 means requested indicator data was not found. Neither message, by itself, proves that the indicator formula is broken. Check the handle, buffer number, requested bars, and data readiness before changing your trading rules.
This is a runtime problem, not necessarily a compilation problem. An EA can build successfully while its first indicator read happens before price history or indicator calculations are ready. This guide isolates the read operation without placing trades, so there are no backtest returns or profitability claims attached to the example.
What should you check first?
Create your indicator handle once in OnInit(), then reject INVALID_HANDLE. In MQL5, iRSI() returns an integer handle, not an RSI value. Its arguments specify the symbol, timeframe, averaging period, and applied price. RSI has one buffer, numbered zero.
Next, inspect BarsCalculated(handle). It returns the number of calculated data elements, or -1 when data has not been calculated yet or an error occurs. A valid handle is not a promise that the requested values are immediately available. Even after a readiness check, the result of the actual copy remains the final gate.
For CopyBuffer(handle, 0, 1, 2, values), you request two values beginning one bar back: the two most recent closed bars. Position zero would include the current, still-changing bar. Accept the read only when the return value equals two; a partial copy must not feed your signal logic.
A minimal closed-bar RSI diagnostic
Save this as an Expert Advisor source file in MetaEditor. It attempts a read on incoming ticks until it obtains two closed-bar RSI values, logs them once, and makes no orders. The fixed-size array keeps the indexing convention explicit.
int rsi_handle = INVALID_HANDLE;
bool reported = false;
int OnInit()
{
ResetLastError();
rsi_handle = iRSI(_Symbol, PERIOD_CURRENT, 14, PRICE_CLOSE);
if(rsi_handle == INVALID_HANDLE)
{
PrintFormat("iRSI creation failed: %d", GetLastError());
return INIT_FAILED;
}
return INIT_SUCCEEDED;
}
void OnTick()
{
if(reported || BarsCalculated(rsi_handle) < 15)
return;
double values[2];
ResetLastError();
int copied = CopyBuffer(rsi_handle, 0, 1, 2, values);
if(copied != 2)
{
PrintFormat("CopyBuffer copied=%d error=%d", copied, GetLastError());
return;
}
PrintFormat("RSI bar 2=%.5f; bar 1=%.5f", values[0], values[1]);
reported = true;
}
void OnDeinit(const int reason)
{
if(rsi_handle != INVALID_HANDLE)
IndicatorRelease(rsi_handle);
}
The 15-element readiness threshold is a conservative initial screen for this 14-period RSI example, not a universal indicator warm-up rule. The exact-copy check is still required. If this diagnostic remains silent, inspect the handle and calculated-bar count, confirm the selected symbol has history, and check that ticks are arriving. No ticks means no OnTick() retry.
Why do the two values look reversed?
CopyBuffer() places the oldest requested element at the beginning of physical memory. In the ordinary fixed-size array above, values[0] therefore represents bar two, and values[1] represents bar one. Reversing those meanings can reverse a crossover test even when the copy succeeds.
Do not try to fix this static array with ArraySetAsSeries(): the series flag cannot be set on arrays whose size is fixed at compilation. Dynamic arrays can use series indexing, but mixing the two conventions makes debugging harder. Pick one convention, label the bar positions, and verify them against the chart.
Distinguish missing data from an invalid request
Error 4806 is ERR_INDICATOR_DATA_NOT_FOUND, meaning requested data was not found. Error 4807 is a different condition: a wrong indicator handle. Capture the error immediately after the failing operation rather than assuming every unsuccessful read has the same cause.
ResetLastError() clears the stored error before the operation being diagnosed. GetLastError() reads that stored value without clearing it. Without the reset, an old failure can mislead you when investigating a later call. Log both the copied count and the error, as the example does.
For another symbol or timeframe, ensure that its history exists and has had time to load. MetaQuotes documents that an EA request may initiate downloading or building the required series and return whatever data is ready by the timeout. Returning from the handler and retrying on a later tick is preferable to assuming one immediate request must succeed. Persistent failures need investigation, not endless retries or fabricated zero values.
How do you verify the fix?
- Compile the diagnostic in MetaEditor; compilation alone does not establish runtime correctness.
- Attach it to a chart with available history and arriving ticks.
- Compare the logged closed-bar values with RSI configured for the same symbol, timeframe, period, and applied price.
- Confirm that unsuccessful reads never reach your entry or exit conditions.
- When integrating it into a once-per-bar EA, mark the bar processed only after the required data has been read successfully; otherwise a failed first read can skip that bar entirely.
This article's API signatures and array-order rules were checked against the locally mirrored official MQL5 reference. The snippet is documentation-checked, not presented as a compiler-verified or live-tested result. No trading strategy was backtested for this diagnostic guide.
From a diagnostic to a complete EA
Ranar Algo can turn a plain-English strategy into MQL5 source, compile-check it, and run a real MetaTrader 5 backtest. You retain your intellectual property and can download the source. Describe the intended closed-bar timing and failure behavior alongside the trading rules, then inspect the generated code and report rather than treating compilation as proof of profitability. The tool is still improving; feedback is welcome.
Keep the debugging sequence simple: validate the handle, request the correct buffer and bars, require the full copied count, then evaluate the signal. Once indicator reads are trustworthy, test the actual strategy separately with realistic execution assumptions. Past performance does not guarantee future results.
Build & backtest your own EA free →