Files
Pierre8rTeam f73c061349 Commit
2018-04-06 20:55:57 +02:00

322 lines
25 KiB
Plaintext
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//+------------------------------------------------------------------+
//| TimeSeries.mqh |
//| Copyright 2017, Vasiliy Sokolov. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, Vasiliy Sokolov."
#property link "http://www.mql5.com"
#include <Arrays\ArrayObj.mqh>
#include "TimeValue.mqh"
//+------------------------------------------------------------------+
//| Universal timeseries: stores the values of TimeValue and |
//| provides quick access to them |
//+------------------------------------------------------------------+
class CTimeSeries
{
private:
CArrayObj m_series;
bool m_reverse;
datetime FromFinamData(string data);
public:
bool Add(datetime time, double value);
bool Add(datetime time, double& values[]);
void AddOrChange(datetime time, double value, int buff_index=0);
void Clear();
int Total(void){return m_series.Total();}
double operator[](int index);
double operator[](datetime time);
bool GetReverse(void);
void SetReverse(bool reverse);
CTimeValue* GetTimeValue(datetime time);
CTimeValue* GetTimeValue(int index);
void OrderBy(ENUM_COMP_TYPE comp_type);
int SearchLessOrEqual(datetime time);
bool SaveToCsv(datetime begin_time, datetime end_time, string path, int common=FILE_COMMON, int time_format=TIME_DATE|TIME_MINUTES, int digits = 4, uchar del = ';');
CTimeSeries(void);
bool LoadFromCsv(string path_csv, uchar del=',', int line_begin=0, int common = FILE_COMMON);
int LoadFromArray(uchar& array[], uchar del=',', int line_begin=0);
bool ExitsDataByTime(datetime time);
void ToDoubleArray(double& array[]);
void ToDoubleArray(int column, double& array[]);
};
//+------------------------------------------------------------------+
//| Default initialization |
//+------------------------------------------------------------------+
CTimeSeries::CTimeSeries() : m_reverse(false)
{
OrderBy(COMP_BY_TIME);
}
//+------------------------------------------------------------------+
//| Sorting series |
//+------------------------------------------------------------------+
void CTimeSeries::OrderBy(ENUM_COMP_TYPE comp_type)
{
m_series.Sort(comp_type);
}
//+------------------------------------------------------------------+
//| Adds a new value to the collection. If the data for the specified|
//| date already exist, returns false, and the data are not added |
//+------------------------------------------------------------------+
bool CTimeSeries::Add(datetime time,double value)
{
if(ExitsDataByTime(time))
return false;
CTimeValue* tv = new CTimeValue(time, value);
return m_series.InsertSort(tv);
}
//+------------------------------------------------------------------+
//| Returns the first column as an array of type double              |
//+------------------------------------------------------------------+
void CTimeSeries::ToDoubleArray(double &array[])
{
ToDoubleArray(0, array);
}
//+------------------------------------------------------------------+
//| Returns column with number 'column' as an array of type double   |
//+------------------------------------------------------------------+
void CTimeSeries::ToDoubleArray(int column,double &array[])
{
int total = m_series.Total();
ArrayResize(array, total);
for(int i = 0; i < total; i++)
{
CTimeValue* tv = m_series.At(i);
array[i] = tv.Value(column);
}
}
//+------------------------------------------------------------------+
//| Returns true if the data for the specified date exist |
//| returns false otherwise |
//+------------------------------------------------------------------+
bool CTimeSeries::ExitsDataByTime(datetime time)
{
if(m_series.Total() == 0)
return false;
CTimeValue* t = m_series.At(m_series.Total()-1);
if(t.Time() < time)
return false;
if(t.Time() == time)
return true;
CTimeValue* tv_s = new CTimeValue(time, 0.0);
int index = m_series.Search(tv_s);
delete tv_s;
return (index != -1);
}
//+------------------------------------------------------------------+
//| Adds a new value to the collection, if a value with such time |
//| is not present. If an element with this time at the specified |
//| index exists, modifies its values |
//+------------------------------------------------------------------+
void CTimeSeries::AddOrChange(datetime time,double value, int buff_index=0)
{
if(m_series.SortMode() != COMP_BY_TIME)
m_series.Sort(COMP_BY_TIME);
int index = -1;
if(m_series.Total() > 0)
{
CTimeValue* t = m_series.At(m_series.Total()-1);
if(t.Time() > time)
{
CTimeValue* tv_s = new CTimeValue(time, value);
index = m_series.Search(tv_s);
delete tv_s;
}
}
CTimeValue* tv = NULL;
if(index == -1)
{
tv = new CTimeValue(time, value);
m_series.InsertSort(tv);
}
else
{
tv = m_series.At(index);
tv.Value(buff_index, value);
}
}
//+------------------------------------------------------------------+
//| Saves content to a CSV file |
//+------------------------------------------------------------------+
bool CTimeSeries::SaveToCsv(datetime begin_time, datetime end_time, string path, int common=FILE_COMMON, int time_format=TIME_DATE|TIME_MINUTES, int digits = 4, uchar del = ';')
{
string lines[];
int total = ArrayResize(lines, m_series.Total());
string s = "";
int count = 0;
for(int i = 0; i < total; i++)
{
CTimeValue* tv = m_series.At(i);
if(tv.Time() < begin_time)
continue;
if(tv.Time() > end_time)
break;
lines[count] = tv.ToString(time_format, digits, del)+"\r\n";
count++;
s = lines[i];
}
total = ArrayResize(lines, count);
int h = FileOpen(path, FILE_WRITE|FILE_TXT|common, del, CP_ACP);
if(h == INVALID_HANDLE)
return false;
for(int i = 0; i < total; i++)
FileWriteString(h, lines[i]);
FileClose(h);
return true;
}
//+------------------------------------------------------------------+
//| Removes all items from the collection |
//+------------------------------------------------------------------+
void CTimeSeries::Clear(void)
{
m_series.Clear();
}
//+------------------------------------------------------------------+
//| Adds a list of new values to the collection |
//+------------------------------------------------------------------+
bool CTimeSeries::Add(datetime time,double& values[])
{
if(time == D'2017.06.12')
int dbg = 4;
if(ExitsDataByTime(time))
return false;
CTimeValue* tv = new CTimeValue(time, values);
return m_series.InsertSort(tv);
}
//+------------------------------------------------------------------+
//| Sets direct or reverse indexation in a collection |
//+------------------------------------------------------------------+
void CTimeSeries::SetReverse(bool reverse)
{
m_reverse = reverse;
}
//+------------------------------------------------------------------+
//| Returns true if reverse indexation is used, returns false |
//| if otherwise. |
//+------------------------------------------------------------------+
bool CTimeSeries::GetReverse(void)
{
return m_reverse;
}
//+------------------------------------------------------------------+
//| Get the index value |
//+------------------------------------------------------------------+
double CTimeSeries::operator[](int index)
{
CTimeValue* tv = NULL;
if(!m_reverse)
tv = m_series.At(index);
else
{
int ri = m_series.Total() - index - 1;
tv = m_series.At(ri);
}
return tv.Value();
}
//+------------------------------------------------------------------+
//| Returns the closest value with a smaller or the same time |
//+------------------------------------------------------------------+
double CTimeSeries::operator[](datetime time)
{
int index = SearchLessOrEqual(time);
if(index == -1)
return EMPTY_VALUE;
CTimeValue* tv = m_series.At(index);
return tv.Value();
}
//+------------------------------------------------------------------+
//| Returns the closest value with a smaller or the same time |
//| TimeValue |
//+------------------------------------------------------------------+
CTimeValue* CTimeSeries::GetTimeValue(datetime time)
{
CTimeValue* tv = NULL;
int index = SearchLessOrEqual(time);
if(index == -1)
return tv;
tv = m_series.At(index);
return tv;
}
//+------------------------------------------------------------------+
//| Returns the TimeValue corresponding to the index |
//+------------------------------------------------------------------+
CTimeValue* CTimeSeries::GetTimeValue(int index)
{
return m_series.At(index);
}
//+------------------------------------------------------------------+
//| Returns index of element with time equal to specified. |
//| If no element with this time exist, returns an element with time |
//| less than specified but greater than other elements with smaller |
//| time |
//+------------------------------------------------------------------+
int CTimeSeries::SearchLessOrEqual(datetime time)
{
CTimeValue* tv_s = new CTimeValue(time, EMPTY_VALUE);
if(m_series.SortMode() != COMP_BY_TIME)
m_series.Sort(COMP_BY_TIME);
int index = m_series.SearchLessOrEqual(tv_s);
delete tv_s;
return index;
}
//+------------------------------------------------------------------+
//| Loads a CSV file from the drive to a timeseries |
//+------------------------------------------------------------------+
bool CTimeSeries::LoadFromCsv(string path_csv, uchar del=',', int line_begin=0, int common = FILE_COMMON)
{
int h = FileOpen(path_csv, FILE_READ|FILE_BIN|common);
if(h == INVALID_HANDLE)
{
printf("Failed open file " + path_csv + " Last error: " + (string)GetLastError());
return false;
}
uchar array[];
FileReadArray(h, array, 0, WHOLE_ARRAY);
FileClose(h);
return (LoadFromArray(array, del, line_begin)>0);
}
//+------------------------------------------------------------------+
//| Loads a CSV file passed as a byte array to a timeseries. |
//| |
//| Returns the number of lines added |
//+------------------------------------------------------------------+
int CTimeSeries::LoadFromArray(uchar &array[], uchar del=',',int line_begin=0)
{
string csv = CharArrayToString(array, 0, WHOLE_ARRAY, CP_ACP);
string lines[];
StringSplit(csv, '\n', lines);
int total = ArraySize(lines);
int count = 0;
for(int i = line_begin; i < total; i++)
{
string col[];
double values[];
string l = lines[i];
if(StringSplit(lines[i], del, col)<=1)
continue;
int col_size = ArraySize(col)-1;
ArrayResize(values, col_size);
datetime time = FromFinamData(col[0]);
for(int c = 1; c <= col_size; c++)
values[c-1] = StringToDouble(col[c]);
if(Add(time, values))
count++;
}
return count;
}
//+------------------------------------------------------------------+
//| Parses the broker date |
//+------------------------------------------------------------------+
datetime CTimeSeries::FromFinamData(string data)
{
int l = StringLen(data);
uchar ch = (uchar)StringGetCharacter(data, 0);
int year = (int)StringSubstr(data, 0, 4);
int month = (int)StringSubstr(data, 4, 2);
int day = (int)StringSubstr(data, 6, 2);
MqlDateTime time_str={0};
time_str.day = day;
time_str.year = year;
time_str.mon = month;
return StructToTime(time_str);
}