forked from airat77786/MQL5Book
197 lines
7.8 KiB
MQL5
197 lines
7.8 KiB
MQL5
//+------------------------------------------------------------------+
| |||
//| FileAtomic.mq5 |
| |||
//| Copyright 2021, MetaQuotes Ltd. |
| |||
//| https://www.mql5.com |
| |||
//+------------------------------------------------------------------+
| |||
#include "..\..\Include\PRTF.mqh"
| |||
#include "..\..\Include\Periods.mqh"
| |||
#include "..\..\Include\FileHandle.mqh"
| |||
| |||
| |||
#define BARLIMIT 10 // number of bars to write into test file
| |||
#define TFLEN 3 // length of timeframe name in the file
| |||
| |||
const string filename = "MQL5Book/atomic.raw";
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Interface for writing/reading objects to/from files |
| |||
//+------------------------------------------------------------------+
| |||
interface Persistent
| |||
{
| |||
bool write(int handle);
| |||
bool read(int handle);
| |||
};
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Class with specific file format header |
| |||
//+------------------------------------------------------------------+
| |||
class FileHeader : public Persistent
| |||
{
| |||
const string signature;
| |||
public:
| |||
FileHeader() : signature("CANDLES/1.1") { }
| |||
bool write(int handle) override
| |||
{
| |||
PRTF(FileWriteString(handle, signature, StringLen(signature))); // 11
| |||
PRTF(FileWriteInteger(handle, StringLen(_Symbol), CHAR_VALUE)); // 1
| |||
PRTF(FileWriteString(handle, _Symbol)); // 6, for XAUUSD
| |||
PRTF(FileWriteString(handle, PeriodToString(), TFLEN)); // 3
| |||
// TODO: check _LastError
| |||
return true;
| |||
}
| |||
bool read(int handle) override
| |||
{
| |||
const string sig = PRTF(FileReadString(handle, StringLen(signature))); // CANDLES/1.1
| |||
if(sig != signature)
| |||
{
| |||
PrintFormat("Wrong file format, header is missing: want=%s vs got %s",
| |||
signature, sig);
| |||
return false;
| |||
}
| |||
const int len = PRTF(FileReadInteger(handle, CHAR_VALUE)); // 6
| |||
const string sym = PRTF(FileReadString(handle, len)); // XAUUSD (example)
| |||
if(_Symbol != sym)
| |||
{
| |||
PrintFormat("Wrong symbol: file=%s vs chart=%s", sym, _Symbol);
| |||
return false;
| |||
}
| |||
const string stf = PRTF(FileReadString(handle, TFLEN)); // H1 (example)
| |||
if(_Period != StringToPeriod(stf))
| |||
{
| |||
PrintFormat("Wrong timeframe: file=%s(%s) vs chart=%s",
| |||
stf, EnumToString(StringToPeriod(stf)), EnumToString(_Period));
| |||
return false;
| |||
}
| |||
return true;
| |||
}
| |||
};
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Simple class to write and read partial rates using files |
| |||
//+------------------------------------------------------------------+
| |||
class Candles : public Persistent
| |||
{
| |||
FileHeader header;
| |||
int limit;
| |||
MqlRates rates[];
| |||
public:
| |||
Candles(const int size = 0) : limit(size)
| |||
{
| |||
if(size == 0) return;
| |||
int n = PRTF(CopyRates(_Symbol, _Period, 0, limit, rates)); // 10
| |||
if(n < 1)
| |||
{
| |||
limit = 0; // init failed
| |||
}
| |||
limit = n; // can be less than requested
| |||
}
| |||
| |||
bool write(int handle) override
| |||
{
| |||
if(!limit) return false; // no data
| |||
// delegate header writing to the header itself
| |||
if(!header.write(handle)) return false;
| |||
// save record count
| |||
PRTF(FileWriteInteger(handle, limit)); // 4
| |||
// save date range (last, first)
| |||
PRTF(FileWriteLong(handle, rates[0].time)); // 8
| |||
PRTF(FileWriteLong(handle, rates[limit - 1].time)); // 8
| |||
// save array of rates
| |||
for(int i = 0; i < limit; ++i)
| |||
{
| |||
FileWriteStruct(handle, rates[i], offsetof(MqlRates, tick_volume));
| |||
}
| |||
return true;
| |||
}
| |||
| |||
bool read(int handle) override
| |||
{
| |||
if(!header.read(handle))
| |||
{
| |||
return false;
| |||
}
| |||
limit = PRTF(FileReadInteger(handle)); // 10
| |||
ArrayResize(rates, limit);
| |||
ZeroMemory(rates);
| |||
// dates must be read but are not used so far
| |||
datetime dt0 = (datetime)PRTF(FileReadLong(handle)); // 1629212400 (example)
| |||
datetime dt1 = (datetime)PRTF(FileReadLong(handle)); // 1629248400 (example)
| |||
| |||
for(int i = 0; i < limit; ++i)
| |||
{
| |||
FileReadStruct(handle, rates[i], offsetof(MqlRates, tick_volume));
| |||
}
| |||
return true;
| |||
}
| |||
| |||
void print() const
| |||
{
| |||
ArrayPrint(rates);
| |||
}
| |||
};
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Script program start function |
| |||
//+------------------------------------------------------------------+
| |||
void OnStart()
| |||
{
| |||
// Part I. Writing
| |||
// create new file or open existing one and empty it
| |||
FileHandle handle(PRTF(FileOpen(filename,
| |||
FILE_BIN | FILE_WRITE | FILE_ANSI | FILE_SHARE_READ))); // 1
| |||
// request rates
| |||
Candles output(BARLIMIT);
| |||
// fill the file with data by persistent object
| |||
if(!output.write(~handle))
| |||
{
| |||
Print("Can't write file");
| |||
return;
| |||
}
| |||
output.print();
| |||
/*
| |||
example output for XAUUSD,H1
| |||
[time] [open] [high] [low] [close] [tick_volume] [spread] [real_volume]
| |||
[0] 2021.08.17 15:00:00 1791.40 1794.57 1788.04 1789.46 8157 5 0
| |||
[1] 2021.08.17 16:00:00 1789.46 1792.99 1786.69 1789.69 9285 5 0
| |||
[2] 2021.08.17 17:00:00 1789.76 1790.45 1780.95 1783.30 8165 5 0
| |||
[3] 2021.08.17 18:00:00 1783.30 1783.98 1780.53 1782.73 5114 5 0
| |||
[4] 2021.08.17 19:00:00 1782.69 1784.16 1782.09 1782.49 3586 6 0
| |||
[5] 2021.08.17 20:00:00 1782.49 1786.23 1782.17 1784.23 3515 5 0
| |||
[6] 2021.08.17 21:00:00 1784.20 1784.85 1782.73 1783.12 2627 6 0
| |||
[7] 2021.08.17 22:00:00 1783.10 1785.52 1782.37 1785.16 2114 5 0
| |||
[8] 2021.08.17 23:00:00 1785.11 1785.84 1784.71 1785.80 922 5 0
| |||
[9] 2021.08.18 01:00:00 1786.30 1786.34 1786.18 1786.20 13 5 0
| |||
*/
| |||
| |||
// Part II. Reading
| |||
// open existing file and read it out by persistent object
| |||
// meta-data from leading header drives the following process of reading actual data
| |||
handle = PRTF(FileOpen(filename,
| |||
FILE_BIN | FILE_READ | FILE_ANSI | FILE_SHARE_READ | FILE_SHARE_WRITE)); // 2
| |||
// empty object
| |||
Candles inputs;
| |||
// fill it with data from the file
| |||
if(!inputs.read(~handle))
| |||
{
| |||
Print("Can't read file");
| |||
}
| |||
else
| |||
{
| |||
inputs.print();
| |||
}
| |||
/*
| |||
example output for XAUUSD,H1
| |||
[time] [open] [high] [low] [close] [tick_volume] [spread] [real_volume]
| |||
[0] 2021.08.17 15:00:00 1791.40 1794.57 1788.04 1789.46 0 0 0
| |||
[1] 2021.08.17 16:00:00 1789.46 1792.99 1786.69 1789.69 0 0 0
| |||
[2] 2021.08.17 17:00:00 1789.76 1790.45 1780.95 1783.30 0 0 0
| |||
[3] 2021.08.17 18:00:00 1783.30 1783.98 1780.53 1782.73 0 0 0
| |||
[4] 2021.08.17 19:00:00 1782.69 1784.16 1782.09 1782.49 0 0 0
| |||
[5] 2021.08.17 20:00:00 1782.49 1786.23 1782.17 1784.23 0 0 0
| |||
[6] 2021.08.17 21:00:00 1784.20 1784.85 1782.73 1783.12 0 0 0
| |||
[7] 2021.08.17 22:00:00 1783.10 1785.52 1782.37 1785.16 0 0 0
| |||
[8] 2021.08.17 23:00:00 1785.11 1785.84 1784.71 1785.80 0 0 0
| |||
[9] 2021.08.18 01:00:00 1786.30 1786.34 1786.18 1786.20 0 0 0
| |||
*/
| |||
}
| |||
//+------------------------------------------------------------------+
|