forked from rosh/MQL5Book
120 lines
3.9 KiB
MQL5
120 lines
3.9 KiB
MQL5
//+------------------------------------------------------------------+
| |
//| CalendarChangeSaver.mq5 |
| |
//| Copyright 2022, MetaQuotes Ltd. |
| |
//| https://www.mql5.com |
| |
//+------------------------------------------------------------------+
| |
#property copyright "Copyright 2022, MetaQuotes Ltd."
| |
#property link "https://www.mql5.com"
| |
#property description "Periodically request and save calendar change IDs and their timestamps."
| |
#property service
| |
| |
#define PACK_DATETIME_COUNTER(D,C) (D | (((ulong)(C)) << 48))
| |
#define DATETIME(A) ((datetime)((A) & 0x7FFFFFFFF))
| |
#define COUNTER(A) ((ushort)((A) >> 48))
| |
#define BULK_LIMIT 100
| |
| |
input string Filename = "calendar.chn";
| |
input int PeriodMsc = 1000;
| |
| |
//+------------------------------------------------------------------+
| |
//| Generate user-friendly short description of the event |
| |
//+------------------------------------------------------------------+
| |
string Description(const MqlCalendarValue &value)
| |
{
| |
MqlCalendarEvent event;
| |
MqlCalendarCountry country;
| |
CalendarEventById(value.event_id, event);
| |
CalendarCountryById(event.country_id, country);
| |
return StringFormat("%lld (%s/%s @ %s)",
| |
value.id, country.code, event.name, TimeToString(value.time));
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| Service program start function |
| |
//+------------------------------------------------------------------+
| |
void OnStart()
| |
{
| |
bool online = true;
| |
ulong change = 0, last = 0;
| |
int count = 0;
| |
int handle = FileOpen(Filename,
| |
FILE_WRITE | FILE_READ | FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_BIN);
| |
if(handle == INVALID_HANDLE)
| |
{
| |
PrintFormat("Can't open file '%s' for writing", Filename);
| |
return;
| |
}
| |
| |
const ulong p = FileSize(handle);
| |
if(p > 0)
| |
{
| |
PrintFormat("Resuming file %lld bytes", p);
| |
FileSeek(handle, 0, SEEK_END);
| |
}
| |
| |
Print("Requesting start ID...");
| |
| |
while(!IsStopped())
| |
{
| |
if(!TerminalInfoInteger(TERMINAL_CONNECTED))
| |
{
| |
if(online)
| |
{
| |
Print("Waiting for connection...");
| |
online = false;
| |
}
| |
Sleep(PeriodMsc);
| |
continue;
| |
}
| |
else if(!online)
| |
{
| |
Print("Connected");
| |
online = true;
| |
}
| |
| |
MqlCalendarValue values[];
| |
const int n = CalendarValueLast(change, values);
| |
if(n > 0)
| |
{
| |
// check for unreliable responce from terminal,
| |
// when outdated irrelevant changes are returned,
| |
// which usually happens just after terminal start-up
| |
if(n >= BULK_LIMIT)
| |
{
| |
Print("New change ID: ", change);
| |
PrintFormat("Too many records (%d), malfunction assumed, skipping", n);
| |
}
| |
else
| |
{
| |
string records = "[" + Description(values[0]);
| |
for(int i = 1; i < n; ++i)
| |
{
| |
records += "," + Description(values[i]);
| |
}
| |
records += "]";
| |
Print("New change ID: ", change, " ",
| |
TimeToString(TimeTradeServer(), TIME_DATE | TIME_SECONDS), "\n", records);
| |
FileWriteLong(handle, PACK_DATETIME_COUNTER(TimeTradeServer(), n));
| |
for(int i = 0; i < n; ++i)
| |
{
| |
FileWriteLong(handle, values[i].id);
| |
}
| |
FileFlush(handle);
| |
++count;
| |
}
| |
}
| |
else if(_LastError == 0)
| |
{
| |
if(!last && change)
| |
{
| |
Print("Start change ID obtained: ", change);
| |
}
| |
}
| |
| |
last = change;
| |
Sleep(PeriodMsc);
| |
}
| |
PrintFormat("%d records added", count);
| |
FileClose(handle);
| |
}
| |
//+------------------------------------------------------------------+
|