Problem Description
Solution
To retrieve the Open, High, Low, and Close (OHLC) prices for the last 100 bars in MQL4, the most efficient and modern method is to use the CopyRates function. This function copies historical data into an array of MqlRates structures, allowing you to access all price types and the time for each bar simultaneously.
MQL4 Script to Get OHLC Data
Here is a complete script that retrieves the last 100 bars of data for the current symbol and timeframe and prints them to the "Experts" log.
//+------------------------------------------------------------------+
//| GetOHLC_Data.mq4 |
//| Copyright 2023, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
#property script_show_inputs
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
// --- 1. Define parameters
int barsToCopy = 100; // Number of bars to retrieve
int startPosition = 0; // 0 means start from the current (newest) bar
// --- 2. Declare an array of MqlRates structures
// MqlRates stores time, open, high, low, close, tick_volume, spread, and real_volume
MqlRates rates[];
// --- 3. Set array indexing direction
// true = Index 0 is the newest bar (Time Series format)
// false = Index 0 is the oldest bar
ArraySetAsSeries(rates, true);
// --- 4. Copy the data
// Syntax: CopyRates(Symbol, Timeframe, StartPos, Count, DestinationArray)
int copied = CopyRates(Symbol(), Period(), startPosition, barsToCopy, rates);
// --- 5. Check for errors and process data
if(copied > 0)
{
Print("Successfully retrieved ", copied, " bars for ", Symbol());
// Loop through the retrieved data
for(int i = 0; i < copied; i++)
{
// Access specific fields within the structure
string barInfo = StringFormat("Index %d | Time: %s | O: %.5f | H: %.5f | L: %.5f | C: %.5f",
i,
TimeToString(rates[i].time),
rates[i].open,
rates[i].high,
rates[i].low,
rates[i].close);
Print(barInfo);
}
}
else
{
Print("Failed to copy rates. Error code: ", GetLastError());
}
}
//+------------------------------------------------------------------+
Key Functions Explained
MqlRatesStructure: This is a built-in structure in modern MQL4 that holds all history data for a specific bar. It is more efficient than creating four separate arrays for Open, High, Low, and Close.ArraySetAsSeries(rates, true): This is crucial. By setting this totrue,rates[0]will represent the current (most recent) bar, andrates[99]will be the oldest of the 100 bars. If set tofalse,rates[0]would be the oldest.CopyRates: This function handles the actual data retrieval. It returns the number of bars successfully copied. If it returns-1, an error occurred (e.g., history data not yet synchronized).
Alternative Method: Individual Arrays
If you only need specific price types (e.g., only Close prices) to save memory, you can use specific copy functions:
double closePrices[];
ArraySetAsSeries(closePrices, true);
int copied = CopyClose(Symbol(), Period(), 0, 100, closePrices);
Available functions include CopyOpen, CopyHigh, CopyLow, CopyClose, CopyTime, and CopyTickVolume.
Q&A: Retrieving Historical Data in MQL4
Q: Why use CopyRates instead of the predefined arrays like Open[] or Close[]?
A: While Open[] and Close[] are valid for the current symbol and timeframe, CopyRates is safer and more versatile. It allows you to easily retrieve data for other symbols or timeframes (e.g., getting H1 data while running on an M5 chart) and handles memory management for the arrays automatically.
Q: What happens if I request 100 bars but only 50 are available in history?
A: CopyRates will copy the available 50 bars and return the value 50. You should always check the return value of the function (stored in the copied variable in the example above) to ensure you have enough data before performing calculations.
Q: How do I get the data for a specific date range instead of the last N bars?
A: CopyRates has an overload that accepts datetime parameters. You can use:
CopyRates(Symbol(), Period(), startTime, stopTime, ratesArray);
Note that startTime must be the earlier date and stopTime the later date.
Q: Does ArraySetAsSeries physically resort the data?
A: No. It only changes the indexing method (how you access the data). It does not move data around in memory, making it a very fast operation. Setting it to true is standard practice in trading strategies so that index 0 always refers to the current price action.