Working with Price Data & Arrays

Access OHLCV data, use built-in arrays, and iterate through price history in MQL5.

Accessing Price Data in MQL5

There are two main ways to access price data in MQL5: individual price functions and the MqlRates structure. Understanding both is essential for building any indicator or EA.

Individual Price Functions

These functions return a single value for a specific bar:

// Get price data for bar at index 'shift' (0 = current bar)
double open  = iOpen(_Symbol, PERIOD_CURRENT, 0);   // current bar open
double high  = iHigh(_Symbol, PERIOD_CURRENT, 0);   // current bar high
double low   = iLow(_Symbol, PERIOD_CURRENT, 0);    // current bar low
double close = iClose(_Symbol, PERIOD_CURRENT, 1);  // previous bar close
long   vol   = iVolume(_Symbol, PERIOD_CURRENT, 0); // current bar volume
datetime t   = iTime(_Symbol, PERIOD_CURRENT, 0);   // current bar time

The shift parameter counts backward from the current bar: 0 = current (forming) bar, 1 = last completed bar, 2 = the bar before that, etc.

The MqlRates Structure

For bulk data access, CopyRates() fills an array of MqlRates structures. Each element contains all OHLCVT data for one bar:

MqlRates rates[];
ArraySetAsSeries(rates, true);  // index 0 = most recent bar

int copied = CopyRates(_Symbol, PERIOD_H1, 0, 100, rates);
if(copied > 0)
{
    Print("Latest bar:");
    Print("  Open:  ", rates[0].open);
    Print("  High:  ", rates[0].high);
    Print("  Low:   ", rates[0].low);
    Print("  Close: ", rates[0].close);
    Print("  Volume:", rates[0].tick_volume);
    Print("  Time:  ", TimeToString(rates[0].time));
}
⚠️
Always call ArraySetAsSeries before CopyRates

By default, MQL5 arrays index from oldest to newest (index 0 = oldest bar). Calling ArraySetAsSeries(array, true) reverses this so index 0 = most recent bar, which is the convention most traders expect.

CopyBuffer — Reading Indicator Values

To read values from any indicator (built-in or custom), use CopyBuffer():

// Step 1: Create an indicator handle (usually in OnInit)
int rsiHandle = iRSI(_Symbol, PERIOD_CURRENT, 14, PRICE_CLOSE);

// Step 2: Copy values into a buffer array
double rsiValues[];
ArraySetAsSeries(rsiValues, true);
int copied = CopyBuffer(rsiHandle, 0, 0, 10, rsiValues);

// Step 3: Use the values
if(copied > 0)
{
    Print("Current RSI: ", DoubleToString(rsiValues[0], 2));
    Print("Previous RSI: ", DoubleToString(rsiValues[1], 2));

    if(rsiValues[0] > 70)
        Print("RSI is OVERBOUGHT");
    else if(rsiValues[0] < 30)
        Print("RSI is OVERSOLD");
}

CopyBuffer Parameters Explained

CopyBuffer(
    indicator_handle,  // handle from iRSI(), iMA(), etc.
    buffer_index,      // which buffer (0 = main, 1 = signal, etc.)
    start_position,    // 0 = most recent bar
    count,             // how many values to copy
    destination_array  // array to fill
);

Common buffer indices:

  • iMA() — buffer 0: MA values
  • iRSI() — buffer 0: RSI values
  • iMACD() — buffer 0: MACD line, buffer 1: signal line
  • iBands() — buffer 0: base line, buffer 1: upper band, buffer 2: lower band
  • iStochastic() — buffer 0: %K line, buffer 1: %D line

Multi-Symbol and Multi-Timeframe Data

You can access data from any symbol and any timeframe, not just the current chart:

// Get daily close of GBPUSD (even if your chart shows EURUSD on H1)
double gbpDaily = iClose("GBPUSD", PERIOD_D1, 1);

// Get H4 RSI for the current symbol
int h4Rsi = iRSI(_Symbol, PERIOD_H4, 14, PRICE_CLOSE);
double h4Values[];
ArraySetAsSeries(h4Values, true);
CopyBuffer(h4Rsi, 0, 0, 3, h4Values);

Detecting New Bars

A common pattern — only run logic once per new bar instead of on every tick:

datetime lastBarTime = 0;

bool IsNewBar()
{
    datetime currentBarTime = iTime(_Symbol, PERIOD_CURRENT, 0);
    if(currentBarTime != lastBarTime)
    {
        lastBarTime = currentBarTime;
        return true;
    }
    return false;
}

void OnTick()
{
    if(!IsNewBar()) return;  // skip if no new bar

    // This code runs only once per bar
    Print("New bar opened at ", TimeToString(TimeCurrent()));
}

Practical Example: Find Highest High

// Find the highest high of the last N bars
double FindHighestHigh(int lookback)
{
    double highs[];
    ArraySetAsSeries(highs, true);
    CopyHigh(_Symbol, PERIOD_CURRENT, 0, lookback, highs);

    int highestIndex = ArrayMaximum(highs, 0, lookback);
    return highs[highestIndex];
}

void OnStart()
{
    double highest20 = FindHighestHigh(20);
    Print("Highest high of last 20 bars: ", DoubleToString(highest20, _Digits));
}