MQL5Book/Scripts/p7/CalendarChangeReader.mq5

139 lines
4.1 KiB
MQL5
Raw Permalink Normal View History

2025-05-30 16:09:41 +02:00
//+------------------------------------------------------------------+
//| CalendarChangeReader.mq5 |
//| Copyright 2022, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property description "Test script to show how to read saved calendar changes from CalendarChangeSaver service."
#property script_show_inputs
#include "..\..\Include\Defines.mqh"
#define PACK_DATETIME_COUNTER(D,C) (D | (((ulong)(C)) << 48))
#define DATETIME(A) ((datetime)((A) & 0x7FFFFFFFF))
#define COUNTER(A) ((ushort)((A) >> 48))
input string Filename = "calendar2.chn";
input datetime Start;
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
const long day = 60 * 60 * 24;
datetime now = Start ? Start : (datetime)(TimeCurrent() / day * day);
int handle = FileOpen(Filename,
FILE_READ | FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_BIN);
if(handle == INVALID_HANDLE)
{
PrintFormat("Can't open file '%s' for reading", Filename);
return;
}
ChangeFileReader reader(handle, now);
// read the file step by step, incrementing time artificially in this demo
while(!FileIsEnding(handle))
{
// in real application testing could call reader.check on every tick,
// or postpond further checks until reader.getState().dt (if it's not LONG_MAX)
ulong records[];
if(reader.check(now, records))
{
Print(now);
ArrayPrint(records);
}
now += 60; // increment time by 1 minute at once, can be 1 second
}
FileClose(handle);
}
//+------------------------------------------------------------------+
//| Single change (datetime + array of affected calendar record IDs) |
//+------------------------------------------------------------------+
struct ChangeState
{
datetime dt;
ulong ids[];
ChangeState(): dt(LONG_MAX) {}
ChangeState(const datetime at, ulong &_ids[])
{
dt = at;
ArraySwap(ids, _ids);
}
void operator=(const ChangeState &other)
{
dt = other.dt;
ArrayCopy(ids, other.ids);
}
};
//+------------------------------------------------------------------+
//| Class to walk through changes saved in a file for advancing time |
//+------------------------------------------------------------------+
class ChangeFileReader
{
const int handle;
ChangeState current;
const ChangeState zero;
public:
ChangeFileReader(const int h, const datetime start = 0): handle(h)
{
if(readState())
{
if(start)
{
ulong dummy[];
check(start, dummy, true); // jump to first edit after 'start'
}
}
}
bool check(datetime now, ulong &records[], const bool fastforward = false)
{
if(current.dt > now) return false;
ArrayFree(records);
if(!fastforward)
{
ArrayCopy(records, current.ids);
current = zero;
}
while(readState() && current.dt <= now)
{
if(!fastforward) ArrayInsert(records, current.ids, ArraySize(records));
}
return true;
}
bool readState()
{
if(FileIsEnding(handle)) return false;
ResetLastError();
const ulong v = FileReadLong(handle);
current.dt = DATETIME(v);
ArrayFree(current.ids);
const int n = COUNTER(v);
for(int i = 0; i < n; ++i)
{
PUSH(current.ids, FileReadLong(handle));
}
return _LastError == 0;
}
ChangeState getState() const
{
return current;
}
};
//+------------------------------------------------------------------+