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));
}
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));
}