Complete MQL5 guide & code

MQL5 Close Array in Expert Advisor: CopyRates & CopyClose Guide

Learn how to read close prices, MqlRates, and historical bars in MQL5 Expert Advisors using CopyRates, CopyClose, and ArraySetAsSeries without MT4 array errors.

What this MQL5 guide covers

In MQL5 Expert Advisors, predefined MT4 arrays like Close[] and Open[] do not exist and trigger compiler errors if referenced directly.

Use CopyClose() to copy bar close values into a dynamic double array, or CopyRates() to copy full MqlRates structures with open, high, low, close, time, and tick volume.

Choose one indexing convention explicitly. With series indexing, index 0 is the newest copied record; it is the forming bar only when copying starts at shift 0.

Single bar lookups can use iClose(_Symbol, _Period, shift), while multi-bar loops benefit from copying arrays in one call.

Why Close[] Is Undeclared in MQL5 Expert Advisors

Developers transitioning from MetaTrader 4 often expect predefined time series arrays such as Close[], Open[], High[], Low[], and Time[] to be globally accessible. In MQL5, those arrays are not available inside Expert Advisors or Scripts.

Writing code like double prev = Close[1]; in an MQL5 EA results in the compiler error: Close - undeclared identifier. MQL5 separates chart data access into explicit copy functions to support multi-currency backtesting and async history management.

  • The full OnCalculate signature receives price arrays as parameters, commonly named close[], open[], high[] and low[]; these are not global MT4 arrays.
  • Expert Advisors must explicitly fetch bars into local arrays using CopyClose() or CopyRates().
  • Single value queries can use iClose(), iOpen(), iHigh(), iLow(), and iTime() helpers.

CopyClose and CopyRates Function Signatures

MQL5 provides two primary functions for reading price history into arrays. CopyClose copies only close prices into a double array. CopyRates copies complete bar data into an array of MqlRates structures.

Both functions accept three parameter overloads: copying by start bar position and count, copying by start datetime and count, or copying between two boundary datetimes.

ParameterTypeDescription
symbol_namestringFinancial instrument symbol (e.g. _Symbol or "EURUSD")
timeframeENUM_TIMEFRAMESChart timeframe constant (e.g. _Period or PERIOD_H1)
start_posintStarting bar index (0 = current bar, 1 = previous closed bar)
countintNumber of history bars to copy into target array
rates_array[] / close_array[]MqlRates[] / double[]Target array with sufficient capacity; dynamic arrays can resize, static arrays have fixed capacity

The MqlRates Structure and Field Reference

When calling CopyRates, MQL5 fills an array of MqlRates structures. This structure packs all standard candlestick fields into a single record per bar.

Struct MemberTypeField Description
timedatetimePeriod start time for the bar
opendoubleOpen price of the candle
highdoubleHighest price reached during the period
lowdoubleLowest price reached during the period
closedoubleClose price of the candle
tick_volumelongTick volume count recorded on the bar
spreadintSpread in points recorded for the bar
real_volumelongReal volume recorded on exchange instruments

Array Indexing Direction: ArraySetAsSeries

Copy functions place the oldest copied item first in physical memory. Choose chronological or series indexing to match the algorithm, and do not mix the two conventions.

ArraySetAsSeries changes logical indexing on a supported dynamic one-dimensional array. For a request starting at shift 0, series indices 0, 1 and 2 correspond to the forming bar and two completed bars. Starting at shift 1 instead makes series index 0 the last completed bar. Static arrays cannot acquire the series flag.

Performance: CopyRates vs iClose

The helper function iClose(_Symbol, _Period, shift) returns a single close price as a double. It is convenient for one-off condition checks, such as verifying whether yesterday closed above a benchmark level.

When your strategy inspects 10, 50, or 200 bars in a loop (for example, checking a rolling pivot or swing high), calling iClose repeatedly introduces individual lookup overhead. Calling CopyClose or CopyRates once retrieves all requested bars in a single memory block.

Implementation details & mechanics

Core implementation pattern

