#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#define OBJ_NAME_ASK "TestObjectMoveAsk" // name of the graphical object for the Ask price
#define OBJ_NAME_BID "TestObjectMoveBid" // name of the graphical object for the Bid price
#define COUNT 100000000 // number of ticks to load history
#define DELAY 1 // delay between ticks in ms
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//--- current chart ID, the chart symbol, and symbol Digits
long chart_id= ChartID();
string symbol = ChartSymbol(chart_id);
int digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
//--- create two price labels to display the Ask price and Bid price on the chart
if(!CreatePriceLabel(chart_id, true) || !CreatePriceLabel(chart_id, false))
return;
//--- array for receiving ticks
MqlTick ticks[]={};
//--- get the number of the next visible bar on the chart and the opening time of this bar in milliseconds
int first= (int)ChartGetInteger(chart_id, CHART_FIRST_VISIBLE_BAR)-1;
ulong from = GetTime(symbol, PERIOD_CURRENT, first)*1000;
//--- load the tick history into the array
Print("Started collecting ticks...");
if(!GetTicksToArray(symbol, ticks))
return;
//--- reset the tick array and get ticks from the visible range of bars on the chart
ZeroMemory(ticks);
if(CopyTicksRange(symbol, ticks, COPY_TICKS_INFO, from)<1)
{
PrintFormat("CopyTicksRange() from date %s failed. Error %d", TimeToString(GetTime(symbol, PERIOD_CURRENT, first)), GetLastError());
return;
}
Sleep(500);
PrintFormat("Tick visualization started at %s (%I64u), ticks total: %u", TimeToString(GetTime(symbol, PERIOD_CURRENT, first)), from, ticks.Size());
int count=0; // number of ticks processed
int changes=0; // number of processed price changes
int total=(int)ticks.Size(); // tick array size
//--- in a loop through the tick array
for(int i=0; i<total && !IsStopped(); i++)
{
//--- get a tick from the array and increment the tick counter
MqlTick tick=ticks[i];
count++;
//--- check the tick Ask and Bid flags
bool ask_tick=((tick.flags &TICK_FLAG_ASK)==TICK_FLAG_ASK);
bool bid_tick=((tick.flags &TICK_FLAG_BID)==TICK_FLAG_BID);
bool done=false;
//--- if the Ask price changes
if(ask_tick)
{
if(Move(chart_id, OBJ_NAME_ASK, tick.time, tick.ask))
{
changes++;
done=true;
}
}
//--- if the Bid price changes
if(bid_tick)
{
if(Move(chart_id, OBJ_NAME_BID, tick.time, tick.bid))
{
changes++;
done=true;
}
}
//--- if any (or both) of the graphical objects have been moved, update the chart
if(done)
{
ChartRedraw(chart_id);
Sleep(DELAY);
}
}
//--- at the end of the loop, we will report in the journal the number of ticks processed,
//--- wait a couple of seconds, delete the created objects and redraw the chart
PrintFormat("Total ticks completed: %u, Total price changes: %d", count, changes);
Sleep(2000);
if(ObjectsDeleteAll(chart_id, "TestObjectMove")>0)
ChartRedraw(chart_id);
/*
as a result of the script execution, the movement of Ask and Bid prices will be displayed on the visible chart,
starting from the left edge of the chart and to the end of the historical data,
the following data will be displayed in the journal:
Started collecting ticks...
AUDUSD: received 13726794 ticks in 969 ms
Tick visualization started at 2025.01.31 09:00 (1738314000000), ticks total: 44380
Total ticks completed: 44380, Total price changes: 68513
*/
}
//+------------------------------------------------------------------+
//| Create a "Price label" object |
//+------------------------------------------------------------------+
bool CreatePriceLabel(const long chart_id, const bool obj_ask)
{
string obj_name=(obj_ask ? OBJ_NAME_ASK : OBJ_NAME_BID);
ResetLastError();
if(!ObjectCreate(chart_id, obj_name, (obj_ask ? OBJ_ARROW_RIGHT_PRICE : OBJ_ARROW_LEFT_PRICE), 0, 0, 0))
{
PrintFormat("%s: ObjectCreate() failed. Error %d",__FUNCTION__, GetLastError());
return(false);
}
return(ObjectSetInteger(chart_id, obj_name, OBJPROP_COLOR, (obj_ask ? clrRed : clrBlue)));
}
//+------------------------------------------------------------------+
//| Move the graphical object to the specified price/time coordinates|
//+------------------------------------------------------------------+
bool Move(const long chart_id, const string obj_name, const datetime time, const double price)
{
ResetLastError();
if(!ObjectSetInteger(chart_id, obj_name, OBJPROP_TIME, time))
{
PrintFormat("%s: ObjectSetInteger() failed. Error %d",__FUNCTION__, GetLastError());
return(false);
}
if(!ObjectSetDouble(chart_id, obj_name, OBJPROP_PRICE, price))
{
PrintFormat("%s: ObjectSetDouble() failed. Error %d",__FUNCTION__, GetLastError());
return(false);
}
return(true);
}
//+------------------------------------------------------------------+
//| Load ticks into the array |
//+------------------------------------------------------------------+
bool GetTicksToArray(const string symbol, MqlTick &array[])
{
int attempts=0; // counter of attempts to obtain tick history
bool success =false; // flag of successful copying of ticks
//--- make 3 attempts to receive ticks
while(attempts<3)
{
//--- measure the start time before receiving the ticks
uint start=GetTickCount();
//--- request the tick history since 1970.01.01 00:00.001 (parameter from=1 ms)
ResetLastError();
int received=CopyTicks(symbol, array, COPY_TICKS_ALL, 1, COUNT);
if(received!=-1)
{
//--- display data on the number of ticks and spent time
PrintFormat("%s: received %d ticks in %d ms", symbol, received, GetTickCount()-start);
//--- if the tick history is synchronized, the error code is equal to zero
if(GetLastError()==0)
{
success=true;
break;
}
else
PrintFormat("%s: %s ticks are not synchronized yet, %d ticks received for %d ms. Error=%d",
__FUNCTION__, symbol, received, GetTickCount()-start, GetLastError());
}
//--- count attempts
attempts++;
//--- a one-second pause to wait for the end of synchronization of the tick database
Sleep(1000);
}
//--- receiving the requested ticks from the beginning of the tick history failed in three attempts
if(!success)
{
PrintFormat("Error! Failed to get ticks for symbol %s after three attempts", symbol);
return(false);
}
return(true);
}
//+------------------------------------------------------------------+
//| Return the time by bar index |
//+------------------------------------------------------------------+
datetime GetTime(const string symbol, const ENUM_TIMEFRAMES timeframe, const int index)
{
datetime array[1]={};
ResetLastError();
if(CopyTime(symbol, timeframe, index, 1, array)!=1)
PrintFormat("%s: CopyTime() failed. Error %d",__FUNCTION__, GetLastError());
return(array[0]);
}
|