MQL5 CopyTicks & CopyTicksRange: Real-Time & Historical Tick Data
Master the MQL5 CopyTicks function. Learn how to fetch real-time and historical tick data into MqlTick structures, use COPY_TICKS flags, and handle async caching.
What this MQL5 guide covers
CopyTicks retrieves tick data from terminal memory or broker trade servers into dynamic arrays of MqlTick structures.
Three query flags control data filtering: COPY_TICKS_ALL for complete streams, COPY_TICKS_INFO for bid/ask price shifts, and COPY_TICKS_TRADE for execution deals.
Each MqlTick record provides millisecond precision timestamps (time_msc) along with flags indicating whether a tick represents buyer or seller pressure.
If historical ticks are not yet cached locally, CopyTicks initiates a background download; verify that returned tick count matches expectations before processing.
CopyTicks Function Signatures and Query Flags
The CopyTicks function extracts ticks for a designated symbol into an array of MqlTick structures. Its signature is int CopyTicks(string symbol_name, MqlTick &ticks_array[], uint flags = COPY_TICKS_ALL, ulong from = 0, uint count = 0).
Filtering flags allow algorithms to restrict data transmission to relevant events, saving memory and processing overhead in high-frequency trading systems.
| Query Flag Constant | Bit Mask | Data Stream Included |
|---|---|---|
| COPY_TICKS_ALL | Full tick history | All price quote changes, execution deals, and volume updates |
| COPY_TICKS_INFO | Info ticks only | Only bid and ask price alterations (quote updates) |
| COPY_TICKS_TRADE | Trade ticks only | Only last price changes and real trade deal executions |
The MqlTick Structure and Millisecond Precision
Each element filled by CopyTicks is an MqlTick struct. Unlike standard datetime variables that resolve to whole seconds, MqlTick includes time_msc, a 64-bit integer tracking the exact millisecond elapsed since 1970.01.01.
| MqlTick Field | Data Type | Description and Significance |
|---|---|---|
| time | datetime | Standard timestamp rounded to seconds |
| bid | double | Current bid price recorded on tick |
| ask | double | Current ask price recorded on tick |
| last | double | Last trade execution price |
| volume | ulong | Tick volume or contract volume for the deal |
| time_msc | long | Millisecond precision timestamp |
| flags | uint | Bitmask identifying tick cause (TICK_FLAG_BUY, TICK_FLAG_BID, etc.) |
| volume_real | double | Floating-point trade volume for exchange instruments |
Interpreting Tick Direction: TICK_FLAG Constants
The flags member reveals the market action that triggered the tick. Using bitwise AND checks, your Expert Advisor can isolate buyer-initiated aggressive orders from seller-initiated orders.
- (tick.flags & TICK_FLAG_BUY): Indicates a market buy deal that lifted the offer.
- (tick.flags & TICK_FLAG_SELL): Indicates a market sell deal that hit the bid.
- (tick.flags & TICK_FLAG_BID): Indicates the bid price changed.
- (tick.flags & TICK_FLAG_ASK): Indicates the ask price changed.
CopyTicks vs CopyTicksRange and Server Synchronization
CopyTicks fetches count ticks starting backward or forward from a specified millisecond timestamp. CopyTicksRange requests all ticks that occurred within an explicit interval [from_msc, to_msc].
When requesting historical ticks that are stored on the broker server but not yet synced locally, the terminal starts an asynchronous background download. The initial call may return 0 or fewer ticks than requested. Always check the return value, and retry on subsequent ticks if data is loading.
Implementation details & mechanics
Core implementation pattern
In OnTick(), copy the most recent 30 ticks using CopyTicks(_Symbol, g_ticks, COPY_TICKS_ALL, 0, 30). Confirm that returned count equals 30. Calculate order flow imbalance by summing buy flags vs sell flags across the buffer. If buyer-initiated ticks exceed 70% and the spread is below maximum threshold, trigger a market buy entry.
Error handling & safety rules
Continuously track tick latency and spread widening in OnTick(). If bid drops past trailing stop tick levels or seller volume spikes beyond risk parameters, exit immediately via CTrade. Clean up the dynamic tick array in OnDeinit(const int reason) with ArrayFree(g_ticks).
MQL5 Code Implementation Code
//+------------------------------------------------------------------+
//| CopyTicksGuideEA.mq5|
//| Copyright 2026, Pineify Guides Series |
//| https://pineify.app |
//+------------------------------------------------------------------+
#property copyright "Pineify Guides Series"
#property link "https://pineify.app/mql5/copyticks-guide"
#property version "1.00"
#property strict
//--- Input parameters
input uint InpTickCount = 20; // Number of recent ticks to monitor
//--- Dynamic buffer for tick data
MqlTick g_ticks[];
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
PrintFormat("CopyTicks EA initialized for %s. Requesting %u ticks per tick.",
_Symbol, InpTickCount);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
ArrayFree(g_ticks);
PrintFormat("Tick buffer released. Deinit reason: %d", reason);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// Copy the last N ticks from current time (0 = current moment backward)
int copied = CopyTicks(_Symbol, g_ticks, COPY_TICKS_ALL, 0, InpTickCount);
// Check if data is synchronized
if(copied < (int)InpTickCount)
{
PrintFormat("Tick history synchronizing... Copied %d of %u requested ticks.",
copied, InpTickCount);
return;
}
int buyCount = 0;
int sellCount = 0;
double totalSpread = 0.0;
// Process copied ticks
for(int i = 0; i < copied; i++)
{
// Inspect tick flags
if((g_ticks[i].flags & TICK_FLAG_BUY) != 0)
buyCount++;
if((g_ticks[i].flags & TICK_FLAG_SELL) != 0)
sellCount++;
double tickSpread = (g_ticks[i].ask - g_ticks[i].bid) / _Point;
totalSpread += tickSpread;
}
double avgSpread = totalSpread / copied;
MqlTick latestTick = g_ticks[copied - 1]; // Newest tick in array
PrintFormat("Latest Tick -> Bid: %.5f | Ask: %.5f | Spread: %.1f pts | Time: %I64d ms",
latestTick.bid, latestTick.ask, avgSpread, latestTick.time_msc);
PrintFormat("Order flow window -> Buys: %d | Sells: %d", buyCount, sellCount);
// Simple momentum check: aggressive buyer flow dominance
if(buyCount >= (int)(InpTickCount * 0.70) && avgSpread <= 25.0)
{
// Order flow confirms bullish aggressive buying
}
}
Copy this code into MetaEditor, save it in your MQL5 folder (Experts, Scripts, or Include), and compile with F7.
Generate custom MQL5 code with Pineify AI
Describe the trade execution, indicator calculations, risk management, or data processing logic you need. Pineify produces clean, typed MQL5 source code ready to compile in MetaEditor.
Frequently Asked Questions
Related MQL5 pages
Technical references
Risk and testing note
Past performance is not indicative of future results. Backtest statistics are based on historical data and do not guarantee future profits. Trading involves significant risk of loss. This content is for educational purposes only and does not constitute financial advice.