Problem Description
Solution
To use the MqlRates structure in MQL4, you typically use it in conjunction with the CopyRates() function. This approach allows you to store Open, High, Low, Close, Time, and Volume data for a specific bar into a single structure, rather than accessing separate arrays (like Open[], High[], etc.).
Here is a step-by-step guide and a complete script example.
1. The MqlRates Structure Definition
The MqlRates structure stores information about the prices, volume, and spread of a single bar. It contains the following fields:
datetime time: Period start time.double open: Open price.double high: The highest price of the period.double low: The lowest price of the period.double close: Close price.long tick_volume: Tick volume.int spread: Spread.long real_volume: Trade volume (usually 0 for Forex).
2. Implementation Steps
- Declare an array of type
MqlRates. - Set array indexing using
ArraySetAsSeries(true)if you want index0to represent the current (newest) bar. - Copy data using
CopyRates(). - Access data using the dot operator (e.g.,
rates[0].close).
3. Code Example
This script retrieves the last 10 bars of history for the current symbol and prints the details to the "Experts" log.
#property copyright "Copyright 2023, Quantitative Trading"
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
#property script_show_inputs
//--- Input parameters
input int BarsToCopy = 10; // Number of bars to retrieve
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
// 1. Declare the array of MqlRates structures
MqlRates rates[];
// 2. Set indexing as time series
// true = Index 0 is the newest bar, Index 1 is the previous bar, etc.
// false = Index 0 is the oldest bar retrieved.
ArraySetAsSeries(rates, true);
// 3. Copy historical data
// Parameters: Symbol, Timeframe, Start Position, Count, Target Array
int copied = CopyRates(Symbol(), Period(), 0, BarsToCopy, rates);
// 4. Check if data was copied successfully
if(copied <= 0)
{
Print("Error copying price data. Error Code: ", GetLastError());
return;
}
Print("Successfully copied ", copied, " bars.");
// 5. Loop through the data and print details
// Since we set ArraySetAsSeries to true, i=0 is the current forming bar
for(int i = 0; i < copied; i++)
{
string info = StringFormat("Bar Index [%d]: Time=%s, O=%.5f, H=%.5f, L=%.5f, C=%.5f, Vol=%I64d",
i,
TimeToString(rates[i].time),
rates[i].open,
rates[i].high,
rates[i].low,
rates[i].close,
rates[i].tick_volume);
Print(info);
}
// Example: Accessing specific data
double previousClose = rates[1].close;
Print("Previous Bar Close: ", previousClose);
}
//+------------------------------------------------------------------+
Key Considerations
- Efficiency: Using
CopyRatesis generally faster and cleaner than callingiOpen,iHigh,iLow, etc., individually inside a loop, especially when you need multiple data points for the same bar. - Portability: This syntax is highly compatible with MQL5, making it easier to port your strategies to MetaTrader 5 in the future.
- Error Handling: Always check the return value of
CopyRates. If it returns-1or0, the data copy failed (often due to history not being synced yet), and you should handle the error usingGetLastError().
Q&A
Q: What is the difference between MqlRates and standard arrays like Open[]?
A: Open[], Close[], etc., are predefined arrays that give direct access to specific price types. MqlRates is a structure that groups all data (OHLCV) for a specific bar into a single object. MqlRates is better for passing bar data to functions or storing history snapshots.
Q: Does CopyRates handle the current forming bar?
A: Yes. If you start copying from index 0, the first element will contain the data of the current unfinished bar. The close price in the structure will represent the current Bid price.
Q: Why use ArraySetAsSeries(rates, true)?
A: By default, dynamic arrays fill from left to right (Index 0 is the oldest). Traders usually prefer Index 0 to be the "current" bar (matching the behavior of Open[] or Close[]). ArraySetAsSeries(true) enforces this reverse indexing.