forked from airat77786/MQL5Book
138 lines
4.1 KiB
MQL5
138 lines
4.1 KiB
MQL5
//+------------------------------------------------------------------+
| |||
//| 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;
| |||
}
| |||
};
| |||
//+------------------------------------------------------------------+
|