Files
2025-02-07 19:13:59 +03:30

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 &timeserie[]) { 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();
}
//+------------------------------------------------------------------+