Problem Description
Solution
In MQL4, the difference between using the predefined variable Ask and using functions like SymbolInfoDouble() or MarketInfo() is significant regarding data freshness and scope.
Here is a detailed breakdown of the differences and best practices.
1. The Predefined Variable Ask
The Ask variable is a cached value. When an event function (like OnTick) starts, the terminal takes a "snapshot" of the market prices for the symbol the EA is attached to.
- Scope: Only returns the price for the current chart's symbol.
- Freshness: The value remains constant throughout the execution of the function, even if the function takes 10 seconds to run and the market moves.
- Performance: Extremely fast (direct memory access).
Limitation Example:
If you use Sleep() or perform heavy calculations, Ask will become outdated (stale) unless you manually update it.
void OnTick()
{
double price1 = Ask;
Sleep(5000); // Pause for 5 seconds
double price2 = Ask;
// price1 and price2 are IDENTICAL, even if the market moved during the Sleep().
// The variable 'Ask' does not update automatically inside the function.
}
2. The Functions: SymbolInfoDouble() and MarketInfo()
These functions query the terminal for the most recent price data available at the exact moment the line of code is executed.
- Scope: Can retrieve prices for any symbol (e.g., getting EURUSD prices while running on GBPUSD).
- Freshness: Always returns the latest known price.
- Performance: Slightly slower than the
Askvariable (function call overhead), but negligible in modern computing.
Real-time Example:
void OnTick()
{
double price1 = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
Sleep(5000); // Pause for 5 seconds
double price2 = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
// price2 will reflect the NEW market price after the 5-second pause.
}
Key Differences Table
| Feature | Ask (Variable) |
SymbolInfoDouble / MarketInfo |
|---|---|---|
| Symbol Scope | Current Chart Only | Any Symbol (Multi-currency) |
| Data Age | Snapshot at start of OnTick |
Real-time at moment of call |
| Updates in Loops | No (requires RefreshRates) |
Yes |
| Syntax | Ask |
SymbolInfoDouble("EURUSD", SYMBOL_ASK) |
| Best Use Case | Simple, single-symbol logic | Multi-currency or long-running logic |
The RefreshRates() Factor
If you prefer using the Ask variable but need updated prices after a delay (like a Sleep call or a trade execution loop), you must use the RefreshRates() function. This function forces the terminal to update the predefined variables (Ask, Bid, Time, etc.).
// Using Ask with RefreshRates
OrderSend(Symbol(), OP_BUY, ...); // Attempt trade
Sleep(1000); // Wait
RefreshRates(); // Update the 'Ask' variable
if(Ask > ...) // Now 'Ask' is fresh
Which one is better?
SymbolInfoDouble(Symbol(), SYMBOL_ASK) is generally better.
While Ask is slightly faster to type, using the function approach is more robust for the following reasons:
- Consistency: It behaves the same way whether you are coding a single-currency or multi-currency strategy.
- Safety: It prevents "Stale Price" errors (Error 138: Requote) in scripts or EAs that perform multiple operations in one tick, as it always fetches the latest price.
- Portability: It is closer to MQL5 syntax, making it easier to port your code to MetaTrader 5 later.
Code Example: Robust Price Retrieval
Here is a helper function that ensures you always get the correct Ask price, handling both the symbol requirement and normalization.
//+------------------------------------------------------------------+
//| Get the current Ask price for any symbol |
//+------------------------------------------------------------------+
double GetAsk(string symbol)
{
// Use SymbolInfoDouble for the freshest data
double price = SymbolInfoDouble(symbol, SYMBOL_ASK);
// Fallback if SymbolInfoDouble fails (returns 0)
if(price == 0.0)
{
// If querying the current chart, RefreshRates might help if using predefined vars
if(symbol == _Symbol)
{
RefreshRates();
price = Ask;
}
else
{
// Legacy function for specific symbols
price = MarketInfo(symbol, MODE_ASK);
}
}
// Normalize to prevent floating point errors
return(NormalizeDouble(price, (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS)));
}
void OnTick()
{
// Usage
double currentAsk = GetAsk(_Symbol);
double otherAsk = GetAsk("GBPUSD");
Print("Current Ask: ", currentAsk, " | GBPUSD Ask: ", otherAsk);
}
Q&A: MQL4 Price Retrieval
Q: Does Ask work if I am running an EA on EURUSD but want to trade GBPUSD?
A: No. The Ask variable only holds the price of the chart the EA is attached to. To get the GBPUSD price while on a EURUSD chart, you must use MarketInfo("GBPUSD", MODE_ASK) or SymbolInfoDouble("GBPUSD", SYMBOL_ASK).
Q: Why does my order fail with "Invalid Price" even when I use Ask?
A: This often happens in fast-moving markets. By the time your logic processes the signal and sends the order, the market price may have moved away from the snapshot stored in Ask. Using RefreshRates() immediately before OrderSend() or using SymbolInfoDouble can reduce this risk.
Q: Is MarketInfo deprecated?
A: MarketInfo is not strictly deprecated in MQL4 and is still widely used, but SymbolInfoDouble is the modern standard introduced to align MQL4 with MQL5. It is recommended to use SymbolInfoDouble for new projects.