forked from rosh/MQL5Book
152 lines
4.9 KiB
MQL5
152 lines
4.9 KiB
MQL5
//+------------------------------------------------------------------+
| |||
//| FileTxtCsv.mq5 |
| |||
//| Copyright 2021, MetaQuotes Ltd. |
| |||
//| https://www.mql5.com |
| |||
//+------------------------------------------------------------------+
| |||
#include "..\..\Include\PRTF.mqh"
| |||
#include "..\..\Include\StringUtils.mqh"
| |||
| |||
#define LIMIT 10
| |||
| |||
const string txtfile = "MQL5Book/atomic.txt";
| |||
const string csvfile = "MQL5Book/atomic.csv";
| |||
const short delimiter = ',';
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Simple MqlRates-wrapper for setting data by field number |
| |||
//+------------------------------------------------------------------+
| |||
struct MqlRatesM : public MqlRates
| |||
{
| |||
template<typename T>
| |||
void set(int field, T v)
| |||
{
| |||
switch(field)
| |||
{
| |||
case 0:
| |||
this.time = (datetime)v;
| |||
break;
| |||
case 1:
| |||
this.open = (double)v;
| |||
break;
| |||
case 2:
| |||
this.high = (double)v;
| |||
break;
| |||
case 3:
| |||
this.low = (double)v;
| |||
break;
| |||
case 4:
| |||
this.close = (double)v;
| |||
break;
| |||
case 5:
| |||
this.tick_volume = (long)v;
| |||
break;
| |||
case 6:
| |||
this.spread = (int)v;
| |||
break;
| |||
case 7:
| |||
this.real_volume = (long)v;
| |||
break;
| |||
}
| |||
}
| |||
};
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Script program start function |
| |||
//+------------------------------------------------------------------+
| |||
void OnStart()
| |||
{
| |||
MqlRates rates[];
| |||
int n = PRTF(CopyRates(_Symbol, _Period, 0, LIMIT, rates)); // 10
| |||
| |||
const string columns[] = {"DateTime", "Open", "High", "Low", "Close", "Ticks", "Spread", "True"};
| |||
// last column name can be interpreted as "True Volume" and is used for FileReadBool
| |||
const string caption = StringCombine(columns, delimiter) + "\r\n";
| |||
| |||
// Part I. Writing TXT and CSV
| |||
// create new file or open existing one and empty it
| |||
int fh1 = PRTF(FileOpen(txtfile, FILE_TXT | FILE_ANSI | FILE_WRITE, delimiter)); // 1
| |||
int fh2 = PRTF(FileOpen(csvfile, FILE_CSV | FILE_ANSI | FILE_WRITE, delimiter)); // 2
| |||
| |||
// PRTF(FileWriteArray(fh1, rates)); // FILE_NOTBIN(5011)
| |||
| |||
PRTF(FileWriteString(fh1, caption));
| |||
PRTF(FileWriteString(fh2, caption));
| |||
| |||
for(int i = 0; i < n; ++i)
| |||
{
| |||
FileWrite(fh1, rates[i].time,
| |||
rates[i].open, rates[i].high, rates[i].low, rates[i].close,
| |||
rates[i].tick_volume, rates[i].spread, rates[i].real_volume);
| |||
FileWrite(fh2, rates[i].time,
| |||
rates[i].open, rates[i].high, rates[i].low, rates[i].close,
| |||
rates[i].tick_volume, rates[i].spread, rates[i].real_volume);
| |||
}
| |||
| |||
FileClose(fh1);
| |||
FileClose(fh2);
| |||
| |||
// Part II. Reading TXT and CSV with FileReadString
| |||
// open just written files for reading and testing
| |||
string read;
| |||
fh1 = PRTF(FileOpen(txtfile, FILE_TXT | FILE_ANSI | FILE_READ, delimiter)); // 1
| |||
fh2 = PRTF(FileOpen(csvfile, FILE_CSV | FILE_ANSI | FILE_READ, delimiter)); // 2
| |||
| |||
Print("===== Reading TXT");
| |||
do
| |||
{
| |||
read = PRTF(FileReadString(fh1));
| |||
}
| |||
while(StringLen(read) > 0);
| |||
| |||
Print("===== Reading CSV");
| |||
do
| |||
{
| |||
read = PRTF(FileReadString(fh2));
| |||
}
| |||
while(StringLen(read) > 0);
| |||
| |||
FileClose(fh1);
| |||
FileClose(fh2);
| |||
| |||
// Part III. Reading CSV with specific functions
| |||
// FileReadDatetime, FileReadNumber, FileReadBool
| |||
Print("===== Reading CSV (alternative)");
| |||
MqlRatesM r[1];// declare as array to print the struct easily by ArrayPrint
| |||
int count = 0; // number of records read
| |||
int column = 0;// monitor current column to change convertion types
| |||
const int maxColumn = ArraySize(columns);
| |||
fh2 = PRTF(FileOpen(csvfile, FILE_CSV | FILE_ANSI | FILE_READ, delimiter)); // 1
| |||
do
| |||
{
| |||
// Note: first record is not a data, it holds column titles
| |||
if(column)
| |||
{
| |||
if(count == 1) // demonstrate FileReadBool on 1-st record with titles
| |||
{
| |||
r[0].set(column, PRTF(FileReadBool(fh2)));
| |||
}
| |||
else
| |||
{
| |||
r[0].set(column, FileReadNumber(fh2));
| |||
}
| |||
}
| |||
else // 0-th column is a datetime
| |||
{
| |||
++count;
| |||
if(count > 1) // struct from previous line is ready
| |||
{
| |||
ArrayPrint(r, _Digits, NULL, 0, 1, 0);
| |||
}
| |||
r[0].time = FileReadDatetime(fh2);
| |||
}
| |||
column = (column + 1) % maxColumn;
| |||
}
| |||
while(_LastError == 0); // normal termination implies 5027 (FILE_ENDOFFILE)
| |||
| |||
// last struct print
| |||
if(column == maxColumn - 1)
| |||
{
| |||
ArrayPrint(r, _Digits, NULL, 0, 1, 0);
| |||
}
| |||
}
| |||
//+------------------------------------------------------------------+
|