Add files via upload
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,377 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| String.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Object.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CString. |
|
||||
//| Appointment: Class-string. |
|
||||
//| Derives from class CObject. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CString : public CObject
|
||||
{
|
||||
protected:
|
||||
string m_string;
|
||||
|
||||
public:
|
||||
CString(void);
|
||||
~CString(void);
|
||||
//--- methods access
|
||||
string Str(void) const { return(m_string); };
|
||||
uint Len(void) const { return(StringLen(m_string)); };
|
||||
void Copy(string ©) const;
|
||||
void Copy(CString *copy) const;
|
||||
//--- methods fill
|
||||
bool Fill(const short character) { return(StringFill(m_string,character)); };
|
||||
void Assign(const string str) { m_string=str; };
|
||||
void Assign(const CString *str) { m_string=str.Str(); };
|
||||
void Append(const string str);
|
||||
void Append(const CString *str);
|
||||
uint Insert(const uint pos,const string substring);
|
||||
uint Insert(const uint pos,const CString *substring);
|
||||
//--- methods compare
|
||||
int Compare(const string str) const;
|
||||
int Compare(const CString *str) const;
|
||||
int CompareNoCase(const string str) const;
|
||||
int CompareNoCase(const CString *str) const;
|
||||
//--- methods prepare
|
||||
string Left(const uint count) const;
|
||||
string Right(const uint count) const;
|
||||
string Mid(const uint pos,const uint count) const;
|
||||
//--- methods truncation/deletion
|
||||
int Trim(const string targets);
|
||||
int TrimLeft(const string targets);
|
||||
int TrimRight(const string targets);
|
||||
bool Clear(void) { return(StringInit(m_string)); };
|
||||
//--- methods conversion
|
||||
bool ToUpper(void) { return(StringToUpper(m_string)); };
|
||||
bool ToLower(void) { return(StringToLower(m_string)); };
|
||||
void Reverse(void);
|
||||
//--- methods find
|
||||
int Find(const uint start,const string substring) const;
|
||||
int FindRev(const string substring) const;
|
||||
uint Remove(const string substring);
|
||||
uint Replace(const string substring,const string newstring);
|
||||
|
||||
protected:
|
||||
virtual int Compare(const CObject *node,const int mode=0) const;
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CString::CString(void) : m_string("")
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CString::~CString(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Copy the string value member to copy |
|
||||
//+------------------------------------------------------------------+
|
||||
void CString::Copy(string ©) const
|
||||
{
|
||||
copy=m_string;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Copy the string value member to copy |
|
||||
//+------------------------------------------------------------------+
|
||||
void CString::Copy(CString *copy) const
|
||||
{
|
||||
copy.Assign(m_string);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Add a string to the end |
|
||||
//+------------------------------------------------------------------+
|
||||
void CString::Append(const string str)
|
||||
{
|
||||
m_string+=str;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Add a string to the end |
|
||||
//+------------------------------------------------------------------+
|
||||
void CString::Append(const CString *str)
|
||||
{
|
||||
//--- check
|
||||
if(!CheckPointer(str))
|
||||
return;
|
||||
//---
|
||||
m_string+=str.Str();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Insert a string in specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
uint CString::Insert(const uint pos,const string substring)
|
||||
{
|
||||
string tmp=StringSubstr(m_string,0,pos);
|
||||
//---
|
||||
tmp+=substring;
|
||||
m_string=tmp+StringSubstr(m_string,pos);
|
||||
//--- result
|
||||
return(StringLen(m_string));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Insert a string in specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
uint CString::Insert(const uint pos,const CString *substring)
|
||||
{
|
||||
//--- check
|
||||
if(!CheckPointer(substring))
|
||||
return(0);
|
||||
//---
|
||||
string tmp=StringSubstr(m_string,0,pos);
|
||||
//---
|
||||
tmp+=substring.Str();
|
||||
m_string=tmp+StringSubstr(m_string,pos);
|
||||
//--- result
|
||||
return(StringLen(m_string));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Comparison with the string |
|
||||
//+------------------------------------------------------------------+
|
||||
int CString::Compare(const string str) const
|
||||
{
|
||||
if(m_string<str)
|
||||
return(-1);
|
||||
if(m_string>str)
|
||||
return(1);
|
||||
//--- equal
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Comparison with the string |
|
||||
//+------------------------------------------------------------------+
|
||||
int CString::Compare(const CString *str) const
|
||||
{
|
||||
//--- check
|
||||
if(!CheckPointer(str))
|
||||
return(0);
|
||||
//---
|
||||
if(m_string<str.Str())
|
||||
return(-1);
|
||||
if(m_string>str.Str())
|
||||
return(1);
|
||||
//--- equal
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Comparison with the string without case |
|
||||
//+------------------------------------------------------------------+
|
||||
int CString::CompareNoCase(const string str) const
|
||||
{
|
||||
string tmp1,tmp2;
|
||||
//---
|
||||
tmp1=m_string;
|
||||
tmp2=str;
|
||||
StringToLower(tmp1);
|
||||
StringToLower(tmp2);
|
||||
//---
|
||||
if(tmp1<tmp2)
|
||||
return(-1);
|
||||
if(tmp1>tmp2)
|
||||
return(1);
|
||||
//--- equal
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Comparison with the string without case |
|
||||
//+------------------------------------------------------------------+
|
||||
int CString::CompareNoCase(const CString *str) const
|
||||
{
|
||||
string tmp1,tmp2;
|
||||
//--- check
|
||||
if(!CheckPointer(str))
|
||||
return(0);
|
||||
//---
|
||||
tmp1=m_string;
|
||||
tmp2=str.Str();
|
||||
StringToLower(tmp1);
|
||||
StringToLower(tmp2);
|
||||
//---
|
||||
if(tmp1<tmp2)
|
||||
return(-1);
|
||||
if(tmp1>tmp2)
|
||||
return(1);
|
||||
//--- equal
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find occurrences of substring from the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
int CString::Find(const uint start,const string substring) const
|
||||
{
|
||||
return(StringFind(m_string,substring,start));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find last occurrence of substring |
|
||||
//+------------------------------------------------------------------+
|
||||
int CString::FindRev(const string substring) const
|
||||
{
|
||||
int result,pos=-1;
|
||||
//---
|
||||
do
|
||||
{
|
||||
result=pos;
|
||||
}
|
||||
while((pos=StringFind(m_string,substring,pos+1))>=0);
|
||||
//--- result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get a substring consisting of count elements of the left string |
|
||||
//+------------------------------------------------------------------+
|
||||
string CString::Left(const uint count) const
|
||||
{
|
||||
return(StringSubstr(m_string,0,count));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get a substring consisting of count elements of the right string.|
|
||||
//+------------------------------------------------------------------+
|
||||
string CString::Right(const uint count) const
|
||||
{
|
||||
return(StringSubstr(m_string,StringLen(m_string)-count,count));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get a substring consisting of count elements of the pos string |
|
||||
//+------------------------------------------------------------------+
|
||||
string CString::Mid(const uint pos,const uint count) const
|
||||
{
|
||||
return(StringSubstr(m_string,pos,count));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Remove from the string, all characters in the begin and |
|
||||
//| in the end if they arein targets, or space, \t,\n or \r |
|
||||
//+------------------------------------------------------------------+
|
||||
int CString::Trim(const string targets)
|
||||
{
|
||||
return(TrimLeft(targets)+TrimRight(targets));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Remove from the string, all characters in the begin if they are |
|
||||
//| in targets, or space, \t,\n or \r |
|
||||
//+------------------------------------------------------------------+
|
||||
int CString::TrimLeft(const string targets)
|
||||
{
|
||||
ushort ch;
|
||||
//---
|
||||
for(int i=0;i<StringLen(m_string);i++)
|
||||
{
|
||||
ch=StringGetCharacter(m_string,i);
|
||||
if(ch<=' ')
|
||||
continue;
|
||||
for(int j=0;j<StringLen(targets);j++)
|
||||
{
|
||||
if(ch==StringGetCharacter(targets,j))
|
||||
{
|
||||
StringSetCharacter(m_string,i,' ');
|
||||
ch=' ';
|
||||
}
|
||||
}
|
||||
if(ch!=' ')
|
||||
break;
|
||||
}
|
||||
//--- result
|
||||
return(StringTrimLeft(m_string));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Remove from the string, all characters in the end if they are |
|
||||
//| in targets, or space, \t,\n or \r |
|
||||
//+------------------------------------------------------------------+
|
||||
int CString::TrimRight(const string targets)
|
||||
{
|
||||
ushort ch;
|
||||
//---
|
||||
for(int i=StringLen(m_string)-1;i>=0;i--)
|
||||
{
|
||||
ch=StringGetCharacter(m_string,i);
|
||||
if(ch<=' ')
|
||||
continue;
|
||||
for(int j=0;j<StringLen(targets);j++)
|
||||
{
|
||||
if(ch==StringGetCharacter(targets,j))
|
||||
{
|
||||
StringSetCharacter(m_string,i,' ');
|
||||
ch=' ';
|
||||
}
|
||||
}
|
||||
if(ch!=' ')
|
||||
break;
|
||||
}
|
||||
//--- result
|
||||
return(StringTrimRight(m_string));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deploy the sequence of characters in a string |
|
||||
//+------------------------------------------------------------------+
|
||||
void CString::Reverse(void)
|
||||
{
|
||||
ushort ch;
|
||||
int i,j;
|
||||
//---
|
||||
for(i=StringLen(m_string)-1,j=0;i>j;i--,j++)
|
||||
{
|
||||
ch=StringGetCharacter(m_string,i);
|
||||
StringSetCharacter(m_string,i,StringGetCharacter(m_string,j));
|
||||
StringSetCharacter(m_string,j,ch);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Remove all occurrences of the substring |
|
||||
//+------------------------------------------------------------------+
|
||||
uint CString::Remove(const string substring)
|
||||
{
|
||||
int result=0,len,pos=-1;
|
||||
string tmp;
|
||||
//---
|
||||
len=StringLen(substring);
|
||||
while((pos=StringFind(m_string,substring,pos))>=0)
|
||||
{
|
||||
tmp=StringSubstr(m_string,0,pos);
|
||||
m_string=tmp+StringSubstr(m_string,pos+len);
|
||||
result++;
|
||||
}
|
||||
//--- result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Replace all occurrences of a substring in the specified string |
|
||||
//+------------------------------------------------------------------+
|
||||
uint CString::Replace(const string substring,const string newstring)
|
||||
{
|
||||
int result=0,len,pos=-1;
|
||||
string tmp;
|
||||
//---
|
||||
len=StringLen(substring);
|
||||
while((pos=StringFind(m_string,substring,pos))>=0)
|
||||
{
|
||||
tmp=StringSubstr(m_string,0,pos)+newstring;
|
||||
m_string=tmp+StringSubstr(m_string,pos+len);
|
||||
// to eliminate possible loops
|
||||
pos+=StringLen(newstring);
|
||||
result++;
|
||||
}
|
||||
//--- result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Comparison with the string by algorithm |
|
||||
//+------------------------------------------------------------------+
|
||||
int CString::Compare(const CObject *node,const int mode=0) const
|
||||
{
|
||||
CString *str=(CString*)node;
|
||||
//--- check
|
||||
if(str==NULL)
|
||||
return(0);
|
||||
//---
|
||||
switch(mode)
|
||||
{
|
||||
case 0: return(Compare(str));
|
||||
case 1: return(CompareNoCase(str));
|
||||
}
|
||||
//--- equal
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,581 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| DateTime.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
//+------------------------------------------------------------------+
|
||||
//| Structure CDateTime. |
|
||||
//| Purpose: Working with dates and time. |
|
||||
//| Extends the MqlDateTime structure. |
|
||||
//+------------------------------------------------------------------+
|
||||
struct CDateTime : public MqlDateTime
|
||||
{
|
||||
//--- additional information
|
||||
string MonthName(const int num) const;
|
||||
string ShortMonthName(const int num) const;
|
||||
string DayName(const int num) const;
|
||||
string ShortDayName(const int num) const;
|
||||
string MonthName(void) const { return(MonthName(mon)); }
|
||||
string ShortMonthName(void) const { return(ShortMonthName(mon)); }
|
||||
string DayName(void) const { return(DayName(day_of_week)); }
|
||||
string ShortDayName(void) const { return(ShortDayName(day_of_week)); }
|
||||
int DaysInMonth(void) const;
|
||||
//--- data access
|
||||
datetime DateTime(void) { return(StructToTime(this)); }
|
||||
void DateTime(const datetime value) { TimeToStruct(value,this); }
|
||||
void DateTime(const MqlDateTime& value) { this=value; }
|
||||
void Date(const datetime value);
|
||||
void Date(const MqlDateTime &value);
|
||||
void Time(const datetime value);
|
||||
void Time(const MqlDateTime &value);
|
||||
//--- settings
|
||||
void Sec(const int value);
|
||||
void Min(const int value);
|
||||
void Hour(const int value);
|
||||
void Day(const int value);
|
||||
void Mon(const int value);
|
||||
void Year(const int value);
|
||||
//--- increments
|
||||
void SecDec(int delta=1);
|
||||
void SecInc(int delta=1);
|
||||
void MinDec(int delta=1);
|
||||
void MinInc(int delta=1);
|
||||
void HourDec(int delta=1);
|
||||
void HourInc(int delta=1);
|
||||
void DayDec(int delta=1);
|
||||
void DayInc(int delta=1);
|
||||
void MonDec(int delta=1);
|
||||
void MonInc(int delta=1);
|
||||
void YearDec(int delta=1);
|
||||
void YearInc(int delta=1);
|
||||
//--- check
|
||||
void DayCheck(void);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Gets month name |
|
||||
//+------------------------------------------------------------------+
|
||||
string CDateTime::MonthName(const int num) const
|
||||
{
|
||||
switch(num)
|
||||
{
|
||||
case 1: return("January");
|
||||
case 2: return("February");
|
||||
case 3: return("March");
|
||||
case 4: return("April");
|
||||
case 5: return("May");
|
||||
case 6: return("June");
|
||||
case 7: return("July");
|
||||
case 8: return("August");
|
||||
case 9: return("September");
|
||||
case 10: return("October");
|
||||
case 11: return("November");
|
||||
case 12: return("December");
|
||||
}
|
||||
//---
|
||||
return("Bad month");
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Gets short name of month |
|
||||
//+------------------------------------------------------------------+
|
||||
string CDateTime::ShortMonthName(const int num) const
|
||||
{
|
||||
switch(num)
|
||||
{
|
||||
case 1: return("jan");
|
||||
case 2: return("feb");
|
||||
case 3: return("mar");
|
||||
case 4: return("apr");
|
||||
case 5: return("may");
|
||||
case 6: return("jun");
|
||||
case 7: return("jul");
|
||||
case 8: return("aug");
|
||||
case 9: return("sep");
|
||||
case 10: return("oct");
|
||||
case 11: return("nov");
|
||||
case 12: return("dec");
|
||||
}
|
||||
//---
|
||||
return("Bad month");
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Gets name of week day |
|
||||
//+------------------------------------------------------------------+
|
||||
string CDateTime::DayName(const int num) const
|
||||
{
|
||||
switch(num)
|
||||
{
|
||||
case 0: return("Sunday");
|
||||
case 1: return("Monday");
|
||||
case 2: return("Tuesday");
|
||||
case 3: return("Wednesday");
|
||||
case 4: return("Thursday");
|
||||
case 5: return("Friday");
|
||||
case 6: return("Saturday");
|
||||
}
|
||||
//---
|
||||
return("Bad day of week");
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Gets short name of week day |
|
||||
//+------------------------------------------------------------------+
|
||||
string CDateTime::ShortDayName(const int num) const
|
||||
{
|
||||
switch(num)
|
||||
{
|
||||
case 0: return("Su");
|
||||
case 1: return("Mo");
|
||||
case 2: return("Tu");
|
||||
case 3: return("We");
|
||||
case 4: return("Th");
|
||||
case 5: return("Fr");
|
||||
case 6: return("Sa");
|
||||
}
|
||||
//---
|
||||
return("Bad day of week");
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Gets number of days in month |
|
||||
//+------------------------------------------------------------------+
|
||||
int CDateTime::DaysInMonth(void) const
|
||||
{
|
||||
int leap_year;
|
||||
//---
|
||||
switch(mon)
|
||||
{
|
||||
case 1:
|
||||
case 3:
|
||||
case 5:
|
||||
case 7:
|
||||
case 8:
|
||||
case 10:
|
||||
case 12:
|
||||
return(31);
|
||||
case 2:
|
||||
leap_year=year;
|
||||
if(year%100==0)
|
||||
leap_year/=100;
|
||||
return((leap_year%4==0)? 29 : 28);
|
||||
case 4:
|
||||
case 6:
|
||||
case 9:
|
||||
case 11:
|
||||
return(30);
|
||||
}
|
||||
//---
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Sets date |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDateTime::Date(const datetime value)
|
||||
{
|
||||
MqlDateTime dt;
|
||||
//--- convert to structure
|
||||
TimeToStruct(value,dt);
|
||||
//--- set
|
||||
Date(dt);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Sets date |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDateTime::Date(const MqlDateTime &value)
|
||||
{
|
||||
day =value.day;
|
||||
mon =value.mon;
|
||||
year=value.year;
|
||||
//--- check if day is correct
|
||||
DayCheck();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Sets time |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDateTime::Time(const datetime value)
|
||||
{
|
||||
MqlDateTime dt;
|
||||
//--- convert to structure
|
||||
TimeToStruct(value,dt);
|
||||
//--- set
|
||||
Time(dt);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Sets time |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDateTime::Time(const MqlDateTime &value)
|
||||
{
|
||||
hour=value.hour;
|
||||
min =value.min;
|
||||
sec =value.sec;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Sets seconds |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDateTime::Sec(const int value)
|
||||
{
|
||||
//--- check and set
|
||||
if(value>=0 && value<60)
|
||||
sec=value;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Sets minutes |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDateTime::Min(const int value)
|
||||
{
|
||||
//--- check and set
|
||||
if(value>=0 && value<60)
|
||||
min=value;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Sets hours |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDateTime::Hour(const int value)
|
||||
{
|
||||
//--- check and set
|
||||
if(value>=0 && value<24)
|
||||
hour=value;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Sets day of month |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDateTime::Day(const int value)
|
||||
{
|
||||
//--- check and set
|
||||
if(value>0 && value<=DaysInMonth())
|
||||
{
|
||||
day=value;
|
||||
//--- check if day is correct
|
||||
DayCheck();
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Sets month |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDateTime::Mon(const int value)
|
||||
{
|
||||
//--- check and set
|
||||
if(value>0 && value<=12)
|
||||
{
|
||||
mon=value;
|
||||
//--- check if day is correct
|
||||
DayCheck();
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Sets year |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDateTime::Year(const int value)
|
||||
{
|
||||
//--- check and set
|
||||
if(value>=1970)
|
||||
{
|
||||
year=value;
|
||||
//--- check if day is correct
|
||||
DayCheck();
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Subtracts specified number of seconds |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDateTime::SecDec(int delta)
|
||||
{
|
||||
//--- if increment is 0 - exit
|
||||
if(delta==0)
|
||||
return;
|
||||
//--- if increment is negative - inverse the operation
|
||||
if(delta<0)
|
||||
{
|
||||
SecInc(-delta);
|
||||
return;
|
||||
}
|
||||
//--- check if subtract from upper number positions
|
||||
if(delta>60)
|
||||
{
|
||||
MinDec(delta/60);
|
||||
delta%=60;
|
||||
}
|
||||
sec-=delta;
|
||||
if(sec<0)
|
||||
{
|
||||
sec+=60;
|
||||
MinDec();
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds specified number of seconds |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDateTime::SecInc(int delta)
|
||||
{
|
||||
//--- if increment is 0 - exit
|
||||
if(delta==0)
|
||||
return;
|
||||
//--- if increment is negative - inverse the operation
|
||||
if(delta<0)
|
||||
{
|
||||
SecDec(-delta);
|
||||
return;
|
||||
}
|
||||
//--- check if add to upper number positions
|
||||
if(delta>60)
|
||||
{
|
||||
MinInc(delta/60);
|
||||
delta%=60;
|
||||
}
|
||||
sec+=delta;
|
||||
if(sec>=60)
|
||||
{
|
||||
sec-=60;
|
||||
MinInc();
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Subtracts specified number of minutes |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDateTime::MinDec(int delta)
|
||||
{
|
||||
//--- if increment is 0 - exit
|
||||
if(delta==0)
|
||||
return;
|
||||
//--- if increment is negative - inverse the operation
|
||||
if(delta<0)
|
||||
{
|
||||
MinInc(-delta);
|
||||
return;
|
||||
}
|
||||
//--- check if subtract from upper number positions
|
||||
if(delta>60)
|
||||
{
|
||||
HourDec(delta/60);
|
||||
delta%=60;
|
||||
}
|
||||
min-=delta;
|
||||
if(min<0)
|
||||
{
|
||||
min+=60;
|
||||
HourDec();
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds specified number of minutes |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDateTime::MinInc(int delta)
|
||||
{
|
||||
//--- if increment is 0 - exit
|
||||
if(delta==0)
|
||||
return;
|
||||
//--- if increment is negative - inverse the operation
|
||||
if(delta<0)
|
||||
{
|
||||
MinDec(-delta);
|
||||
return;
|
||||
}
|
||||
//--- check if add to upper number positions
|
||||
if(delta>60)
|
||||
{
|
||||
HourInc(delta/60);
|
||||
delta%=60;
|
||||
}
|
||||
min+=delta;
|
||||
if(min>=60)
|
||||
{
|
||||
min-=60;
|
||||
HourInc();
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Subtracts specified number of hours |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDateTime::HourDec(int delta)
|
||||
{
|
||||
//--- if increment is 0 - exit
|
||||
if(delta==0)
|
||||
return;
|
||||
//--- if increment is negative - inverse the operation
|
||||
if(delta<0)
|
||||
{
|
||||
HourInc(-delta);
|
||||
return;
|
||||
}
|
||||
//--- check if subtract from upper number positions
|
||||
if(delta>24)
|
||||
{
|
||||
DayDec(delta/24);
|
||||
delta%=24;
|
||||
}
|
||||
hour-=delta;
|
||||
if(hour<0)
|
||||
{
|
||||
hour+=24;
|
||||
DayDec();
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds specified number of hours |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDateTime::HourInc(int delta)
|
||||
{
|
||||
//--- if increment is 0 - exit
|
||||
if(delta==0)
|
||||
return;
|
||||
//--- if increment is negative - inverse the operation
|
||||
if(delta<0)
|
||||
{
|
||||
HourDec(-delta);
|
||||
return;
|
||||
}
|
||||
//--- check if add to upper number positions
|
||||
if(delta>24)
|
||||
{
|
||||
DayInc(delta/24);
|
||||
delta%=24;
|
||||
}
|
||||
hour+=delta;
|
||||
if(hour>=24)
|
||||
{
|
||||
hour-=24;
|
||||
DayInc();
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Subtracts specified number of days |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDateTime::DayDec(int delta)
|
||||
{
|
||||
//--- if increment is 0 - exit
|
||||
if(delta==0)
|
||||
return;
|
||||
//--- if increment is negative - inverse the operation
|
||||
if(delta<0)
|
||||
{
|
||||
DayInc(-delta);
|
||||
return;
|
||||
}
|
||||
//--- uncertain condition, as the number of days in month can differ
|
||||
while(day<=delta)
|
||||
{
|
||||
delta-=day;
|
||||
MonDec();
|
||||
day=DaysInMonth();
|
||||
}
|
||||
day-=delta;
|
||||
//--- check if day is correct
|
||||
DayCheck();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds specified number of days |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDateTime::DayInc(int delta)
|
||||
{
|
||||
//--- if increment is 0 - exit
|
||||
if(delta==0)
|
||||
return;
|
||||
//--- if increment is negative - inverse the operation
|
||||
if(delta<0)
|
||||
{
|
||||
DayDec(-delta);
|
||||
return;
|
||||
}
|
||||
//--- uncertain condition, as the number of days in month can differ
|
||||
while(DaysInMonth()-day<delta)
|
||||
{
|
||||
delta-=DaysInMonth()-day+1;
|
||||
MonInc();
|
||||
day=1;
|
||||
}
|
||||
day+=delta;
|
||||
//--- check if day is correct
|
||||
DayCheck();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Subtracts specified number of months |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDateTime::MonDec(int delta)
|
||||
{
|
||||
//--- if increment is 0 - exit
|
||||
if(delta==0)
|
||||
return;
|
||||
//--- if increment is negative - inverse the operation
|
||||
if(delta<0)
|
||||
{
|
||||
MonInc(-delta);
|
||||
return;
|
||||
}
|
||||
//--- check if subtract from upper number positions
|
||||
if(delta>12)
|
||||
{
|
||||
YearDec(delta/12);
|
||||
delta%=12;
|
||||
}
|
||||
mon-=delta;
|
||||
if(mon<=0)
|
||||
{
|
||||
mon+=12;
|
||||
YearDec();
|
||||
}
|
||||
//--- check if day is correct
|
||||
DayCheck();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds specified number of months |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDateTime::MonInc(int delta)
|
||||
{
|
||||
//--- if increment is 0 - exit
|
||||
if(delta==0)
|
||||
return;
|
||||
//--- if increment is negative - inverse the operation
|
||||
if(delta<0)
|
||||
{
|
||||
MonDec(-delta);
|
||||
return;
|
||||
}
|
||||
//--- check if add to upper number positions
|
||||
if(delta>12)
|
||||
{
|
||||
YearInc(delta/12);
|
||||
delta%=12;
|
||||
}
|
||||
mon+=delta;
|
||||
if(mon>12)
|
||||
{
|
||||
mon-=12;
|
||||
YearInc();
|
||||
}
|
||||
//--- check if day is correct
|
||||
DayCheck();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Subtracts specified number of years |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDateTime::YearDec(int delta)
|
||||
{
|
||||
//--- if increment is 0 - exit
|
||||
if(delta!=0)
|
||||
{
|
||||
year-=delta;
|
||||
//--- check if day is correct
|
||||
DayCheck();
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds specified number of years |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDateTime::YearInc(int delta)
|
||||
{
|
||||
//--- if increment is 0 - exit
|
||||
if(delta!=0)
|
||||
{
|
||||
year+=delta;
|
||||
//--- check if day is correct
|
||||
DayCheck();
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Checks if day number is correct |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDateTime::DayCheck(void)
|
||||
{
|
||||
if(day>DaysInMonth())
|
||||
day=DaysInMonth();
|
||||
//--- this is required to get day of week and day of year
|
||||
TimeToStruct(StructToTime(this),this);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,397 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| AccountInfo.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Object.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CAccountInfo. |
|
||||
//| Appointment: Class for access to account info. |
|
||||
//| Derives from class CObject. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CAccountInfo : public CObject
|
||||
{
|
||||
public:
|
||||
CAccountInfo(void);
|
||||
~CAccountInfo(void);
|
||||
//--- fast access methods to the integer account propertyes
|
||||
long Login(void) const;
|
||||
ENUM_ACCOUNT_TRADE_MODE TradeMode(void) const;
|
||||
string TradeModeDescription(void) const;
|
||||
long Leverage(void) const;
|
||||
ENUM_ACCOUNT_STOPOUT_MODE StopoutMode(void) const;
|
||||
string StopoutModeDescription(void) const;
|
||||
ENUM_ACCOUNT_MARGIN_MODE MarginMode(void) const;
|
||||
string MarginModeDescription(void) const;
|
||||
bool TradeAllowed(void) const;
|
||||
bool TradeExpert(void) const;
|
||||
int LimitOrders(void) const;
|
||||
//--- fast access methods to the double account propertyes
|
||||
double Balance(void) const;
|
||||
double Credit(void) const;
|
||||
double Profit(void) const;
|
||||
double Equity(void) const;
|
||||
double Margin(void) const;
|
||||
double FreeMargin(void) const;
|
||||
double MarginLevel(void) const;
|
||||
double MarginCall(void) const;
|
||||
double MarginStopOut(void) const;
|
||||
//--- fast access methods to the string account propertyes
|
||||
string Name(void) const;
|
||||
string Server(void) const;
|
||||
string Currency(void) const;
|
||||
string Company(void) const;
|
||||
//--- access methods to the API MQL5 functions
|
||||
long InfoInteger(const ENUM_ACCOUNT_INFO_INTEGER prop_id) const;
|
||||
double InfoDouble(const ENUM_ACCOUNT_INFO_DOUBLE prop_id) const;
|
||||
string InfoString(const ENUM_ACCOUNT_INFO_STRING prop_id) const;
|
||||
//--- checks
|
||||
double OrderProfitCheck(const string symbol,const ENUM_ORDER_TYPE trade_operation,
|
||||
const double volume,const double price_open,const double price_close) const;
|
||||
double MarginCheck(const string symbol,const ENUM_ORDER_TYPE trade_operation,
|
||||
const double volume,const double price) const;
|
||||
double FreeMarginCheck(const string symbol,const ENUM_ORDER_TYPE trade_operation,
|
||||
const double volume,const double price) const;
|
||||
double MaxLotCheck(const string symbol,const ENUM_ORDER_TYPE trade_operation,
|
||||
const double price,const double percent=100) const;
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CAccountInfo::CAccountInfo(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CAccountInfo::~CAccountInfo(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ACCOUNT_LOGIN" |
|
||||
//+------------------------------------------------------------------+
|
||||
long CAccountInfo::Login(void) const
|
||||
{
|
||||
return(AccountInfoInteger(ACCOUNT_LOGIN));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ACCOUNT_TRADE_MODE" |
|
||||
//+------------------------------------------------------------------+
|
||||
ENUM_ACCOUNT_TRADE_MODE CAccountInfo::TradeMode(void) const
|
||||
{
|
||||
return((ENUM_ACCOUNT_TRADE_MODE)AccountInfoInteger(ACCOUNT_TRADE_MODE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ACCOUNT_TRADE_MODE" as string |
|
||||
//+------------------------------------------------------------------+
|
||||
string CAccountInfo::TradeModeDescription(void) const
|
||||
{
|
||||
string str;
|
||||
//---
|
||||
switch(TradeMode())
|
||||
{
|
||||
case ACCOUNT_TRADE_MODE_DEMO:
|
||||
str="Demo trading account";
|
||||
break;
|
||||
case ACCOUNT_TRADE_MODE_CONTEST:
|
||||
str="Contest trading account";
|
||||
break;
|
||||
case ACCOUNT_TRADE_MODE_REAL:
|
||||
str="Real trading account";
|
||||
break;
|
||||
default:
|
||||
str="Unknown trade account";
|
||||
}
|
||||
//---
|
||||
return(str);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ACCOUNT_LEVERAGE" |
|
||||
//+------------------------------------------------------------------+
|
||||
long CAccountInfo::Leverage(void) const
|
||||
{
|
||||
return(AccountInfoInteger(ACCOUNT_LEVERAGE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ACCOUNT_MARGIN_SO_MODE" |
|
||||
//+------------------------------------------------------------------+
|
||||
ENUM_ACCOUNT_STOPOUT_MODE CAccountInfo::StopoutMode(void) const
|
||||
{
|
||||
return((ENUM_ACCOUNT_STOPOUT_MODE)AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ACCOUNT_MARGIN_SO_MODE" as string |
|
||||
//+------------------------------------------------------------------+
|
||||
string CAccountInfo::StopoutModeDescription(void) const
|
||||
{
|
||||
string str;
|
||||
//---
|
||||
switch(StopoutMode())
|
||||
{
|
||||
case ACCOUNT_STOPOUT_MODE_PERCENT:
|
||||
str="Level is specified in percentage";
|
||||
break;
|
||||
case ACCOUNT_STOPOUT_MODE_MONEY:
|
||||
str="Level is specified in money";
|
||||
break;
|
||||
default:
|
||||
str="Unknown stopout mode";
|
||||
}
|
||||
//---
|
||||
return(str);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ACCOUNT_MARGIN_MODE" |
|
||||
//+------------------------------------------------------------------+
|
||||
ENUM_ACCOUNT_MARGIN_MODE CAccountInfo::MarginMode(void) const
|
||||
{
|
||||
return((ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ACCOUNT_MARGIN_MODE" as string |
|
||||
//+------------------------------------------------------------------+
|
||||
string CAccountInfo::MarginModeDescription(void) const
|
||||
{
|
||||
string str;
|
||||
//---
|
||||
switch(MarginMode())
|
||||
{
|
||||
case ACCOUNT_MARGIN_MODE_RETAIL_NETTING:
|
||||
str="Netting";
|
||||
break;
|
||||
case ACCOUNT_MARGIN_MODE_EXCHANGE:
|
||||
str="Exchange";
|
||||
break;
|
||||
case ACCOUNT_MARGIN_MODE_RETAIL_HEDGING:
|
||||
str="Hedging";
|
||||
break;
|
||||
default:
|
||||
str="Unknown margin mode";
|
||||
}
|
||||
//---
|
||||
return(str);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ACCOUNT_TRADE_ALLOWED" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CAccountInfo::TradeAllowed(void) const
|
||||
{
|
||||
return((bool)AccountInfoInteger(ACCOUNT_TRADE_ALLOWED));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ACCOUNT_TRADE_EXPERT" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CAccountInfo::TradeExpert(void) const
|
||||
{
|
||||
return((bool)AccountInfoInteger(ACCOUNT_TRADE_EXPERT));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ACCOUNT_LIMIT_ORDERS" |
|
||||
//+------------------------------------------------------------------+
|
||||
int CAccountInfo::LimitOrders(void) const
|
||||
{
|
||||
return((int)AccountInfoInteger(ACCOUNT_LIMIT_ORDERS));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ACCOUNT_BALANCE" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CAccountInfo::Balance(void) const
|
||||
{
|
||||
return(AccountInfoDouble(ACCOUNT_BALANCE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ACCOUNT_CREDIT" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CAccountInfo::Credit(void) const
|
||||
{
|
||||
return(AccountInfoDouble(ACCOUNT_CREDIT));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ACCOUNT_PROFIT" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CAccountInfo::Profit(void) const
|
||||
{
|
||||
return(AccountInfoDouble(ACCOUNT_PROFIT));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ACCOUNT_EQUITY" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CAccountInfo::Equity(void) const
|
||||
{
|
||||
return(AccountInfoDouble(ACCOUNT_EQUITY));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ACCOUNT_MARGIN" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CAccountInfo::Margin(void) const
|
||||
{
|
||||
return(AccountInfoDouble(ACCOUNT_MARGIN));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ACCOUNT_MARGIN_FREE" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CAccountInfo::FreeMargin(void) const
|
||||
{
|
||||
return(AccountInfoDouble(ACCOUNT_MARGIN_FREE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ACCOUNT_MARGIN_LEVEL" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CAccountInfo::MarginLevel(void) const
|
||||
{
|
||||
return(AccountInfoDouble(ACCOUNT_MARGIN_LEVEL));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ACCOUNT_MARGIN_SO_CALL" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CAccountInfo::MarginCall(void) const
|
||||
{
|
||||
return(AccountInfoDouble(ACCOUNT_MARGIN_SO_CALL));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ACCOUNT_MARGIN_SO_SO" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CAccountInfo::MarginStopOut(void) const
|
||||
{
|
||||
return(AccountInfoDouble(ACCOUNT_MARGIN_SO_SO));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ACCOUNT_NAME" |
|
||||
//+------------------------------------------------------------------+
|
||||
string CAccountInfo::Name(void) const
|
||||
{
|
||||
return(AccountInfoString(ACCOUNT_NAME));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ACCOUNT_SERVER" |
|
||||
//+------------------------------------------------------------------+
|
||||
string CAccountInfo::Server(void) const
|
||||
{
|
||||
return(AccountInfoString(ACCOUNT_SERVER));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ACCOUNT_CURRENCY" |
|
||||
//+------------------------------------------------------------------+
|
||||
string CAccountInfo::Currency(void) const
|
||||
{
|
||||
return(AccountInfoString(ACCOUNT_CURRENCY));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ACCOUNT_COMPANY" |
|
||||
//+------------------------------------------------------------------+
|
||||
string CAccountInfo::Company(void) const
|
||||
{
|
||||
return(AccountInfoString(ACCOUNT_COMPANY));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access functions AccountInfoInteger(...) |
|
||||
//+------------------------------------------------------------------+
|
||||
long CAccountInfo::InfoInteger(const ENUM_ACCOUNT_INFO_INTEGER prop_id) const
|
||||
{
|
||||
return(AccountInfoInteger(prop_id));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access functions AccountInfoDouble(...) |
|
||||
//+------------------------------------------------------------------+
|
||||
double CAccountInfo::InfoDouble(const ENUM_ACCOUNT_INFO_DOUBLE prop_id) const
|
||||
{
|
||||
return(AccountInfoDouble(prop_id));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access functions AccountInfoString(...) |
|
||||
//+------------------------------------------------------------------+
|
||||
string CAccountInfo::InfoString(const ENUM_ACCOUNT_INFO_STRING prop_id) const
|
||||
{
|
||||
return(AccountInfoString(prop_id));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access functions OrderCalcProfit(...). |
|
||||
//| INPUT: name - symbol name, |
|
||||
//| trade_operation - trade operation, |
|
||||
//| volume - volume of the opening position, |
|
||||
//| price_open - price of the opening position, |
|
||||
//| price_close - price of the closing position. |
|
||||
//+------------------------------------------------------------------+
|
||||
double CAccountInfo::OrderProfitCheck(const string symbol,const ENUM_ORDER_TYPE trade_operation,
|
||||
const double volume,const double price_open,const double price_close) const
|
||||
{
|
||||
double profit=EMPTY_VALUE;
|
||||
//---
|
||||
if(!OrderCalcProfit(trade_operation,symbol,volume,price_open,price_close,profit))
|
||||
return(EMPTY_VALUE);
|
||||
//---
|
||||
return(profit);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access functions OrderCalcMargin(...). |
|
||||
//| INPUT: name - symbol name, |
|
||||
//| trade_operation - trade operation, |
|
||||
//| volume - volume of the opening position, |
|
||||
//| price - price of the opening position. |
|
||||
//+------------------------------------------------------------------+
|
||||
double CAccountInfo::MarginCheck(const string symbol,const ENUM_ORDER_TYPE trade_operation,
|
||||
const double volume,const double price) const
|
||||
{
|
||||
double margin=EMPTY_VALUE;
|
||||
//---
|
||||
if(!OrderCalcMargin(trade_operation,symbol,volume,price,margin))
|
||||
return(EMPTY_VALUE);
|
||||
//---
|
||||
return(margin);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access functions OrderCalcMargin(...). |
|
||||
//| INPUT: name - symbol name, |
|
||||
//| trade_operation - trade operation, |
|
||||
//| volume - volume of the opening position, |
|
||||
//| price - price of the opening position. |
|
||||
//+------------------------------------------------------------------+
|
||||
double CAccountInfo::FreeMarginCheck(const string symbol,const ENUM_ORDER_TYPE trade_operation,
|
||||
const double volume,const double price) const
|
||||
{
|
||||
return(FreeMargin()-MarginCheck(symbol,trade_operation,volume,price));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access functions OrderCalcMargin(...). |
|
||||
//| INPUT: name - symbol name, |
|
||||
//| trade_operation - trade operation, |
|
||||
//| price - price of the opening position, |
|
||||
//| percent - percent of available margin [1-100%]. |
|
||||
//+------------------------------------------------------------------+
|
||||
double CAccountInfo::MaxLotCheck(const string symbol,const ENUM_ORDER_TYPE trade_operation,
|
||||
const double price,const double percent) const
|
||||
{
|
||||
double margin=0.0;
|
||||
//--- checks
|
||||
if(symbol=="" || price<=0.0 || percent<1 || percent>100)
|
||||
{
|
||||
Print("CAccountInfo::MaxLotCheck invalid parameters");
|
||||
return(0.0);
|
||||
}
|
||||
//--- calculate margin requirements for 1 lot
|
||||
if(!OrderCalcMargin(trade_operation,symbol,1.0,price,margin) || margin<0.0)
|
||||
{
|
||||
Print("CAccountInfo::MaxLotCheck margin calculation failed");
|
||||
return(0.0);
|
||||
}
|
||||
//---
|
||||
if(margin==0.0) // for pending orders
|
||||
return(SymbolInfoDouble(symbol,SYMBOL_VOLUME_MAX));
|
||||
//--- calculate maximum volume
|
||||
double volume=NormalizeDouble(FreeMargin()*percent/100.0/margin,2);
|
||||
//--- normalize and check limits
|
||||
double stepvol=SymbolInfoDouble(symbol,SYMBOL_VOLUME_STEP);
|
||||
if(stepvol>0.0)
|
||||
volume=stepvol*MathFloor(volume/stepvol);
|
||||
//---
|
||||
double minvol=SymbolInfoDouble(symbol,SYMBOL_VOLUME_MIN);
|
||||
if(volume<minvol)
|
||||
volume=0.0;
|
||||
//---
|
||||
double maxvol=SymbolInfoDouble(symbol,SYMBOL_VOLUME_MAX);
|
||||
if(volume>maxvol)
|
||||
volume=maxvol;
|
||||
//--- return volume
|
||||
return(volume);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,430 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| DealInfo.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Object.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CDealInfo. |
|
||||
//| Appointment: Class for access to history deal info. |
|
||||
//| Derives from class CObject. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CDealInfo : public CObject
|
||||
{
|
||||
protected:
|
||||
ulong m_ticket; // ticket of history order
|
||||
|
||||
public:
|
||||
CDealInfo(void);
|
||||
~CDealInfo(void);
|
||||
//--- methods of access to protected data
|
||||
void Ticket(const ulong ticket) { m_ticket=ticket; }
|
||||
ulong Ticket(void) const { return(m_ticket); }
|
||||
//--- fast access methods to the integer position propertyes
|
||||
long Order(void) const;
|
||||
datetime Time(void) const;
|
||||
ulong TimeMsc(void) const;
|
||||
ENUM_DEAL_TYPE DealType(void) const;
|
||||
string TypeDescription(void) const;
|
||||
ENUM_DEAL_ENTRY Entry(void) const;
|
||||
string EntryDescription(void) const;
|
||||
long Magic(void) const;
|
||||
long PositionId(void) const;
|
||||
//--- fast access methods to the double position propertyes
|
||||
double Volume(void) const;
|
||||
double Price(void) const;
|
||||
double Commission(void) const;
|
||||
double Swap(void) const;
|
||||
double Profit(void) const;
|
||||
//--- fast access methods to the string position propertyes
|
||||
string Symbol(void) const;
|
||||
string Comment(void) const;
|
||||
string ExternalId(void) const;
|
||||
//--- access methods to the API MQL5 functions
|
||||
bool InfoInteger(ENUM_DEAL_PROPERTY_INTEGER prop_id,long &var) const;
|
||||
bool InfoDouble(ENUM_DEAL_PROPERTY_DOUBLE prop_id,double &var) const;
|
||||
bool InfoString(ENUM_DEAL_PROPERTY_STRING prop_id,string &var) const;
|
||||
//--- info methods
|
||||
string FormatAction(string &str,const uint action) const;
|
||||
string FormatEntry(string &str,const uint entry) const;
|
||||
string FormatDeal(string &str) const;
|
||||
//--- method for select deal
|
||||
bool SelectByIndex(const int index);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CDealInfo::CDealInfo(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CDealInfo::~CDealInfo(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "DEAL_ORDER" |
|
||||
//+------------------------------------------------------------------+
|
||||
long CDealInfo::Order(void) const
|
||||
{
|
||||
return(HistoryDealGetInteger(m_ticket,DEAL_ORDER));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "DEAL_TIME" |
|
||||
//+------------------------------------------------------------------+
|
||||
datetime CDealInfo::Time(void) const
|
||||
{
|
||||
return((datetime)HistoryDealGetInteger(m_ticket,DEAL_TIME));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "DEAL_TIME_MSC" |
|
||||
//+------------------------------------------------------------------+
|
||||
ulong CDealInfo::TimeMsc(void) const
|
||||
{
|
||||
return(HistoryDealGetInteger(m_ticket,DEAL_TIME_MSC));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "DEAL_TYPE" |
|
||||
//+------------------------------------------------------------------+
|
||||
ENUM_DEAL_TYPE CDealInfo::DealType(void) const
|
||||
{
|
||||
return((ENUM_DEAL_TYPE)HistoryDealGetInteger(m_ticket,DEAL_TYPE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "DEAL_TYPE" as string |
|
||||
//+------------------------------------------------------------------+
|
||||
string CDealInfo::TypeDescription(void) const
|
||||
{
|
||||
string str;
|
||||
//---
|
||||
switch(DealType())
|
||||
{
|
||||
case DEAL_TYPE_BUY:
|
||||
str="Buy type";
|
||||
break;
|
||||
case DEAL_TYPE_SELL:
|
||||
str="Sell type";
|
||||
break;
|
||||
case DEAL_TYPE_BALANCE:
|
||||
str="Balance type";
|
||||
break;
|
||||
case DEAL_TYPE_CREDIT:
|
||||
str="Credit type";
|
||||
break;
|
||||
case DEAL_TYPE_CHARGE:
|
||||
str="Charge type";
|
||||
break;
|
||||
case DEAL_TYPE_CORRECTION:
|
||||
str="Correction type";
|
||||
break;
|
||||
case DEAL_TYPE_BONUS:
|
||||
str="Bonus type";
|
||||
break;
|
||||
case DEAL_TYPE_COMMISSION:
|
||||
str="Commission type";
|
||||
break;
|
||||
case DEAL_TYPE_COMMISSION_DAILY:
|
||||
str="Daily Commission type";
|
||||
break;
|
||||
case DEAL_TYPE_COMMISSION_MONTHLY:
|
||||
str="Monthly Commission type";
|
||||
break;
|
||||
case DEAL_TYPE_COMMISSION_AGENT_DAILY:
|
||||
str="Daily Agent Commission type";
|
||||
break;
|
||||
case DEAL_TYPE_COMMISSION_AGENT_MONTHLY:
|
||||
str="Monthly Agent Commission type";
|
||||
break;
|
||||
case DEAL_TYPE_INTEREST:
|
||||
str="Interest Rate type";
|
||||
break;
|
||||
case DEAL_TYPE_BUY_CANCELED:
|
||||
str="Canceled Buy type";
|
||||
break;
|
||||
case DEAL_TYPE_SELL_CANCELED:
|
||||
str="Canceled Sell type";
|
||||
break;
|
||||
default:
|
||||
str="Unknown type";
|
||||
}
|
||||
//---
|
||||
return(str);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "DEAL_ENTRY" |
|
||||
//+------------------------------------------------------------------+
|
||||
ENUM_DEAL_ENTRY CDealInfo::Entry(void) const
|
||||
{
|
||||
return((ENUM_DEAL_ENTRY)HistoryDealGetInteger(m_ticket,DEAL_ENTRY));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "DEAL_ENTRY" as string |
|
||||
//+------------------------------------------------------------------+
|
||||
string CDealInfo::EntryDescription(void) const
|
||||
{
|
||||
string str;
|
||||
//---
|
||||
switch(CDealInfo::Entry())
|
||||
{
|
||||
case DEAL_ENTRY_IN:
|
||||
str="In entry";
|
||||
break;
|
||||
case DEAL_ENTRY_OUT:
|
||||
str="Out entry";
|
||||
break;
|
||||
case DEAL_ENTRY_INOUT:
|
||||
str="InOut entry";
|
||||
break;
|
||||
case DEAL_ENTRY_STATE:
|
||||
str="Status record";
|
||||
break;
|
||||
case DEAL_ENTRY_OUT_BY:
|
||||
str="Out By entry";
|
||||
break;
|
||||
default:
|
||||
str="Unknown entry";
|
||||
}
|
||||
//---
|
||||
return(str);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "DEAL_MAGIC" |
|
||||
//+------------------------------------------------------------------+
|
||||
long CDealInfo::Magic(void) const
|
||||
{
|
||||
return(HistoryDealGetInteger(m_ticket,DEAL_MAGIC));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "DEAL_POSITION_ID" |
|
||||
//+------------------------------------------------------------------+
|
||||
long CDealInfo::PositionId(void) const
|
||||
{
|
||||
return(HistoryDealGetInteger(m_ticket,DEAL_POSITION_ID));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "DEAL_VOLUME" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CDealInfo::Volume(void) const
|
||||
{
|
||||
return(HistoryDealGetDouble(m_ticket,DEAL_VOLUME));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "DEAL_PRICE_OPEN" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CDealInfo::Price(void) const
|
||||
{
|
||||
return(HistoryDealGetDouble(m_ticket,DEAL_PRICE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "DEAL_COMMISSION" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CDealInfo::Commission(void) const
|
||||
{
|
||||
return(HistoryDealGetDouble(m_ticket,DEAL_COMMISSION));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "DEAL_SWAP" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CDealInfo::Swap(void) const
|
||||
{
|
||||
return(HistoryDealGetDouble(m_ticket,DEAL_SWAP));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "DEAL_PROFIT" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CDealInfo::Profit(void) const
|
||||
{
|
||||
return(HistoryDealGetDouble(m_ticket,DEAL_PROFIT));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "DEAL_SYMBOL" |
|
||||
//+------------------------------------------------------------------+
|
||||
string CDealInfo::Symbol(void) const
|
||||
{
|
||||
return(HistoryDealGetString(m_ticket,DEAL_SYMBOL));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "DEAL_COMMENT" |
|
||||
//+------------------------------------------------------------------+
|
||||
string CDealInfo::Comment(void) const
|
||||
{
|
||||
return(HistoryDealGetString(m_ticket,DEAL_COMMENT));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "DEAL_EXTERNAL_ID" |
|
||||
//+------------------------------------------------------------------+
|
||||
string CDealInfo::ExternalId(void) const
|
||||
{
|
||||
return(HistoryDealGetString(m_ticket,DEAL_EXTERNAL_ID));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access functions HistoryDealGetInteger(...) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDealInfo::InfoInteger(ENUM_DEAL_PROPERTY_INTEGER prop_id,long &var) const
|
||||
{
|
||||
return(HistoryDealGetInteger(m_ticket,prop_id,var));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access functions HistoryDealGetDouble(...) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDealInfo::InfoDouble(ENUM_DEAL_PROPERTY_DOUBLE prop_id,double &var) const
|
||||
{
|
||||
return(HistoryDealGetDouble(m_ticket,prop_id,var));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access functions HistoryDealGetString(...) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDealInfo::InfoString(ENUM_DEAL_PROPERTY_STRING prop_id,string &var) const
|
||||
{
|
||||
return(HistoryDealGetString(m_ticket,prop_id,var));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Converths the type of a deal to text |
|
||||
//+------------------------------------------------------------------+
|
||||
string CDealInfo::FormatAction(string &str,const uint action) const
|
||||
{
|
||||
//--- see the type
|
||||
switch(action)
|
||||
{
|
||||
case DEAL_TYPE_BUY:
|
||||
str="buy";
|
||||
break;
|
||||
case DEAL_TYPE_SELL:
|
||||
str="sell";
|
||||
break;
|
||||
case DEAL_TYPE_BALANCE:
|
||||
str="balance";
|
||||
break;
|
||||
case DEAL_TYPE_CREDIT:
|
||||
str="credit";
|
||||
break;
|
||||
case DEAL_TYPE_CHARGE:
|
||||
str="charge";
|
||||
break;
|
||||
case DEAL_TYPE_CORRECTION:
|
||||
str="correction";
|
||||
break;
|
||||
case DEAL_TYPE_BONUS:
|
||||
str="bonus";
|
||||
break;
|
||||
case DEAL_TYPE_COMMISSION:
|
||||
str="commission";
|
||||
break;
|
||||
case DEAL_TYPE_COMMISSION_DAILY:
|
||||
str="daily commission";
|
||||
break;
|
||||
case DEAL_TYPE_COMMISSION_MONTHLY:
|
||||
str="monthly commission";
|
||||
break;
|
||||
case DEAL_TYPE_COMMISSION_AGENT_DAILY:
|
||||
str="daily agent commission";
|
||||
break;
|
||||
case DEAL_TYPE_COMMISSION_AGENT_MONTHLY:
|
||||
str="monthly agent commission";
|
||||
break;
|
||||
case DEAL_TYPE_INTEREST:
|
||||
str="interest rate";
|
||||
break;
|
||||
case DEAL_TYPE_BUY_CANCELED:
|
||||
str="canceled buy";
|
||||
break;
|
||||
case DEAL_TYPE_SELL_CANCELED:
|
||||
str="canceled sell";
|
||||
break;
|
||||
default:
|
||||
str="unknown deal type "+(string)action;
|
||||
}
|
||||
//--- return the result
|
||||
return(str);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Converts the deal direction to text |
|
||||
//+------------------------------------------------------------------+
|
||||
string CDealInfo::FormatEntry(string &str,const uint entry) const
|
||||
{
|
||||
//--- see the type
|
||||
switch(entry)
|
||||
{
|
||||
case DEAL_ENTRY_IN:
|
||||
str="in";
|
||||
break;
|
||||
case DEAL_ENTRY_OUT:
|
||||
str="out";
|
||||
break;
|
||||
case DEAL_ENTRY_INOUT:
|
||||
str="in/out";
|
||||
break;
|
||||
case DEAL_ENTRY_OUT_BY:
|
||||
str="out by";
|
||||
break;
|
||||
default:
|
||||
str="unknown deal entry "+(string)entry;
|
||||
}
|
||||
//--- return the result
|
||||
return(str);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Converts the deal parameters to text |
|
||||
//+------------------------------------------------------------------+
|
||||
string CDealInfo::FormatDeal(string &str) const
|
||||
{
|
||||
string type;
|
||||
long tmp_long;
|
||||
//--- set up
|
||||
string symbol_name=this.Symbol();
|
||||
int digits=_Digits;
|
||||
if(SymbolInfoInteger(symbol_name,SYMBOL_DIGITS,tmp_long))
|
||||
digits=(int)tmp_long;
|
||||
//--- form the description of the deal
|
||||
switch(DealType())
|
||||
{
|
||||
//--- Buy-Sell
|
||||
case DEAL_TYPE_BUY:
|
||||
case DEAL_TYPE_SELL:
|
||||
str=StringFormat("#%I64u %s %s %s at %s",
|
||||
Ticket(),
|
||||
FormatAction(type,DealType()),
|
||||
DoubleToString(Volume(),2),
|
||||
symbol_name,
|
||||
DoubleToString(Price(),digits));
|
||||
break;
|
||||
|
||||
//--- balance operations
|
||||
case DEAL_TYPE_BALANCE:
|
||||
case DEAL_TYPE_CREDIT:
|
||||
case DEAL_TYPE_CHARGE:
|
||||
case DEAL_TYPE_CORRECTION:
|
||||
case DEAL_TYPE_BONUS:
|
||||
case DEAL_TYPE_COMMISSION:
|
||||
case DEAL_TYPE_COMMISSION_DAILY:
|
||||
case DEAL_TYPE_COMMISSION_MONTHLY:
|
||||
case DEAL_TYPE_COMMISSION_AGENT_DAILY:
|
||||
case DEAL_TYPE_COMMISSION_AGENT_MONTHLY:
|
||||
case DEAL_TYPE_INTEREST:
|
||||
str=StringFormat("#%I64u %s %s [%s]",
|
||||
Ticket(),
|
||||
FormatAction(type,DealType()),
|
||||
DoubleToString(Profit(),2),
|
||||
this.Comment());
|
||||
break;
|
||||
|
||||
default:
|
||||
str="unknown deal type "+(string)DealType();
|
||||
}
|
||||
//--- return the result
|
||||
return(str);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Select a deal on the index |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDealInfo::SelectByIndex(const int index)
|
||||
{
|
||||
ulong ticket=HistoryDealGetTicket(index);
|
||||
if(ticket==0)
|
||||
return(false);
|
||||
Ticket(ticket);
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,472 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| HistoryOrderInfo.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Object.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CHistoryOrderInfo. |
|
||||
//| Appointment: Class for access to history order info. |
|
||||
//| Derives from class CObject. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CHistoryOrderInfo : public CObject
|
||||
{
|
||||
protected:
|
||||
ulong m_ticket; // ticket of history order
|
||||
public:
|
||||
CHistoryOrderInfo(void);
|
||||
~CHistoryOrderInfo(void);
|
||||
//--- methods of access to protected data
|
||||
void Ticket(const ulong ticket) { m_ticket=ticket; }
|
||||
ulong Ticket(void) const { return(m_ticket); }
|
||||
//--- fast access methods to the integer order propertyes
|
||||
datetime TimeSetup(void) const;
|
||||
ulong TimeSetupMsc(void) const;
|
||||
datetime TimeDone(void) const;
|
||||
ulong TimeDoneMsc(void) const;
|
||||
ENUM_ORDER_TYPE OrderType(void) const;
|
||||
string TypeDescription(void) const;
|
||||
ENUM_ORDER_STATE State(void) const;
|
||||
string StateDescription(void) const;
|
||||
datetime TimeExpiration(void) const;
|
||||
ENUM_ORDER_TYPE_FILLING TypeFilling(void) const;
|
||||
string TypeFillingDescription(void) const;
|
||||
ENUM_ORDER_TYPE_TIME TypeTime(void) const;
|
||||
string TypeTimeDescription(void) const;
|
||||
long Magic(void) const;
|
||||
long PositionId(void) const;
|
||||
long PositionById(void) const;
|
||||
//--- fast access methods to the double order propertyes
|
||||
double VolumeInitial(void) const;
|
||||
double VolumeCurrent(void) const;
|
||||
double PriceOpen(void) const;
|
||||
double StopLoss(void) const;
|
||||
double TakeProfit(void) const;
|
||||
double PriceCurrent(void) const;
|
||||
double PriceStopLimit(void) const;
|
||||
//--- fast access methods to the string order propertyes
|
||||
string Symbol(void) const;
|
||||
string Comment(void) const;
|
||||
string ExternalId(void) const;
|
||||
//--- access methods to the API MQL5 functions
|
||||
bool InfoInteger(const ENUM_ORDER_PROPERTY_INTEGER prop_id,long &var) const;
|
||||
bool InfoDouble(const ENUM_ORDER_PROPERTY_DOUBLE prop_id,double &var) const;
|
||||
bool InfoString(const ENUM_ORDER_PROPERTY_STRING prop_id,string &var) const;
|
||||
//--- info methods
|
||||
string FormatType(string &str,const uint type) const;
|
||||
string FormatStatus(string &str,const uint status) const;
|
||||
string FormatTypeFilling(string &str,const uint type) const;
|
||||
string FormatTypeTime(string &str,const uint type) const;
|
||||
string FormatOrder(string &str) const;
|
||||
string FormatPrice(string &str,const double price_order,const double price_trigger,const uint digits) const;
|
||||
//--- method for select history order
|
||||
bool SelectByIndex(const int index);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CHistoryOrderInfo::CHistoryOrderInfo(void) : m_ticket(0)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CHistoryOrderInfo::~CHistoryOrderInfo(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_TIME_SETUP" |
|
||||
//+------------------------------------------------------------------+
|
||||
datetime CHistoryOrderInfo::TimeSetup(void) const
|
||||
{
|
||||
return((datetime)HistoryOrderGetInteger(m_ticket,ORDER_TIME_SETUP));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_TIME_SETUP_MSC" |
|
||||
//+------------------------------------------------------------------+
|
||||
ulong CHistoryOrderInfo::TimeSetupMsc(void) const
|
||||
{
|
||||
return(HistoryOrderGetInteger(m_ticket,ORDER_TIME_SETUP_MSC));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_TIME_DONE" |
|
||||
//+------------------------------------------------------------------+
|
||||
datetime CHistoryOrderInfo::TimeDone(void) const
|
||||
{
|
||||
return((datetime)HistoryOrderGetInteger(m_ticket,ORDER_TIME_DONE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_TIME_DONE_MSC" |
|
||||
//+------------------------------------------------------------------+
|
||||
ulong CHistoryOrderInfo::TimeDoneMsc(void) const
|
||||
{
|
||||
return(HistoryOrderGetInteger(m_ticket,ORDER_TIME_DONE_MSC));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_TYPE" |
|
||||
//+------------------------------------------------------------------+
|
||||
ENUM_ORDER_TYPE CHistoryOrderInfo::OrderType(void) const
|
||||
{
|
||||
return((ENUM_ORDER_TYPE)HistoryOrderGetInteger(m_ticket,ORDER_TYPE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_TYPE" as string |
|
||||
//+------------------------------------------------------------------+
|
||||
string CHistoryOrderInfo::TypeDescription(void) const
|
||||
{
|
||||
string str;
|
||||
//---
|
||||
return(FormatType(str,OrderType()));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_STATE" |
|
||||
//+------------------------------------------------------------------+
|
||||
ENUM_ORDER_STATE CHistoryOrderInfo::State(void) const
|
||||
{
|
||||
return((ENUM_ORDER_STATE)HistoryOrderGetInteger(m_ticket,ORDER_STATE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_STATE" as string |
|
||||
//+------------------------------------------------------------------+
|
||||
string CHistoryOrderInfo::StateDescription(void) const
|
||||
{
|
||||
string str;
|
||||
//---
|
||||
return(FormatStatus(str,State()));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_TIME_EXPIRATION" |
|
||||
//+------------------------------------------------------------------+
|
||||
datetime CHistoryOrderInfo::TimeExpiration(void) const
|
||||
{
|
||||
return((datetime)HistoryOrderGetInteger(m_ticket,ORDER_TIME_EXPIRATION));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_TYPE_FILLING" |
|
||||
//+------------------------------------------------------------------+
|
||||
ENUM_ORDER_TYPE_FILLING CHistoryOrderInfo::TypeFilling(void) const
|
||||
{
|
||||
return((ENUM_ORDER_TYPE_FILLING)HistoryOrderGetInteger(m_ticket,ORDER_TYPE_FILLING));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_TYPE_FILLING" as string |
|
||||
//+------------------------------------------------------------------+
|
||||
string CHistoryOrderInfo::TypeFillingDescription(void) const
|
||||
{
|
||||
string str;
|
||||
//---
|
||||
return(FormatTypeFilling(str,TypeFilling()));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_TYPE_TIME" |
|
||||
//+------------------------------------------------------------------+
|
||||
ENUM_ORDER_TYPE_TIME CHistoryOrderInfo::TypeTime(void) const
|
||||
{
|
||||
return((ENUM_ORDER_TYPE_TIME)HistoryOrderGetInteger(m_ticket,ORDER_TYPE_TIME));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_TYPE_TIME" as string |
|
||||
//+------------------------------------------------------------------+
|
||||
string CHistoryOrderInfo::TypeTimeDescription(void) const
|
||||
{
|
||||
string str;
|
||||
//---
|
||||
return(FormatTypeTime(str,TypeTime()));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_EXPERT" |
|
||||
//+------------------------------------------------------------------+
|
||||
long CHistoryOrderInfo::Magic(void) const
|
||||
{
|
||||
return(HistoryOrderGetInteger(m_ticket,ORDER_MAGIC));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_POSITION_ID" |
|
||||
//+------------------------------------------------------------------+
|
||||
long CHistoryOrderInfo::PositionId(void) const
|
||||
{
|
||||
return(HistoryOrderGetInteger(m_ticket,ORDER_POSITION_ID));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_POSITION_BY_ID" |
|
||||
//+------------------------------------------------------------------+
|
||||
long CHistoryOrderInfo::PositionById(void) const
|
||||
{
|
||||
return(HistoryOrderGetInteger(m_ticket,ORDER_POSITION_BY_ID));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_VOLUME_INITIAL" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CHistoryOrderInfo::VolumeInitial(void) const
|
||||
{
|
||||
return(HistoryOrderGetDouble(m_ticket,ORDER_VOLUME_INITIAL));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_VOLUME_CURRENT" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CHistoryOrderInfo::VolumeCurrent(void) const
|
||||
{
|
||||
return(HistoryOrderGetDouble(m_ticket,ORDER_VOLUME_CURRENT));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_PRICE_OPEN" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CHistoryOrderInfo::PriceOpen(void) const
|
||||
{
|
||||
return(HistoryOrderGetDouble(m_ticket,ORDER_PRICE_OPEN));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_SL" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CHistoryOrderInfo::StopLoss(void) const
|
||||
{
|
||||
return(HistoryOrderGetDouble(m_ticket,ORDER_SL));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_TP" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CHistoryOrderInfo::TakeProfit(void) const
|
||||
{
|
||||
return(HistoryOrderGetDouble(m_ticket,ORDER_TP));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_PRICE_CURRENT" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CHistoryOrderInfo::PriceCurrent(void) const
|
||||
{
|
||||
return(HistoryOrderGetDouble(m_ticket,ORDER_PRICE_CURRENT));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_PRICE_STOPLIMIT" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CHistoryOrderInfo::PriceStopLimit(void) const
|
||||
{
|
||||
return(HistoryOrderGetDouble(m_ticket,ORDER_PRICE_STOPLIMIT));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_SYMBOL" |
|
||||
//+------------------------------------------------------------------+
|
||||
string CHistoryOrderInfo::Symbol(void) const
|
||||
{
|
||||
return(HistoryOrderGetString(m_ticket,ORDER_SYMBOL));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_COMMENT" |
|
||||
//+------------------------------------------------------------------+
|
||||
string CHistoryOrderInfo::Comment(void) const
|
||||
{
|
||||
return(HistoryOrderGetString(m_ticket,ORDER_COMMENT));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_EXTERNAL_ID" |
|
||||
//+------------------------------------------------------------------+
|
||||
string CHistoryOrderInfo::ExternalId(void) const
|
||||
{
|
||||
return(HistoryOrderGetString(m_ticket,ORDER_EXTERNAL_ID));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access functions OrderGetInteger(...) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CHistoryOrderInfo::InfoInteger(const ENUM_ORDER_PROPERTY_INTEGER prop_id,long &var) const
|
||||
{
|
||||
return(HistoryOrderGetInteger(m_ticket,prop_id,var));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access functions OrderGetDouble(...) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CHistoryOrderInfo::InfoDouble(const ENUM_ORDER_PROPERTY_DOUBLE prop_id,double &var) const
|
||||
{
|
||||
return(HistoryOrderGetDouble(m_ticket,prop_id,var));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access functions OrderGetString(...) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CHistoryOrderInfo::InfoString(const ENUM_ORDER_PROPERTY_STRING prop_id,string &var) const
|
||||
{
|
||||
return(HistoryOrderGetString(m_ticket,prop_id,var));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Converts the order type to text |
|
||||
//+------------------------------------------------------------------+
|
||||
string CHistoryOrderInfo::FormatType(string &str,const uint type) const
|
||||
{
|
||||
//--- see the type
|
||||
switch(type)
|
||||
{
|
||||
case ORDER_TYPE_BUY:
|
||||
str="buy";
|
||||
break;
|
||||
case ORDER_TYPE_SELL:
|
||||
str="sell";
|
||||
break;
|
||||
case ORDER_TYPE_BUY_LIMIT:
|
||||
str="buy limit";
|
||||
break;
|
||||
case ORDER_TYPE_SELL_LIMIT:
|
||||
str="sell limit";
|
||||
break;
|
||||
case ORDER_TYPE_BUY_STOP:
|
||||
str="buy stop";
|
||||
break;
|
||||
case ORDER_TYPE_SELL_STOP:
|
||||
str="sell stop";
|
||||
break;
|
||||
case ORDER_TYPE_BUY_STOP_LIMIT:
|
||||
str="buy stop limit";
|
||||
break;
|
||||
case ORDER_TYPE_SELL_STOP_LIMIT:
|
||||
str="sell stop limit";
|
||||
break;
|
||||
case ORDER_TYPE_CLOSE_BY:
|
||||
str="close by";
|
||||
break;
|
||||
default:
|
||||
str="unknown order type "+(string)type;
|
||||
}
|
||||
//--- return the result
|
||||
return(str);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Converts the order status to text |
|
||||
//+------------------------------------------------------------------+
|
||||
string CHistoryOrderInfo::FormatStatus(string &str,const uint status) const
|
||||
{
|
||||
//--- see the type
|
||||
switch(status)
|
||||
{
|
||||
case ORDER_STATE_STARTED:
|
||||
str="started";
|
||||
break;
|
||||
case ORDER_STATE_PLACED:
|
||||
str="placed";
|
||||
break;
|
||||
case ORDER_STATE_CANCELED:
|
||||
str="canceled";
|
||||
break;
|
||||
case ORDER_STATE_PARTIAL:
|
||||
str="partial";
|
||||
break;
|
||||
case ORDER_STATE_FILLED:
|
||||
str="filled";
|
||||
break;
|
||||
case ORDER_STATE_REJECTED:
|
||||
str="rejected";
|
||||
break;
|
||||
case ORDER_STATE_EXPIRED:
|
||||
str="expired";
|
||||
break;
|
||||
default:
|
||||
str="unknown order status "+(string)status;
|
||||
}
|
||||
//--- return the result
|
||||
return(str);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Converts the order filling type to text |
|
||||
//+------------------------------------------------------------------+
|
||||
string CHistoryOrderInfo::FormatTypeFilling(string &str,const uint type) const
|
||||
{
|
||||
//--- see the type
|
||||
switch(type)
|
||||
{
|
||||
case ORDER_FILLING_RETURN:
|
||||
str="return remainder";
|
||||
break;
|
||||
case ORDER_FILLING_IOC:
|
||||
str="cancel remainder";
|
||||
break;
|
||||
case ORDER_FILLING_FOK:
|
||||
str="fill or kill";
|
||||
break;
|
||||
default:
|
||||
str="unknown type filling "+(string)type;
|
||||
}
|
||||
//--- return the result
|
||||
return(str);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Converts the type of order by expiration to text |
|
||||
//+------------------------------------------------------------------+
|
||||
string CHistoryOrderInfo::FormatTypeTime(string &str,const uint type) const
|
||||
{
|
||||
//--- see the type
|
||||
switch(type)
|
||||
{
|
||||
case ORDER_TIME_GTC:
|
||||
str="gtc";
|
||||
break;
|
||||
case ORDER_TIME_DAY:
|
||||
str="day";
|
||||
break;
|
||||
case ORDER_TIME_SPECIFIED:
|
||||
str="specified";
|
||||
break;
|
||||
case ORDER_TIME_SPECIFIED_DAY:
|
||||
str="specified day";
|
||||
break;
|
||||
default:
|
||||
str="unknown type time "+(string)type;
|
||||
}
|
||||
//--- return the result
|
||||
return(str);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Converts the order parameters to text |
|
||||
//+------------------------------------------------------------------+
|
||||
string CHistoryOrderInfo::FormatOrder(string &str) const
|
||||
{
|
||||
string type,price;
|
||||
long tmp_long;
|
||||
//--- set up
|
||||
string symbol_name=this.Symbol();
|
||||
int digits=_Digits;
|
||||
if(SymbolInfoInteger(symbol_name,SYMBOL_DIGITS,tmp_long))
|
||||
digits=(int)tmp_long;
|
||||
//--- form the order description
|
||||
str=StringFormat("#%I64u %s %s %s",
|
||||
Ticket(),
|
||||
FormatType(type,OrderType()),
|
||||
DoubleToString(VolumeInitial(),2),
|
||||
symbol_name);
|
||||
//--- receive the price of the order
|
||||
FormatPrice(price,PriceOpen(),PriceStopLimit(),digits);
|
||||
//--- if there is price, write it
|
||||
if(price!="")
|
||||
{
|
||||
str+=" at ";
|
||||
str+=price;
|
||||
}
|
||||
//--- return the result
|
||||
return(str);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Converts the order prices to text |
|
||||
//+------------------------------------------------------------------+
|
||||
string CHistoryOrderInfo::FormatPrice(string &str,const double price_order,const double price_trigger,const uint digits) const
|
||||
{
|
||||
string price,trigger;
|
||||
//--- Is there its trigger price?
|
||||
if(price_trigger)
|
||||
{
|
||||
price =DoubleToString(price_order,digits);
|
||||
trigger=DoubleToString(price_trigger,digits);
|
||||
str =StringFormat("%s (%s)",price,trigger);
|
||||
}
|
||||
else
|
||||
str=DoubleToString(price_order,digits);
|
||||
//--- return the result
|
||||
return(str);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Select a history order on the index |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CHistoryOrderInfo::SelectByIndex(const int index)
|
||||
{
|
||||
ulong ticket=HistoryOrderGetTicket(index);
|
||||
if(ticket==0)
|
||||
return(false);
|
||||
Ticket(ticket);
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
Binary file not shown.
@@ -0,0 +1,553 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| OrderInfo.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Object.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class COrderInfo. |
|
||||
//| Appointment: Class for access to order info. |
|
||||
//| Derives from class CObject. |
|
||||
//+------------------------------------------------------------------+
|
||||
class COrderInfo : public CObject
|
||||
{
|
||||
protected:
|
||||
ulong m_ticket;
|
||||
ENUM_ORDER_TYPE m_type;
|
||||
ENUM_ORDER_STATE m_state;
|
||||
datetime m_expiration;
|
||||
double m_volume_curr;
|
||||
double m_price_open;
|
||||
double m_stop_loss;
|
||||
double m_take_profit;
|
||||
|
||||
public:
|
||||
COrderInfo(void);
|
||||
~COrderInfo(void);
|
||||
//--- methods of access to protected data
|
||||
ulong Ticket(void) const { return(m_ticket); }
|
||||
//--- fast access methods to the integer order propertyes
|
||||
datetime TimeSetup(void) const;
|
||||
ulong TimeSetupMsc(void) const;
|
||||
datetime TimeDone(void) const;
|
||||
ulong TimeDoneMsc(void) const;
|
||||
ENUM_ORDER_TYPE OrderType(void) const;
|
||||
string TypeDescription(void) const;
|
||||
ENUM_ORDER_STATE State(void) const;
|
||||
string StateDescription(void) const;
|
||||
datetime TimeExpiration(void) const;
|
||||
ENUM_ORDER_TYPE_FILLING TypeFilling(void) const;
|
||||
string TypeFillingDescription(void) const;
|
||||
ENUM_ORDER_TYPE_TIME TypeTime(void) const;
|
||||
string TypeTimeDescription(void) const;
|
||||
long Magic(void) const;
|
||||
long PositionId(void) const;
|
||||
long PositionById(void) const;
|
||||
//--- fast access methods to the double order propertyes
|
||||
double VolumeInitial(void) const;
|
||||
double VolumeCurrent(void) const;
|
||||
double PriceOpen(void) const;
|
||||
double StopLoss(void) const;
|
||||
double TakeProfit(void) const;
|
||||
double PriceCurrent(void) const;
|
||||
double PriceStopLimit(void) const;
|
||||
//--- fast access methods to the string order propertyes
|
||||
string Symbol(void) const;
|
||||
string Comment(void) const;
|
||||
string ExternalId(void) const;
|
||||
//--- access methods to the API MQL5 functions
|
||||
bool InfoInteger(const ENUM_ORDER_PROPERTY_INTEGER prop_id,long &var) const;
|
||||
bool InfoDouble(const ENUM_ORDER_PROPERTY_DOUBLE prop_id,double &var) const;
|
||||
bool InfoString(const ENUM_ORDER_PROPERTY_STRING prop_id,string &var) const;
|
||||
//--- info methods
|
||||
string FormatType(string &str,const uint type) const;
|
||||
string FormatStatus(string &str,const uint status) const;
|
||||
string FormatTypeFilling(string &str,const uint type) const;
|
||||
string FormatTypeTime(string &str,const uint type) const;
|
||||
string FormatOrder(string &str) const;
|
||||
string FormatPrice(string &str,const double price_order,const double price_trigger,const uint digits) const;
|
||||
//--- method for select order
|
||||
bool Select(void);
|
||||
bool Select(const ulong ticket);
|
||||
bool SelectByIndex(const int index);
|
||||
//--- additional methods
|
||||
void StoreState(void);
|
||||
bool CheckState(void);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
COrderInfo::COrderInfo(void) : m_ticket(ULONG_MAX),
|
||||
m_type(WRONG_VALUE),
|
||||
m_state(WRONG_VALUE),
|
||||
m_expiration(0),
|
||||
m_volume_curr(0.0),
|
||||
m_price_open(0.0),
|
||||
m_stop_loss(0.0),
|
||||
m_take_profit(0.0)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
COrderInfo::~COrderInfo(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_TIME_SETUP" |
|
||||
//+------------------------------------------------------------------+
|
||||
datetime COrderInfo::TimeSetup(void) const
|
||||
{
|
||||
return((datetime)OrderGetInteger(ORDER_TIME_SETUP));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_TIME_SETUP_MSC" |
|
||||
//+------------------------------------------------------------------+
|
||||
ulong COrderInfo::TimeSetupMsc(void) const
|
||||
{
|
||||
return(OrderGetInteger(ORDER_TIME_SETUP_MSC));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_TIME_DONE" |
|
||||
//+------------------------------------------------------------------+
|
||||
datetime COrderInfo::TimeDone(void) const
|
||||
{
|
||||
return((datetime)OrderGetInteger(ORDER_TIME_DONE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_TIME_DONE_MSC" |
|
||||
//+------------------------------------------------------------------+
|
||||
ulong COrderInfo::TimeDoneMsc(void) const
|
||||
{
|
||||
return(OrderGetInteger(ORDER_TIME_DONE_MSC));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_TYPE" |
|
||||
//+------------------------------------------------------------------+
|
||||
ENUM_ORDER_TYPE COrderInfo::OrderType(void) const
|
||||
{
|
||||
return((ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_TYPE" as string |
|
||||
//+------------------------------------------------------------------+
|
||||
string COrderInfo::TypeDescription(void) const
|
||||
{
|
||||
string str;
|
||||
//---
|
||||
return(FormatType(str,OrderType()));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_STATE" |
|
||||
//+------------------------------------------------------------------+
|
||||
ENUM_ORDER_STATE COrderInfo::State(void) const
|
||||
{
|
||||
return((ENUM_ORDER_STATE)OrderGetInteger(ORDER_STATE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_STATE" as string |
|
||||
//+------------------------------------------------------------------+
|
||||
string COrderInfo::StateDescription(void) const
|
||||
{
|
||||
string str;
|
||||
//---
|
||||
return(FormatStatus(str,State()));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_TIME_EXPIRATION" |
|
||||
//+------------------------------------------------------------------+
|
||||
datetime COrderInfo::TimeExpiration(void) const
|
||||
{
|
||||
return((datetime)OrderGetInteger(ORDER_TIME_EXPIRATION));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_TYPE_FILLING" |
|
||||
//+------------------------------------------------------------------+
|
||||
ENUM_ORDER_TYPE_FILLING COrderInfo::TypeFilling(void) const
|
||||
{
|
||||
return((ENUM_ORDER_TYPE_FILLING)OrderGetInteger(ORDER_TYPE_FILLING));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_TYPE_FILLING" as string |
|
||||
//+------------------------------------------------------------------+
|
||||
string COrderInfo::TypeFillingDescription(void) const
|
||||
{
|
||||
string str;
|
||||
//---
|
||||
return(FormatTypeFilling(str,TypeFilling()));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_TYPE_TIME" |
|
||||
//+------------------------------------------------------------------+
|
||||
ENUM_ORDER_TYPE_TIME COrderInfo::TypeTime(void) const
|
||||
{
|
||||
return((ENUM_ORDER_TYPE_TIME)OrderGetInteger(ORDER_TYPE_TIME));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_TYPE_TIME" as string |
|
||||
//+------------------------------------------------------------------+
|
||||
string COrderInfo::TypeTimeDescription(void) const
|
||||
{
|
||||
string str;
|
||||
//---
|
||||
return(FormatTypeTime(str,TypeFilling()));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_MAGIC" |
|
||||
//+------------------------------------------------------------------+
|
||||
long COrderInfo::Magic(void) const
|
||||
{
|
||||
return(OrderGetInteger(ORDER_MAGIC));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_POSITION_ID" |
|
||||
//+------------------------------------------------------------------+
|
||||
long COrderInfo::PositionId(void) const
|
||||
{
|
||||
return(OrderGetInteger(ORDER_POSITION_ID));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_POSITION_BY_ID" |
|
||||
//+------------------------------------------------------------------+
|
||||
long COrderInfo::PositionById(void) const
|
||||
{
|
||||
return(OrderGetInteger(ORDER_POSITION_BY_ID));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_VOLUME_INITIAL" |
|
||||
//+------------------------------------------------------------------+
|
||||
double COrderInfo::VolumeInitial(void) const
|
||||
{
|
||||
return(OrderGetDouble(ORDER_VOLUME_INITIAL));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_VOLUME_CURRENT" |
|
||||
//+------------------------------------------------------------------+
|
||||
double COrderInfo::VolumeCurrent(void) const
|
||||
{
|
||||
return(OrderGetDouble(ORDER_VOLUME_CURRENT));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_PRICE_OPEN" |
|
||||
//+------------------------------------------------------------------+
|
||||
double COrderInfo::PriceOpen(void) const
|
||||
{
|
||||
return(OrderGetDouble(ORDER_PRICE_OPEN));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_SL" |
|
||||
//+------------------------------------------------------------------+
|
||||
double COrderInfo::StopLoss(void) const
|
||||
{
|
||||
return(OrderGetDouble(ORDER_SL));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_TP" |
|
||||
//+------------------------------------------------------------------+
|
||||
double COrderInfo::TakeProfit(void) const
|
||||
{
|
||||
return(OrderGetDouble(ORDER_TP));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_PRICE_CURRENT" |
|
||||
//+------------------------------------------------------------------+
|
||||
double COrderInfo::PriceCurrent(void) const
|
||||
{
|
||||
return(OrderGetDouble(ORDER_PRICE_CURRENT));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_PRICE_STOPLIMIT" |
|
||||
//+------------------------------------------------------------------+
|
||||
double COrderInfo::PriceStopLimit(void) const
|
||||
{
|
||||
return(OrderGetDouble(ORDER_PRICE_STOPLIMIT));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_SYMBOL" |
|
||||
//+------------------------------------------------------------------+
|
||||
string COrderInfo::Symbol(void) const
|
||||
{
|
||||
return(OrderGetString(ORDER_SYMBOL));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_COMMENT" |
|
||||
//+------------------------------------------------------------------+
|
||||
string COrderInfo::Comment(void) const
|
||||
{
|
||||
return(OrderGetString(ORDER_COMMENT));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "ORDER_EXTERNAL_ID" |
|
||||
//+------------------------------------------------------------------+
|
||||
string COrderInfo::ExternalId(void) const
|
||||
{
|
||||
return(OrderGetString(ORDER_EXTERNAL_ID));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access functions OrderGetInteger(...) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool COrderInfo::InfoInteger(const ENUM_ORDER_PROPERTY_INTEGER prop_id,long &var) const
|
||||
{
|
||||
return(OrderGetInteger(prop_id,var));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access functions OrderGetDouble(...) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool COrderInfo::InfoDouble(const ENUM_ORDER_PROPERTY_DOUBLE prop_id,double &var) const
|
||||
{
|
||||
return(OrderGetDouble(prop_id,var));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access functions OrderGetString(...) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool COrderInfo::InfoString(const ENUM_ORDER_PROPERTY_STRING prop_id,string &var) const
|
||||
{
|
||||
return(OrderGetString(prop_id,var));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Converts the order type to text |
|
||||
//+------------------------------------------------------------------+
|
||||
string COrderInfo::FormatType(string &str,const uint type) const
|
||||
{
|
||||
//--- see the type
|
||||
switch(type)
|
||||
{
|
||||
case ORDER_TYPE_BUY:
|
||||
str="buy";
|
||||
break;
|
||||
case ORDER_TYPE_SELL:
|
||||
str="sell";
|
||||
break;
|
||||
case ORDER_TYPE_BUY_LIMIT:
|
||||
str="buy limit";
|
||||
break;
|
||||
case ORDER_TYPE_SELL_LIMIT:
|
||||
str="sell limit";
|
||||
break;
|
||||
case ORDER_TYPE_BUY_STOP:
|
||||
str="buy stop";
|
||||
break;
|
||||
case ORDER_TYPE_SELL_STOP:
|
||||
str="sell stop";
|
||||
break;
|
||||
case ORDER_TYPE_BUY_STOP_LIMIT:
|
||||
str="buy stop limit";
|
||||
break;
|
||||
case ORDER_TYPE_SELL_STOP_LIMIT:
|
||||
str="sell stop limit";
|
||||
break;
|
||||
case ORDER_TYPE_CLOSE_BY:
|
||||
str="close by";
|
||||
break;
|
||||
default :
|
||||
str="unknown order type "+(string)type;
|
||||
}
|
||||
//--- return the result
|
||||
return(str);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Converts the order status to text |
|
||||
//+------------------------------------------------------------------+
|
||||
string COrderInfo::FormatStatus(string &str,const uint status) const
|
||||
{
|
||||
//--- see the type
|
||||
switch(status)
|
||||
{
|
||||
case ORDER_STATE_STARTED:
|
||||
str="started";
|
||||
break;
|
||||
case ORDER_STATE_PLACED:
|
||||
str="placed";
|
||||
break;
|
||||
case ORDER_STATE_CANCELED:
|
||||
str="canceled";
|
||||
break;
|
||||
case ORDER_STATE_PARTIAL:
|
||||
str="partial";
|
||||
break;
|
||||
case ORDER_STATE_FILLED:
|
||||
str="filled";
|
||||
break;
|
||||
case ORDER_STATE_REJECTED:
|
||||
str="rejected";
|
||||
break;
|
||||
case ORDER_STATE_EXPIRED:
|
||||
str="expired";
|
||||
break;
|
||||
case ORDER_STATE_REQUEST_ADD:
|
||||
str="request adding";
|
||||
break;
|
||||
case ORDER_STATE_REQUEST_MODIFY:
|
||||
str="request modifying";
|
||||
break;
|
||||
case ORDER_STATE_REQUEST_CANCEL:
|
||||
str="request cancelling";
|
||||
break;
|
||||
default :
|
||||
str="unknown order status "+(string)status;
|
||||
}
|
||||
//--- return the result
|
||||
return(str);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Converts the order filling type to text |
|
||||
//+------------------------------------------------------------------+
|
||||
string COrderInfo::FormatTypeFilling(string &str,const uint type) const
|
||||
{
|
||||
//--- see the type
|
||||
switch(type)
|
||||
{
|
||||
case ORDER_FILLING_RETURN:
|
||||
str="return remainder";
|
||||
break;
|
||||
case ORDER_FILLING_IOC:
|
||||
str="cancel remainder";
|
||||
break;
|
||||
case ORDER_FILLING_FOK:
|
||||
str="fill or kill";
|
||||
break;
|
||||
default:
|
||||
str="unknown type filling "+(string)type;
|
||||
}
|
||||
//--- return the result
|
||||
return(str);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Converts the type of order by expiration to text |
|
||||
//+------------------------------------------------------------------+
|
||||
string COrderInfo::FormatTypeTime(string &str,const uint type) const
|
||||
{
|
||||
//--- see the type
|
||||
switch(type)
|
||||
{
|
||||
case ORDER_TIME_GTC:
|
||||
str="gtc";
|
||||
break;
|
||||
case ORDER_TIME_DAY:
|
||||
str="day";
|
||||
break;
|
||||
case ORDER_TIME_SPECIFIED:
|
||||
str="specified";
|
||||
break;
|
||||
case ORDER_TIME_SPECIFIED_DAY:
|
||||
str="specified day";
|
||||
break;
|
||||
default:
|
||||
str="unknown type time "+(string)type;
|
||||
}
|
||||
//--- return the result
|
||||
return(str);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Converts the order parameters to text |
|
||||
//+------------------------------------------------------------------+
|
||||
string COrderInfo::FormatOrder(string &str) const
|
||||
{
|
||||
string type,price;
|
||||
long tmp_long;
|
||||
//--- set up
|
||||
string symbol_name=this.Symbol();
|
||||
int digits=_Digits;
|
||||
if(SymbolInfoInteger(symbol_name,SYMBOL_DIGITS,tmp_long))
|
||||
digits=(int)tmp_long;
|
||||
//--- form the order description
|
||||
str=StringFormat("#%I64u %s %s %s",
|
||||
Ticket(),
|
||||
FormatType(type,OrderType()),
|
||||
DoubleToString(VolumeInitial(),2),
|
||||
symbol_name);
|
||||
//--- receive the price of the order
|
||||
FormatPrice(price,PriceOpen(),PriceStopLimit(),digits);
|
||||
//--- if there is price, write it
|
||||
if(price!="")
|
||||
{
|
||||
str+=" at ";
|
||||
str+=price;
|
||||
}
|
||||
//--- return the result
|
||||
return(str);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Converts the order prices to text |
|
||||
//+------------------------------------------------------------------+
|
||||
string COrderInfo::FormatPrice(string &str,const double price_order,const double price_trigger,const uint digits) const
|
||||
{
|
||||
string price,trigger;
|
||||
//--- Is there its trigger price?
|
||||
if(price_trigger)
|
||||
{
|
||||
price =DoubleToString(price_order,digits);
|
||||
trigger=DoubleToString(price_trigger,digits);
|
||||
str =StringFormat("%s (%s)",price,trigger);
|
||||
}
|
||||
else
|
||||
str=DoubleToString(price_order,digits);
|
||||
//--- return the result
|
||||
return(str);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Selecting an order to access |
|
||||
//+------------------------------------------------------------------+
|
||||
bool COrderInfo::Select(void)
|
||||
{
|
||||
return(OrderSelect(m_ticket));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Selecting an order to access |
|
||||
//+------------------------------------------------------------------+
|
||||
bool COrderInfo::Select(const ulong ticket)
|
||||
{
|
||||
if(OrderSelect(ticket))
|
||||
{
|
||||
m_ticket=ticket;
|
||||
return(true);
|
||||
}
|
||||
m_ticket=ULONG_MAX;
|
||||
//---
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Select an order by the index |
|
||||
//+------------------------------------------------------------------+
|
||||
bool COrderInfo::SelectByIndex(const int index)
|
||||
{
|
||||
ulong ticket=OrderGetTicket(index);
|
||||
if(ticket==0)
|
||||
{
|
||||
m_ticket=ULONG_MAX;
|
||||
return(false);
|
||||
}
|
||||
m_ticket=ticket;
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Stored order's current state |
|
||||
//+------------------------------------------------------------------+
|
||||
void COrderInfo::StoreState(void)
|
||||
{
|
||||
m_type =OrderType();
|
||||
m_state =State();
|
||||
m_expiration =TimeExpiration();
|
||||
m_volume_curr=VolumeCurrent();
|
||||
m_price_open =PriceOpen();
|
||||
m_stop_loss =StopLoss();
|
||||
m_take_profit=TakeProfit();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check order change |
|
||||
//+------------------------------------------------------------------+
|
||||
bool COrderInfo::CheckState(void)
|
||||
{
|
||||
if(m_type==OrderType() &&
|
||||
m_state==State() &&
|
||||
m_expiration==TimeExpiration() &&
|
||||
m_volume_curr==VolumeCurrent() &&
|
||||
m_price_open==PriceOpen() &&
|
||||
m_stop_loss==StopLoss() &&
|
||||
m_take_profit==TakeProfit())
|
||||
return(false);
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,364 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| PositionInfo.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Object.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CPositionInfo. |
|
||||
//| Appointment: Class for access to position info. |
|
||||
//| Derives from class CObject. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CPositionInfo : public CObject
|
||||
{
|
||||
protected:
|
||||
ENUM_POSITION_TYPE m_type;
|
||||
double m_volume;
|
||||
double m_price;
|
||||
double m_stop_loss;
|
||||
double m_take_profit;
|
||||
|
||||
public:
|
||||
CPositionInfo(void);
|
||||
~CPositionInfo(void);
|
||||
//--- fast access methods to the integer position propertyes
|
||||
ulong Ticket(void) const;
|
||||
datetime Time(void) const;
|
||||
ulong TimeMsc(void) const;
|
||||
datetime TimeUpdate(void) const;
|
||||
ulong TimeUpdateMsc(void) const;
|
||||
ENUM_POSITION_TYPE PositionType(void) const;
|
||||
string TypeDescription(void) const;
|
||||
long Magic(void) const;
|
||||
long Identifier(void) const;
|
||||
//--- fast access methods to the double position propertyes
|
||||
double Volume(void) const;
|
||||
double PriceOpen(void) const;
|
||||
double StopLoss(void) const;
|
||||
double TakeProfit(void) const;
|
||||
double PriceCurrent(void) const;
|
||||
double Commission(void) const;
|
||||
double Swap(void) const;
|
||||
double Profit(void) const;
|
||||
//--- fast access methods to the string position propertyes
|
||||
string Symbol(void) const;
|
||||
string Comment(void) const;
|
||||
//--- access methods to the API MQL5 functions
|
||||
bool InfoInteger(const ENUM_POSITION_PROPERTY_INTEGER prop_id,long &var) const;
|
||||
bool InfoDouble(const ENUM_POSITION_PROPERTY_DOUBLE prop_id,double &var) const;
|
||||
bool InfoString(const ENUM_POSITION_PROPERTY_STRING prop_id,string &var) const;
|
||||
//--- info methods
|
||||
string FormatType(string &str,const uint type) const;
|
||||
string FormatPosition(string &str) const;
|
||||
//--- methods for select position
|
||||
bool Select(const string symbol);
|
||||
bool SelectByMagic(const string symbol,const ulong magic);
|
||||
bool SelectByTicket(const ulong ticket);
|
||||
bool SelectByIndex(const int index);
|
||||
//---
|
||||
void StoreState(void);
|
||||
bool CheckState(void);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CPositionInfo::CPositionInfo(void) : m_type(WRONG_VALUE),
|
||||
m_volume(0.0),
|
||||
m_price(0.0),
|
||||
m_stop_loss(0.0),
|
||||
m_take_profit(0.0)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CPositionInfo::~CPositionInfo(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "POSITION_TICKET" |
|
||||
//+------------------------------------------------------------------+
|
||||
ulong CPositionInfo::Ticket(void) const
|
||||
{
|
||||
return((ulong)PositionGetInteger(POSITION_TICKET));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "POSITION_TIME" |
|
||||
//+------------------------------------------------------------------+
|
||||
datetime CPositionInfo::Time(void) const
|
||||
{
|
||||
return((datetime)PositionGetInteger(POSITION_TIME));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "POSITION_TIME_MSC" |
|
||||
//+------------------------------------------------------------------+
|
||||
ulong CPositionInfo::TimeMsc(void) const
|
||||
{
|
||||
return((ulong)PositionGetInteger(POSITION_TIME_MSC));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "POSITION_TIME_UPDATE" |
|
||||
//+------------------------------------------------------------------+
|
||||
datetime CPositionInfo::TimeUpdate(void) const
|
||||
{
|
||||
return((datetime)PositionGetInteger(POSITION_TIME_UPDATE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "POSITION_TIME_UPDATE_MSC" |
|
||||
//+------------------------------------------------------------------+
|
||||
ulong CPositionInfo::TimeUpdateMsc(void) const
|
||||
{
|
||||
return((ulong)PositionGetInteger(POSITION_TIME_UPDATE_MSC));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "POSITION_TYPE" |
|
||||
//+------------------------------------------------------------------+
|
||||
ENUM_POSITION_TYPE CPositionInfo::PositionType(void) const
|
||||
{
|
||||
return((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "POSITION_TYPE" as string |
|
||||
//+------------------------------------------------------------------+
|
||||
string CPositionInfo::TypeDescription(void) const
|
||||
{
|
||||
string str;
|
||||
//---
|
||||
return(FormatType(str,PositionType()));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "POSITION_MAGIC" |
|
||||
//+------------------------------------------------------------------+
|
||||
long CPositionInfo::Magic(void) const
|
||||
{
|
||||
return(PositionGetInteger(POSITION_MAGIC));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "POSITION_IDENTIFIER" |
|
||||
//+------------------------------------------------------------------+
|
||||
long CPositionInfo::Identifier(void) const
|
||||
{
|
||||
return(PositionGetInteger(POSITION_IDENTIFIER));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "POSITION_VOLUME" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CPositionInfo::Volume(void) const
|
||||
{
|
||||
return(PositionGetDouble(POSITION_VOLUME));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "POSITION_PRICE_OPEN" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CPositionInfo::PriceOpen(void) const
|
||||
{
|
||||
return(PositionGetDouble(POSITION_PRICE_OPEN));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "POSITION_SL" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CPositionInfo::StopLoss(void) const
|
||||
{
|
||||
return(PositionGetDouble(POSITION_SL));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "POSITION_TP" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CPositionInfo::TakeProfit(void) const
|
||||
{
|
||||
return(PositionGetDouble(POSITION_TP));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "POSITION_PRICE_CURRENT" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CPositionInfo::PriceCurrent(void) const
|
||||
{
|
||||
return(PositionGetDouble(POSITION_PRICE_CURRENT));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "POSITION_COMMISSION" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CPositionInfo::Commission(void) const
|
||||
{
|
||||
return(PositionGetDouble(POSITION_COMMISSION));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "POSITION_SWAP" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CPositionInfo::Swap(void) const
|
||||
{
|
||||
return(PositionGetDouble(POSITION_SWAP));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "POSITION_PROFIT" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CPositionInfo::Profit(void) const
|
||||
{
|
||||
return(PositionGetDouble(POSITION_PROFIT));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "POSITION_SYMBOL" |
|
||||
//+------------------------------------------------------------------+
|
||||
string CPositionInfo::Symbol(void) const
|
||||
{
|
||||
return(PositionGetString(POSITION_SYMBOL));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "POSITION_COMMENT" |
|
||||
//+------------------------------------------------------------------+
|
||||
string CPositionInfo::Comment(void) const
|
||||
{
|
||||
return(PositionGetString(POSITION_COMMENT));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access functions PositionGetInteger(...) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPositionInfo::InfoInteger(const ENUM_POSITION_PROPERTY_INTEGER prop_id,long &var) const
|
||||
{
|
||||
return(PositionGetInteger(prop_id,var));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access functions PositionGetDouble(...) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPositionInfo::InfoDouble(const ENUM_POSITION_PROPERTY_DOUBLE prop_id,double &var) const
|
||||
{
|
||||
return(PositionGetDouble(prop_id,var));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access functions PositionGetString(...) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPositionInfo::InfoString(const ENUM_POSITION_PROPERTY_STRING prop_id,string &var) const
|
||||
{
|
||||
return(PositionGetString(prop_id,var));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Converts the position type to text |
|
||||
//+------------------------------------------------------------------+
|
||||
string CPositionInfo::FormatType(string &str,const uint type) const
|
||||
{
|
||||
//--- see the type
|
||||
switch(type)
|
||||
{
|
||||
case POSITION_TYPE_BUY:
|
||||
str="buy";
|
||||
break;
|
||||
case POSITION_TYPE_SELL:
|
||||
str="sell";
|
||||
break;
|
||||
default:
|
||||
str="unknown position type "+(string)type;
|
||||
}
|
||||
//--- return the result
|
||||
return(str);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Converts the position parameters to text |
|
||||
//+------------------------------------------------------------------+
|
||||
string CPositionInfo::FormatPosition(string &str) const
|
||||
{
|
||||
string tmp,type;
|
||||
long tmp_long;
|
||||
ENUM_ACCOUNT_MARGIN_MODE margin_mode=(ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE);
|
||||
//--- set up
|
||||
string symbol_name=this.Symbol();
|
||||
int digits=_Digits;
|
||||
if(SymbolInfoInteger(symbol_name,SYMBOL_DIGITS,tmp_long))
|
||||
digits=(int)tmp_long;
|
||||
//--- form the position description
|
||||
if(margin_mode==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING)
|
||||
str=StringFormat("#%I64u %s %s %s %s",
|
||||
Ticket(),
|
||||
FormatType(type,PositionType()),
|
||||
DoubleToString(Volume(),2),
|
||||
symbol_name,
|
||||
DoubleToString(PriceOpen(),digits+3));
|
||||
else
|
||||
str=StringFormat("%s %s %s %s",
|
||||
FormatType(type,PositionType()),
|
||||
DoubleToString(Volume(),2),
|
||||
symbol_name,
|
||||
DoubleToString(PriceOpen(),digits+3));
|
||||
//--- add stops if there are any
|
||||
double sl=StopLoss();
|
||||
double tp=TakeProfit();
|
||||
if(sl!=0.0)
|
||||
{
|
||||
tmp=StringFormat(" sl: %s",DoubleToString(sl,digits));
|
||||
str+=tmp;
|
||||
}
|
||||
if(tp!=0.0)
|
||||
{
|
||||
tmp=StringFormat(" tp: %s",DoubleToString(tp,digits));
|
||||
str+=tmp;
|
||||
}
|
||||
//--- return the result
|
||||
return(str);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access functions PositionSelect(...) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPositionInfo::Select(const string symbol)
|
||||
{
|
||||
return(PositionSelect(symbol));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access functions PositionSelect(...) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPositionInfo::SelectByMagic(const string symbol,const ulong magic)
|
||||
{
|
||||
bool res=false;
|
||||
uint total=PositionsTotal();
|
||||
//---
|
||||
for(uint i=0; i<total; i++)
|
||||
{
|
||||
string position_symbol=PositionGetSymbol(i);
|
||||
if(position_symbol==symbol && magic==PositionGetInteger(POSITION_MAGIC))
|
||||
{
|
||||
res=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//---
|
||||
return(res);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access functions PositionSelectByTicket(...) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPositionInfo::SelectByTicket(const ulong ticket)
|
||||
{
|
||||
return(PositionSelectByTicket(ticket));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Select a position on the index |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPositionInfo::SelectByIndex(const int index)
|
||||
{
|
||||
ulong ticket=PositionGetTicket(index);
|
||||
return(ticket>0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Stored position's current state |
|
||||
//+------------------------------------------------------------------+
|
||||
void CPositionInfo::StoreState(void)
|
||||
{
|
||||
m_type =PositionType();
|
||||
m_volume =Volume();
|
||||
m_price =PriceOpen();
|
||||
m_stop_loss =StopLoss();
|
||||
m_take_profit=TakeProfit();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check position change |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPositionInfo::CheckState(void)
|
||||
{
|
||||
if(m_type==PositionType() &&
|
||||
m_volume==Volume() &&
|
||||
m_price==PriceOpen() &&
|
||||
m_stop_loss==StopLoss() &&
|
||||
m_take_profit==TakeProfit())
|
||||
return(false);
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,789 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SymbolInfo.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Object.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CSymbolInfo. |
|
||||
//| Appointment: Class for access to symbol info. |
|
||||
//| Derives from class CObject. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CSymbolInfo : public CObject
|
||||
{
|
||||
protected:
|
||||
string m_name; // symbol name
|
||||
MqlTick m_tick; // structure of tick;
|
||||
double m_point; // symbol point
|
||||
double m_tick_value; // symbol tick value
|
||||
double m_tick_value_profit; // symbol tick value profit
|
||||
double m_tick_value_loss; // symbol tick value loss
|
||||
double m_tick_size; // symbol tick size
|
||||
double m_contract_size; // symbol contract size
|
||||
double m_lots_min; // symbol lots min
|
||||
double m_lots_max; // symbol lots max
|
||||
double m_lots_step; // symbol lots step
|
||||
double m_lots_limit; // symbol lots limit
|
||||
double m_swap_long; // symbol swap long
|
||||
double m_swap_short; // symbol swap short
|
||||
int m_digits; // symbol digits
|
||||
int m_order_mode; // symbol valid orders
|
||||
ENUM_SYMBOL_TRADE_EXECUTION m_trade_execution; // symbol trade execution
|
||||
ENUM_SYMBOL_CALC_MODE m_trade_calcmode; // symbol trade calcmode
|
||||
ENUM_SYMBOL_TRADE_MODE m_trade_mode; // symbol trade mode
|
||||
ENUM_SYMBOL_SWAP_MODE m_swap_mode; // symbol swap mode
|
||||
ENUM_DAY_OF_WEEK m_swap3; // symbol swap3
|
||||
double m_margin_initial; // symbol margin initial
|
||||
double m_margin_maintenance; // symbol margin maintenance
|
||||
bool m_margin_hedged_use_leg; // calculate hedged margin using larger leg
|
||||
double m_margin_hedged; // symbol margin hedged
|
||||
int m_trade_time_flags; // symbol trade time flags
|
||||
int m_trade_fill_flags; // symbol trade fill flags
|
||||
|
||||
public:
|
||||
CSymbolInfo(void);
|
||||
~CSymbolInfo(void);
|
||||
//--- methods of access to protected data
|
||||
string Name(void) const { return(m_name); }
|
||||
bool Name(const string name);
|
||||
bool Refresh(void);
|
||||
bool RefreshRates(void);
|
||||
//--- fast access methods to the integer symbol propertyes
|
||||
bool Select(void) const;
|
||||
bool Select(const bool select);
|
||||
bool IsSynchronized(void) const;
|
||||
//--- volumes
|
||||
ulong Volume(void) const { return(m_tick.volume); }
|
||||
ulong VolumeHigh(void) const;
|
||||
ulong VolumeLow(void) const;
|
||||
//--- miscellaneous
|
||||
datetime Time(void) const { return(m_tick.time); }
|
||||
int Spread(void) const;
|
||||
bool SpreadFloat(void) const;
|
||||
int TicksBookDepth(void) const;
|
||||
//--- trade levels
|
||||
int StopsLevel(void) const;
|
||||
int FreezeLevel(void) const;
|
||||
//--- fast access methods to the double symbol propertyes
|
||||
//--- bid parameters
|
||||
double Bid(void) const { return(m_tick.bid); }
|
||||
double BidHigh(void) const;
|
||||
double BidLow(void) const;
|
||||
//--- ask parameters
|
||||
double Ask(void) const { return(m_tick.ask); }
|
||||
double AskHigh(void) const;
|
||||
double AskLow(void) const;
|
||||
//--- last parameters
|
||||
double Last(void) const { return(m_tick.last); }
|
||||
double LastHigh(void) const;
|
||||
double LastLow(void) const;
|
||||
//--- fast access methods to the mix symbol propertyes
|
||||
int OrderMode(void) const { return(m_order_mode); }
|
||||
//--- terms of trade
|
||||
ENUM_SYMBOL_CALC_MODE TradeCalcMode(void) const { return(m_trade_calcmode); }
|
||||
string TradeCalcModeDescription(void) const;
|
||||
ENUM_SYMBOL_TRADE_MODE TradeMode(void) const { return(m_trade_mode); }
|
||||
string TradeModeDescription(void) const;
|
||||
//--- execution terms of trade
|
||||
ENUM_SYMBOL_TRADE_EXECUTION TradeExecution(void) const { return(m_trade_execution); }
|
||||
string TradeExecutionDescription(void) const;
|
||||
//--- swap terms of trade
|
||||
ENUM_SYMBOL_SWAP_MODE SwapMode(void) const { return(m_swap_mode); }
|
||||
string SwapModeDescription(void) const;
|
||||
ENUM_DAY_OF_WEEK SwapRollover3days(void) const { return(m_swap3); }
|
||||
string SwapRollover3daysDescription(void) const;
|
||||
//--- dates for futures
|
||||
datetime StartTime(void) const;
|
||||
datetime ExpirationTime(void) const;
|
||||
//--- margin parameters
|
||||
double MarginInitial(void) const { return(m_margin_initial); }
|
||||
double MarginMaintenance(void) const { return(m_margin_maintenance); }
|
||||
bool MarginHedgedUseLeg(void) const { return(m_margin_hedged_use_leg); }
|
||||
double MarginHedged(void) const { return(m_margin_hedged); }
|
||||
//--- left for backward compatibility
|
||||
double MarginLong(void) const { return(0.0); }
|
||||
double MarginShort(void) const { return(0.0); }
|
||||
double MarginLimit(void) const { return(0.0); }
|
||||
double MarginStop(void) const { return(0.0); }
|
||||
double MarginStopLimit(void) const { return(0.0); }
|
||||
//--- trade flags parameters
|
||||
int TradeTimeFlags(void) const { return(m_trade_time_flags); }
|
||||
int TradeFillFlags(void) const { return(m_trade_fill_flags); }
|
||||
//--- tick parameters
|
||||
int Digits(void) const { return(m_digits); }
|
||||
double Point(void) const { return(m_point); }
|
||||
double TickValue(void) const { return(m_tick_value); }
|
||||
double TickValueProfit(void) const { return(m_tick_value_profit); }
|
||||
double TickValueLoss(void) const { return(m_tick_value_loss); }
|
||||
double TickSize(void) const { return(m_tick_size); }
|
||||
//--- lots parameters
|
||||
double ContractSize(void) const { return(m_contract_size); }
|
||||
double LotsMin(void) const { return(m_lots_min); }
|
||||
double LotsMax(void) const { return(m_lots_max); }
|
||||
double LotsStep(void) const { return(m_lots_step); }
|
||||
double LotsLimit(void) const { return(m_lots_limit); }
|
||||
//--- swaps
|
||||
double SwapLong(void) const { return(m_swap_long); }
|
||||
double SwapShort(void) const { return(m_swap_short); }
|
||||
//--- fast access methods to the string symbol propertyes
|
||||
string CurrencyBase(void) const;
|
||||
string CurrencyProfit(void) const;
|
||||
string CurrencyMargin(void) const;
|
||||
string Bank(void) const;
|
||||
string Description(void) const;
|
||||
string Path(void) const;
|
||||
//--- session information
|
||||
long SessionDeals(void) const;
|
||||
long SessionBuyOrders(void) const;
|
||||
long SessionSellOrders(void) const;
|
||||
double SessionTurnover(void) const;
|
||||
double SessionInterest(void) const;
|
||||
double SessionBuyOrdersVolume(void) const;
|
||||
double SessionSellOrdersVolume(void) const;
|
||||
double SessionOpen(void) const;
|
||||
double SessionClose(void) const;
|
||||
double SessionAW(void) const;
|
||||
double SessionPriceSettlement(void) const;
|
||||
double SessionPriceLimitMin(void) const;
|
||||
double SessionPriceLimitMax(void) const;
|
||||
//--- access methods to the API MQL5 functions
|
||||
bool InfoInteger(const ENUM_SYMBOL_INFO_INTEGER prop_id,long& var) const;
|
||||
bool InfoDouble(const ENUM_SYMBOL_INFO_DOUBLE prop_id,double& var) const;
|
||||
bool InfoString(const ENUM_SYMBOL_INFO_STRING prop_id,string& var) const;
|
||||
bool InfoMarginRate(const ENUM_ORDER_TYPE order_type,double& initial_margin_rate,double& maintenance_margin_rate) const;
|
||||
//--- service methods
|
||||
double NormalizePrice(const double price) const;
|
||||
bool CheckMarketWatch(void);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSymbolInfo::CSymbolInfo(void) : m_name(NULL),
|
||||
m_point(0.0),
|
||||
m_tick_value(0.0),
|
||||
m_tick_value_profit(0.0),
|
||||
m_tick_value_loss(0.0),
|
||||
m_tick_size(0.0),
|
||||
m_contract_size(0.0),
|
||||
m_lots_min(0.0),
|
||||
m_lots_max(0.0),
|
||||
m_lots_step(0.0),
|
||||
m_swap_long(0.0),
|
||||
m_swap_short(0.0),
|
||||
m_digits(0),
|
||||
m_order_mode(0),
|
||||
m_trade_execution(0),
|
||||
m_trade_calcmode(0),
|
||||
m_trade_mode(0),
|
||||
m_swap_mode(0),
|
||||
m_swap3(0),
|
||||
m_margin_initial(0.0),
|
||||
m_margin_maintenance(0.0),
|
||||
m_margin_hedged_use_leg(false),
|
||||
m_margin_hedged(0.0),
|
||||
m_trade_time_flags(0),
|
||||
m_trade_fill_flags(0)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSymbolInfo::~CSymbolInfo(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set name |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSymbolInfo::Name(const string name)
|
||||
{
|
||||
string symbol_name=StringLen(name)>0 ? name : _Symbol;
|
||||
//--- check previous set name
|
||||
if(m_name!=symbol_name)
|
||||
{
|
||||
m_name=symbol_name;
|
||||
//---
|
||||
if(!CheckMarketWatch())
|
||||
return(false);
|
||||
//---
|
||||
if(!Refresh())
|
||||
{
|
||||
m_name="";
|
||||
Print(__FUNCTION__+": invalid data of symbol '"+symbol_name+"'");
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Refresh cached data |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSymbolInfo::Refresh(void)
|
||||
{
|
||||
long tmp_long=0;
|
||||
//---
|
||||
if(!SymbolInfoDouble(m_name,SYMBOL_POINT,m_point))
|
||||
return(false);
|
||||
if(!SymbolInfoDouble(m_name,SYMBOL_TRADE_TICK_VALUE,m_tick_value))
|
||||
return(false);
|
||||
if(!SymbolInfoDouble(m_name,SYMBOL_TRADE_TICK_VALUE_PROFIT,m_tick_value_profit))
|
||||
return(false);
|
||||
if(!SymbolInfoDouble(m_name,SYMBOL_TRADE_TICK_VALUE_LOSS,m_tick_value_loss))
|
||||
return(false);
|
||||
if(!SymbolInfoDouble(m_name,SYMBOL_TRADE_TICK_SIZE,m_tick_size))
|
||||
return(false);
|
||||
if(!SymbolInfoDouble(m_name,SYMBOL_TRADE_CONTRACT_SIZE,m_contract_size))
|
||||
return(false);
|
||||
if(!SymbolInfoDouble(m_name,SYMBOL_VOLUME_MIN,m_lots_min))
|
||||
return(false);
|
||||
if(!SymbolInfoDouble(m_name,SYMBOL_VOLUME_MAX,m_lots_max))
|
||||
return(false);
|
||||
if(!SymbolInfoDouble(m_name,SYMBOL_VOLUME_STEP,m_lots_step))
|
||||
return(false);
|
||||
if(!SymbolInfoDouble(m_name,SYMBOL_VOLUME_LIMIT,m_lots_limit))
|
||||
return(false);
|
||||
if(!SymbolInfoDouble(m_name,SYMBOL_SWAP_LONG,m_swap_long))
|
||||
return(false);
|
||||
if(!SymbolInfoDouble(m_name,SYMBOL_SWAP_SHORT,m_swap_short))
|
||||
return(false);
|
||||
if(!SymbolInfoInteger(m_name,SYMBOL_DIGITS,tmp_long))
|
||||
return(false);
|
||||
m_digits=(int)tmp_long;
|
||||
if(!SymbolInfoInteger(m_name,SYMBOL_ORDER_MODE,tmp_long))
|
||||
return(false);
|
||||
m_order_mode=(int)tmp_long;
|
||||
if(!SymbolInfoInteger(m_name,SYMBOL_TRADE_EXEMODE,tmp_long))
|
||||
return(false);
|
||||
m_trade_execution=(ENUM_SYMBOL_TRADE_EXECUTION)tmp_long;
|
||||
if(!SymbolInfoInteger(m_name,SYMBOL_TRADE_CALC_MODE,tmp_long))
|
||||
return(false);
|
||||
m_trade_calcmode=(ENUM_SYMBOL_CALC_MODE)tmp_long;
|
||||
if(!SymbolInfoInteger(m_name,SYMBOL_TRADE_MODE,tmp_long))
|
||||
return(false);
|
||||
m_trade_mode=(ENUM_SYMBOL_TRADE_MODE)tmp_long;
|
||||
if(!SymbolInfoInteger(m_name,SYMBOL_SWAP_MODE,tmp_long))
|
||||
return(false);
|
||||
m_swap_mode=(ENUM_SYMBOL_SWAP_MODE)tmp_long;
|
||||
if(!SymbolInfoInteger(m_name,SYMBOL_SWAP_ROLLOVER3DAYS,tmp_long))
|
||||
return(false);
|
||||
m_swap3=(ENUM_DAY_OF_WEEK)tmp_long;
|
||||
if(!SymbolInfoDouble(m_name,SYMBOL_MARGIN_INITIAL,m_margin_initial))
|
||||
return(false);
|
||||
if(!SymbolInfoDouble(m_name,SYMBOL_MARGIN_MAINTENANCE,m_margin_maintenance))
|
||||
return(false);
|
||||
if(!SymbolInfoDouble(m_name,SYMBOL_MARGIN_HEDGED,m_margin_hedged))
|
||||
return(false);
|
||||
if(!SymbolInfoInteger(m_name,SYMBOL_MARGIN_HEDGED_USE_LEG,tmp_long))
|
||||
return(false);
|
||||
m_margin_hedged_use_leg=(bool)tmp_long;
|
||||
if(!SymbolInfoInteger(m_name,SYMBOL_EXPIRATION_MODE,tmp_long))
|
||||
return(false);
|
||||
m_trade_time_flags=(int)tmp_long;
|
||||
if(!SymbolInfoInteger(m_name,SYMBOL_FILLING_MODE,tmp_long))
|
||||
return(false);
|
||||
m_trade_fill_flags=(int)tmp_long;
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Refresh cached data |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSymbolInfo::RefreshRates(void)
|
||||
{
|
||||
return(SymbolInfoTick(m_name,m_tick));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_SELECT" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSymbolInfo::Select(void) const
|
||||
{
|
||||
return((bool)SymbolInfoInteger(m_name,SYMBOL_SELECT));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the property value "SYMBOL_SELECT" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSymbolInfo::Select(const bool select)
|
||||
{
|
||||
return(SymbolSelect(m_name,select));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check synchronize symbol |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSymbolInfo::IsSynchronized(void) const
|
||||
{
|
||||
return(SymbolIsSynchronized(m_name));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_VOLUMEHIGH" |
|
||||
//+------------------------------------------------------------------+
|
||||
ulong CSymbolInfo::VolumeHigh(void) const
|
||||
{
|
||||
return(SymbolInfoInteger(m_name,SYMBOL_VOLUMEHIGH));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_VOLUMELOW" |
|
||||
//+------------------------------------------------------------------+
|
||||
ulong CSymbolInfo::VolumeLow(void) const
|
||||
{
|
||||
return(SymbolInfoInteger(m_name,SYMBOL_VOLUMELOW));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_SPREAD" |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSymbolInfo::Spread(void) const
|
||||
{
|
||||
return((int)SymbolInfoInteger(m_name,SYMBOL_SPREAD));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_SPREAD_FLOAT" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSymbolInfo::SpreadFloat(void) const
|
||||
{
|
||||
return((bool)SymbolInfoInteger(m_name,SYMBOL_SPREAD_FLOAT));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_TICKS_BOOKDEPTH" |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSymbolInfo::TicksBookDepth(void) const
|
||||
{
|
||||
return((int)SymbolInfoInteger(m_name,SYMBOL_TICKS_BOOKDEPTH));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_TRADE_STOPS_LEVEL" |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSymbolInfo::StopsLevel(void) const
|
||||
{
|
||||
return((int)SymbolInfoInteger(m_name,SYMBOL_TRADE_STOPS_LEVEL));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_TRADE_FREEZE_LEVEL" |
|
||||
//+------------------------------------------------------------------+
|
||||
int CSymbolInfo::FreezeLevel(void) const
|
||||
{
|
||||
return((int)SymbolInfoInteger(m_name,SYMBOL_TRADE_FREEZE_LEVEL));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_BIDHIGH" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CSymbolInfo::BidHigh(void) const
|
||||
{
|
||||
return(SymbolInfoDouble(m_name,SYMBOL_BIDHIGH));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_BIDLOW" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CSymbolInfo::BidLow(void) const
|
||||
{
|
||||
return(SymbolInfoDouble(m_name,SYMBOL_BIDLOW));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_ASKHIGH" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CSymbolInfo::AskHigh(void) const
|
||||
{
|
||||
return(SymbolInfoDouble(m_name,SYMBOL_ASKHIGH));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_ASKLOW" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CSymbolInfo::AskLow(void) const
|
||||
{
|
||||
return(SymbolInfoDouble(m_name,SYMBOL_ASKLOW));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_LASTHIGH" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CSymbolInfo::LastHigh(void) const
|
||||
{
|
||||
return(SymbolInfoDouble(m_name,SYMBOL_LASTHIGH));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_LASTLOW" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CSymbolInfo::LastLow(void) const
|
||||
{
|
||||
return(SymbolInfoDouble(m_name,SYMBOL_LASTLOW));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_TRADE_CALC_MODE" as string |
|
||||
//+------------------------------------------------------------------+
|
||||
string CSymbolInfo::TradeCalcModeDescription(void) const
|
||||
{
|
||||
string str;
|
||||
//---
|
||||
switch(m_trade_calcmode)
|
||||
{
|
||||
case SYMBOL_CALC_MODE_FOREX:
|
||||
str="Calculation of profit and margin for Forex";
|
||||
break;
|
||||
case SYMBOL_CALC_MODE_CFD:
|
||||
str="Calculation of collateral and earnings for CFD";
|
||||
break;
|
||||
case SYMBOL_CALC_MODE_FUTURES:
|
||||
str="Calculation of collateral and profits for futures";
|
||||
break;
|
||||
case SYMBOL_CALC_MODE_CFDINDEX:
|
||||
str="Calculation of collateral and earnings for CFD on indices";
|
||||
break;
|
||||
case SYMBOL_CALC_MODE_CFDLEVERAGE:
|
||||
str="Calculation of collateral and earnings for the CFD when trading with leverage";
|
||||
break;
|
||||
case SYMBOL_CALC_MODE_EXCH_STOCKS:
|
||||
str="Calculation for exchange stocks";
|
||||
break;
|
||||
case SYMBOL_CALC_MODE_EXCH_FUTURES:
|
||||
str="Calculation for exchange futures";
|
||||
break;
|
||||
case SYMBOL_CALC_MODE_EXCH_FUTURES_FORTS:
|
||||
str="Calculation for FORTS futures";
|
||||
break;
|
||||
default:
|
||||
str="Unknown calculation mode";
|
||||
}
|
||||
//--- result
|
||||
return(str);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_TRADE_MODE" as string |
|
||||
//+------------------------------------------------------------------+
|
||||
string CSymbolInfo::TradeModeDescription(void) const
|
||||
{
|
||||
string str;
|
||||
//---
|
||||
switch(m_trade_mode)
|
||||
{
|
||||
case SYMBOL_TRADE_MODE_DISABLED:
|
||||
str="Disabled";
|
||||
break;
|
||||
case SYMBOL_TRADE_MODE_LONGONLY:
|
||||
str="Long only";
|
||||
break;
|
||||
case SYMBOL_TRADE_MODE_SHORTONLY:
|
||||
str="Short only";
|
||||
break;
|
||||
case SYMBOL_TRADE_MODE_CLOSEONLY:
|
||||
str="Close only";
|
||||
break;
|
||||
case SYMBOL_TRADE_MODE_FULL:
|
||||
str="Full access";
|
||||
break;
|
||||
default:
|
||||
str="Unknown trade mode";
|
||||
}
|
||||
//--- result
|
||||
return(str);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_TRADE_EXEMODE" as string |
|
||||
//+------------------------------------------------------------------+
|
||||
string CSymbolInfo::TradeExecutionDescription(void) const
|
||||
{
|
||||
string str;
|
||||
//---
|
||||
switch(m_trade_execution)
|
||||
{
|
||||
case SYMBOL_TRADE_EXECUTION_REQUEST:
|
||||
str="Trading on request";
|
||||
break;
|
||||
case SYMBOL_TRADE_EXECUTION_INSTANT:
|
||||
str="Trading on live streaming prices";
|
||||
break;
|
||||
case SYMBOL_TRADE_EXECUTION_MARKET:
|
||||
str="Execution of orders on the market";
|
||||
break;
|
||||
case SYMBOL_TRADE_EXECUTION_EXCHANGE:
|
||||
str="Exchange execution";
|
||||
break;
|
||||
default:
|
||||
str="Unknown trade execution";
|
||||
}
|
||||
//--- result
|
||||
return(str);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_SWAP_MODE" as string |
|
||||
//+------------------------------------------------------------------+
|
||||
string CSymbolInfo::SwapModeDescription(void) const
|
||||
{
|
||||
string str;
|
||||
//---
|
||||
switch(m_swap_mode)
|
||||
{
|
||||
case SYMBOL_SWAP_MODE_DISABLED:
|
||||
str="No swaps";
|
||||
break;
|
||||
case SYMBOL_SWAP_MODE_POINTS:
|
||||
str="Swaps are calculated in points";
|
||||
break;
|
||||
case SYMBOL_SWAP_MODE_CURRENCY_SYMBOL:
|
||||
str="Swaps are calculated in base currency";
|
||||
break;
|
||||
case SYMBOL_SWAP_MODE_CURRENCY_MARGIN:
|
||||
str="Swaps are calculated in margin currency";
|
||||
break;
|
||||
case SYMBOL_SWAP_MODE_CURRENCY_DEPOSIT:
|
||||
str="Swaps are calculated in deposit currency";
|
||||
break;
|
||||
case SYMBOL_SWAP_MODE_INTEREST_CURRENT:
|
||||
str="Swaps are calculated as annual interest using the current price";
|
||||
break;
|
||||
case SYMBOL_SWAP_MODE_INTEREST_OPEN:
|
||||
str="Swaps are calculated as annual interest using the open price";
|
||||
break;
|
||||
case SYMBOL_SWAP_MODE_REOPEN_CURRENT:
|
||||
str="Swaps are charged by reopening positions at the close price";
|
||||
break;
|
||||
case SYMBOL_SWAP_MODE_REOPEN_BID:
|
||||
str="Swaps are charged by reopening positions at the Bid price";
|
||||
break;
|
||||
default:
|
||||
str="Unknown swap mode";
|
||||
}
|
||||
//--- result
|
||||
return(str);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_SWAP_ROLLOVER3DAYS" as string |
|
||||
//+------------------------------------------------------------------+
|
||||
string CSymbolInfo::SwapRollover3daysDescription(void) const
|
||||
{
|
||||
string str;
|
||||
//---
|
||||
switch(m_swap3)
|
||||
{
|
||||
case SUNDAY:
|
||||
str="Sunday";
|
||||
break;
|
||||
case MONDAY:
|
||||
str="Monday";
|
||||
break;
|
||||
case TUESDAY:
|
||||
str="Tuesday";
|
||||
break;
|
||||
case WEDNESDAY:
|
||||
str="Wednesday";
|
||||
break;
|
||||
case THURSDAY:
|
||||
str="Thursday";
|
||||
break;
|
||||
case FRIDAY:
|
||||
str="Friday";
|
||||
break;
|
||||
case SATURDAY:
|
||||
str="Saturday";
|
||||
break;
|
||||
default:
|
||||
str="Unknown";
|
||||
}
|
||||
//--- result
|
||||
return(str);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_START_TIME" |
|
||||
//+------------------------------------------------------------------+
|
||||
datetime CSymbolInfo::StartTime(void) const
|
||||
{
|
||||
return((datetime)SymbolInfoInteger(m_name,SYMBOL_START_TIME));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_EXPIRATION_TIME" |
|
||||
//+------------------------------------------------------------------+
|
||||
datetime CSymbolInfo::ExpirationTime(void) const
|
||||
{
|
||||
return((datetime)SymbolInfoInteger(m_name,SYMBOL_EXPIRATION_TIME));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_CURRENCY_BASE" |
|
||||
//+------------------------------------------------------------------+
|
||||
string CSymbolInfo::CurrencyBase(void) const
|
||||
{
|
||||
return(SymbolInfoString(m_name,SYMBOL_CURRENCY_BASE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_CURRENCY_PROFIT" |
|
||||
//+------------------------------------------------------------------+
|
||||
string CSymbolInfo::CurrencyProfit(void) const
|
||||
{
|
||||
return(SymbolInfoString(m_name,SYMBOL_CURRENCY_PROFIT));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_CURRENCY_MARGIN" |
|
||||
//+------------------------------------------------------------------+
|
||||
string CSymbolInfo::CurrencyMargin(void) const
|
||||
{
|
||||
return(SymbolInfoString(m_name,SYMBOL_CURRENCY_MARGIN));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_BANK" |
|
||||
//+------------------------------------------------------------------+
|
||||
string CSymbolInfo::Bank(void) const
|
||||
{
|
||||
return(SymbolInfoString(m_name,SYMBOL_BANK));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_DESCRIPTION" |
|
||||
//+------------------------------------------------------------------+
|
||||
string CSymbolInfo::Description(void) const
|
||||
{
|
||||
return(SymbolInfoString(m_name,SYMBOL_DESCRIPTION));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_PATH" |
|
||||
//+------------------------------------------------------------------+
|
||||
string CSymbolInfo::Path(void) const
|
||||
{
|
||||
return(SymbolInfoString(m_name,SYMBOL_PATH));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_SESSION_DEALS" |
|
||||
//+------------------------------------------------------------------+
|
||||
long CSymbolInfo::SessionDeals(void) const
|
||||
{
|
||||
return(SymbolInfoInteger(m_name,SYMBOL_SESSION_DEALS));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_SESSION_BUY_ORDERS" |
|
||||
//+------------------------------------------------------------------+
|
||||
long CSymbolInfo::SessionBuyOrders(void) const
|
||||
{
|
||||
return(SymbolInfoInteger(m_name,SYMBOL_SESSION_BUY_ORDERS));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_SESSION_SELL_ORDERS" |
|
||||
//+------------------------------------------------------------------+
|
||||
long CSymbolInfo::SessionSellOrders(void) const
|
||||
{
|
||||
return(SymbolInfoInteger(m_name,SYMBOL_SESSION_SELL_ORDERS));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_SESSION_TURNOVER" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CSymbolInfo::SessionTurnover(void) const
|
||||
{
|
||||
return(SymbolInfoDouble(m_name,SYMBOL_SESSION_TURNOVER));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_SESSION_INTEREST" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CSymbolInfo::SessionInterest(void) const
|
||||
{
|
||||
return(SymbolInfoDouble(m_name,SYMBOL_SESSION_INTEREST));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_SESSION_BUY_ORDERS_VOLUME" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CSymbolInfo::SessionBuyOrdersVolume(void) const
|
||||
{
|
||||
return(SymbolInfoDouble(m_name,SYMBOL_SESSION_BUY_ORDERS_VOLUME));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_SESSION_SELL_ORDERS_VOLUME" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CSymbolInfo::SessionSellOrdersVolume(void) const
|
||||
{
|
||||
return(SymbolInfoDouble(m_name,SYMBOL_SESSION_SELL_ORDERS_VOLUME));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_SESSION_OPEN" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CSymbolInfo::SessionOpen(void) const
|
||||
{
|
||||
return(SymbolInfoDouble(m_name,SYMBOL_SESSION_OPEN));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_SESSION_CLOSE" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CSymbolInfo::SessionClose(void) const
|
||||
{
|
||||
return(SymbolInfoDouble(m_name,SYMBOL_SESSION_CLOSE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_SESSION_AW" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CSymbolInfo::SessionAW(void) const
|
||||
{
|
||||
return(SymbolInfoDouble(m_name,SYMBOL_SESSION_AW));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_SESSION_PRICE_SETTLEMENT" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CSymbolInfo::SessionPriceSettlement(void) const
|
||||
{
|
||||
return(SymbolInfoDouble(m_name,SYMBOL_SESSION_PRICE_SETTLEMENT));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_SESSION_PRICE_LIMIT_MIN" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CSymbolInfo::SessionPriceLimitMin(void) const
|
||||
{
|
||||
return(SymbolInfoDouble(m_name,SYMBOL_SESSION_PRICE_LIMIT_MIN));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "SYMBOL_SESSION_PRICE_LIMIT_MAX" |
|
||||
//+------------------------------------------------------------------+
|
||||
double CSymbolInfo::SessionPriceLimitMax(void) const
|
||||
{
|
||||
return(SymbolInfoDouble(m_name,SYMBOL_SESSION_PRICE_LIMIT_MAX));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access functions SymbolInfoInteger(...) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSymbolInfo::InfoInteger(const ENUM_SYMBOL_INFO_INTEGER prop_id,long &var) const
|
||||
{
|
||||
return(SymbolInfoInteger(m_name,prop_id,var));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access functions SymbolInfoDouble(...) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSymbolInfo::InfoDouble(const ENUM_SYMBOL_INFO_DOUBLE prop_id,double &var) const
|
||||
{
|
||||
return(SymbolInfoDouble(m_name,prop_id,var));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access functions SymbolInfoString(...) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSymbolInfo::InfoString(const ENUM_SYMBOL_INFO_STRING prop_id,string &var) const
|
||||
{
|
||||
return(SymbolInfoString(m_name,prop_id,var));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access functions SymbolInfoMarginRate(...) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSymbolInfo::InfoMarginRate(const ENUM_ORDER_TYPE order_type,double& initial_margin_rate,double& maintenance_margin_rate) const
|
||||
{
|
||||
return(SymbolInfoMarginRate(m_name,order_type,initial_margin_rate,maintenance_margin_rate));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Normalize price |
|
||||
//+------------------------------------------------------------------+
|
||||
double CSymbolInfo::NormalizePrice(const double price) const
|
||||
{
|
||||
if(m_tick_size!=0)
|
||||
return(NormalizeDouble(MathRound(price/m_tick_size)*m_tick_size,m_digits));
|
||||
//---
|
||||
return(NormalizeDouble(price,m_digits));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Checks if symbol is selected in the MarketWatch |
|
||||
//| and adds symbol to the MarketWatch, if necessary |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSymbolInfo::CheckMarketWatch(void)
|
||||
{
|
||||
//--- check if symbol is selected in the MarketWatch
|
||||
if(!Select())
|
||||
{
|
||||
if(GetLastError()==ERR_MARKET_UNKNOWN_SYMBOL)
|
||||
{
|
||||
printf(__FUNCTION__+": Unknown symbol '%s'",m_name);
|
||||
return(false);
|
||||
}
|
||||
if(!Select(true))
|
||||
{
|
||||
printf(__FUNCTION__+": Error adding symbol %d",GetLastError());
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,225 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| TerminalInfo.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Object.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CTerminalInfo. |
|
||||
//| Appointment: Class for access to terminal info. |
|
||||
//| Derives from class CObject. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CTerminalInfo : public CObject
|
||||
{
|
||||
public:
|
||||
CTerminalInfo(void);
|
||||
~CTerminalInfo(void);
|
||||
//--- fast access methods to the integer terminal propertyes
|
||||
int Build(void) const;
|
||||
bool IsConnected(void) const;
|
||||
bool IsDLLsAllowed(void) const;
|
||||
bool IsTradeAllowed(void) const;
|
||||
bool IsEmailEnabled(void) const;
|
||||
bool IsFtpEnabled(void) const;
|
||||
int MaxBars(void) const;
|
||||
int CodePage(void) const;
|
||||
int CPUCores(void) const;
|
||||
int MemoryPhysical(void) const;
|
||||
int MemoryTotal(void) const;
|
||||
int MemoryAvailable(void) const;
|
||||
int MemoryUsed(void) const;
|
||||
bool IsX64(void) const;
|
||||
int OpenCLSupport(void) const;
|
||||
int DiskSpace(void) const;
|
||||
//--- fast access methods to the string terminal propertyes
|
||||
string Language(void) const;
|
||||
string Name(void) const;
|
||||
string Company(void) const;
|
||||
string Path(void) const;
|
||||
string DataPath(void) const;
|
||||
string CommonDataPath(void) const;
|
||||
//--- access methods to the API MQL5 functions
|
||||
long InfoInteger(const ENUM_TERMINAL_INFO_INTEGER prop_id) const;
|
||||
string InfoString(const ENUM_TERMINAL_INFO_STRING prop_id) const;
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CTerminalInfo::CTerminalInfo(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CTerminalInfo::~CTerminalInfo(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "TERMINAL_BUILD" |
|
||||
//+------------------------------------------------------------------+
|
||||
int CTerminalInfo::Build(void) const
|
||||
{
|
||||
return((int)TerminalInfoInteger(TERMINAL_BUILD));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "TERMINAL_CONNECTED" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CTerminalInfo::IsConnected(void) const
|
||||
{
|
||||
return((bool)TerminalInfoInteger(TERMINAL_CONNECTED));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "TERMINAL_DLLS_ALLOWED" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CTerminalInfo::IsDLLsAllowed(void) const
|
||||
{
|
||||
return((bool)TerminalInfoInteger(TERMINAL_DLLS_ALLOWED));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "TERMINAL_TRADE_ALLOWED" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CTerminalInfo::IsTradeAllowed(void) const
|
||||
{
|
||||
return((bool)TerminalInfoInteger(TERMINAL_TRADE_ALLOWED));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "TERMINAL_EMAIL_ENABLED" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CTerminalInfo::IsEmailEnabled(void) const
|
||||
{
|
||||
return((bool)TerminalInfoInteger(TERMINAL_EMAIL_ENABLED));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "TERMINAL_FTP_ENABLED" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CTerminalInfo::IsFtpEnabled(void) const
|
||||
{
|
||||
return((bool)TerminalInfoInteger(TERMINAL_FTP_ENABLED));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "TERMINAL_MAXBARS" |
|
||||
//+------------------------------------------------------------------+
|
||||
int CTerminalInfo::MaxBars(void) const
|
||||
{
|
||||
return((int)TerminalInfoInteger(TERMINAL_MAXBARS));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "TERMINAL_CODEPAGE" |
|
||||
//+------------------------------------------------------------------+
|
||||
int CTerminalInfo::CodePage(void) const
|
||||
{
|
||||
return((int)TerminalInfoInteger(TERMINAL_CODEPAGE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "TERMINAL_CPU_CORES" |
|
||||
//+------------------------------------------------------------------+
|
||||
int CTerminalInfo::CPUCores(void) const
|
||||
{
|
||||
return((int)TerminalInfoInteger(TERMINAL_CPU_CORES));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "TERMINAL_MEMORY_PHYSICAL" |
|
||||
//+------------------------------------------------------------------+
|
||||
int CTerminalInfo::MemoryPhysical(void) const
|
||||
{
|
||||
return((int)TerminalInfoInteger(TERMINAL_MEMORY_PHYSICAL));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "TERMINAL_MEMORY_TOTAL" |
|
||||
//+------------------------------------------------------------------+
|
||||
int CTerminalInfo::MemoryTotal(void) const
|
||||
{
|
||||
return((int)TerminalInfoInteger(TERMINAL_MEMORY_TOTAL));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "TERMINAL_MEMORY_AVAILABLE" |
|
||||
//+------------------------------------------------------------------+
|
||||
int CTerminalInfo::MemoryAvailable(void) const
|
||||
{
|
||||
return((int)TerminalInfoInteger(TERMINAL_MEMORY_AVAILABLE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "TERMINAL_MEMORY_USED" |
|
||||
//+------------------------------------------------------------------+
|
||||
int CTerminalInfo::MemoryUsed(void) const
|
||||
{
|
||||
return((int)TerminalInfoInteger(TERMINAL_MEMORY_USED));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "TERMINAL_X64" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CTerminalInfo::IsX64(void) const
|
||||
{
|
||||
return((bool)TerminalInfoInteger(TERMINAL_X64));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "TERMINAL_OPENCL_SUPPORT" |
|
||||
//+------------------------------------------------------------------+
|
||||
int CTerminalInfo::OpenCLSupport(void) const
|
||||
{
|
||||
return((int)TerminalInfoInteger(TERMINAL_OPENCL_SUPPORT));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "TERMINAL_DISK_SPACE" |
|
||||
//+------------------------------------------------------------------+
|
||||
int CTerminalInfo::DiskSpace(void) const
|
||||
{
|
||||
return((int)TerminalInfoInteger(TERMINAL_DISK_SPACE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "TERMINAL_LANGUAGE" |
|
||||
//+------------------------------------------------------------------+
|
||||
string CTerminalInfo::Language(void) const
|
||||
{
|
||||
return(TerminalInfoString(TERMINAL_LANGUAGE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "TERMINAL_NAME" |
|
||||
//+------------------------------------------------------------------+
|
||||
string CTerminalInfo::Name(void) const
|
||||
{
|
||||
return(TerminalInfoString(TERMINAL_NAME));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "TERMINAL_COMPANY" |
|
||||
//+------------------------------------------------------------------+
|
||||
string CTerminalInfo::Company(void) const
|
||||
{
|
||||
return(TerminalInfoString(TERMINAL_COMPANY));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "TERMINAL_PATH" |
|
||||
//+------------------------------------------------------------------+
|
||||
string CTerminalInfo::Path(void) const
|
||||
{
|
||||
return(TerminalInfoString(TERMINAL_PATH));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "TERMINAL_DATA_PATH" |
|
||||
//+------------------------------------------------------------------+
|
||||
string CTerminalInfo::DataPath(void) const
|
||||
{
|
||||
return(TerminalInfoString(TERMINAL_DATA_PATH));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "TERMINAL_COMMONDATA_PATH" |
|
||||
//+------------------------------------------------------------------+
|
||||
string CTerminalInfo::CommonDataPath(void) const
|
||||
{
|
||||
return(TerminalInfoString(TERMINAL_COMMONDATA_PATH));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access functions AccountInfoInteger(...) |
|
||||
//+------------------------------------------------------------------+
|
||||
long CTerminalInfo::InfoInteger(const ENUM_TERMINAL_INFO_INTEGER prop_id) const
|
||||
{
|
||||
return(TerminalInfoInteger(prop_id));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access functions AccountInfoString(...) |
|
||||
//+------------------------------------------------------------------+
|
||||
string CTerminalInfo::InfoString(const ENUM_TERMINAL_INFO_STRING prop_id) const
|
||||
{
|
||||
return(TerminalInfoString(prop_id));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
+1708
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,385 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Box.mqh |
|
||||
//| Enrico Lambino |
|
||||
//| www.mql5.com/en/users/iceron|
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Enrico Lambino"
|
||||
#property link "www.mql5.com/en/users/iceron"
|
||||
#include <Controls\WndClient.mqh>
|
||||
#define CLASS_LAYOUT 999
|
||||
|
||||
#ifdef LAYOUT_BOX_DEBUG
|
||||
#define COLOR_BOX_BORDER clrRed
|
||||
#else
|
||||
#define COLOR_BOX_BORDER clrNONE
|
||||
#endif
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
enum LAYOUT_STYLE
|
||||
{
|
||||
LAYOUT_STYLE_VERTICAL,
|
||||
LAYOUT_STYLE_HORIZONTAL
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
enum VERTICAL_ALIGN
|
||||
{
|
||||
VERTICAL_ALIGN_CENTER,
|
||||
VERTICAL_ALIGN_CENTER_NOSIDES,
|
||||
VERTICAL_ALIGN_TOP,
|
||||
VERTICAL_ALIGN_BOTTOM
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
enum HORIZONTAL_ALIGN
|
||||
{
|
||||
HORIZONTAL_ALIGN_CENTER,
|
||||
HORIZONTAL_ALIGN_CENTER_NOSIDES,
|
||||
HORIZONTAL_ALIGN_LEFT,
|
||||
HORIZONTAL_ALIGN_RIGHT
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
class CBox: public CWndClient
|
||||
{
|
||||
protected:
|
||||
LAYOUT_STYLE m_layout_style;
|
||||
VERTICAL_ALIGN m_vertical_align;
|
||||
HORIZONTAL_ALIGN m_horizontal_align;
|
||||
CSize m_min_size;
|
||||
int m_controls_total;
|
||||
int m_padding_top;
|
||||
int m_padding_bottom;
|
||||
int m_padding_left;
|
||||
int m_padding_right;
|
||||
int m_total_x;
|
||||
int m_total_y;
|
||||
|
||||
public:
|
||||
CBox();
|
||||
~CBox();
|
||||
virtual int Type() const
|
||||
{
|
||||
return CLASS_LAYOUT;
|
||||
}
|
||||
virtual bool Create(const long chart, const string name, const int subwin,
|
||||
const int x1, const int y1, const int x2, const int y2);
|
||||
virtual bool Pack();
|
||||
void LayoutStyle(LAYOUT_STYLE style)
|
||||
{
|
||||
m_layout_style = style;
|
||||
}
|
||||
LAYOUT_STYLE LayoutStyle() const
|
||||
{
|
||||
return (m_layout_style);
|
||||
}
|
||||
void HorizontalAlign(const HORIZONTAL_ALIGN align)
|
||||
{
|
||||
m_horizontal_align = align;
|
||||
}
|
||||
HORIZONTAL_ALIGN HorizontalAlign() const
|
||||
{
|
||||
return (m_horizontal_align);
|
||||
}
|
||||
void VerticalAlign(const VERTICAL_ALIGN align)
|
||||
{
|
||||
m_vertical_align = align;
|
||||
}
|
||||
VERTICAL_ALIGN VerticalAlign() const
|
||||
{
|
||||
return (m_vertical_align);
|
||||
}
|
||||
void Padding(const int top, const int bottom, const int left, const int right);
|
||||
void Padding(const int padding);
|
||||
void PaddingTop(const int padding)
|
||||
{
|
||||
m_padding_top = padding;
|
||||
}
|
||||
int PaddingTop() const
|
||||
{
|
||||
return (m_padding_top);
|
||||
}
|
||||
void PaddingRight(const int padding)
|
||||
{
|
||||
m_padding_right = padding;
|
||||
}
|
||||
int PaddingRight() const
|
||||
{
|
||||
return (m_padding_right);
|
||||
}
|
||||
void PaddingBottom(const int padding)
|
||||
{
|
||||
m_padding_bottom = padding;
|
||||
}
|
||||
int PaddingBottom() const
|
||||
{
|
||||
return (m_padding_bottom);
|
||||
}
|
||||
void PaddingLeft(const int padding)
|
||||
{
|
||||
m_padding_left = padding;
|
||||
}
|
||||
int PaddingLeft() const
|
||||
{
|
||||
return (m_padding_left);
|
||||
}
|
||||
CSize GetMinSize() const
|
||||
{
|
||||
CSize sz;
|
||||
sz.cx = m_min_size.cx + m_padding_left + m_padding_right;
|
||||
sz.cy = m_min_size.cy + m_padding_top + m_padding_bottom;
|
||||
return sz;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void CheckControlSize(CWnd *control);
|
||||
virtual void GetTotalControlsSize(void);
|
||||
virtual bool GetSpace(int &x_space, int &y_space);
|
||||
virtual bool Render(void);
|
||||
virtual void Shift(CWnd *control, int &x, int &y, const int x_space, const int y_space);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
CBox::CBox():
|
||||
m_layout_style(LAYOUT_STYLE_HORIZONTAL),
|
||||
m_vertical_align(VERTICAL_ALIGN_CENTER),
|
||||
m_horizontal_align(HORIZONTAL_ALIGN_CENTER),
|
||||
m_controls_total(0),
|
||||
m_padding_top(2),
|
||||
m_padding_bottom(2),
|
||||
m_padding_left(2),
|
||||
m_padding_right(2),
|
||||
m_total_x(0),
|
||||
m_total_y(0)
|
||||
|
||||
{
|
||||
m_min_size.cx = 0;
|
||||
m_min_size.cy = 0;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
CBox::~CBox()
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CBox::Create(const long chart, const string name, const int subwin,
|
||||
const int x1, const int y1, const int x2, const int y2)
|
||||
{
|
||||
if(!CWndContainer::Create(chart, name, subwin, x1, y1, x2, y2))
|
||||
return (false);
|
||||
if(!CreateBack())
|
||||
return (false);
|
||||
if(!ColorBackground(CONTROLS_DIALOG_COLOR_CLIENT_BG))
|
||||
return (false);
|
||||
if(!ColorBorder(COLOR_BOX_BORDER))
|
||||
return (false);
|
||||
return (true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CBox::Pack(void)
|
||||
{
|
||||
GetTotalControlsSize();
|
||||
return (Render());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
void CBox::CheckControlSize(CWnd *control)
|
||||
{
|
||||
bool adjust = false;
|
||||
CSize size = Size();
|
||||
CSize control_size = control.Size();
|
||||
if(control_size.cx > size.cx - (m_padding_left + m_padding_right))
|
||||
{
|
||||
control_size.cx = size.cx - (m_padding_left + m_padding_right);
|
||||
adjust = true;
|
||||
}
|
||||
if(control_size.cy > size.cy - (m_padding_top + m_padding_bottom))
|
||||
{
|
||||
control_size.cy = size.cy - (m_padding_top + m_padding_bottom);
|
||||
adjust = true;
|
||||
}
|
||||
if(adjust)
|
||||
control.Size(control_size.cx, control_size.cy);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
void CBox::GetTotalControlsSize(void)
|
||||
{
|
||||
m_total_x = 0;
|
||||
m_total_y = 0;
|
||||
m_controls_total = 0;
|
||||
m_min_size.cx = 0;
|
||||
m_min_size.cy = 0;
|
||||
int total = ControlsTotal();
|
||||
|
||||
|
||||
for(int i = 0; i < total; i++)
|
||||
{
|
||||
CWnd *control = Control(i);
|
||||
if(control == NULL) continue;
|
||||
if(control == &m_background) continue;
|
||||
CheckControlSize(control);
|
||||
if(control.Type() == CLASS_LAYOUT)
|
||||
{
|
||||
((CBox *)control).GetTotalControlsSize();
|
||||
}
|
||||
|
||||
CSize control_size = control.Size();
|
||||
if(m_min_size.cx < control_size.cx)
|
||||
m_min_size.cx = control_size.cx;
|
||||
if(m_min_size.cy < control_size.cy)
|
||||
m_min_size.cy = control_size.cy;
|
||||
if(m_layout_style == LAYOUT_STYLE_HORIZONTAL) m_total_x += control_size.cx;
|
||||
else m_total_x = MathMax(m_min_size.cx, m_total_x);
|
||||
if(m_layout_style == LAYOUT_STYLE_VERTICAL) m_total_y += control_size.cy;
|
||||
else m_total_y = MathMax(m_min_size.cy, m_total_y);
|
||||
m_controls_total++;
|
||||
}
|
||||
|
||||
CSize size = Size();
|
||||
|
||||
if(m_total_x > size.cx && m_layout_style == LAYOUT_STYLE_HORIZONTAL)
|
||||
{
|
||||
size.cx = m_total_x;
|
||||
}
|
||||
if(m_total_y > size.cy && m_layout_style == LAYOUT_STYLE_VERTICAL) // shrink
|
||||
{
|
||||
size.cy = m_total_y;
|
||||
}
|
||||
|
||||
Size(size);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CBox::GetSpace(int &x_space, int &y_space)
|
||||
{
|
||||
if(m_controls_total == 0)
|
||||
return (true);
|
||||
if(m_controls_total == 1)
|
||||
{
|
||||
if(m_horizontal_align == HORIZONTAL_ALIGN_CENTER_NOSIDES)
|
||||
m_horizontal_align = HORIZONTAL_ALIGN_CENTER;
|
||||
if(m_vertical_align == VERTICAL_ALIGN_CENTER_NOSIDES)
|
||||
m_vertical_align = VERTICAL_ALIGN_CENTER;
|
||||
}
|
||||
CSize size = Size();
|
||||
|
||||
int x_space_total = 0;
|
||||
int y_space_total = 0;
|
||||
if(m_layout_style == LAYOUT_STYLE_HORIZONTAL)
|
||||
{
|
||||
x_space_total = size.cx - (m_total_x + m_padding_left + m_padding_right);
|
||||
y_space_total = size.cy - (m_min_size.cy + m_padding_top + m_padding_bottom);
|
||||
|
||||
if(m_horizontal_align == HORIZONTAL_ALIGN_CENTER_NOSIDES)
|
||||
x_space = x_space_total / (m_controls_total - 1);
|
||||
else if(m_horizontal_align == HORIZONTAL_ALIGN_CENTER)
|
||||
x_space = x_space_total / (m_controls_total + 1);
|
||||
else
|
||||
x_space = x_space_total / m_controls_total;
|
||||
|
||||
if(m_vertical_align == VERTICAL_ALIGN_CENTER || m_vertical_align == VERTICAL_ALIGN_CENTER_NOSIDES)
|
||||
y_space = y_space_total / 2;
|
||||
else
|
||||
y_space = y_space_total;
|
||||
}
|
||||
else if(m_layout_style == LAYOUT_STYLE_VERTICAL)
|
||||
{
|
||||
x_space_total = size.cx - (m_min_size.cx + m_padding_left + m_padding_right);
|
||||
y_space_total = size.cy - (m_total_y + m_padding_top + m_padding_bottom);
|
||||
|
||||
if(m_horizontal_align == HORIZONTAL_ALIGN_CENTER || m_horizontal_align == HORIZONTAL_ALIGN_CENTER_NOSIDES)
|
||||
x_space = x_space_total / 2;
|
||||
else
|
||||
x_space = x_space_total;
|
||||
|
||||
if(m_vertical_align == VERTICAL_ALIGN_CENTER_NOSIDES)
|
||||
y_space = y_space_total / (m_controls_total - 1);
|
||||
else if(m_vertical_align == VERTICAL_ALIGN_CENTER)
|
||||
y_space = y_space_total / (m_controls_total + 1);
|
||||
else
|
||||
y_space = y_space_total / m_controls_total;
|
||||
}
|
||||
else
|
||||
return (false);
|
||||
|
||||
if(x_space < 0) x_space = 0;
|
||||
if(y_space < 0) y_space = 0;
|
||||
|
||||
return (true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
void CBox::Shift(CWnd *control, int &x, int &y, const int x_space, const int y_space)
|
||||
{
|
||||
if(m_layout_style == LAYOUT_STYLE_HORIZONTAL)
|
||||
x += x_space + control.Width();
|
||||
else if(m_layout_style == LAYOUT_STYLE_VERTICAL)
|
||||
y += y_space + control.Height();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CBox::Render(void)
|
||||
{
|
||||
int x_space = 0, y_space = 0;
|
||||
if(!GetSpace(x_space, y_space))
|
||||
return (false);
|
||||
int x = Left() + m_padding_left +
|
||||
((m_horizontal_align == HORIZONTAL_ALIGN_LEFT || m_horizontal_align == HORIZONTAL_ALIGN_CENTER_NOSIDES) ? 0 : x_space);
|
||||
int y = Top() + m_padding_top +
|
||||
((m_vertical_align == VERTICAL_ALIGN_TOP || m_vertical_align == VERTICAL_ALIGN_CENTER_NOSIDES) ? 0 : y_space);
|
||||
for(int j = 0; j < ControlsTotal(); j++)
|
||||
{
|
||||
CWnd *control = Control(j);
|
||||
if(control == NULL)
|
||||
continue;
|
||||
if(control == GetPointer(m_background))
|
||||
continue;
|
||||
control.Move(x, y);
|
||||
if(control.Type() == CLASS_LAYOUT)
|
||||
{
|
||||
CBox *container = control;
|
||||
container.Pack();
|
||||
}
|
||||
if(j < ControlsTotal() - 1)
|
||||
Shift(GetPointer(control), x, y, x_space, y_space);
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
CBox::Padding(const int top, const int right, const int bottom, const int left)
|
||||
{
|
||||
m_padding_top = top;
|
||||
m_padding_right = right;
|
||||
m_padding_bottom = bottom;
|
||||
m_padding_left = left;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
CBox::Padding(const int padding)
|
||||
{
|
||||
m_padding_top = padding;
|
||||
m_padding_right = padding;
|
||||
m_padding_bottom = padding;
|
||||
m_padding_left = padding;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,66 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ComboBoxResizable.mqh |
|
||||
//| Copyright (c) 2019, Marketeer |
|
||||
//| https://www.mql5.com/en/users/marketeer |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
#include <Controls/ComboBox.mqh>
|
||||
|
||||
class ComboBoxResizable: public CComboBox
|
||||
{
|
||||
public:
|
||||
virtual bool OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam) override;
|
||||
|
||||
virtual bool OnResize(void) override
|
||||
{
|
||||
m_edit.Width(Width());
|
||||
|
||||
int x1 = Width() - (CONTROLS_BUTTON_SIZE + CONTROLS_COMBO_BUTTON_X_OFF);
|
||||
int y1 = (Height() - CONTROLS_BUTTON_SIZE) / 2;
|
||||
m_drop.Move(Left() + x1, Top() + y1);
|
||||
|
||||
m_list.Width(Width());
|
||||
|
||||
return CWndContainer::OnResize();
|
||||
}
|
||||
|
||||
virtual bool OnClickButton(void) override
|
||||
{
|
||||
// this is a hack to trigger resizing of elements in the list
|
||||
// we need it because standard ListView is incorrectly coded in such a way
|
||||
// that elements are resized only if vscroll is present
|
||||
bool vs = m_list.VScrolled();
|
||||
if(m_drop.Pressed())
|
||||
{
|
||||
m_list.VScrolled(true);
|
||||
}
|
||||
bool b = CComboBox::OnClickButton();
|
||||
m_list.VScrolled(vs);
|
||||
return b;
|
||||
}
|
||||
|
||||
virtual bool Enable(void) override
|
||||
{
|
||||
m_edit.Show();
|
||||
m_drop.Show();
|
||||
return CComboBox::Enable();
|
||||
}
|
||||
|
||||
virtual bool Disable(void) override
|
||||
{
|
||||
m_edit.Hide();
|
||||
m_drop.Hide();
|
||||
return CComboBox::Disable();
|
||||
}
|
||||
};
|
||||
|
||||
#define EXIT_ON_DISABLED \
|
||||
if(!IsEnabled()) \
|
||||
{ \
|
||||
return false; \
|
||||
}
|
||||
|
||||
EVENT_MAP_BEGIN(ComboBoxResizable)
|
||||
EXIT_ON_DISABLED
|
||||
ON_EVENT(ON_CLICK, m_drop, OnClickButton)
|
||||
EVENT_MAP_END(CComboBox)
|
||||
@@ -0,0 +1,153 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Grid.mqh |
|
||||
//| Enrico Lambino |
|
||||
//| www.mql5.com/en/users/iceron|
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Enrico Lambino"
|
||||
#property link "http://www.mql5.com"
|
||||
#property strict
|
||||
#include "Box.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
class CGrid: public CBox
|
||||
{
|
||||
protected:
|
||||
int m_cols;
|
||||
int m_rows;
|
||||
int m_hgap;
|
||||
int m_vgap;
|
||||
CSize m_cell_size;
|
||||
|
||||
public:
|
||||
CGrid();
|
||||
CGrid(int rows, int cols, int hgap = 0, int vgap = 0);
|
||||
~CGrid();
|
||||
virtual int Type() const
|
||||
{
|
||||
return CLASS_LAYOUT;
|
||||
}
|
||||
virtual bool Init(int rows, int cols, int hgap = 0, int vgap = 0);
|
||||
virtual bool Create(const long chart, const string name, const int subwin,
|
||||
const int x1, const int y1, const int x2, const int y2);
|
||||
virtual int Columns()
|
||||
{
|
||||
return (m_cols);
|
||||
}
|
||||
virtual void Columns(int cols)
|
||||
{
|
||||
m_cols = cols;
|
||||
}
|
||||
virtual int Rows()
|
||||
{
|
||||
return (m_rows);
|
||||
}
|
||||
virtual void Rows(int rows)
|
||||
{
|
||||
m_rows = rows;
|
||||
}
|
||||
virtual int HGap()
|
||||
{
|
||||
return (m_hgap);
|
||||
}
|
||||
virtual void HGap(int gap)
|
||||
{
|
||||
m_hgap = gap;
|
||||
}
|
||||
virtual int VGap()
|
||||
{
|
||||
return (m_vgap);
|
||||
}
|
||||
virtual void VGap(int gap)
|
||||
{
|
||||
m_vgap = gap;
|
||||
}
|
||||
virtual bool Pack();
|
||||
|
||||
protected:
|
||||
virtual void CheckControlSize(CWnd *control);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
CGrid::CGrid()
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
CGrid::CGrid(int rows, int cols, int hgap = 0, int vgap = 0)
|
||||
{
|
||||
Init(rows, cols, hgap, vgap);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
CGrid::~CGrid()
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CGrid::Init(int rows, int cols, int hgap = 0, int vgap = 0)
|
||||
{
|
||||
Columns(cols);
|
||||
Rows(rows);
|
||||
HGap(hgap);
|
||||
VGap(vgap);
|
||||
return (true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CGrid::Create(const long chart, const string name, const int subwin,
|
||||
const int x1, const int y1, const int x2, const int y2)
|
||||
{
|
||||
return (CBox::Create(chart, name, subwin, x1, y1, x2, y2));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CGrid::Pack()
|
||||
{
|
||||
CSize size = Size();
|
||||
m_cell_size.cx = (size.cx - ((m_cols + 1) * m_hgap)) / m_cols;
|
||||
m_cell_size.cy = (size.cy - ((m_rows + 1) * m_vgap)) / m_rows;
|
||||
int x = Left(), y = Top();
|
||||
int cnt = 0;
|
||||
for(int i = 0; i < ControlsTotal(); i++)
|
||||
{
|
||||
CWnd *control = Control(i);
|
||||
if(control == NULL)
|
||||
continue;
|
||||
if(control == GetPointer(m_background))
|
||||
continue;
|
||||
if(cnt == 0 || Right() - (x + m_cell_size.cx) < m_cell_size.cx + m_hgap)
|
||||
{
|
||||
if(cnt == 0)
|
||||
y += m_vgap;
|
||||
else
|
||||
y += m_vgap + m_cell_size.cy;
|
||||
x = Left() + m_hgap;
|
||||
}
|
||||
else
|
||||
x += m_cell_size.cx + m_hgap;
|
||||
CheckControlSize(control);
|
||||
control.Move(x, y);
|
||||
if(control.Type() == CLASS_LAYOUT)
|
||||
{
|
||||
CBox *container = control;
|
||||
container.Pack();
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
CGrid::CheckControlSize(CWnd *control)
|
||||
{
|
||||
control.Size(m_cell_size.cx, m_cell_size.cy);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,154 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| GridTk.mqh |
|
||||
//| Enrico Lambino |
|
||||
//| www.mql5.com/en/users/iceron|
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Enrico Lambino"
|
||||
#property link "http://www.mql5.com"
|
||||
#property strict
|
||||
#include "Grid.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
class CGridConstraints: public CObject
|
||||
{
|
||||
protected:
|
||||
CWnd *m_control;
|
||||
int m_row;
|
||||
int m_col;
|
||||
int m_rowspan;
|
||||
int m_colspan;
|
||||
|
||||
public:
|
||||
CGridConstraints(CWnd *control, int row, int column, int rowspan = 1, int colspan = 1);
|
||||
~CGridConstraints();
|
||||
CWnd *Control()
|
||||
{
|
||||
return (m_control);
|
||||
}
|
||||
int Row()
|
||||
{
|
||||
return (m_row);
|
||||
}
|
||||
int Column()
|
||||
{
|
||||
return (m_col);
|
||||
}
|
||||
int RowSpan()
|
||||
{
|
||||
return (m_rowspan);
|
||||
}
|
||||
int ColSpan()
|
||||
{
|
||||
return (m_colspan);
|
||||
}
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
CGridConstraints::CGridConstraints(CWnd *control, int row, int column, int rowspan = 1, int colspan = 1)
|
||||
{
|
||||
m_control = control;
|
||||
m_row = MathMax(0, row);
|
||||
m_col = MathMax(0, column);
|
||||
m_rowspan = MathMax(1, rowspan);
|
||||
m_colspan = MathMax(1, colspan);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
CGridConstraints::~CGridConstraints()
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
class CGridTk: public CGrid
|
||||
{
|
||||
protected:
|
||||
CArrayObj m_constraints;
|
||||
|
||||
public:
|
||||
CGridTk();
|
||||
~CGridTk();
|
||||
bool Grid(CWnd *control, int row, int column, int rowspan, int colspan);
|
||||
bool Pack();
|
||||
CGridConstraints *GetGridConstraints(CWnd *control);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
CGridTk::CGridTk(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
CGridTk::~CGridTk(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CGridTk::Grid(CWnd *control, int row, int column, int rowspan = 1, int colspan = 1)
|
||||
{
|
||||
CGridConstraints *constraints = new CGridConstraints(control, row, column, rowspan, colspan);
|
||||
if(!CheckPointer(constraints))
|
||||
return (false);
|
||||
if(!m_constraints.Add(constraints))
|
||||
return (false);
|
||||
return (Add(control));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CGridTk::Pack()
|
||||
{
|
||||
CGrid::Pack();
|
||||
CSize size = Size();
|
||||
m_cell_size.cx = (size.cx - (m_cols + 1) * m_hgap) / m_cols;
|
||||
m_cell_size.cy = (size.cy - (m_rows + 1) * m_vgap) / m_rows;
|
||||
for(int i = 0; i < ControlsTotal(); i++)
|
||||
{
|
||||
int x = Left(), y = Top();
|
||||
CWnd *control = Control(i);
|
||||
if(control == NULL)
|
||||
continue;
|
||||
if(control == GetPointer(m_background))
|
||||
continue;
|
||||
CGridConstraints *constraints = GetGridConstraints(control);
|
||||
if(constraints == NULL)
|
||||
continue;
|
||||
int column = constraints.Column();
|
||||
int row = constraints.Row();
|
||||
x += (column * m_cell_size.cx) + ((column + 1) * m_hgap);
|
||||
y += (row * m_cell_size.cy) + ((row + 1) * m_vgap);
|
||||
int colspan = constraints.ColSpan();
|
||||
int rowspan = constraints.RowSpan();
|
||||
control.Size(colspan * m_cell_size.cx + ((colspan - 1) * m_hgap), rowspan * m_cell_size.cy + ((rowspan - 1) * m_vgap));
|
||||
control.Move(x, y);
|
||||
if(control.Type() == CLASS_LAYOUT)
|
||||
{
|
||||
CBox *container = control;
|
||||
container.Pack();
|
||||
}
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
CGridConstraints *CGridTk::GetGridConstraints(CWnd *control)
|
||||
{
|
||||
for(int i = 0; i < m_constraints.Total(); i++)
|
||||
{
|
||||
CGridConstraints *constraints = m_constraints.At(i);
|
||||
CWnd *ctrl = constraints.Control();
|
||||
if(ctrl == NULL)
|
||||
continue;
|
||||
if(ctrl == control)
|
||||
return (constraints);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,337 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| MaximizableAppDialog.mqh |
|
||||
//| Copyright (c) 2019, Marketeer |
|
||||
//| https://www.mql5.com/en/users/marketeer |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
#include <Controls\Dialog.mqh>
|
||||
#include <Controls\Button.mqh>
|
||||
|
||||
#resource "res\\Expand2.bmp"
|
||||
#resource "res\\size6.bmp"
|
||||
#resource "res\\size10.bmp"
|
||||
|
||||
class MaximizableAppDialog: public CAppDialog
|
||||
{
|
||||
protected:
|
||||
CBmpButton m_button_truemax;
|
||||
CBmpButton m_button_size;
|
||||
bool m_maximized;
|
||||
CRect m_max_rect;
|
||||
CSize m_size_limit;
|
||||
bool m_sizing;
|
||||
|
||||
// window maximization
|
||||
virtual bool CreateButtonMinMax(void) override;
|
||||
virtual void OnClickButtonMinMax(void) override;
|
||||
virtual void OnClickButtonTrueMax(void);
|
||||
virtual void OnClickButtonSizeFixMe(void);
|
||||
virtual void Expand(void);
|
||||
virtual void Restore(void);
|
||||
|
||||
virtual void Minimize(void) override;
|
||||
|
||||
// window resizing
|
||||
bool CreateButtonSize(void);
|
||||
bool OnDialogSizeStart(void);
|
||||
virtual bool OnDialogDragStart(void) override;
|
||||
virtual bool OnDialogDragProcess(void) override;
|
||||
virtual bool OnDialogDragEnd(void) override;
|
||||
|
||||
virtual void SelfAdjustment(const bool minimized = false) = 0;
|
||||
|
||||
public:
|
||||
MaximizableAppDialog(): m_maximized(false), m_sizing(false) {}
|
||||
virtual bool Create(const long chart, const string name, const int subwin, const int x1, const int y1, const int x2, const int y2) override;
|
||||
virtual bool OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam) override;
|
||||
|
||||
virtual bool OnChartChange(const long &lparam, const double &dparam, const string &sparam);
|
||||
|
||||
void ChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam);
|
||||
|
||||
void SetSizeLimit(const CSize &limit) { m_size_limit = limit; }
|
||||
CSize GetSizeLimit() { return m_size_limit; }
|
||||
};
|
||||
|
||||
void MaximizableAppDialog::ChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
|
||||
{
|
||||
if(id == CHARTEVENT_CHART_CHANGE)
|
||||
{
|
||||
if(OnChartChange(lparam, dparam, sparam)) return;
|
||||
}
|
||||
CAppDialog::ChartEvent(id, lparam, dparam, sparam);
|
||||
}
|
||||
|
||||
EVENT_MAP_BEGIN(MaximizableAppDialog)
|
||||
ON_EVENT(ON_CLICK, m_button_truemax, OnClickButtonTrueMax)
|
||||
ON_EVENT(ON_CLICK, m_button_size, OnClickButtonSizeFixMe)
|
||||
ON_EVENT(ON_DRAG_START, m_button_size, OnDialogSizeStart)
|
||||
ON_EVENT_PTR(ON_DRAG_PROCESS, m_drag_object, OnDialogDragProcess)
|
||||
ON_EVENT_PTR(ON_DRAG_END, m_drag_object, OnDialogDragEnd)
|
||||
EVENT_MAP_END(CAppDialog)
|
||||
|
||||
bool MaximizableAppDialog::Create(const long chart, const string name, const int subwin, const int x1, const int y1, const int x2, const int y2)
|
||||
{
|
||||
// 1 * CONTROLS_BORDER_WIDTH - stays here, because the standard control library minimizes window
|
||||
// when it's height is 1 pixel smaller than the entire chart height
|
||||
m_max_rect.SetBound(0,
|
||||
0,
|
||||
(int)ChartGetInteger(ChartID(), CHART_WIDTH_IN_PIXELS) - 0 * CONTROLS_BORDER_WIDTH,
|
||||
(int)ChartGetInteger(ChartID(), CHART_HEIGHT_IN_PIXELS) - 1 * CONTROLS_BORDER_WIDTH);
|
||||
if(!CAppDialog::Create(chart, name, subwin, x1, y1, x2, y2)) return false;
|
||||
if(!CreateButtonSize()) return false;
|
||||
m_size_limit.cx = x2 - x1;
|
||||
m_size_limit.cy = y2 - y1;
|
||||
if(m_size_limit.cx >= m_max_rect.Width() || m_size_limit.cy >= m_max_rect.Height())
|
||||
{
|
||||
m_size_limit.cx = m_min_rect.Width() * 3;
|
||||
m_size_limit.cy = m_min_rect.Height() * 7;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaximizableAppDialog::CreateButtonMinMax(void) override
|
||||
{
|
||||
if(!CAppDialog::CreateButtonMinMax()) return false;
|
||||
|
||||
// add maximization button
|
||||
int off = (m_panel_flag) ? 0 : 2 * CONTROLS_BORDER_WIDTH;
|
||||
|
||||
int x1 = Width() - off - 3 * (CONTROLS_BUTTON_SIZE + CONTROLS_DIALOG_BUTTON_OFF);
|
||||
int y1 = off + CONTROLS_DIALOG_BUTTON_OFF;
|
||||
int x2 = x1 + CONTROLS_BUTTON_SIZE;
|
||||
int y2 = y1 + CONTROLS_BUTTON_SIZE;
|
||||
|
||||
if(!m_button_truemax.Create(m_chart_id, m_name + "TrueMax", m_subwin, x1, y1, x2, y2)) return false;
|
||||
if(!m_button_truemax.BmpNames("::res\\Expand2.bmp", "::res\\Restore.bmp")) return false;
|
||||
if(!CWndContainer::Add(m_button_truemax)) return false;
|
||||
|
||||
m_button_truemax.Locking(true);
|
||||
m_button_truemax.Alignment(WND_ALIGN_RIGHT, 0, 0, off + 2 * CONTROLS_BUTTON_SIZE + 2 * CONTROLS_DIALOG_BUTTON_OFF, 0);
|
||||
|
||||
CaptionAlignment(WND_ALIGN_WIDTH, off, 0, off + 3 * (CONTROLS_BUTTON_SIZE + CONTROLS_DIALOG_BUTTON_OFF), 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaximizableAppDialog::CreateButtonSize(void)
|
||||
{
|
||||
int off = (m_panel_flag) ? 0 : 2 * CONTROLS_BORDER_WIDTH;
|
||||
|
||||
int x1 = Width() - CONTROLS_BUTTON_SIZE + 1;
|
||||
int y1 = Height() - CONTROLS_BUTTON_SIZE + 1;
|
||||
int x2 = x1 + CONTROLS_BUTTON_SIZE - 1;
|
||||
int y2 = y1 + CONTROLS_BUTTON_SIZE - 1;
|
||||
|
||||
if(!m_button_size.Create(m_chart_id, m_name + "Size", m_subwin, x1, y1, x2, y2)) return false;
|
||||
if(!m_button_size.BmpNames("::res\\size6.bmp", "::res\\size10.bmp")) return false;
|
||||
if(!CWndContainer::Add(m_button_size)) return false;
|
||||
m_button_size.Alignment(WND_ALIGN_RIGHT|WND_ALIGN_BOTTOM, 0, 0, 0, 0);
|
||||
m_button_size.PropFlagsSet(WND_PROP_FLAG_CAN_DRAG);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MaximizableAppDialog::OnClickButtonTrueMax(void)
|
||||
{
|
||||
if(m_button_truemax.Pressed())
|
||||
Expand();
|
||||
else
|
||||
Restore();
|
||||
|
||||
SubwinOff();
|
||||
}
|
||||
|
||||
// This is a hack. It's required because in minimized state sizing button somehow "overlaps"
|
||||
// the close button and intercepts clicks on it (which prevents exit from minimized app).
|
||||
// This happens despite the fact that the sizing button is hidden, disabled and assigned
|
||||
// with minimal Z-order (checked out, then removed).
|
||||
// Looks like a bug in the standard control library, specifically:
|
||||
// In CWnd::OnMouseEvent there must be a line:
|
||||
//
|
||||
// if(!IS_ENABLED || !IS_VISIBLE) return false;
|
||||
//
|
||||
// but it's not there, so invisible, disabled and even background objects are processed
|
||||
// in the same manner as all other objects. Specifically in CWndContainer::OnMouseEvent
|
||||
// there is a reverse loop through all objects (it does _not_ respect Z-order anyhow).
|
||||
|
||||
void MaximizableAppDialog::OnClickButtonSizeFixMe(void)
|
||||
{
|
||||
if(m_minimized)
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void MaximizableAppDialog::Expand(void)
|
||||
{
|
||||
m_maximized = true;
|
||||
m_minimized = false;
|
||||
m_button_minmax.Pressed(false);
|
||||
Rebound(m_max_rect);
|
||||
m_button_size.Hide();
|
||||
m_button_size.StateFlagsReset(WND_STATE_FLAG_ENABLE);
|
||||
m_button_size.PropFlagsReset(WND_PROP_FLAG_CAN_DRAG);
|
||||
if(!m_panel_flag)
|
||||
{
|
||||
m_caption.PropFlagsReset(WND_PROP_FLAG_CAN_DRAG);
|
||||
}
|
||||
|
||||
ClientAreaVisible(true);
|
||||
SelfAdjustment();
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Restore dialog window |
|
||||
//+------------------------------------------------------------------+
|
||||
void MaximizableAppDialog::Restore(void)
|
||||
{
|
||||
m_maximized = false;
|
||||
m_minimized = false;
|
||||
m_button_minmax.Pressed(false);
|
||||
m_button_size.Show();
|
||||
m_button_size.StateFlagsSet(WND_STATE_FLAG_ENABLE);
|
||||
m_button_size.PropFlagsSet(WND_PROP_FLAG_CAN_DRAG);
|
||||
CAppDialog::Maximize();
|
||||
if(!m_panel_flag)
|
||||
{
|
||||
m_caption.PropFlagsSet(WND_PROP_FLAG_CAN_DRAG);
|
||||
}
|
||||
SelfAdjustment();
|
||||
}
|
||||
|
||||
void MaximizableAppDialog::Minimize()
|
||||
{
|
||||
CAppDialog::Minimize();
|
||||
m_button_size.Hide();
|
||||
m_button_size.StateFlagsReset(WND_STATE_FLAG_ENABLE);
|
||||
m_button_size.PropFlagsReset(WND_PROP_FLAG_CAN_DRAG);
|
||||
}
|
||||
|
||||
bool MaximizableAppDialog::OnChartChange(const long &lparam, const double &dparam, const string &sparam)
|
||||
{
|
||||
m_max_rect.SetBound(0, 0,
|
||||
(int)ChartGetInteger(ChartID(), CHART_WIDTH_IN_PIXELS) - 0 * CONTROLS_BORDER_WIDTH,
|
||||
(int)ChartGetInteger(ChartID(), CHART_HEIGHT_IN_PIXELS) - 1 * CONTROLS_BORDER_WIDTH);
|
||||
if(m_maximized)
|
||||
{
|
||||
if(m_rect.Width() != m_max_rect.Width() || m_rect.Height() != m_max_rect.Height())
|
||||
{
|
||||
Rebound(m_max_rect);
|
||||
SelfAdjustment();
|
||||
m_chart.Redraw();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MaximizableAppDialog::OnClickButtonMinMax(void)
|
||||
{
|
||||
CAppDialog::OnClickButtonMinMax();
|
||||
m_button_truemax.Pressed(false);
|
||||
m_maximized = false;
|
||||
if(m_minimized)
|
||||
{
|
||||
m_button_size.Hide();
|
||||
m_button_size.StateFlagsReset(WND_STATE_FLAG_ENABLE);
|
||||
m_button_size.PropFlagsReset(WND_PROP_FLAG_CAN_DRAG);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_button_size.Show();
|
||||
m_button_size.StateFlagsSet(WND_STATE_FLAG_ENABLE);
|
||||
m_button_size.PropFlagsSet(WND_PROP_FLAG_CAN_DRAG);
|
||||
}
|
||||
if(!m_panel_flag)
|
||||
{
|
||||
m_caption.PropFlagsSet(WND_PROP_FLAG_CAN_DRAG);
|
||||
}
|
||||
SelfAdjustment(m_minimized);
|
||||
}
|
||||
|
||||
bool MaximizableAppDialog::OnDialogSizeStart(void)
|
||||
{
|
||||
if(m_drag_object == NULL)
|
||||
{
|
||||
m_drag_object = new CDragWnd;
|
||||
if(m_drag_object == NULL) return false;
|
||||
}
|
||||
int x1 = m_button_size.Left() - CONTROLS_DRAG_SPACING;
|
||||
int y1 = m_button_size.Top() - CONTROLS_DRAG_SPACING;
|
||||
int x2 = m_button_size.Right() + CONTROLS_DRAG_SPACING;
|
||||
int y2 = m_button_size.Bottom() + CONTROLS_DRAG_SPACING;
|
||||
|
||||
m_drag_object.Create(m_chart_id, "", m_subwin, x1, y1, x2, y2);
|
||||
m_drag_object.PropFlagsSet(WND_PROP_FLAG_CAN_DRAG);
|
||||
|
||||
CChart chart;
|
||||
chart.Attach(m_chart_id);
|
||||
m_drag_object.Limits(-CONTROLS_DRAG_SPACING, -CONTROLS_DRAG_SPACING,
|
||||
chart.WidthInPixels() + CONTROLS_DRAG_SPACING,
|
||||
chart.HeightInPixels(m_subwin) + CONTROLS_DRAG_SPACING);
|
||||
chart.Detach();
|
||||
|
||||
m_drag_object.MouseX(m_button_size.MouseX());
|
||||
m_drag_object.MouseY(m_button_size.MouseY());
|
||||
m_drag_object.MouseFlags(m_button_size.MouseFlags());
|
||||
|
||||
m_sizing = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaximizableAppDialog::OnDialogDragStart(void)
|
||||
{
|
||||
if(m_maximized) return false;
|
||||
|
||||
return CAppDialog::OnDialogDragStart();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Continue dragging the dialog box |
|
||||
//+------------------------------------------------------------------+
|
||||
bool MaximizableAppDialog::OnDialogDragProcess(void)
|
||||
{
|
||||
if(!m_sizing) return CDialog::OnDialogDragProcess();
|
||||
|
||||
if(m_drag_object == NULL) return false;
|
||||
|
||||
int x = m_drag_object.Right() - Right() - CONTROLS_DRAG_SPACING;
|
||||
int y = m_drag_object.Bottom() - Bottom() - CONTROLS_DRAG_SPACING;
|
||||
|
||||
// resize dialog
|
||||
CRect r = Rect();
|
||||
r.right += x;
|
||||
r.bottom += y;
|
||||
|
||||
if(r.Width() < m_size_limit.cx) r.right = r.left + m_size_limit.cx;
|
||||
if(r.Height() < m_size_limit.cy) r.bottom = r.top + m_size_limit.cy;
|
||||
|
||||
Rebound(r);
|
||||
|
||||
SelfAdjustment();
|
||||
|
||||
return true;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| End dragging the dialog box |
|
||||
//+------------------------------------------------------------------+
|
||||
bool MaximizableAppDialog::OnDialogDragEnd(void)
|
||||
{
|
||||
if(!m_sizing) return CDialog::OnDialogDragEnd();
|
||||
|
||||
if(m_drag_object != NULL)
|
||||
{
|
||||
m_button_size.MouseFlags(m_drag_object.MouseFlags());
|
||||
delete m_drag_object;
|
||||
m_drag_object = NULL;
|
||||
}
|
||||
|
||||
m_norm_rect.SetBound(m_rect);
|
||||
m_sizing = false;
|
||||
|
||||
SelfAdjustment();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SpinEditResizable.mqh |
|
||||
//| Copyright (c) 2019, Marketeer |
|
||||
//| https://www.mql5.com/en/users/marketeer |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
#include <Controls/SpinEdit.mqh>
|
||||
|
||||
class SpinEditResizable: public CSpinEdit
|
||||
{
|
||||
public:
|
||||
virtual bool OnResize(void) override
|
||||
{
|
||||
m_edit.Width(Width());
|
||||
m_edit.Height(Height());
|
||||
|
||||
int x1 = Width() - (CONTROLS_BUTTON_SIZE + CONTROLS_SPIN_BUTTON_X_OFF);
|
||||
int y1 = (Height() - 2 * CONTROLS_SPIN_BUTTON_SIZE) / 2;
|
||||
m_inc.Move(Left() + x1, Top() + y1);
|
||||
|
||||
x1 = Width() - (CONTROLS_BUTTON_SIZE + CONTROLS_SPIN_BUTTON_X_OFF);
|
||||
y1 = (Height() - 2 * CONTROLS_SPIN_BUTTON_SIZE) / 2 + CONTROLS_SPIN_BUTTON_SIZE;
|
||||
m_dec.Move(Left() + x1, Top() + y1);
|
||||
|
||||
return CWndContainer::OnResize();
|
||||
}
|
||||
};
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
File diff suppressed because one or more lines are too long
@@ -0,0 +1,112 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| CSVReader.mqh |
|
||||
//| Copyright (c) 2019, Marketeer |
|
||||
//| https://www.mql5.com/ru/articles/5913 |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
#include <Marketeer/IndexMap.mqh>
|
||||
#include <Marketeer/GroupSettings.mqh>
|
||||
|
||||
|
||||
input GroupSettings SCV_Settings; // C S V S E T T I N G S
|
||||
|
||||
input string CSVDelimiter = ";" /*mql5 signals use ';' instead of ','*/; // · Delimiter
|
||||
|
||||
|
||||
class CSVConverter
|
||||
{
|
||||
private:
|
||||
class File
|
||||
{
|
||||
int file;
|
||||
|
||||
public:
|
||||
File(const string name, const int flags, const short delimiter)
|
||||
{
|
||||
file = FileOpen(name, flags, delimiter, CP_UTF8);
|
||||
}
|
||||
|
||||
File(const string name, const int flags)
|
||||
{
|
||||
file = FileOpen(name, flags);
|
||||
}
|
||||
|
||||
bool isOpened()
|
||||
{
|
||||
return (file != INVALID_HANDLE);
|
||||
}
|
||||
|
||||
int handle()
|
||||
{
|
||||
return file;
|
||||
}
|
||||
|
||||
~File()
|
||||
{
|
||||
if(file != INVALID_HANDLE) FileClose(file);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
static IndexMap *ReadCSV(const string inputFileName)
|
||||
{
|
||||
// history.csv - 13 columns, positions.csv - 10 columns
|
||||
int columns = StringFind(inputFileName, ".history.csv") > 0 ? 13 : (StringFind(inputFileName, ".positions.csv") > 0 ? 10 : 0);
|
||||
if(columns == 0)
|
||||
{
|
||||
Print("Supported files: *.history.csv and .positions.csv");
|
||||
return NULL;
|
||||
}
|
||||
Print("Reading csv-file ", inputFileName);
|
||||
uchar delimiter = (uchar)CSVDelimiter[0];
|
||||
File f(inputFileName, FILE_READ|FILE_TXT|FILE_ANSI|FILE_SHARE_READ|FILE_SHARE_WRITE, delimiter);
|
||||
if(!f.isOpened())
|
||||
{
|
||||
Alert("Can't read file " + inputFileName);
|
||||
return NULL;
|
||||
}
|
||||
int file = f.handle();
|
||||
|
||||
bool headerLine = true;
|
||||
IndexMap *data = new IndexMap();
|
||||
string headers[];
|
||||
uint count = 0;
|
||||
|
||||
while(!FileIsEnding(file))
|
||||
{
|
||||
string stLine = "";
|
||||
string stParts[];
|
||||
|
||||
stLine = FileReadString(file);
|
||||
|
||||
int nParts = StringSplit(stLine, delimiter, stParts);
|
||||
if(nParts != columns)
|
||||
{
|
||||
Print("File " + inputFileName + " contains " + (string)nParts + " columns (" + (string)(columns) + "+ required)");
|
||||
Print("Line: ", stLine);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(headerLine)
|
||||
{
|
||||
headerLine = false;
|
||||
ArrayCopy(headers, stParts);
|
||||
continue;
|
||||
}
|
||||
|
||||
IndexMap *row = new IndexMap();
|
||||
|
||||
for(int i = 0; i < nParts; i++)
|
||||
{
|
||||
row.setValue((string)i + "." + headers[i], stParts[i]);
|
||||
}
|
||||
|
||||
data.add((string)count, row);
|
||||
++count;
|
||||
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
#define CSV_COLUMN_TIME1 0
|
||||
#define CSV_COLUMN_TYPE 1
|
||||
#define CSV_COLUMN_VOLUME 2
|
||||
#define CSV_COLUMN_SYMBOL 3
|
||||
#define CSV_COLUMN_PRICE1 4
|
||||
#define CSV_COLUMN_TIME2 5 // 7
|
||||
#define CSV_COLUMN_PRICE2 6 // 8
|
||||
#define CSV_COLUMN_COMMISSION 7 // 9
|
||||
#define CSV_COLUMN_SWAP 8 // 10
|
||||
#define CSV_COLUMN_PROFIT 9 // 11
|
||||
#define CSV_COLUMN_COMMENT 12
|
||||
@@ -0,0 +1,24 @@
|
||||
template<typename T1,typename T2>
|
||||
class Converter
|
||||
{
|
||||
private:
|
||||
union _L2D
|
||||
{
|
||||
T1 L;
|
||||
T2 D;
|
||||
}
|
||||
L2D;
|
||||
|
||||
public:
|
||||
T2 operator[](const T1 L)
|
||||
{
|
||||
L2D.L = L;
|
||||
return L2D.D;
|
||||
}
|
||||
|
||||
T1 operator[](const T2 D)
|
||||
{
|
||||
L2D.D = D;
|
||||
return L2D.L;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
enum GroupSettings {};
|
||||
@@ -0,0 +1,15 @@
|
||||
#define COLUMNS_COUNT 13
|
||||
|
||||
#define COLUMN_TIME 0
|
||||
#define COLUMN_DEAL 1
|
||||
#define COLUMN_SYMBOL 2
|
||||
#define COLUMN_TYPE 3
|
||||
#define COLUMN_DIRECTION 4
|
||||
#define COLUMN_VOLUME 5
|
||||
#define COLUMN_PRICE 6
|
||||
#define COLUMN_ORDER 7
|
||||
#define COLUMN_COMISSION 8
|
||||
#define COLUMN_SWAP 9
|
||||
#define COLUMN_PROFIT 10
|
||||
#define COLUMN_BALANCE 11
|
||||
#define COLUMN_COMMENT 12
|
||||
@@ -0,0 +1,401 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| IndexMapT.mqh |
|
||||
//| https://www.mql5.com/ru/articles/5706/ |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
#define EMPTY ((int)EMPTY_VALUE)
|
||||
|
||||
#ifdef HASHMAP_WARNING
|
||||
#define NULL_PLACEHOLDER "n/a"
|
||||
#else
|
||||
#define NULL_PLACEHOLDER ""
|
||||
#endif
|
||||
|
||||
class Object
|
||||
{
|
||||
public:
|
||||
|
||||
virtual string asString() const
|
||||
{
|
||||
return(__FUNCSIG__);
|
||||
}
|
||||
|
||||
virtual string asCSVString() const
|
||||
{
|
||||
return(__FUNCSIG__);
|
||||
}
|
||||
|
||||
virtual string getTypeName() const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Base container for indexed map. Can contain plain types and pointers.
|
||||
*/
|
||||
class Container: public Object
|
||||
{
|
||||
protected:
|
||||
enum datatype
|
||||
{
|
||||
null,
|
||||
s,
|
||||
d,
|
||||
t,
|
||||
i,
|
||||
o,
|
||||
u
|
||||
};
|
||||
|
||||
datatype type;
|
||||
|
||||
public:
|
||||
datatype getType() const
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
// helper method to access plain type values from the base class
|
||||
template<typename R>
|
||||
R get() const;
|
||||
|
||||
// helper method to access object pointers from the base class
|
||||
template<typename R>
|
||||
Object *getObject() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Variable type data for indexed map; plain types only.
|
||||
*/
|
||||
template<typename T>
|
||||
class TypeContainer: public Container
|
||||
{
|
||||
private:
|
||||
int digits;
|
||||
int flags;
|
||||
|
||||
protected:
|
||||
T v;
|
||||
|
||||
TypeContainer()
|
||||
{
|
||||
digits = _Digits;
|
||||
flags = TIME_DATE | TIME_MINUTES;
|
||||
}
|
||||
|
||||
public:
|
||||
TypeContainer(T _v, int precision = INT_MIN, int timeflags = TIME_DATE | TIME_MINUTES)
|
||||
{
|
||||
v = _v;
|
||||
digits = precision == INT_MIN ? _Digits : precision;
|
||||
flags = timeflags;
|
||||
|
||||
if(typename(T) == "string")
|
||||
{
|
||||
type = datatype::s;
|
||||
}
|
||||
else
|
||||
if(typename(T) == "double" || typename(T) == "float")
|
||||
{
|
||||
type = datatype::d;
|
||||
}
|
||||
else
|
||||
if(typename(T) == "datetime")
|
||||
{
|
||||
type = datatype::t;
|
||||
}
|
||||
else
|
||||
if(typename(T) == "char" || typename(T) == "short" || typename(T) == "int" || typename(T) == "long")
|
||||
{
|
||||
type = datatype::i;
|
||||
}
|
||||
else
|
||||
{
|
||||
type = datatype::u;
|
||||
}
|
||||
}
|
||||
|
||||
virtual T getValue() const
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
// represent data as a string, convert if necessary
|
||||
virtual string asString() const
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case datatype::s: return (string)v;
|
||||
case datatype::d: return DoubleToString((double)v, digits);
|
||||
case datatype::t: return TimeToString((datetime)v, flags);
|
||||
case datatype::i: return IntegerToString((long)v);
|
||||
default: return (string)v;
|
||||
}
|
||||
}
|
||||
|
||||
virtual string asCSVString() const
|
||||
{
|
||||
return asString();
|
||||
}
|
||||
|
||||
virtual string getTypeName() const override
|
||||
{
|
||||
return typename(this);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Object pointer types for indexed map.
|
||||
* Pointer will be deleted automatically.
|
||||
*/
|
||||
template<typename T>
|
||||
class ObjectContainer: public Container
|
||||
{
|
||||
protected:
|
||||
Object *o;
|
||||
|
||||
public:
|
||||
ObjectContainer(T _v)
|
||||
{
|
||||
o = _v;
|
||||
type = datatype::o;
|
||||
}
|
||||
|
||||
~ObjectContainer()
|
||||
{
|
||||
if(CheckPointer(o) == POINTER_DYNAMIC)
|
||||
{
|
||||
delete(o);
|
||||
}
|
||||
}
|
||||
|
||||
T getObject() const
|
||||
{
|
||||
return o;
|
||||
}
|
||||
|
||||
virtual string asString() const override
|
||||
{
|
||||
return o.asString();
|
||||
}
|
||||
|
||||
virtual string asCSVString() const
|
||||
{
|
||||
return o.asCSVString();
|
||||
}
|
||||
|
||||
virtual string getTypeName() const override
|
||||
{
|
||||
return typename(this);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename R>
|
||||
R Container::get() const
|
||||
{
|
||||
const TypeContainer<R> *ptr = dynamic_cast<const TypeContainer<R> *>(&this);
|
||||
if(ptr != NULL) return (R)ptr.getValue();
|
||||
return (R)NULL;
|
||||
}
|
||||
|
||||
template<typename R> // R is supposed to be an object pointer
|
||||
Object *Container::getObject() const
|
||||
{
|
||||
const ObjectContainer<R> *obj = dynamic_cast<const ObjectContainer<R> *>(&this);
|
||||
if(obj != NULL) return obj.getObject();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Indexed map with random access by key and index.
|
||||
*/
|
||||
template<typename T>
|
||||
class IndexMapT: public Container // Object
|
||||
{
|
||||
private:
|
||||
T keys[];
|
||||
Container *values[];
|
||||
int count;
|
||||
string id;
|
||||
uchar delimiter;
|
||||
|
||||
public:
|
||||
IndexMapT(): count(0), delimiter(',') {}
|
||||
IndexMapT(string obj): id (obj), count(0), delimiter(',') {}
|
||||
IndexMapT(uchar d): count(0), delimiter(d) {}
|
||||
|
||||
~IndexMapT()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
virtual string getTypeName() const override
|
||||
{
|
||||
return typename(this);
|
||||
}
|
||||
|
||||
void add(const T key, Container *value)
|
||||
{
|
||||
ArrayResize(keys, count + 1);
|
||||
ArrayResize(values, count + 1);
|
||||
keys[count] = key;
|
||||
values[count] = value;
|
||||
count++;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
if(CheckPointer(values[i]) == POINTER_DYNAMIC)
|
||||
{
|
||||
delete(values[i]);
|
||||
}
|
||||
}
|
||||
ArrayResize(keys, 0);
|
||||
ArrayResize(values, 0);
|
||||
count = 0;
|
||||
}
|
||||
|
||||
bool isKeyExisting(const T key) const
|
||||
{
|
||||
return (getIndex(key) != EMPTY);
|
||||
}
|
||||
|
||||
int getIndex(const T key) const
|
||||
{
|
||||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
if(keys[i] == key) return(i);
|
||||
}
|
||||
#ifdef HASHMAP_VERBOSE
|
||||
Print(__FUNCSIG__, ": no key=", key);
|
||||
#endif
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
Container *operator[](const int index) const
|
||||
{
|
||||
if(index < 0 || index >= count)
|
||||
{
|
||||
#ifdef HASHMAP_VERBOSE
|
||||
Print(__FUNCSIG__, ": index=", index);
|
||||
#endif
|
||||
return(NULL);
|
||||
}
|
||||
return(GetPointer(values[index]));
|
||||
}
|
||||
|
||||
Container *operator[](const T key) const
|
||||
{
|
||||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
if(keys[i] == key) return(GetPointer(values[i]));
|
||||
}
|
||||
#ifdef HASHMAP_VERBOSE
|
||||
Print(__FUNCSIG__, ": no key=", key);
|
||||
#endif
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
T getKey(const int index) const
|
||||
{
|
||||
if(index < 0 || index >= count)
|
||||
{
|
||||
Print(__FUNCSIG__, ": index=", index);
|
||||
}
|
||||
return(keys[index]);
|
||||
}
|
||||
|
||||
template<typename R>
|
||||
void setValue(const T key, R value)
|
||||
{
|
||||
// NB: implementation specific
|
||||
// in HTML every attribute can occur only once in a tag,
|
||||
// all successive assignments are ignored
|
||||
if(!isKeyExisting(key))
|
||||
{
|
||||
set(key, new TypeContainer<R>(value));
|
||||
}
|
||||
}
|
||||
|
||||
void set(const T key, Container *value)
|
||||
{
|
||||
int index = getIndex(key);
|
||||
if(index != EMPTY)
|
||||
{
|
||||
#ifdef HASHMAP_WARNING
|
||||
Print(__FUNCSIG__, ": overwritten key=", key, ", old value=", (values[index] != NULL ? values[index].asString() : "null"), ", new value=", (value != NULL ? value.asString() : "null"));
|
||||
#endif
|
||||
values[index] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
add(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
void set(const T key)
|
||||
{
|
||||
int index = getIndex(key);
|
||||
if(index == EMPTY)
|
||||
{
|
||||
add(key, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
int getSize() const
|
||||
{
|
||||
return(count);
|
||||
}
|
||||
|
||||
virtual string asString() const
|
||||
{
|
||||
string result = "";
|
||||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
result += (string)keys[i] + "=" + (CheckPointer(values[i]) == POINTER_INVALID ? NULL_PLACEHOLDER : values[i].asString()) + ";";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual string asCSVString() const
|
||||
{
|
||||
string result = "";
|
||||
string d = CharToString(delimiter);
|
||||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
string v = NULL_PLACEHOLDER;
|
||||
|
||||
if(CheckPointer(values[i]) != POINTER_INVALID)
|
||||
{
|
||||
v = values[i].asCSVString();
|
||||
StringReplace(v, d, "");
|
||||
}
|
||||
|
||||
if(i < count - 1)
|
||||
{
|
||||
result += v + d;
|
||||
}
|
||||
else
|
||||
{
|
||||
result += v;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
class IndexMap: public IndexMapT<string>
|
||||
{
|
||||
public:
|
||||
IndexMap(): IndexMapT() {}
|
||||
IndexMap(string obj): IndexMapT(obj) {}
|
||||
IndexMap(uchar d): IndexMapT(d) {}
|
||||
string get(const string key)
|
||||
{
|
||||
Container *c = this[key];
|
||||
if(c == NULL) return NULL;
|
||||
return c.get<string>();
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,195 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| RubbArray.mqh |
|
||||
//| Copyright (c) 2019, Marketeer |
|
||||
//| https://www.mql5.com/en/users/marketeer |
|
||||
//| https://www.mql5.com/ru/articles/5638 |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
template <typename T>
|
||||
interface Clonable
|
||||
{
|
||||
T clone();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class BaseArray
|
||||
{
|
||||
protected:
|
||||
T data[];
|
||||
|
||||
public:
|
||||
virtual ~BaseArray()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
virtual void clear()
|
||||
{
|
||||
ArrayResize(data, 0);
|
||||
}
|
||||
|
||||
T operator[](int i) const
|
||||
{
|
||||
return get(i);
|
||||
}
|
||||
|
||||
T get(int i) const
|
||||
{
|
||||
if(i < 0 || i >= ArraySize(data))
|
||||
{
|
||||
Print("Array size=", ArraySize(data), ", index=", i);
|
||||
return NULL;
|
||||
}
|
||||
return data[i];
|
||||
}
|
||||
|
||||
T top() const
|
||||
{
|
||||
if(ArraySize(data) == 0)
|
||||
{
|
||||
Print("Array size=0");
|
||||
return NULL;
|
||||
}
|
||||
return data[ArraySize(data) - 1];
|
||||
}
|
||||
|
||||
T peek() const
|
||||
{
|
||||
return top();
|
||||
}
|
||||
|
||||
BaseArray *add(T d)
|
||||
{
|
||||
int n = ArraySize(data);
|
||||
ArrayResize(data, n + 1);
|
||||
data[n] = d;
|
||||
return &this;
|
||||
}
|
||||
|
||||
BaseArray *operator<<(T d)
|
||||
{
|
||||
return add(d);
|
||||
}
|
||||
|
||||
BaseArray *operator<<(const BaseArray<T> *x)
|
||||
{
|
||||
for(int i = 0; i < x.size(); i++)
|
||||
{
|
||||
Clonable<T> *clone = dynamic_cast<Clonable<T> *>(x[i]);
|
||||
if(clone != NULL)
|
||||
{
|
||||
add(clone.clone());
|
||||
}
|
||||
else
|
||||
{
|
||||
add(x[i]);
|
||||
}
|
||||
}
|
||||
return &this;
|
||||
}
|
||||
|
||||
BaseArray *push(T d)
|
||||
{
|
||||
return add(d);
|
||||
}
|
||||
|
||||
void operator=(const BaseArray &d)
|
||||
{
|
||||
int i, n = d.size();
|
||||
ArrayResize(data, n);
|
||||
for(i = 0; i < n; i++)
|
||||
{
|
||||
data[i] = d[i];
|
||||
}
|
||||
}
|
||||
|
||||
T operator>>(int i)
|
||||
{
|
||||
T d = this[i];
|
||||
if(d == NULL) return NULL;
|
||||
int n = ArraySize(data) - 1;
|
||||
if(i < n)
|
||||
{
|
||||
ArrayCopy(data, data, i, i + 1);
|
||||
}
|
||||
ArrayResize(data, n);
|
||||
return d;
|
||||
}
|
||||
|
||||
T pop()
|
||||
{
|
||||
int _size = ArraySize(data) - 1;
|
||||
T d = this[_size];
|
||||
ArrayResize(data, _size);
|
||||
return d;
|
||||
}
|
||||
|
||||
int size() const
|
||||
{
|
||||
return ArraySize(data);
|
||||
}
|
||||
|
||||
|
||||
string toString() const
|
||||
{
|
||||
static string formats[4][2] = {{"double", "%f"}, {"long", "%i"}, {"string", "%s"}, {"int", "%i"}};
|
||||
string fmt = "%x";
|
||||
for(int k = 0; k < ArrayRange(formats, 0); k++)
|
||||
{
|
||||
if(typename(T) == formats[k][0])
|
||||
{
|
||||
fmt = formats[k][1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int i, n = ArraySize(data);
|
||||
string s;
|
||||
for(i = 0; i < n; i++)
|
||||
{
|
||||
s += StringFormat(fmt, data[i]) + ",";
|
||||
}
|
||||
return (s);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class RubbArray: public BaseArray<T>
|
||||
{
|
||||
public:
|
||||
RubbArray()
|
||||
{
|
||||
}
|
||||
|
||||
~RubbArray()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
virtual void clear() override
|
||||
{
|
||||
int i, n = ArraySize(data);
|
||||
for(i = 0; i < n; i++)
|
||||
{
|
||||
if(CheckPointer(data[i]) == POINTER_DYNAMIC) delete data[i];
|
||||
}
|
||||
ArrayResize(data, 0);
|
||||
}
|
||||
|
||||
T replace(const int i, T v)
|
||||
{
|
||||
int n = ArraySize(data);
|
||||
if(i < n)
|
||||
{
|
||||
if(CheckPointer(data[i]) == POINTER_DYNAMIC) delete data[i];
|
||||
data[i] = v;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#define List RubbArray
|
||||
#define Stack RubbArray
|
||||
@@ -0,0 +1,43 @@
|
||||
//#define DATETIME_PLACEHOLDER ((datetime)0xFFFFFFFFFFFFFFFF)
|
||||
|
||||
class DateTime
|
||||
{
|
||||
private:
|
||||
MqlDateTime mdtstruct;
|
||||
|
||||
public:
|
||||
DateTime(){TimeToStruct(0, mdtstruct);}
|
||||
DateTime *assign(datetime dt) {TimeToStruct(dt, mdtstruct); return &this;}
|
||||
int __TimeDayOfWeek() {return mdtstruct.day_of_week;}
|
||||
int __TimeDayOfYear() {return mdtstruct.day_of_year;}
|
||||
int __TimeYear() {return mdtstruct.year;}
|
||||
int __TimeMonth() {return mdtstruct.mon;}
|
||||
int __TimeDay() {return mdtstruct.day;}
|
||||
int __TimeHour() {return mdtstruct.hour;}
|
||||
int __TimeMinute() {return mdtstruct.min;}
|
||||
int __TimeSeconds() {return mdtstruct.sec;}
|
||||
};
|
||||
|
||||
DateTime _DateTime;
|
||||
|
||||
#define TimeDayOfWeek(T) _DateTime.assign(T).__TimeDayOfWeek()
|
||||
#define TimeYear(T) _DateTime.assign(T).__TimeYear()
|
||||
#define TimeMonth(T) _DateTime.assign(T).__TimeMonth()
|
||||
#define TimeDay(T) _DateTime.assign(T).__TimeDay()
|
||||
#define TimeHour(T) _DateTime.assign(T).__TimeHour()
|
||||
#define TimeMinute(T) _DateTime.assign(T).__TimeMinute()
|
||||
#define TimeSeconds(T) _DateTime.assign(T).__TimeSeconds()
|
||||
|
||||
#define _TimeYear _DateTime.__TimeYear
|
||||
#define _TimeMonth _DateTime.__TimeMonth
|
||||
#define _TimeDay _DateTime.__TimeDay
|
||||
#define _TimeHour _DateTime.__TimeHour
|
||||
#define _TimeMinute _DateTime.__TimeMinute
|
||||
#define _TimeSeconds _DateTime.__TimeSeconds
|
||||
|
||||
#define Year _DateTime.assign(TimeCurrent()).__TimeYear
|
||||
#define Month _DateTime.assign(TimeCurrent()).__TimeMonth
|
||||
#define Day _DateTime.assign(TimeCurrent()).__TimeDay
|
||||
#define Hour _DateTime.assign(TimeCurrent()).__TimeHour
|
||||
#define Minute _DateTime.assign(TimeCurrent()).__TimeMinute
|
||||
#define Seconds _DateTime.assign(TimeCurrent()).__TimeSeconds
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,20 @@
|
||||
// header
|
||||
"isindex",
|
||||
"base",
|
||||
"meta",
|
||||
"link",
|
||||
"nextid",
|
||||
"range",
|
||||
// elsewhere
|
||||
"img",
|
||||
"br",
|
||||
"hr",
|
||||
"frame",
|
||||
"wbr",
|
||||
"basefont",
|
||||
"spacer",
|
||||
"area",
|
||||
"param",
|
||||
"keygen",
|
||||
"col",
|
||||
"limittext"
|
||||
@@ -0,0 +1,151 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| CSVcube.mqh |
|
||||
//| Copyright (c) 2019, Marketeer |
|
||||
//| https://www.mql5.com/en/users/marketeer |
|
||||
//| Online Analytical Processing of trading hypercubes |
|
||||
//| https://www.mql5.com/ru/articles/6602 |
|
||||
//| https://www.mql5.com/ru/articles/6603 |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
#include <Marketeer/CSVReader.mqh>
|
||||
#include <Marketeer/CSVcolumns.mqh>
|
||||
|
||||
template<typename T>
|
||||
class CSVTradeRecord: public T // TradeRecord
|
||||
{
|
||||
public:
|
||||
CSVTradeRecord(const double balance, const string symbol, const IndexMap *row)
|
||||
{
|
||||
const int add = row.getSize() == 13 ? 2 : 0;
|
||||
set(FIELD_NUMBER, counter);
|
||||
set(FIELD_TICKET, counter++);
|
||||
set(FIELD_SYMBOL, symbols.add(symbol));
|
||||
string t = row[CSV_COLUMN_TYPE].get<string>();
|
||||
StringToLower(t);
|
||||
const int _type = t == "buy" ? +1 : (t == "sell" ? -1 : 0);
|
||||
set(FIELD_TYPE, _type == +1 ? OP_BUY : (_type == -1 ? OP_SELL : OP_BALANCE));
|
||||
datetime time1 = StringToTime(row[CSV_COLUMN_TIME1].get<string>()) + TimeShift;
|
||||
datetime time2 = StringToTime(row[CSV_COLUMN_TIME2 + add].get<string>()) + TimeShift;
|
||||
set(FIELD_DATETIME1, time1);
|
||||
set(FIELD_DATETIME2, time2);
|
||||
set(FIELD_DURATION, time2 - time1);
|
||||
double price1 = StringToDouble(row[CSV_COLUMN_PRICE1].get<string>());
|
||||
double price2 = StringToDouble(row[CSV_COLUMN_PRICE2 + add].get<string>());
|
||||
set(FIELD_PRICE1, price1);
|
||||
set(FIELD_PRICE2, price2);
|
||||
set(FIELD_MAGIC, 0);
|
||||
magics.add(0);
|
||||
set(FIELD_LOT, StringToDouble(row[CSV_COLUMN_VOLUME].get<string>()));
|
||||
t = row[CSV_COLUMN_PROFIT + add].get<string>();
|
||||
StringReplace(t, " ", "");
|
||||
const double profit = StringToDouble(t);
|
||||
set(FIELD_PROFIT_AMOUNT, profit);
|
||||
set(FIELD_PROFIT_PERCENT, (profit / balance));
|
||||
set(FIELD_PROFIT_POINT, (_type * (price2 - price1) / SymbolInfoDouble(symbol, SYMBOL_POINT)));
|
||||
set(FIELD_COMMISSION, StringToDouble(row[CSV_COLUMN_COMMISSION + add].get<string>()));
|
||||
set(FIELD_SWAP, StringToDouble(row[CSV_COLUMN_SWAP + add].get<string>()));
|
||||
|
||||
fillCustomFields();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class CSVReportAdapter: public DataAdapter
|
||||
{
|
||||
private:
|
||||
RubbArray<CSVTradeRecord<T> *> trades;
|
||||
|
||||
int cursor;
|
||||
int size;
|
||||
double balance;
|
||||
IndexMap *data;
|
||||
|
||||
void reset()
|
||||
{
|
||||
size = 0;
|
||||
cursor = 0;
|
||||
balance = 0;
|
||||
if(CheckPointer(data) == POINTER_DYNAMIC) delete data;
|
||||
}
|
||||
|
||||
public:
|
||||
CSVReportAdapter()
|
||||
{
|
||||
reset();
|
||||
TradeRecord::reset();
|
||||
}
|
||||
|
||||
~CSVReportAdapter()
|
||||
{
|
||||
if(CheckPointer(data) == POINTER_DYNAMIC) delete data;
|
||||
}
|
||||
|
||||
bool load(const string file)
|
||||
{
|
||||
reset();
|
||||
data = CSVConverter::ReadCSV(file);
|
||||
if(data != NULL)
|
||||
{
|
||||
size = generate();
|
||||
Print(data.getSize(), " records transferred to ", size, " trades");
|
||||
}
|
||||
return data != NULL;
|
||||
}
|
||||
|
||||
virtual int reservedSize() override
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
virtual Record *getNext() override
|
||||
{
|
||||
if(cursor < size)
|
||||
{
|
||||
return trades[cursor++];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
protected:
|
||||
int generate()
|
||||
{
|
||||
int count = 0;
|
||||
balance = 0;
|
||||
for(int i = data.getSize() - 1; i >= 0; --i) // csv-files have reverse chronological order
|
||||
{
|
||||
IndexMap *row = data[i];
|
||||
const int add = row.getSize() == 13 ? 2 : 0;
|
||||
string s = row[CSV_COLUMN_SYMBOL].get<string>();
|
||||
StringTrimLeft(s);
|
||||
if(StringLen(s) > 0)
|
||||
{
|
||||
if(balance == 0)
|
||||
{
|
||||
Print("Zero balance, 10000 emulated");
|
||||
balance = 10000;
|
||||
}
|
||||
|
||||
string real = TradeRecord::realsymbol(s);
|
||||
if(real == NULL) continue;
|
||||
|
||||
trades << new CSVTradeRecord<T>(balance, real, row);
|
||||
++count;
|
||||
}
|
||||
else
|
||||
{
|
||||
string type = row[CSV_COLUMN_TYPE].get<string>();
|
||||
StringToLower(type);
|
||||
if(type == "balance")
|
||||
{
|
||||
string t = row[CSV_COLUMN_PROFIT + add].get<string>();
|
||||
StringReplace(t, " ", "");
|
||||
balance += StringToDouble(t);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,350 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| HTMLcube.mqh |
|
||||
//| Copyright (c) 2019, Marketeer |
|
||||
//| https://www.mql5.com/en/users/marketeer |
|
||||
//| Online Analytical Processing of trading hypercubes |
|
||||
//| https://www.mql5.com/ru/articles/6602 |
|
||||
//| https://www.mql5.com/ru/articles/6603 |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
#include <Marketeer/GroupSettings.mqh>
|
||||
|
||||
input GroupSettings Common_Settings; // G E N E R A L S E T T I N G S
|
||||
|
||||
input string ReportFile = ""; // · ReportFile
|
||||
input string Prefix = ""; // · Prefix
|
||||
input string Suffix = ""; // · Suffix
|
||||
input int TimeShift = 0; // · TimeShift
|
||||
|
||||
|
||||
#include <Marketeer/WebDataExtractor.mqh>
|
||||
#include <Marketeer/RubbArray.mqh>
|
||||
#include <Marketeer/HTMLcolumns.mqh>
|
||||
|
||||
|
||||
template<typename T>
|
||||
class HTMLTradeRecord: public T // TradeRecord
|
||||
{
|
||||
public:
|
||||
HTMLTradeRecord(
|
||||
const double balance,
|
||||
const long ticket,
|
||||
const string symbol,
|
||||
const int type,
|
||||
const datetime time1,
|
||||
const datetime time2,
|
||||
const double price1,
|
||||
const double price2,
|
||||
const double lot,
|
||||
const double profit,
|
||||
const double commission,
|
||||
const double swap)
|
||||
{
|
||||
set(FIELD_NUMBER, counter++);
|
||||
set(FIELD_TICKET, ticket);
|
||||
set(FIELD_SYMBOL, symbols.add(symbol));
|
||||
set(FIELD_TYPE, type);
|
||||
set(FIELD_DATETIME1, time1);
|
||||
set(FIELD_DATETIME2, time2);
|
||||
set(FIELD_DURATION, time2 - time1);
|
||||
set(FIELD_PRICE1, (float)price1);
|
||||
set(FIELD_PRICE2, (float)price2);
|
||||
set(FIELD_MAGIC, 0);
|
||||
magics.add(0);
|
||||
set(FIELD_LOT, (float)lot);
|
||||
set(FIELD_PROFIT_AMOUNT, (float)profit);
|
||||
set(FIELD_PROFIT_PERCENT, (float)(profit / balance));
|
||||
set(FIELD_PROFIT_POINT, (float)((type == OP_BUY ? +1 : -1) * (price2 - price1) / SymbolInfoDouble(symbol, SYMBOL_POINT)));
|
||||
set(FIELD_COMMISSION, (float)commission);
|
||||
set(FIELD_SWAP, (float)swap);
|
||||
|
||||
fillCustomFields(); // calls implementation from T
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class HTMLReportAdapter: public DataAdapter
|
||||
{
|
||||
private:
|
||||
|
||||
class Deal // if MQL5 could respect private access specifier for classes,
|
||||
{ // Trades will be unreachable from outer world, so it would be fine to have
|
||||
public: // fields made public for direct access from Processor only
|
||||
datetime time;
|
||||
double price;
|
||||
int type; // +1 - buy, -1 - sell
|
||||
int direction; // +1 - in, -1 - out, 0 - in/out
|
||||
double volume;
|
||||
double profit;
|
||||
long deal;
|
||||
long order;
|
||||
string comment;
|
||||
string symbol;
|
||||
double commission;
|
||||
double swap;
|
||||
|
||||
public:
|
||||
Deal(const IndexMap *row) // this is MT5 deal
|
||||
{
|
||||
time = StringToTime(row[COLUMN_TIME].get<string>()) + TimeShift;
|
||||
price = StringToDouble(row[COLUMN_PRICE].get<string>());
|
||||
string t = row[COLUMN_TYPE].get<string>();
|
||||
type = t == "buy" ? +1 : (t == "sell" ? -1 : 0);
|
||||
t = row[COLUMN_DIRECTION].get<string>();
|
||||
direction = 0;
|
||||
if(StringFind(t, "in") > -1) ++direction;
|
||||
if(StringFind(t, "out") > -1) --direction;
|
||||
volume = StringToDouble(row[COLUMN_VOLUME].get<string>());
|
||||
t = row[COLUMN_PROFIT].get<string>();
|
||||
StringReplace(t, " ", "");
|
||||
profit = StringToDouble(t);
|
||||
deal = StringToInteger(row[COLUMN_DEAL].get<string>());
|
||||
order = StringToInteger(row[COLUMN_ORDER].get<string>());
|
||||
comment = row[COLUMN_COMMENT].get<string>();
|
||||
symbol = row[COLUMN_SYMBOL].get<string>();
|
||||
commission = StringToDouble(row[COLUMN_COMISSION].get<string>());
|
||||
swap = StringToDouble(row[COLUMN_SWAP].get<string>());
|
||||
}
|
||||
|
||||
bool isIn() const
|
||||
{
|
||||
return direction >= 0;
|
||||
}
|
||||
|
||||
bool isOut() const
|
||||
{
|
||||
return direction <= 0;
|
||||
}
|
||||
|
||||
bool isOpposite(const Deal *t) const
|
||||
{
|
||||
return type * t.type < 0;
|
||||
}
|
||||
|
||||
bool isActive() const
|
||||
{
|
||||
return volume > 0;
|
||||
}
|
||||
|
||||
int op_type() const
|
||||
{
|
||||
if(type == +1) return OP_BUY;
|
||||
else if(type == -1) return OP_SELL;
|
||||
return OP_BALANCE;
|
||||
}
|
||||
};
|
||||
|
||||
RubbArray<Deal *> array;
|
||||
RubbArray<Deal *> queue;
|
||||
|
||||
|
||||
int size;
|
||||
int cursor;
|
||||
double balance;
|
||||
IndexMap *data;
|
||||
|
||||
RubbArray<HTMLTradeRecord<T> *> trades;
|
||||
|
||||
|
||||
protected:
|
||||
int generate()
|
||||
{
|
||||
array.clear();
|
||||
balance = 0;
|
||||
for(int i = 0; i < data.getSize(); ++i)
|
||||
{
|
||||
IndexMap *row = data[i];
|
||||
if(CheckPointer(row) == POINTER_INVALID || row.getSize() != COLUMNS_COUNT) return 0; // something is broken
|
||||
string s = row[COLUMN_SYMBOL].get<string>();
|
||||
StringTrimLeft(s);
|
||||
if(StringLen(s) > 0)
|
||||
{
|
||||
array << new Deal(row);
|
||||
}
|
||||
else if(row[COLUMN_TYPE].get<string>() == "balance")
|
||||
{
|
||||
string t = row[COLUMN_PROFIT].get<string>();
|
||||
StringReplace(t, " ", "");
|
||||
balance += StringToDouble(t);
|
||||
}
|
||||
}
|
||||
|
||||
if(balance == 0) balance = 10000; // default, if missing
|
||||
|
||||
int count = 0;
|
||||
// abstract:
|
||||
// if direction <= 0
|
||||
// collect all Trades from the queue which have direction >= 0 and opposite type
|
||||
// if this volume is greater than collected volumes
|
||||
// reduce volume in this Deal by the total volume of collected Trades
|
||||
// else if collected volumes are greater than this volume
|
||||
// reduce volume in matched Trades in a loop until all volume of this Deal is exhausted
|
||||
// create object-lines from all affected Trades to this Deal
|
||||
// 'delete' all affected Trades with zero volume from queue
|
||||
// if volume == 0, 'delete' this Deal (disactivate)
|
||||
// if direction >= 0 push the new Deal object to the queue
|
||||
|
||||
for(int i = 0; i < array.size(); ++i)
|
||||
{
|
||||
Deal *current = array[i];
|
||||
|
||||
if(!current.isActive()) continue;
|
||||
|
||||
string real = TradeRecord::realsymbol(current.symbol);
|
||||
if(real == NULL) continue;
|
||||
|
||||
if(current.isOut())
|
||||
{
|
||||
// first try to find exact match
|
||||
for(int j = 0; j < queue.size(); ++j)
|
||||
{
|
||||
if(queue[j].isIn() && queue[j].isOpposite(current) && queue[j].volume == current.volume && queue[j].symbol == current.symbol)
|
||||
{
|
||||
trades << new HTMLTradeRecord<T>(
|
||||
balance,
|
||||
queue[j].deal,
|
||||
real, // current.symbol,
|
||||
queue[j].op_type(),
|
||||
queue[j].time,
|
||||
current.time,
|
||||
queue[j].price,
|
||||
current.price,
|
||||
current.volume,
|
||||
current.profit,
|
||||
queue[j].commission + current.commission,
|
||||
current.swap);
|
||||
balance += current.profit;
|
||||
|
||||
current.volume = 0;
|
||||
queue >> j; // remove from queue
|
||||
++count;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!current.isActive()) continue;
|
||||
|
||||
// second try to perform partial close
|
||||
for(int j = 0; j < queue.size(); ++j)
|
||||
{
|
||||
if(queue[j].isIn() && queue[j].isOpposite(current) && queue[j].symbol == current.symbol)
|
||||
{
|
||||
if(current.volume >= queue[j].volume)
|
||||
{
|
||||
double fraction = queue[j].volume / current.volume;
|
||||
|
||||
trades << new HTMLTradeRecord<T>(
|
||||
balance,
|
||||
queue[j].deal,
|
||||
real, // current.symbol,
|
||||
queue[j].op_type(),
|
||||
queue[j].time,
|
||||
current.time,
|
||||
queue[j].price,
|
||||
current.price,
|
||||
queue[j].volume,
|
||||
current.profit * fraction,
|
||||
queue[j].commission + current.commission * fraction,
|
||||
current.swap * fraction);
|
||||
balance += current.profit * fraction;
|
||||
|
||||
current.volume -= queue[j].volume;
|
||||
queue[j].volume = 0;
|
||||
++count;
|
||||
}
|
||||
else
|
||||
{
|
||||
double fraction = current.volume / queue[j].volume;
|
||||
|
||||
trades << new HTMLTradeRecord<T>(
|
||||
balance,
|
||||
queue[j].deal,
|
||||
real, // current.symbol,
|
||||
queue[j].op_type(),
|
||||
queue[j].time,
|
||||
current.time,
|
||||
queue[j].price,
|
||||
current.price,
|
||||
current.volume,
|
||||
queue[j].profit * fraction, // should be 0
|
||||
queue[j].commission * fraction + current.commission,
|
||||
current.swap);
|
||||
balance += queue[j].profit * fraction;
|
||||
|
||||
queue[j].volume -= current.volume;
|
||||
current.volume = 0;
|
||||
++count;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// purge all inactive from queue
|
||||
for(int j = queue.size() - 1; j >= 0; --j)
|
||||
{
|
||||
if(!queue[j].isActive())
|
||||
{
|
||||
queue >> j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(current.isActive()) // is _still_ active
|
||||
{
|
||||
if(current.isIn())
|
||||
{
|
||||
queue << current;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
cursor = 0;
|
||||
balance = 0;
|
||||
if(CheckPointer(data) == POINTER_DYNAMIC) delete data;
|
||||
}
|
||||
|
||||
public:
|
||||
HTMLReportAdapter()
|
||||
{
|
||||
reset();
|
||||
TradeRecord::reset();
|
||||
}
|
||||
|
||||
~HTMLReportAdapter()
|
||||
{
|
||||
if(CheckPointer(data) == POINTER_DYNAMIC) delete data;
|
||||
((BaseArray<Deal *> *)&queue).clear();
|
||||
}
|
||||
|
||||
bool load(const string file)
|
||||
{
|
||||
reset();
|
||||
data = HTMLConverter::convertReport2Map(file, true);
|
||||
if(data != NULL)
|
||||
{
|
||||
size = generate();
|
||||
Print(data.getSize(), " deals transferred to ", size, " trades");
|
||||
}
|
||||
return data != NULL;
|
||||
}
|
||||
|
||||
virtual int reservedSize() override
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
virtual Record *getNext() override
|
||||
{
|
||||
if(cursor < size)
|
||||
{
|
||||
return trades[cursor++];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,241 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| OLAPcore.mqh |
|
||||
//| Copyright © 2019, Marketeer |
|
||||
//| https://www.mql5.com/en/users/marketeer |
|
||||
//| Online Analytical Processing of trading hypercubes |
|
||||
//| https://www.mql5.com/ru/articles/6602 |
|
||||
//| https://www.mql5.com/ru/articles/6603 |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
#include <OLAP/OLAPcube.mqh>
|
||||
#include <OLAP/HTMLcube.mqh>
|
||||
#include <OLAP/CSVcube.mqh>
|
||||
|
||||
|
||||
class DaysRangeSelector: public DateTimeSelector<TRADE_RECORD_FIELDS>
|
||||
{
|
||||
protected:
|
||||
int granulatity;
|
||||
|
||||
public:
|
||||
DaysRangeSelector(const int n): DateTimeSelector<TRADE_RECORD_FIELDS>(FIELD_DURATION, 7), granulatity(n)
|
||||
{
|
||||
_typename = typename(this);
|
||||
}
|
||||
|
||||
virtual int getRange() const
|
||||
{
|
||||
return granulatity;
|
||||
}
|
||||
|
||||
virtual bool select(const Record *r, int &index) const
|
||||
{
|
||||
double d = r.get(selector);
|
||||
int days = (int)(d / (60 * 60 * 24));
|
||||
index = MathMin(days, granulatity - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual string getLabel(const int index) const
|
||||
{
|
||||
return index < granulatity - 1 ? ((index < 10 ? " ": "") + (string)index + "D") : ((string)index + "D+");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class OLAPWrapper
|
||||
{
|
||||
protected:
|
||||
Selector<TRADE_RECORD_FIELDS> *createSelector(const SELECTORS selector, const TRADE_RECORD_FIELDS field)
|
||||
{
|
||||
switch(selector)
|
||||
{
|
||||
case SELECTOR_TYPE:
|
||||
return new TypeSelector();
|
||||
case SELECTOR_SYMBOL:
|
||||
return new SymbolSelector();
|
||||
case SELECTOR_SERIAL:
|
||||
return new SerialNumberSelector();
|
||||
case SELECTOR_MAGIC:
|
||||
return new MagicSelector();
|
||||
case SELECTOR_PROFITABLE:
|
||||
return new ProfitableSelector();
|
||||
case SELECTOR_DURATION:
|
||||
return new DaysRangeSelector(15); // up to 14 days
|
||||
case SELECTOR_WEEKDAY:
|
||||
return field != FIELD_NONE ? new WeekDaySelector(field) : NULL;
|
||||
case SELECTOR_DAYHOUR:
|
||||
return field != FIELD_NONE ? new DayHourSelector(field) : NULL;
|
||||
case SELECTOR_HOURMINUTE:
|
||||
return field != FIELD_NONE ? new DayHourSelector(field) : NULL;
|
||||
case SELECTOR_SCALAR:
|
||||
return field != FIELD_NONE ? new TradeSelector(field) : NULL;
|
||||
case SELECTOR_QUANTS:
|
||||
return field != FIELD_NONE ? new QuantizationSelector(field) : NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
public:
|
||||
void process(
|
||||
const SELECTORS &selectorArray[], const TRADE_RECORD_FIELDS &selectorField[],
|
||||
const AGGREGATORS AggregatorType, const TRADE_RECORD_FIELDS AggregatorField, Display &display,
|
||||
const SORT_BY SortBy = SORT_BY_NONE,
|
||||
const double Filter1value1 = 0, const double Filter1value2 = 0)
|
||||
{
|
||||
int selectorCount = 0;
|
||||
for(int i = 0; i < MathMin(ArraySize(selectorArray), 3); i++)
|
||||
{
|
||||
selectorCount += selectorArray[i] != SELECTOR_NONE;
|
||||
}
|
||||
|
||||
if(selectorCount == 0)
|
||||
{
|
||||
Alert("No selectors. Setup at least one of them.");
|
||||
return;
|
||||
}
|
||||
|
||||
// filter section not used yet >>>
|
||||
SELECTORS Filter1 = SELECTOR_NONE;
|
||||
TRADE_RECORD_FIELDS Filter1Field = FIELD_NONE;
|
||||
|
||||
if(ArraySize(selectorArray) > 3)
|
||||
{
|
||||
Filter1 = selectorArray[3];
|
||||
}
|
||||
|
||||
if(ArraySize(selectorField) > 3)
|
||||
{
|
||||
Filter1Field = selectorField[3];
|
||||
}
|
||||
// <<< filter section not used
|
||||
|
||||
HistoryDataAdapter<CustomTradeRecord> history;
|
||||
HTMLReportAdapter<CustomTradeRecord> report;
|
||||
CSVReportAdapter<CustomTradeRecord> external;
|
||||
|
||||
DataAdapter *adapter = &history;
|
||||
|
||||
if(ReportFile != "")
|
||||
{
|
||||
if(StringFind(ReportFile, ".htm") > 0 && report.load(ReportFile))
|
||||
{
|
||||
adapter = &report;
|
||||
}
|
||||
else
|
||||
if(StringFind(ReportFile, ".csv") > 0 && external.load(ReportFile))
|
||||
{
|
||||
adapter = &external;
|
||||
}
|
||||
else
|
||||
{
|
||||
Alert("Unknown file format: ", ReportFile);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Print("Analyzing account history");
|
||||
}
|
||||
|
||||
Analyst<TRADE_RECORD_FIELDS> *analyst;
|
||||
|
||||
Selector<TRADE_RECORD_FIELDS> *selectors[];
|
||||
ArrayResize(selectors, selectorCount);
|
||||
|
||||
for(int i = 0; i < selectorCount; i++)
|
||||
{
|
||||
selectors[i] = createSelector(selectorArray[i], selectorField[i]);
|
||||
if(selectors[i] == NULL)
|
||||
{
|
||||
Print("Selector ", i, " is empty. Setup selectors successively (don't leave a hole in-between), specify a field when required");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// filter section not used yet >>>
|
||||
Filter<TRADE_RECORD_FIELDS> *filters[];
|
||||
if(Filter1 != SELECTOR_NONE)
|
||||
{
|
||||
ArrayResize(filters, 1);
|
||||
Selector<TRADE_RECORD_FIELDS> *filterSelector = createSelector(Filter1, Filter1Field);
|
||||
if(Filter1value1 != Filter1value2)
|
||||
{
|
||||
filters[0] = new FilterRange<TRADE_RECORD_FIELDS>(filterSelector, Filter1value1, Filter1value2);
|
||||
}
|
||||
else
|
||||
{
|
||||
filters[0] = new Filter<TRADE_RECORD_FIELDS>(filterSelector, Filter1value1);
|
||||
}
|
||||
}
|
||||
// <<< filter section not used
|
||||
|
||||
Aggregator<TRADE_RECORD_FIELDS> *aggregator;
|
||||
|
||||
// MQL does not support a 'class info' metaclass.
|
||||
// Otherwise we could use an array of classes instead of the switch
|
||||
switch(AggregatorType)
|
||||
{
|
||||
case AGGREGATOR_SUM:
|
||||
aggregator = new SumAggregator<TRADE_RECORD_FIELDS>(AggregatorField, selectors, filters);
|
||||
break;
|
||||
case AGGREGATOR_AVERAGE:
|
||||
aggregator = new AverageAggregator<TRADE_RECORD_FIELDS>(AggregatorField, selectors, filters);
|
||||
break;
|
||||
case AGGREGATOR_MAX:
|
||||
aggregator = new MaxAggregator<TRADE_RECORD_FIELDS>(AggregatorField, selectors, filters);
|
||||
break;
|
||||
case AGGREGATOR_MIN:
|
||||
aggregator = new MinAggregator<TRADE_RECORD_FIELDS>(AggregatorField, selectors, filters);
|
||||
break;
|
||||
case AGGREGATOR_COUNT:
|
||||
aggregator = new CountAggregator<TRADE_RECORD_FIELDS>(AggregatorField, selectors, filters);
|
||||
break;
|
||||
case AGGREGATOR_PROFITFACTOR:
|
||||
aggregator = new ProfitFactorAggregator<TRADE_RECORD_FIELDS>(AggregatorField, selectors, filters);
|
||||
break;
|
||||
case AGGREGATOR_PROGRESSIVE:
|
||||
aggregator = new ProgressiveTotalAggregator<TRADE_RECORD_FIELDS>(AggregatorField, selectors, filters);
|
||||
break;
|
||||
case AGGREGATOR_IDENTITY:
|
||||
aggregator = new IdentityAggregator<TRADE_RECORD_FIELDS>(AggregatorField, selectors, filters);
|
||||
break;
|
||||
}
|
||||
|
||||
analyst = new Analyst<TRADE_RECORD_FIELDS>(adapter, aggregator, display);
|
||||
|
||||
analyst.acquireData();
|
||||
|
||||
Print("Symbol number: ", TradeRecord::getSymbolCount());
|
||||
for(int i = 0; i < TradeRecord::getSymbolCount(); i++)
|
||||
{
|
||||
Print(i, "] ", TradeRecord::getSymbol(i));
|
||||
}
|
||||
|
||||
Print("Magic number: ", TradeRecord::getMagicCount());
|
||||
for(int i = 0; i < TradeRecord::getMagicCount(); i++)
|
||||
{
|
||||
Print(i, "] ", TradeRecord::getMagic(i));
|
||||
}
|
||||
|
||||
Print("Filters: ", aggregator.getFilterTitles());
|
||||
|
||||
Print("Selectors: ", selectorCount);
|
||||
|
||||
analyst.build();
|
||||
analyst.display(SortBy, AggregatorType == AGGREGATOR_IDENTITY);
|
||||
|
||||
delete analyst;
|
||||
delete aggregator;
|
||||
for(int i = 0; i < selectorCount; i++)
|
||||
{
|
||||
delete selectors[i];
|
||||
}
|
||||
for(int i = 0; i < ArraySize(filters); i++)
|
||||
{
|
||||
delete filters[i].getSelector();
|
||||
delete filters[i];
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,148 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| PairArray.mqh |
|
||||
//| Copyright © 2019, Marketeer |
|
||||
//| https://www.mql5.com/en/users/marketeer |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
class PairArray
|
||||
{
|
||||
public:
|
||||
// aux struct to populate temp array when sorting is enabled
|
||||
struct Pair
|
||||
{
|
||||
double value;
|
||||
string title;
|
||||
Pair(): value(DBL_MAX), title(NULL) {}
|
||||
Pair(const double v, const string s): value(v), title(s) {}
|
||||
Pair(const string s, const double v): value(v), title(s) {}
|
||||
bool operator>(const double v) const
|
||||
{
|
||||
return value > v;
|
||||
}
|
||||
bool operator>(const string s) const
|
||||
{
|
||||
return title > s;
|
||||
}
|
||||
};
|
||||
|
||||
// this is a common parent, so it can not be templatized
|
||||
class Comparator
|
||||
{
|
||||
public:
|
||||
// templatized method can not be virtual,
|
||||
// so we do artificial dynamic dispatching manually
|
||||
// (see below after declaration of descendant classes)
|
||||
template<typename T>
|
||||
bool compare(const Pair &v1, const T v2);
|
||||
};
|
||||
|
||||
class Greater: public Comparator
|
||||
{
|
||||
public:
|
||||
template<typename T>
|
||||
bool compare(const Pair &v1, const T v2)
|
||||
{
|
||||
return v1 > v2;
|
||||
}
|
||||
};
|
||||
|
||||
class Lesser: public Comparator
|
||||
{
|
||||
public:
|
||||
template<typename T>
|
||||
bool compare(const Pair &v1, const T v2)
|
||||
{
|
||||
return !(v1 > v2);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
Comparator *comparator;
|
||||
|
||||
public:
|
||||
// temp array for sorting (if enabled)
|
||||
Pair array[];
|
||||
|
||||
PairArray(): comparator(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
PairArray(const int reserved, Comparator *c = NULL)
|
||||
{
|
||||
comparator = c;
|
||||
ArrayResize(array, reserved);
|
||||
}
|
||||
|
||||
~PairArray()
|
||||
{
|
||||
ArrayResize(array, 0);
|
||||
if(CheckPointer(comparator) == POINTER_DYNAMIC) delete comparator;
|
||||
}
|
||||
|
||||
void allocate(const int reserved)
|
||||
{
|
||||
ArrayResize(array, reserved);
|
||||
}
|
||||
|
||||
void compareBy(Comparator *c)
|
||||
{
|
||||
if(CheckPointer(comparator) == POINTER_DYNAMIC) delete comparator;
|
||||
comparator = c;
|
||||
}
|
||||
|
||||
void move(const int index, const int count)
|
||||
{
|
||||
for(int i = count - 1; i >= index; --i)
|
||||
{
|
||||
array[i + 1] = array[i];
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T1, typename T2>
|
||||
void insert(const int count, const T1 v, const T2 s)
|
||||
{
|
||||
Pair p(v, s);
|
||||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
if(comparator != NULL && comparator.compare(array[i], v))
|
||||
{
|
||||
move(i, count);
|
||||
array[i] = p;
|
||||
return;
|
||||
}
|
||||
}
|
||||
array[count] = p;
|
||||
}
|
||||
|
||||
void convert(double &x[], string &s[]) const
|
||||
{
|
||||
int n = ArraySize(array);
|
||||
ArrayResize(x, n);
|
||||
ArrayResize(s, n);
|
||||
for(int i = 0; i < n; i++)
|
||||
{
|
||||
x[i] = array[i].value;
|
||||
s[i] = array[i].title;
|
||||
}
|
||||
}
|
||||
|
||||
void convert(double &x[]) const
|
||||
{
|
||||
int n = ArraySize(array);
|
||||
ArrayResize(x, n);
|
||||
for(int i = 0; i < n; i++)
|
||||
{
|
||||
x[i] = array[i].value;
|
||||
}
|
||||
}
|
||||
|
||||
void convert(string &s[]) const
|
||||
{
|
||||
int n = ArraySize(array);
|
||||
ArrayResize(s, n);
|
||||
for(int i = 0; i < n; i++)
|
||||
{
|
||||
s[i] = array[i].title;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,525 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Plot.mqh |
|
||||
//| Copyright (c) 2019, Marketeer |
|
||||
//| https://www.mql5.com/en/users/marketeer |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright (c) 2019, Marketeer"
|
||||
#property link "https://www.mql5.com/en/users/marketeer"
|
||||
#property version "1.0"
|
||||
|
||||
#include <Controls\WndClient.mqh>
|
||||
#include <Graphics\Graphic.mqh>
|
||||
#include <OLAP/PairArray.mqh>
|
||||
|
||||
class CurveSubtitles
|
||||
{
|
||||
public:
|
||||
CCurve *curve;
|
||||
PairArray *data;
|
||||
|
||||
void assign(const CCurve *c, const PairArray *d)
|
||||
{
|
||||
curve = (CCurve *)c;
|
||||
data = (PairArray *)d;
|
||||
}
|
||||
};
|
||||
|
||||
class CGraphicInPlot: public CGraphic
|
||||
{
|
||||
protected:
|
||||
long m_chart_id; // chart ID
|
||||
CurveSubtitles curvecache[];
|
||||
|
||||
void CGraphicInPlot::Customize(CCurve *c, const int points);
|
||||
CCurve *CGraphicInPlot::CacheIt(const CCurve *c, const PairArray *data = NULL);
|
||||
|
||||
public:
|
||||
CGraphicInPlot();
|
||||
~CGraphicInPlot();
|
||||
|
||||
virtual bool Create(const long chart, const string name, const int subwin, const int x1, const int y1, const int x2, const int y2);
|
||||
|
||||
CCurve *CurveAdd(const PairArray *data, ENUM_CURVE_TYPE type, const string name = NULL); // overload
|
||||
CCurve *CurveAdd(const double &x[], const double &y[], ENUM_CURVE_TYPE type, const string name = NULL); // overload
|
||||
|
||||
void CurvesRemoveAll(void);
|
||||
|
||||
virtual bool Shift(const int dx, const int dy);
|
||||
|
||||
virtual bool Show(void);
|
||||
virtual bool Hide(void);
|
||||
|
||||
void Destroy(void);
|
||||
void ResetColors(void);
|
||||
CCurve *CurveDetach(const int index);
|
||||
bool CurveAttach(CCurve *curve);
|
||||
|
||||
int getIndexInCache(CCurve *c);
|
||||
void replaceInCache(const int index, CCurve *c);
|
||||
|
||||
int cacheSize() const
|
||||
{
|
||||
return ArraySize(curvecache);
|
||||
}
|
||||
|
||||
const CurveSubtitles *cacheItem(const int index) const
|
||||
{
|
||||
return &curvecache[index];
|
||||
}
|
||||
|
||||
void InitXAxis(const bool custom);
|
||||
void InitYAxis(const bool custom);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
string CustomDoubleToStringFunction(double value, void *ptr)
|
||||
{
|
||||
CGraphicInPlot *self = dynamic_cast<CGraphicInPlot *>(ptr);
|
||||
if(self != NULL)
|
||||
{
|
||||
if(self.cacheSize() > 0)
|
||||
{
|
||||
const int index = (int)value;
|
||||
if(MathAbs(((double)index) - value) <= DBL_EPSILON)
|
||||
{
|
||||
const CurveSubtitles *s = self.cacheItem(0);
|
||||
if(index < 0 || index >= ArraySize(s.data.array)) return NULL; // (string)(float)value; // debug
|
||||
return s.data.array[index].title;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CGraphicInPlot::CGraphicInPlot()
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
CGraphicInPlot::~CGraphicInPlot()
|
||||
{
|
||||
CurvesRemoveAll();
|
||||
}
|
||||
|
||||
void CGraphicInPlot::Destroy(void)
|
||||
{
|
||||
m_generator.Reset();
|
||||
m_canvas.Destroy();
|
||||
}
|
||||
|
||||
void CGraphicInPlot::ResetColors(void)
|
||||
{
|
||||
m_generator.Reset();
|
||||
}
|
||||
|
||||
/* TODO: enable this to support Y marks customization
|
||||
class AxisCustomizer
|
||||
{
|
||||
public:
|
||||
const bool Y; // true for Y, false for X (default)
|
||||
const CGraphicInPlot *parent;
|
||||
AxisCustomizer(const bool axisY, CGraphicInPlot *p): Y(axisY), parent(p) {}
|
||||
};
|
||||
*/
|
||||
|
||||
void CGraphicInPlot::InitXAxis(const bool custom)
|
||||
{
|
||||
if(custom)
|
||||
{
|
||||
m_x.Type(AXIS_TYPE_CUSTOM);
|
||||
m_x.ValuesFunctionFormat(CustomDoubleToStringFunction);
|
||||
m_x.ValuesFunctionFormatCBData(&this);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_x.Type(AXIS_TYPE_DOUBLE);
|
||||
}
|
||||
}
|
||||
|
||||
void CGraphicInPlot::InitYAxis(const bool custom)
|
||||
{
|
||||
if(custom)
|
||||
{
|
||||
m_y.Type(AXIS_TYPE_CUSTOM);
|
||||
m_y.ValuesFunctionFormat(CustomDoubleToStringFunction);
|
||||
m_y.ValuesFunctionFormatCBData(&this);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_y.Type(AXIS_TYPE_DOUBLE);
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CGraphicInPlot::Create(const long chart, const string name, const int subwin, const int x1, const int y1, const int x2, const int y2)
|
||||
{
|
||||
if(!CGraphic::Create(chart, name, subwin, x1, y1, x2, y2)) return false;
|
||||
m_chart_id = chart;
|
||||
return true;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CGraphicInPlot::Show(void)
|
||||
{
|
||||
string obj_name = ChartObjectName();
|
||||
if(obj_name == NULL || ObjectFind(m_chart_id, obj_name) < 0) return false;
|
||||
if(!ObjectSetInteger(m_chart_id, obj_name, OBJPROP_TIMEFRAMES, OBJ_ALL_PERIODS)) return false;
|
||||
Update(false);
|
||||
return true;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CGraphicInPlot::Hide(void)
|
||||
{
|
||||
string obj_name = ChartObjectName();
|
||||
if(obj_name == NULL || ObjectFind(m_chart_id, obj_name) < 0) return false;
|
||||
return ObjectSetInteger(m_chart_id, obj_name, OBJPROP_TIMEFRAMES, OBJ_NO_PERIODS);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CGraphicInPlot::Shift(const int dx, const int dy)
|
||||
{
|
||||
string obj_name = ChartObjectName();
|
||||
if(obj_name == NULL || ObjectFind(m_chart_id, obj_name) < 0) return false;
|
||||
|
||||
int x = (int)ObjectGetInteger(m_chart_id, obj_name, OBJPROP_XDISTANCE) + dx;
|
||||
int y = (int)ObjectGetInteger(m_chart_id, obj_name, OBJPROP_YDISTANCE) + dy;
|
||||
if(!ObjectSetInteger(m_chart_id, obj_name, OBJPROP_XDISTANCE, x)) return false;
|
||||
if(!ObjectSetInteger(m_chart_id, obj_name, OBJPROP_YDISTANCE, y)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CCurve *CGraphicInPlot::CurveDetach(const int index)
|
||||
{
|
||||
return m_arr_curves.Detach(index);
|
||||
}
|
||||
|
||||
bool CGraphicInPlot::CurveAttach(CCurve *curve)
|
||||
{
|
||||
return m_arr_curves.Add(curve);
|
||||
}
|
||||
|
||||
void CGraphicInPlot::Customize(CCurve *c, const int points)
|
||||
{
|
||||
int w = MathMax(Width() / points / 4, 1);
|
||||
c.HistogramWidth(w);
|
||||
c.LinesWidth(3);
|
||||
c.PointsFill(true);
|
||||
}
|
||||
|
||||
CCurve *CGraphicInPlot::CacheIt(const CCurve *c, const PairArray *data = NULL)
|
||||
{
|
||||
int n = ArraySize(curvecache);
|
||||
ArrayResize(curvecache, n + 1);
|
||||
curvecache[n].assign(c, data);
|
||||
return (CCurve *)c;
|
||||
}
|
||||
|
||||
CCurve *CGraphicInPlot::CurveAdd(const PairArray *data, ENUM_CURVE_TYPE type, const string name = NULL)
|
||||
{
|
||||
double y[];
|
||||
string s[];
|
||||
data.convert(y, s);
|
||||
CCurve *c = CGraphic::CurveAdd(y, type, name);
|
||||
Customize(c, ArraySize(y));
|
||||
|
||||
return CacheIt(c, data);
|
||||
}
|
||||
|
||||
CCurve *CGraphicInPlot::CurveAdd(const double &x[], const double &y[], ENUM_CURVE_TYPE type, const string name = NULL)
|
||||
{
|
||||
CCurve *c = CGraphic::CurveAdd(x, y, type, name);
|
||||
Customize(c, ArraySize(x));
|
||||
|
||||
return CacheIt(c);
|
||||
}
|
||||
|
||||
int CGraphicInPlot::getIndexInCache(CCurve *c)
|
||||
{
|
||||
int n = ArraySize(curvecache);
|
||||
for(int i = 0; i < n; i++)
|
||||
{
|
||||
if(curvecache[i].curve == c) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void CGraphicInPlot::replaceInCache(const int index, CCurve *c)
|
||||
{
|
||||
curvecache[index].curve = c;
|
||||
}
|
||||
|
||||
void CGraphicInPlot::CurvesRemoveAll(void)
|
||||
{
|
||||
int n = m_arr_curves.Total();
|
||||
for(int i = n - 1; i >= 0; i--)
|
||||
{
|
||||
CurveRemoveByIndex(i);
|
||||
}
|
||||
n = ArraySize(curvecache);
|
||||
for(int i = n - 1; i >= 0; i--)
|
||||
{
|
||||
if(CheckPointer(curvecache[i].data) == POINTER_DYNAMIC) delete curvecache[i].data;
|
||||
}
|
||||
ArrayResize(curvecache, 0);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
class CPlot: public CWndClient
|
||||
{
|
||||
private:
|
||||
CGraphicInPlot *m_graphic;
|
||||
ENUM_CURVE_TYPE type;
|
||||
uint i_text_color;
|
||||
CCurve *temp[];
|
||||
|
||||
public:
|
||||
CPlot();
|
||||
~CPlot();
|
||||
|
||||
bool Create(const long chart, const string name, const int subwin, const int x1, const int y1, const int x2, const int y2, const ENUM_CURVE_TYPE t = CURVE_HISTOGRAM);
|
||||
virtual void Destroy(const int reason = 0) override;
|
||||
bool Refresh(const bool enforce = false);
|
||||
bool SetTextColor(color value);
|
||||
|
||||
virtual bool Shift(const int dx, const int dy) override;
|
||||
|
||||
virtual bool Show(void);
|
||||
virtual bool Hide(void);
|
||||
|
||||
bool Resize(const int x1, const int y1, const int x2, const int y2);
|
||||
|
||||
CCurve *CurveAdd(const PairArray *data, const string name = NULL);
|
||||
CCurve *CurveAdd(const double &x[], const double &y[], const string name = NULL);
|
||||
|
||||
void CurvesRemoveAll(void);
|
||||
|
||||
void SetDefaultCurveType(ENUM_CURVE_TYPE t)
|
||||
{
|
||||
type = t;
|
||||
}
|
||||
|
||||
void InitXAxis(const bool custom)
|
||||
{
|
||||
if(CheckPointer(m_graphic) != POINTER_INVALID)
|
||||
{
|
||||
m_graphic.InitXAxis(custom);
|
||||
}
|
||||
}
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
CPlot::CPlot():
|
||||
type(CURVE_HISTOGRAM), i_text_color(ColorToARGB(clrBlack, 255))
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
CPlot::~CPlot()
|
||||
{
|
||||
if(CheckPointer(m_graphic) != POINTER_INVALID)
|
||||
{
|
||||
m_graphic.Destroy();
|
||||
delete m_graphic;
|
||||
}
|
||||
}
|
||||
|
||||
void CPlot::Destroy(const int reason = 0)
|
||||
{
|
||||
if(CheckPointer(m_graphic) != POINTER_INVALID)
|
||||
{
|
||||
m_graphic.Destroy();
|
||||
delete m_graphic;
|
||||
m_graphic = NULL;
|
||||
}
|
||||
CWndClient::Destroy(reason);
|
||||
}
|
||||
|
||||
CCurve *CPlot::CurveAdd(const PairArray *data, const string name = NULL)
|
||||
{
|
||||
if(CheckPointer(m_graphic) == POINTER_INVALID) return NULL;
|
||||
return m_graphic.CurveAdd(data, type, name);
|
||||
}
|
||||
|
||||
CCurve *CPlot::CurveAdd(const double &x[], const double &y[], const string name = NULL)
|
||||
{
|
||||
if(CheckPointer(m_graphic) == POINTER_INVALID) return NULL;
|
||||
return m_graphic.CurveAdd(x, y, type, name);
|
||||
}
|
||||
|
||||
void CPlot::CurvesRemoveAll(void)
|
||||
{
|
||||
m_graphic.CurvesRemoveAll();
|
||||
m_graphic.ResetColors();
|
||||
}
|
||||
|
||||
bool CPlot::Resize(const int x1, const int y1, const int x2, const int y2)
|
||||
{
|
||||
if(CheckPointer(m_graphic) == POINTER_INVALID) return false;
|
||||
|
||||
int width = Width();
|
||||
int height = Height();
|
||||
Size(x2 - x1, y2 - y1);
|
||||
|
||||
string obj_name = m_name + "_0_0";
|
||||
int obj_x1 = m_rect.left;
|
||||
int obj_x2 = obj_x1 + width;
|
||||
int obj_y1 = m_rect.top;
|
||||
int obj_y2 = obj_y1 + height;
|
||||
|
||||
m_graphic.Destroy();
|
||||
if(!m_graphic.Create(m_chart_id, obj_name, m_subwin, obj_x1, obj_y1, obj_x2, obj_y2))
|
||||
{
|
||||
Print(GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
for(int i = 0; i < ArraySize(temp); ++i)
|
||||
{
|
||||
if(CheckPointer(temp[i]) == POINTER_DYNAMIC) delete temp[i];
|
||||
}
|
||||
|
||||
ArrayResize(temp, m_graphic.CurvesTotal());
|
||||
|
||||
// Graphic library does not provide a method to update curve without array copying
|
||||
for(int i = m_graphic.CurvesTotal() - 1; i >= 0; --i)
|
||||
{
|
||||
temp[i] = m_graphic.CurveDetach(i);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPlot::Create(const long chart, const string name, const int subwin, const int x1, const int y1, const int x2, const int y2, const ENUM_CURVE_TYPE t = CURVE_HISTOGRAM)
|
||||
{
|
||||
if(!CWndClient::Create(chart, name, subwin, x1, y1, x2, y2)) return false;
|
||||
type = t;
|
||||
|
||||
int width = Width();
|
||||
int height = Height();
|
||||
|
||||
string obj_name = m_name + "_0_0";
|
||||
int obj_x1 = m_rect.left;
|
||||
int obj_x2 = obj_x1 + width;
|
||||
int obj_y1 = m_rect.top;
|
||||
int obj_y2 = obj_y1 + height;
|
||||
|
||||
m_graphic = new CGraphicInPlot();
|
||||
if(CheckPointer(m_graphic) == POINTER_INVALID) return false;
|
||||
if(!m_graphic.Create(m_chart_id, obj_name, m_subwin, obj_x1, obj_y1, obj_x2, obj_y2)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPlot::Hide(void)
|
||||
{
|
||||
if(CheckPointer(m_graphic) == POINTER_INVALID) return false;
|
||||
if(!m_graphic.Hide()) return false;
|
||||
|
||||
return CWndClient::Hide();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPlot::Show(void)
|
||||
{
|
||||
if(!CWndClient::Show()) return false;
|
||||
|
||||
if(CheckPointer(m_graphic) == POINTER_INVALID) return false;
|
||||
if(m_graphic.Show()) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
bool CPlot::Shift(const int dx, const int dy)
|
||||
{
|
||||
if(CheckPointer(m_graphic) == POINTER_INVALID) return false;
|
||||
if(!m_graphic.Shift(dx, dy)) return false;
|
||||
|
||||
return CWndClient::Shift(dx, dy);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPlot::Refresh(const bool enforce = false)
|
||||
{
|
||||
if(CheckPointer(m_graphic) == POINTER_INVALID) return false;
|
||||
|
||||
if(ArraySize(temp) == 0 && enforce)
|
||||
{
|
||||
m_graphic.ResetColors();
|
||||
ArrayResize(temp, m_graphic.CurvesTotal());
|
||||
for(int i = m_graphic.CurvesTotal() - 1; i >= 0; --i)
|
||||
{
|
||||
temp[i] = m_graphic.CurveDetach(i);
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < ArraySize(temp); ++i)
|
||||
{
|
||||
if(CheckPointer(temp[i]) == POINTER_DYNAMIC)
|
||||
{
|
||||
double x[], y[];
|
||||
temp[i].GetX(x);
|
||||
temp[i].GetY(y);
|
||||
string name = temp[i].Name();
|
||||
|
||||
int index = m_graphic.getIndexInCache(temp[i]);
|
||||
|
||||
delete temp[i];
|
||||
CCurve *curve = NULL;
|
||||
if(ArraySize(x) > 0)
|
||||
{
|
||||
if(ArraySize(y) > 0)
|
||||
{
|
||||
curve = m_graphic.CurveAdd(x, y, type, name);
|
||||
}
|
||||
else
|
||||
{
|
||||
curve = m_graphic.CurveAdd(x, type, name);
|
||||
}
|
||||
}
|
||||
|
||||
m_graphic.replaceInCache(index, curve);
|
||||
|
||||
// axis does not yet calculated, it's done only during CurvePlotAll
|
||||
// so we can't automatically adjust histogram width
|
||||
// double range = (m_graphic.XAxis().Max() - m_graphic.XAxis().Min());
|
||||
// double data = (x[ArrayMaximum(x)] - x[ArrayMinimum(x)]);
|
||||
// int downsize = (int)(range / data);
|
||||
curve.HistogramWidth(Width() / ArraySize(x) / 4);
|
||||
curve.LinesWidth(3);
|
||||
}
|
||||
}
|
||||
ArrayResize(temp, 0);
|
||||
|
||||
if(!m_graphic.CurvePlotAll()) return false;
|
||||
|
||||
m_graphic.Update(false);
|
||||
|
||||
ChartRedraw(m_chart_id);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,344 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| MovingAverages.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Simple Moving Average |
|
||||
//+------------------------------------------------------------------+
|
||||
double SimpleMA(const int position,const int period,const double &price[])
|
||||
{
|
||||
double result=0.0;
|
||||
//--- check period
|
||||
if(period>0 && period<=(position+1))
|
||||
{
|
||||
for(int i=0; i<period; i++)
|
||||
result+=price[position-i];
|
||||
|
||||
result/=period;
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Exponential Moving Average |
|
||||
//+------------------------------------------------------------------+
|
||||
double ExponentialMA(const int position,const int period,const double prev_value,const double &price[], const bool distance, const double distpip,
|
||||
const int buysell)
|
||||
{
|
||||
double result=0.0;
|
||||
//--- check period
|
||||
if(period>0)
|
||||
{
|
||||
if (!distance)
|
||||
{
|
||||
double pr=2.0/(period+1.0);
|
||||
result=price[position]*pr+prev_value*(1-pr);
|
||||
}
|
||||
|
||||
if (distance)
|
||||
{
|
||||
if (buysell == 1)
|
||||
{
|
||||
|
||||
double pr=2.0/(period+1.0);
|
||||
double _dis_point = distpip * Point();
|
||||
double val_dist = (price[position] / _dis_point) - 1.0;
|
||||
double sum_val_dist = price[position] - _dis_point; //val_dist * _dis_point;
|
||||
result = sum_val_dist*pr+prev_value*(1-pr);
|
||||
}
|
||||
else if (buysell == -1)
|
||||
{
|
||||
|
||||
double pr=2.0/(period+1.0);
|
||||
double _dis_point = distpip * Point();
|
||||
double val_dist = (price[position] / _dis_point) - 1.0;
|
||||
double sum_val_dist = price[position] + _dis_point; //val_dist * _dis_point;
|
||||
result = sum_val_dist*pr+prev_value*(1-pr);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Smoothed Moving Average |
|
||||
//+------------------------------------------------------------------+
|
||||
double SmoothedMA(const int position,const int period,const double prev_value,const double &price[])
|
||||
{
|
||||
double result=0.0;
|
||||
//--- check period
|
||||
if(period>0 && period<=(position+1))
|
||||
{
|
||||
if(position==period-1)
|
||||
{
|
||||
for(int i=0; i<period; i++)
|
||||
result+=price[position-i];
|
||||
|
||||
result/=period;
|
||||
}
|
||||
|
||||
result=(prev_value*(period-1)+price[position])/period;
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Linear Weighted Moving Average |
|
||||
//+------------------------------------------------------------------+
|
||||
double LinearWeightedMA(const int position,const int period,const double &price[])
|
||||
{
|
||||
double result=0.0;
|
||||
//--- check period
|
||||
if(period>0 && period<=(position+1))
|
||||
{
|
||||
double sum =0.0;
|
||||
int wsum=0;
|
||||
|
||||
for(int i=period; i>0; i--)
|
||||
{
|
||||
wsum+=i;
|
||||
sum +=price[position-i+1]*(period-i+1);
|
||||
}
|
||||
|
||||
result=sum/wsum;
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Simple moving average on price array |
|
||||
//+------------------------------------------------------------------+
|
||||
int SimpleMAOnBuffer(const int rates_total,const int prev_calculated,const int begin,const int period,const double& price[],double& buffer[])
|
||||
{
|
||||
//--- check period
|
||||
if(period<=1 || period>(rates_total-begin))
|
||||
return(0);
|
||||
//--- save as_series flags
|
||||
bool as_series_price=ArrayGetAsSeries(price);
|
||||
bool as_series_buffer=ArrayGetAsSeries(buffer);
|
||||
|
||||
ArraySetAsSeries(price,false);
|
||||
ArraySetAsSeries(buffer,false);
|
||||
//--- calculate start position
|
||||
int start_position;
|
||||
|
||||
if(prev_calculated==0) // first calculation or number of bars was changed
|
||||
{
|
||||
//--- set empty value for first bars
|
||||
start_position=period+begin;
|
||||
|
||||
for(int i=0; i<start_position-1; i++)
|
||||
buffer[i]=0.0;
|
||||
//--- calculate first visible value
|
||||
double first_value=0;
|
||||
|
||||
for(int i=begin; i<start_position; i++)
|
||||
first_value+=price[i];
|
||||
|
||||
buffer[start_position-1]=first_value/period;
|
||||
}
|
||||
else
|
||||
start_position=prev_calculated-1;
|
||||
//--- main loop
|
||||
for(int i=start_position; i<rates_total; i++)
|
||||
buffer[i]=buffer[i-1]+(price[i]-price[i-period])/period;
|
||||
//--- restore as_series flags
|
||||
ArraySetAsSeries(price,as_series_price);
|
||||
ArraySetAsSeries(buffer,as_series_buffer);
|
||||
//---
|
||||
return(rates_total);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Exponential moving average on price array |
|
||||
//+------------------------------------------------------------------+
|
||||
int ExponentialMAOnBuffer(const int rates_total,const int prev_calculated,const int begin,const int period,const double& price[],double& buffer[])
|
||||
{
|
||||
//--- check period
|
||||
if(period<=1 || period>(rates_total-begin))
|
||||
return(0);
|
||||
//--- save and clear 'as_series' flags
|
||||
bool as_series_price=ArrayGetAsSeries(price);
|
||||
bool as_series_buffer=ArrayGetAsSeries(buffer);
|
||||
|
||||
ArraySetAsSeries(price,false);
|
||||
ArraySetAsSeries(buffer,false);
|
||||
//--- calculate start position
|
||||
int start_position;
|
||||
double smooth_factor=2.0/(1.0+period);
|
||||
|
||||
if(prev_calculated==0) // first calculation or number of bars was changed
|
||||
{
|
||||
//--- set empty value for first bars
|
||||
for(int i=0; i<begin; i++)
|
||||
buffer[i]=0.0;
|
||||
//--- calculate first visible value
|
||||
start_position=period+begin;
|
||||
buffer[begin] =price[begin];
|
||||
|
||||
for(int i=begin+1; i<start_position; i++)
|
||||
buffer[i]=price[i]*smooth_factor+buffer[i-1]*(1.0-smooth_factor);
|
||||
}
|
||||
else
|
||||
start_position=prev_calculated-1;
|
||||
//--- main loop
|
||||
for(int i=start_position; i<rates_total; i++)
|
||||
buffer[i]=price[i]*smooth_factor+buffer[i-1]*(1.0-smooth_factor);
|
||||
//--- restore as_series flags
|
||||
ArraySetAsSeries(price,as_series_price);
|
||||
ArraySetAsSeries(buffer,as_series_buffer);
|
||||
//---
|
||||
return(rates_total);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Linear weighted moving average on price array classic |
|
||||
//+------------------------------------------------------------------+
|
||||
int LinearWeightedMAOnBuffer(const int rates_total,const int prev_calculated,const int begin,const int period,const double& price[],double& buffer[])
|
||||
{
|
||||
//--- check period
|
||||
if(period<=1 || period>(rates_total-begin))
|
||||
return(0);
|
||||
//--- save as_series flags
|
||||
bool as_series_price=ArrayGetAsSeries(price);
|
||||
bool as_series_buffer=ArrayGetAsSeries(buffer);
|
||||
|
||||
ArraySetAsSeries(price,false);
|
||||
ArraySetAsSeries(buffer,false);
|
||||
//--- calculate start position
|
||||
int i,start_position;
|
||||
|
||||
if(prev_calculated<=period+begin+2) // first calculation or number of bars was changed
|
||||
{
|
||||
//--- set empty value for first bars
|
||||
start_position=period+begin;
|
||||
|
||||
for(i=0; i<start_position; i++)
|
||||
buffer[i]=0.0;
|
||||
}
|
||||
else
|
||||
start_position=prev_calculated-2;
|
||||
//--- calculate first visible value
|
||||
double sum=0.0,lsum=0.0;
|
||||
int l,weight=0;
|
||||
|
||||
for(i=start_position-period,l=1; i<start_position; i++,l++)
|
||||
{
|
||||
sum +=price[i]*l;
|
||||
lsum +=price[i];
|
||||
weight+=l;
|
||||
}
|
||||
buffer[start_position-1]=sum/weight;
|
||||
//--- main loop
|
||||
for(i=start_position; i<rates_total; i++)
|
||||
{
|
||||
sum =sum-lsum+price[i]*period;
|
||||
lsum =lsum-price[i-period]+price[i];
|
||||
buffer[i]=sum/weight;
|
||||
}
|
||||
//--- restore as_series flags
|
||||
ArraySetAsSeries(price,as_series_price);
|
||||
ArraySetAsSeries(buffer,as_series_buffer);
|
||||
//---
|
||||
return(rates_total);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Linear weighted moving average on price array fast |
|
||||
//+------------------------------------------------------------------+
|
||||
int LinearWeightedMAOnBuffer(const int rates_total,const int prev_calculated,const int begin,const int period,const double& price[],double& buffer[],int &weight_sum)
|
||||
{
|
||||
//--- check period
|
||||
if(period<=1 || period>(rates_total-begin))
|
||||
return(0);
|
||||
//--- save as_series flags
|
||||
bool as_series_price=ArrayGetAsSeries(price);
|
||||
bool as_series_buffer=ArrayGetAsSeries(buffer);
|
||||
|
||||
ArraySetAsSeries(price,false);
|
||||
ArraySetAsSeries(buffer,false);
|
||||
//--- calculate start position
|
||||
int start_position;
|
||||
|
||||
if(prev_calculated==0) // first calculation or number of bars was changed
|
||||
{
|
||||
//--- set empty value for first bars
|
||||
start_position=period+begin;
|
||||
|
||||
for(int i=0; i<start_position; i++)
|
||||
buffer[i]=0.0;
|
||||
//--- calculate first visible value
|
||||
double first_value=0;
|
||||
int wsum =0;
|
||||
|
||||
for(int i=begin,k=1; i<start_position; i++,k++)
|
||||
{
|
||||
first_value+=k*price[i];
|
||||
wsum +=k;
|
||||
}
|
||||
|
||||
buffer[start_position-1]=first_value/wsum;
|
||||
weight_sum=wsum;
|
||||
}
|
||||
else
|
||||
start_position=prev_calculated-1;
|
||||
//--- main loop
|
||||
for(int i=start_position; i<rates_total; i++)
|
||||
{
|
||||
double sum=0;
|
||||
|
||||
for(int j=0; j<period; j++)
|
||||
sum+=(period-j)*price[i-j];
|
||||
|
||||
buffer[i]=sum/weight_sum;
|
||||
}
|
||||
//--- restore as_series flags
|
||||
ArraySetAsSeries(price,as_series_price);
|
||||
ArraySetAsSeries(buffer,as_series_buffer);
|
||||
//---
|
||||
return(rates_total);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Smoothed moving average on price array |
|
||||
//+------------------------------------------------------------------+
|
||||
int SmoothedMAOnBuffer(const int rates_total,const int prev_calculated,const int begin,const int period,const double& price[],double& buffer[])
|
||||
{
|
||||
//--- check period
|
||||
if(period<=1 || period>(rates_total-begin))
|
||||
return(0);
|
||||
//--- save as_series flags
|
||||
bool as_series_price=ArrayGetAsSeries(price);
|
||||
bool as_series_buffer=ArrayGetAsSeries(buffer);
|
||||
|
||||
ArraySetAsSeries(price,false);
|
||||
ArraySetAsSeries(buffer,false);
|
||||
//--- calculate start position
|
||||
int start_position;
|
||||
|
||||
if(prev_calculated==0) // first calculation or number of bars was changed
|
||||
{
|
||||
//--- set empty value for first bars
|
||||
start_position=period+begin;
|
||||
|
||||
for(int i=0; i<start_position-1; i++)
|
||||
buffer[i]=0.0;
|
||||
//--- calculate first visible value
|
||||
double first_value=0;
|
||||
|
||||
for(int i=begin; i<start_position; i++)
|
||||
first_value+=price[i];
|
||||
|
||||
buffer[start_position-1]=first_value/period;
|
||||
}
|
||||
else
|
||||
start_position=prev_calculated-1;
|
||||
//--- main loop
|
||||
for(int i=start_position; i<rates_total; i++)
|
||||
buffer[i]=(buffer[i-1]*(period-1)+price[i])/period;
|
||||
//--- restore as_series flags
|
||||
ArraySetAsSeries(price,as_series_price);
|
||||
ArraySetAsSeries(buffer,as_series_buffer);
|
||||
//---
|
||||
return(rates_total);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
Reference in New Issue
Block a user