415 lines
31 KiB
Plaintext
415 lines
31 KiB
Plaintext
//+------------------------------------------------------------------+
|
|
//| PairPlot.mqh |
|
|
//| Copyright 2018, DNG® |
|
|
//| http://www.mql5.com/en/users/dng |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2018, DNG®"
|
|
#property link "http://www.mql5.com/en/users/dng"
|
|
#property version "1.00"
|
|
//---
|
|
#include <Controls\WndClient.mqh>
|
|
#include "Histogram.mqh"
|
|
#include "Scatter.mqh"
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
class CTimeserie : public CObject
|
|
{
|
|
protected:
|
|
string s_symbol;
|
|
ENUM_TIMEFRAMES e_timeframe;
|
|
ENUM_APPLIED_PRICE e_price;
|
|
double d_timeserie[];
|
|
int i_bars;
|
|
datetime dt_last_load;
|
|
|
|
public:
|
|
CTimeserie(void);
|
|
~CTimeserie(void);
|
|
bool Create(const string symbol=NULL, const ENUM_TIMEFRAMES timeframe=PERIOD_CURRENT, const ENUM_APPLIED_PRICE price=PRICE_CLOSE);
|
|
//--- Change settings of timeserie
|
|
void SetBars(const int value) { i_bars=value; }
|
|
void Symbol(string value) { s_symbol=value; dt_last_load=0; }
|
|
void Timeframe(ENUM_TIMEFRAMES value) { e_timeframe=value; dt_last_load=0; }
|
|
void Price(ENUM_APPLIED_PRICE value) { e_price=value; dt_last_load=0; }
|
|
//---
|
|
string Symbol(void) { return s_symbol; }
|
|
ENUM_TIMEFRAMES Timeframe(void) { return e_timeframe; }
|
|
ENUM_APPLIED_PRICE Price(void) { return e_price; }
|
|
//--- Load data
|
|
bool UpdateTimeserie(void);
|
|
bool GetTimeserie(double ×erie[]) { return ArrayCopy(timeserie,d_timeserie)>0; }
|
|
};
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
CTimeserie::CTimeserie(void) : s_symbol(_Symbol),
|
|
e_timeframe(PERIOD_CURRENT),
|
|
e_price(PRICE_CLOSE),
|
|
i_bars(1000)
|
|
{
|
|
ArrayFree(d_timeserie);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
CTimeserie::~CTimeserie(void)
|
|
{
|
|
ArrayFree(d_timeserie);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CTimeserie::Create(const string symbol=NULL,const ENUM_TIMEFRAMES timeframe=0, const ENUM_APPLIED_PRICE price=PRICE_CLOSE)
|
|
{
|
|
ResetLastError();
|
|
if(!SymbolInfoInteger(symbol,SYMBOL_SELECT))
|
|
if(GetLastError()==ERR_MARKET_UNKNOWN_SYMBOL || !SymbolSelect(symbol,true))
|
|
return false;
|
|
s_symbol=(symbol==NULL ? _Symbol : symbol);
|
|
e_timeframe=(timeframe==PERIOD_CURRENT ? _Period : timeframe);
|
|
e_price=price;
|
|
UpdateTimeserie();
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CTimeserie::UpdateTimeserie(void)
|
|
{
|
|
datetime cur_date=(datetime)SeriesInfoInteger(s_symbol,e_timeframe,SERIES_LASTBAR_DATE);
|
|
if(dt_last_load>=cur_date && ArraySize(d_timeserie)>=i_bars)
|
|
return true;
|
|
//---
|
|
MqlRates rates[];
|
|
int bars=0,i;
|
|
double data[];
|
|
switch(e_price)
|
|
{
|
|
case PRICE_CLOSE:
|
|
bars=CopyClose(s_symbol,e_timeframe,1,i_bars+1,data);
|
|
break;
|
|
case PRICE_OPEN:
|
|
bars=CopyOpen(s_symbol,e_timeframe,1,i_bars+1,data);
|
|
case PRICE_HIGH:
|
|
bars=CopyHigh(s_symbol,e_timeframe,1,i_bars+1,data);
|
|
case PRICE_LOW:
|
|
bars=CopyLow(s_symbol,e_timeframe,1,i_bars+1,data);
|
|
case PRICE_MEDIAN:
|
|
bars=CopyRates(s_symbol,e_timeframe,1,i_bars+1,rates);
|
|
bars=ArrayResize(data,bars);
|
|
for(i=0;i<bars;i++)
|
|
data[i]=(rates[i].high+rates[i].low)/2;
|
|
break;
|
|
case PRICE_TYPICAL:
|
|
bars=CopyRates(s_symbol,e_timeframe,1,i_bars+1,rates);
|
|
bars=ArrayResize(data,bars);
|
|
for(i=0;i<bars;i++)
|
|
data[i]=(rates[i].high+rates[i].low+rates[i].close)/3;
|
|
break;
|
|
case PRICE_WEIGHTED:
|
|
bars=CopyRates(s_symbol,e_timeframe,1,i_bars+1,rates);
|
|
bars=ArrayResize(data,bars);
|
|
for(i=0;i<bars;i++)
|
|
data[i]=(rates[i].high+rates[i].low+2*rates[i].close)/4;
|
|
break;
|
|
}
|
|
//---
|
|
if(bars<=0)
|
|
return false;
|
|
//---
|
|
dt_last_load=cur_date;
|
|
//---
|
|
if(ArraySize(d_timeserie)!=(bars-1) && ArrayResize(d_timeserie,bars-1)<=0)
|
|
return false;
|
|
double point=SymbolInfoDouble(s_symbol,SYMBOL_POINT);
|
|
for(i=0;i<bars-1;i++)
|
|
d_timeserie[i]=(data[i+1]-data[i])/point;
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
class CPairPlot : public CWndClient
|
|
{
|
|
private:
|
|
CPlotBase *m_arr_graphics[];
|
|
CArrayObj m_arr_symbols;
|
|
ENUM_TIMEFRAMES e_timeframe;
|
|
ENUM_APPLIED_PRICE e_price;
|
|
int i_total_symbols;
|
|
uint i_bars;
|
|
ENUM_HISTOGRAM_ORIENTATION e_orientation;
|
|
uint i_text_color;
|
|
|
|
public:
|
|
CPairPlot();
|
|
~CPairPlot();
|
|
//---
|
|
bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2, const string &symbols[],const ENUM_TIMEFRAMES timeframe=PERIOD_CURRENT, const int bars=1000, const uint cells=10, const ENUM_APPLIED_PRICE price=PRICE_CLOSE);
|
|
bool Refresh(void);
|
|
bool HistogramOrientation(ENUM_HISTOGRAM_ORIENTATION value);
|
|
ENUM_HISTOGRAM_ORIENTATION HistogramOrientation(void) { return e_orientation; }
|
|
bool SetTextColor(color value);
|
|
//--- geometry
|
|
virtual bool Shift(const int dx,const int dy);
|
|
//--- state
|
|
virtual bool Show(void);
|
|
virtual bool Hide(void);
|
|
};
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
CPairPlot::CPairPlot() : e_timeframe(PERIOD_CURRENT),
|
|
i_bars(1000),
|
|
i_total_symbols(0),
|
|
e_orientation(HISTOGRAM_HORIZONTAL)
|
|
{
|
|
ArrayFree(m_arr_graphics);
|
|
i_text_color=ColorToARGB(clrBlack,255);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
CPairPlot::~CPairPlot()
|
|
{
|
|
int total=ArraySize(m_arr_graphics);
|
|
for(int i=0;i<total;i++)
|
|
if(CheckPointer(m_arr_graphics[i])!=POINTER_INVALID)
|
|
{
|
|
m_arr_graphics[i].Destroy();
|
|
delete m_arr_graphics[i];
|
|
}
|
|
ArrayFree(m_arr_graphics);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CPairPlot::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2, const string &symbols[],const ENUM_TIMEFRAMES timeframe=PERIOD_CURRENT, const int bars=1000, const uint cells=10, const ENUM_APPLIED_PRICE price=PRICE_CLOSE)
|
|
{
|
|
i_total_symbols=0;
|
|
int total=ArraySize(symbols);
|
|
if(total<=1 || bars<100)
|
|
return false;
|
|
//---
|
|
e_timeframe=timeframe;
|
|
i_bars=bars;
|
|
e_price=price;
|
|
//---
|
|
for(int i=0;i<total;i++)
|
|
{
|
|
CTimeserie *temp=new CTimeserie;
|
|
if(temp==NULL)
|
|
return false;
|
|
temp.SetBars(i_bars);
|
|
if(!temp.Create(symbols[i],e_timeframe,e_price))
|
|
return false;
|
|
if(!m_arr_symbols.Add(temp))
|
|
return false;
|
|
}
|
|
i_total_symbols=m_arr_symbols.Total();
|
|
if(i_total_symbols<=1)
|
|
return false;
|
|
//---
|
|
if(!CWndClient::Create(chart,name,subwin,x1,y1,x2,y2))
|
|
return false;
|
|
//---
|
|
if(ArraySize(m_arr_graphics)!=(i_total_symbols*i_total_symbols))
|
|
if(ArrayResize(m_arr_graphics,i_total_symbols*i_total_symbols)<=0)
|
|
return false;
|
|
int width=Width()/i_total_symbols;
|
|
int height=Height()/i_total_symbols;
|
|
for(int i=0;i<i_total_symbols;i++)
|
|
{
|
|
CTimeserie *timeserie1=m_arr_symbols.At(i);
|
|
if(timeserie1==NULL)
|
|
continue;
|
|
for(int j=0;j<i_total_symbols;j++)
|
|
{
|
|
string obj_name=m_name+"_"+(string)i+"_"+(string)j;
|
|
int obj_x1=m_rect.left+j*width;
|
|
int obj_x2=obj_x1+width;
|
|
int obj_y1=m_rect.top+i*height;
|
|
int obj_y2=obj_y1+height;
|
|
if(i==j)
|
|
{
|
|
CHistogram *temp=new CHistogram();
|
|
if(CheckPointer(temp)==POINTER_INVALID)
|
|
return false;
|
|
if(!temp.Create(m_chart_id,obj_name,m_subwin,obj_x1,obj_y1,obj_x2,obj_y2,e_orientation))
|
|
return false;
|
|
m_arr_graphics[i*i_total_symbols+j]=temp;
|
|
temp.SetCells(cells);
|
|
}
|
|
else
|
|
{
|
|
CScatter *temp=new CScatter();
|
|
if(CheckPointer(temp)==POINTER_INVALID)
|
|
return false;
|
|
if(!temp.Create(m_chart_id,obj_name,m_subwin,obj_x1,obj_y1,obj_x2,obj_y2))
|
|
return false;
|
|
CTimeserie *timeserie2=m_arr_symbols.At(j);
|
|
if(timeserie2==NULL)
|
|
continue;
|
|
m_arr_graphics[i*i_total_symbols+j]=temp;
|
|
}
|
|
}
|
|
}
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CPairPlot::Hide(void)
|
|
{
|
|
int total=ArraySize(m_arr_graphics);
|
|
for(int i=0;i<total;i++)
|
|
{
|
|
if(CheckPointer(m_arr_graphics[i])==POINTER_INVALID)
|
|
continue;
|
|
if(!m_arr_graphics[i].Hide())
|
|
return false;
|
|
}
|
|
//---
|
|
return CWndClient::Hide();
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CPairPlot::Show(void)
|
|
{
|
|
if(!CWndClient::Show())
|
|
return false;
|
|
//---
|
|
int total=ArraySize(m_arr_graphics);
|
|
for(int i=0;i<total;i++)
|
|
{
|
|
if(CheckPointer(m_arr_graphics[i])==POINTER_INVALID)
|
|
continue;
|
|
if(!m_arr_graphics[i].Show())
|
|
return false;
|
|
}
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CPairPlot::Shift(const int dx,const int dy)
|
|
{
|
|
int total=ArraySize(m_arr_graphics);
|
|
for(int i=0;i<total;i++)
|
|
{
|
|
if(CheckPointer(m_arr_graphics[i])==POINTER_INVALID)
|
|
continue;
|
|
if(!m_arr_graphics[i].Shift(dx,dy))
|
|
return false;
|
|
}
|
|
//---
|
|
return CWndClient::Shift(dx,dy);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CPairPlot::Refresh(void)
|
|
{
|
|
bool updated=true;
|
|
for(int i=0;i<i_total_symbols;i++)
|
|
{
|
|
CTimeserie *timeserie=m_arr_symbols.At(i);
|
|
if(timeserie==NULL)
|
|
continue;
|
|
updated=(updated && timeserie.UpdateTimeserie());
|
|
}
|
|
if(!updated)
|
|
return false;
|
|
//---
|
|
for(int i=0;i<i_total_symbols;i++)
|
|
{
|
|
CTimeserie *timeserie1=m_arr_symbols.At(i);
|
|
if(CheckPointer(timeserie1)==POINTER_INVALID)
|
|
continue;
|
|
double ts1[];
|
|
if(!timeserie1.GetTimeserie(ts1))
|
|
continue;
|
|
//---
|
|
for(int j=0;j<i_total_symbols;j++)
|
|
{
|
|
if(i==j)
|
|
{
|
|
CHistogram *temp=m_arr_graphics[i*i_total_symbols+j];
|
|
if(CheckPointer(temp)==POINTER_INVALID)
|
|
return false;
|
|
if(temp.CurvesTotal()==0)
|
|
{
|
|
if(temp.AddTimeserie(ts1)<0)
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
if(!temp.UpdateTimeserie(ts1))
|
|
continue;
|
|
}
|
|
if(!temp.CurvePlotAll())
|
|
continue;
|
|
// if(i==0)
|
|
// temp.TextUp(timeserie1.Symbol(),i_text_color);
|
|
// if(i==(i_total_symbols-1))
|
|
// temp.TextDown(timeserie1.Symbol(),i_text_color);
|
|
// if(j==0)
|
|
// temp.TextLeft(timeserie1.Symbol(),i_text_color);
|
|
// if(j==(i_total_symbols-1))
|
|
// temp.TextRight(timeserie1.Symbol(),i_text_color);
|
|
temp.Update(false);
|
|
}
|
|
else
|
|
{
|
|
CScatter *temp=m_arr_graphics[i*i_total_symbols+j];
|
|
if(CheckPointer(temp)==POINTER_INVALID)
|
|
return false;
|
|
CTimeserie *timeserie2=m_arr_symbols.At(j);
|
|
if(CheckPointer(timeserie2)==POINTER_INVALID)
|
|
continue;
|
|
double ts2[];
|
|
if(!timeserie2.GetTimeserie(ts2))
|
|
continue;
|
|
if(temp.CurvesTotal()==0)
|
|
{
|
|
if(temp.AddTimeseries(ts1,ts2)<0)
|
|
continue;
|
|
}
|
|
else
|
|
if(!temp.UpdateTimeseries(ts1,ts2))
|
|
continue;
|
|
if(!temp.CurvePlotAll())
|
|
continue;
|
|
// if(i==0)
|
|
// temp.TextUp(timeserie2.Symbol(),i_text_color);
|
|
// if(i==(i_total_symbols-1))
|
|
// temp.TextDown(timeserie2.Symbol(),i_text_color);
|
|
// if(j==0)
|
|
// temp.TextLeft(timeserie1.Symbol(),i_text_color);
|
|
// if(j==(i_total_symbols-1))
|
|
// temp.TextRight(timeserie1.Symbol(),i_text_color);
|
|
temp.Update(false);
|
|
}
|
|
}
|
|
}
|
|
//---
|
|
ChartRedraw(m_chart_id);
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CPairPlot::HistogramOrientation(ENUM_HISTOGRAM_ORIENTATION value)
|
|
{
|
|
e_orientation=value;
|
|
return Refresh();
|
|
}
|
|
//+------------------------------------------------------------------+
|