Declare dynamic array double closePrices[]. Set time series direction using ArraySetAsSeries(closePrices, true). In OnTick(), copy three bars starting from index 0 using CopyClose(_Symbol, _Period, 0, 3, closePrices). Confirm that CopyClose returns exactly 3. Evaluate completed bar closePrices[1] against moving averages or breakout levels to generate long entry signals.

Error handling & safety rules

The example only logs bar data and an illustrative boolean; it does not trade or trail stops. Completed-bar versus tick-level decisions are a strategy choice, not a universal exit rule. Local arrays end with their scope; the example explicitly frees its global dynamic arrays during deinitialization.

MQL5 Code Implementation

//+------------------------------------------------------------------+
//|                                     PriceSeriesCopyRatesGuide.mq5|
//|                             Copyright 2026, Pineify Guides Series |
//|                                              https://pineify.app |
//+------------------------------------------------------------------+
#property copyright "Pineify Guides Series"
#property link      "https://pineify.app/mql5/price-series-copyrates-guide"
#property version   "1.00"
#property strict

//--- Input parameters
input int    InpHistoryBars = 5;       // Number of bars to inspect

//--- Dynamic storage for price data
MqlRates g_rates[];
double   g_closePrices[];

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   if(InpHistoryBars<3 || InpHistoryBars>10000) return INIT_PARAMETERS_INCORRECT;
   // Set both arrays as time series (Index 0 = current bar, Index 1 = closed bar)
   ArraySetAsSeries(g_rates, true);
   ArraySetAsSeries(g_closePrices, true);

   Print("Price series reader initialized. ArraySetAsSeries enabled.");
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   ArrayFree(g_rates);
   ArrayFree(g_closePrices);
   PrintFormat("Price series arrays released. Reason code: %d", reason);
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   static datetime lastBar=0;
   datetime current=iTime(_Symbol,_Period,0);
   if(current<=0 || current==lastBar) return;
   ResetLastError();
   // Method 1: Using CopyClose to extract close[] array
   int copiedCloses = CopyClose(_Symbol, _Period, 0, InpHistoryBars, g_closePrices);
   if(copiedCloses < InpHistoryBars)
     {
      PrintFormat("CopyClose failed! Copied %d of %d requested bars. Error: %d",
                  copiedCloses, InpHistoryBars, GetLastError());
      return;
     }

   // Method 2: Using CopyRates for complete candle metrics
   ResetLastError();
   int copiedRates = CopyRates(_Symbol, _Period, 0, InpHistoryBars, g_rates);
   if(copiedRates < InpHistoryBars)
     {
      PrintFormat("CopyRates failed! Copied %d of %d requested bars. Error: %d",
                  copiedRates, InpHistoryBars, GetLastError());
      return;
     }

   if(iTime(_Symbol,_Period,0)!=current) return; // A bar boundary crossed between calls.
   lastBar=current;
   // Inspect the last completed bar, not the forming one.
   double lastClose = g_closePrices[1];
   double lastOpen  = g_rates[1].open;
   double lastHigh  = g_rates[1].high;
   double lastLow   = g_rates[1].low;
   datetime barTime = g_rates[1].time;

   PrintFormat("Bar [1] (%s) -> O: %.5f | H: %.5f | L: %.5f | C: %.5f | Vol: %I64d",
               TimeToString(barTime, TIME_DATE|TIME_MINUTES),
               lastOpen, lastHigh, lastLow, lastClose, g_rates[1].tick_volume);

   // Simple signal evaluation based on price series
   bool isBullishClose = (lastClose > lastOpen);
   bool isHigherClose  = (g_closePrices[1] > g_closePrices[2]);

   Print("Illustrative bullish-and-higher-close condition: ",isBullishClose && isHigherClose);
  }

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 generates editable MQL5 source code. Review its logic, request a syntax check, and compile and test the final file in MetaEditor.

Frequently Asked Questions

Related MQL5 pages

Technical references

Risk and testing note

These educational examples require independent compilation and testing. A compile pass or an illustrative setting does not establish execution correctness or profitability. Any reported performance must be supported by reproducible data and test settings; past results do not predict future returns. Trading involves significant risk of loss. This content is not financial advice.