436 lines
15 KiB
MQL5
436 lines
15 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| Wavelet.mq5 |
|
|
//| Copyright 2000-2025, MetaQuotes Ltd. |
|
|
//| https://www.mql5.com |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2000-2025, MetaQuotes Ltd."
|
|
#property link "https://www.mql5.com"
|
|
#property version "1.00"
|
|
|
|
#include <Math/Stat/Math.mqh>
|
|
#include <Graphics/Graphic.mqh>
|
|
#include <OpenCL/OpenCL.mqh>
|
|
|
|
#define CPU_DATA 1
|
|
#define GPU_DATA 2
|
|
|
|
#define SIZE_X 600
|
|
#define SIZE_Y 200
|
|
|
|
#resource "Kernels/wavelet.cl" as string cl_program
|
|
//+------------------------------------------------------------------+
|
|
//| CWavelet |
|
|
//+------------------------------------------------------------------+
|
|
class CWavelet
|
|
{
|
|
protected:
|
|
int m_xsize;
|
|
int m_ysize;
|
|
int m_maxcolor;
|
|
string m_res_name;
|
|
string m_label_name;
|
|
uchar m_palette[3*256];
|
|
//---
|
|
float m_data[];
|
|
float m_wavelet_data_CPU[];
|
|
float m_wavelet_data_GPU[];
|
|
uint m_bmp_buffer[];
|
|
|
|
COpenCL m_OpenCL;
|
|
|
|
float Morlet(const float t);
|
|
void ShowWaveletData(const float &m_wavelet_data[]);
|
|
int GetPalColor(const int index);
|
|
void Blend(const uint c1,const uint c2,const uint r1,const uint g1,const uint b1,const uint r2,const uint g2,const uint b2);
|
|
bool WaveletCPU(const float &data[],const int datacount,const int x_size,const int y_size,const int i,const int j,const bool norm,float &result[]);
|
|
public:
|
|
//---
|
|
void Create(const string name,const int x0,const int y0,const int x_size,const int y_size);
|
|
bool CalculateWavelet_CPU(const float &data[],uint &time);
|
|
bool CalculateWavelet_GPU(float &data[],uint &time);
|
|
void ShowWavelet(const int mode);
|
|
};
|
|
//+------------------------------------------------------------------+
|
|
//| Morlet wavelet function |
|
|
//+------------------------------------------------------------------+
|
|
float CWavelet::Morlet(const float t)
|
|
{
|
|
double v=t;
|
|
double res=MathExp(-v*v*0.5)*MathCos(M_2_PI*v);
|
|
return ((float)res);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| GetPalColor |
|
|
//+------------------------------------------------------------------+
|
|
int CWavelet::GetPalColor(const int index)
|
|
{
|
|
int ind=index;
|
|
if(ind<=0)
|
|
ind=0;
|
|
if(ind>255)
|
|
ind=255;
|
|
int idx=3*(ind);
|
|
uchar r=m_palette[idx];
|
|
uchar g=m_palette[idx+1];
|
|
uchar b=m_palette[idx+2];
|
|
//---
|
|
return(b+256*g+65536*r);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Gradient palette |
|
|
//+------------------------------------------------------------------+
|
|
void CWavelet::Blend(const uint c1,const uint c2,const uint r1,const uint g1,const uint b1,const uint r2,const uint g2,const uint b2)
|
|
{
|
|
int n=int(c2-c1);
|
|
for(int i=0; i<=n; i++)
|
|
{
|
|
if((c1+i+2)<m_palette.Size())
|
|
{
|
|
m_palette[3*(c1+i)]=uchar(MathRound(1*(r1*(n-i)+r2*i)*1.0/n));
|
|
m_palette[3*(c1+i)+1]=uchar(MathRound(1*(g1*(n-i)+g2*i)*1.0/n));
|
|
m_palette[3*(c1+i)+2]=uchar(MathRound(1*(b1*(n-i)+b2*i)*1.0/n));
|
|
}
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Create |
|
|
//+------------------------------------------------------------------+
|
|
void CWavelet::Create(const string name,const int x0,const int y0,const int x_size,const int y_size)
|
|
{
|
|
//---
|
|
m_xsize=x_size;
|
|
m_ysize=y_size;
|
|
int size=m_xsize*m_ysize;
|
|
ArrayResize(m_bmp_buffer,size);
|
|
ArrayFill(m_bmp_buffer,0,size,0);
|
|
ArrayResize(m_wavelet_data_CPU,size);
|
|
ArrayResize(m_wavelet_data_GPU,size);
|
|
ArrayFill(m_wavelet_data_CPU,0,size,0);
|
|
ArrayFill(m_wavelet_data_GPU,0,size,0);
|
|
m_res_name=name;
|
|
m_label_name=m_res_name;
|
|
StringToUpper(m_label_name);
|
|
ResourceCreate(m_res_name,m_bmp_buffer,m_xsize,m_ysize,0,0,0,COLOR_FORMAT_XRGB_NOALPHA);
|
|
ObjectCreate(0,m_label_name,OBJ_BITMAP_LABEL,0,0,0);
|
|
ObjectSetInteger(0,m_label_name,OBJPROP_XDISTANCE,x0);
|
|
ObjectSetInteger(0,m_label_name,OBJPROP_YDISTANCE,y0);
|
|
ObjectSetString(0,m_label_name,OBJPROP_BMPFILE,NULL);
|
|
ObjectSetString(0,m_label_name,OBJPROP_BMPFILE,"::"+m_label_name);
|
|
m_maxcolor=100;
|
|
//Blend(0,100,0,0,0,255,255,255);
|
|
Blend(0,20,0,0,95,0,0,246);
|
|
Blend(21,40,0,0,246,0,236,226);
|
|
Blend(41,60,0,236,226,226,246,0);
|
|
Blend(61,80,226,246,0,226,0,0);
|
|
Blend(81,100,226,0,0,123,0,0);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| WaveletCPU |
|
|
//+------------------------------------------------------------------+
|
|
bool CWavelet::WaveletCPU(const float &data[],const int datacount,const int x_size,const int y_size,const int i,const int j,const bool norm,float &result[])
|
|
{
|
|
float a1=(float)10e-10;
|
|
float a2=(float)15.0;
|
|
float da=(float)(a2-a1)/y_size;
|
|
float db=(float)(datacount-0)/x_size;
|
|
int pos=j*x_size+i;
|
|
//---
|
|
float a=a1+j*da;
|
|
float b=i*db;
|
|
float B=(float)1.0; //Morlet
|
|
float B_inv=(float)1.0/B;
|
|
float a_inv=(float)1/a;
|
|
float dt=(float)1.0;
|
|
float coef=(float)0.0;
|
|
if(!norm)
|
|
coef=(float)MathSqrt(a_inv);
|
|
else
|
|
{
|
|
for(int k=0; k<datacount; k++)
|
|
{
|
|
float arg=(dt*k-b)*a_inv;
|
|
arg=-B_inv*arg*arg;
|
|
coef+=(float)MathExp(arg);
|
|
}
|
|
}
|
|
float sum=0.0;
|
|
for(int k=0; k<datacount; k++)
|
|
{
|
|
float arg=(dt*k-b)*a_inv;
|
|
sum+=data[k]*Morlet(arg);
|
|
}
|
|
sum/=coef;
|
|
result[pos]=sum;
|
|
//---
|
|
return(true);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| CalculateWavelet_CPU |
|
|
//+------------------------------------------------------------------+
|
|
bool CWavelet::CalculateWavelet_CPU(const float &data[],uint &time)
|
|
{
|
|
time=GetTickCount();
|
|
int datacount=ArraySize(data);
|
|
ArrayCopy(m_data,data,0,0,WHOLE_ARRAY);
|
|
for(int i=0; i<m_xsize; i++)
|
|
{
|
|
for(int j=0; j<m_ysize; j++)
|
|
{
|
|
WaveletCPU(m_data,datacount,m_xsize,m_ysize,i,j,true,m_wavelet_data_CPU);
|
|
}
|
|
}
|
|
time=GetTickCount()-time;
|
|
//---
|
|
return(true);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| CalculateWavelet_GPU |
|
|
//+------------------------------------------------------------------+
|
|
bool CWavelet::CalculateWavelet_GPU(float &data[],uint &time)
|
|
{
|
|
int datacount=ArraySize(data);
|
|
if(!m_OpenCL.Initialize(cl_program,true))
|
|
{
|
|
PrintFormat("Error in OpenCL initialization. Error code=%d",GetLastError());
|
|
return(false);
|
|
}
|
|
//---
|
|
m_OpenCL.SetKernelsCount(1);
|
|
m_OpenCL.KernelCreate(0,"Wavelet_GPU");
|
|
//---
|
|
m_OpenCL.SetBuffersCount(2);
|
|
if(!m_OpenCL.BufferFromArray(0,data,0,datacount,CL_MEM_READ_ONLY))
|
|
{
|
|
PrintFormat("Error in BufferFromArray for data array. Error code=%d",GetLastError());
|
|
return(false);
|
|
}
|
|
if(!m_OpenCL.BufferCreate(1,m_xsize*m_ysize*sizeof(float),CL_MEM_READ_WRITE))
|
|
{
|
|
PrintFormat("Error in BufferCreate for data array. Error code=%d",GetLastError());
|
|
return(false);
|
|
}
|
|
m_OpenCL.SetArgumentBuffer(0,0,0);
|
|
m_OpenCL.SetArgumentBuffer(0,4,1);
|
|
//---
|
|
ArrayResize(m_wavelet_data_GPU,m_xsize*m_ysize);
|
|
uint work[2];
|
|
uint offset[2]={0,0};
|
|
//--- set dimensions
|
|
work[0]=m_xsize;
|
|
work[1]=m_ysize;
|
|
//--- set parameters and write data to buffer
|
|
m_OpenCL.SetArgument(0,1,datacount);
|
|
m_OpenCL.SetArgument(0,2,m_xsize);
|
|
m_OpenCL.SetArgument(0,3,m_ysize);
|
|
time=GetTickCount();
|
|
//--- GPU calculation start
|
|
if(!m_OpenCL.Execute(0,2,offset,work))
|
|
{
|
|
PrintFormat("Error in Execute. Error code=%d",GetLastError());
|
|
return(false);
|
|
}
|
|
if(!m_OpenCL.BufferRead(1,m_wavelet_data_GPU,0,0,m_xsize*m_ysize))
|
|
{
|
|
PrintFormat("Error in BufferRead for m_wavelet_data_GPU array. Error code=%d",GetLastError());
|
|
return(false);
|
|
}
|
|
//--- GPU calculation finish
|
|
time=GetTickCount()-time;
|
|
//---
|
|
m_OpenCL.Shutdown();
|
|
return(true);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| ShowWavelet |
|
|
//+------------------------------------------------------------------+
|
|
void CWavelet::ShowWavelet(const int mode)
|
|
{
|
|
if(mode==CPU_DATA)
|
|
ShowWaveletData(m_wavelet_data_CPU);
|
|
else
|
|
if(mode==GPU_DATA)
|
|
ShowWaveletData(m_wavelet_data_GPU);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| ShowWaveletData |
|
|
//+------------------------------------------------------------------+
|
|
void CWavelet::ShowWaveletData(const float &m_wavelet_data[])
|
|
{
|
|
//--- calculate min/max and range
|
|
int count=ArraySize(m_wavelet_data);
|
|
float min_value=m_wavelet_data[0];
|
|
float max_value=m_wavelet_data[0];
|
|
for(int i=1; i<count; i++)
|
|
{
|
|
min_value=MathMin(min_value,m_wavelet_data[i]);
|
|
max_value=MathMax(max_value,m_wavelet_data[i]);
|
|
}
|
|
float range=max_value-min_value;
|
|
if(range>0)
|
|
{
|
|
for(int j=0; j<m_ysize; j++)
|
|
{
|
|
for(int i=0; i<m_xsize; i++)
|
|
{
|
|
int pos=j*m_xsize+i;
|
|
int colindex=int(m_maxcolor*(m_wavelet_data[pos]-min_value)/range);
|
|
m_bmp_buffer[pos]=GetPalColor(colindex);
|
|
}
|
|
}
|
|
//--- show image
|
|
ResourceCreate(m_res_name,m_bmp_buffer,m_xsize,m_ysize,0,0,0,COLOR_FORMAT_XRGB_NOALPHA);
|
|
ChartRedraw();
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Weirstrass function |
|
|
//+------------------------------------------------------------------+
|
|
float Weirstrass(float x,float a,float b)
|
|
{
|
|
float sum=0.0;
|
|
float b0=b;
|
|
float a0=a;
|
|
for(int n=0; n<35; n++)
|
|
{
|
|
float v=b0*(float)MathCos(a0*M_PI*x);
|
|
sum=sum+v;
|
|
a0=a0*a;
|
|
b0=b0*b;
|
|
}
|
|
return(sum);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| PrepareModelData |
|
|
//+------------------------------------------------------------------+
|
|
void PrepareModelData(float &price_data[],const int datacount)
|
|
{
|
|
ArrayResize(price_data,datacount);
|
|
//--- Weirstrass function
|
|
float x1=0;
|
|
float x2=2;
|
|
float dx=(x2-x1)/datacount;
|
|
for(int i=0; i<datacount; i++)
|
|
{
|
|
price_data[i]=Weirstrass(x1+dx*i,(float)3,(float)0.62);
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| PreparePriceData |
|
|
//+------------------------------------------------------------------+
|
|
void PreparePriceData(const string symbol,ENUM_TIMEFRAMES timeframe,float &price_data[],const int datacount)
|
|
{
|
|
ArrayResize(price_data,datacount);
|
|
|
|
double price_data_double[];
|
|
CopyClose(symbol,timeframe,0,datacount,price_data_double);
|
|
|
|
int size=ArraySize(price_data_double);
|
|
for(int i=0; i<size; i++)
|
|
{
|
|
price_data[i]=(float)price_data_double[i];
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| PrepareMomentumData |
|
|
//+------------------------------------------------------------------+
|
|
void PrepareMomentumData(float &price_data[],float &momentum_data[],const int momentum_period)
|
|
{
|
|
int size=ArraySize(price_data);
|
|
int datacount=size-momentum_period;
|
|
//---
|
|
ArrayResize(momentum_data,datacount);
|
|
for(int i=0; i<datacount; i+=1)
|
|
{
|
|
momentum_data[i]=price_data[i+momentum_period]-price_data[i];
|
|
}
|
|
ArrayCopy(price_data,price_data,momentum_period,0,datacount);
|
|
ArrayResize(price_data,datacount);
|
|
//--- rescale momentum data
|
|
float min_value=momentum_data[0];
|
|
float max_value=momentum_data[0];
|
|
for(int i=1; i<datacount; i++)
|
|
{
|
|
float value=momentum_data[i];
|
|
if(momentum_data[i]>max_value)
|
|
max_value=value;
|
|
|
|
if(momentum_data[i]<min_value)
|
|
min_value=value;
|
|
}
|
|
float range=max_value-min_value;
|
|
for(int i=0; i<datacount; i+=1)
|
|
momentum_data[i]=-1+2*(momentum_data[i]-min_value)/range;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Script program start function |
|
|
//+------------------------------------------------------------------+
|
|
void OnStart()
|
|
{
|
|
//---
|
|
int momentum_period=8;
|
|
float price_data[];
|
|
float momentum_data[];
|
|
PrepareModelData(price_data,SIZE_X+momentum_period);
|
|
//PreparePriceData("EURUSD",PERIOD_M1,price_data,SIZE_X+momentum_period);
|
|
PrepareMomentumData(price_data,momentum_data,momentum_period);
|
|
|
|
double price_data_double[];
|
|
double momentum_data_double[];
|
|
|
|
int datacount=ArraySize(price_data);
|
|
ArrayResize(price_data_double,datacount);
|
|
for(int i=0; i<datacount; i++)
|
|
{
|
|
price_data_double[i]=(double)price_data[i];
|
|
}
|
|
datacount=ArraySize(momentum_data);
|
|
ArrayResize(momentum_data_double,datacount);
|
|
for(int i=0; i<datacount; i++)
|
|
{
|
|
momentum_data_double[i]=(double)momentum_data[i];
|
|
}
|
|
|
|
CGraphic graph_price;
|
|
CGraphic graph_momentum;
|
|
graph_price.Create(0,"price",0,0,0,SIZE_X+130+6,SIZE_Y);
|
|
graph_price.XAxis().MaxGrace(0);
|
|
graph_price.HistorySymbolSize(10);
|
|
graph_price.CurveAdd(price_data_double,ColorToARGB(clrRed,255),CURVE_LINES,"Price");
|
|
graph_price.CurvePlotAll();
|
|
graph_price.Redraw(true);
|
|
graph_price.Update();
|
|
//---
|
|
graph_momentum.Create(0,"momentum",0,0,SIZE_Y,SIZE_X+130+6,SIZE_Y+SIZE_Y);
|
|
graph_momentum.XAxis().MaxGrace(0);
|
|
graph_momentum.HistorySymbolSize(10);
|
|
graph_momentum.CurveAdd(momentum_data_double,ColorToARGB(clrBlue,255),CURVE_LINES,"Momentum");
|
|
graph_momentum.CurvePlotAll();
|
|
graph_momentum.Redraw(true);
|
|
graph_momentum.Update();
|
|
//---
|
|
uint time_cpu=0;
|
|
CWavelet wavelet;
|
|
wavelet.Create("Wavelet",50,2*SIZE_Y,SIZE_X,SIZE_Y);
|
|
if(!wavelet.CalculateWavelet_CPU(momentum_data,time_cpu))
|
|
{
|
|
PrintFormat("Error in calculation on CPU. Error code=%d",GetLastError());
|
|
return;
|
|
}
|
|
//wavelet.ShowWavelet(CPU_DATA);
|
|
uint time_gpu=0;
|
|
if(!wavelet.CalculateWavelet_GPU(momentum_data,time_gpu))
|
|
{
|
|
PrintFormat("Error in calculation on GPU. Error code=%d",GetLastError());
|
|
return;
|
|
}
|
|
wavelet.ShowWavelet(GPU_DATA);
|
|
//---
|
|
double CPU_GPU_ratio=0;
|
|
if(time_gpu!=0)
|
|
CPU_GPU_ratio=1.0*time_cpu/time_gpu;
|
|
//---
|
|
PrintFormat("time CPU=%d ms, time GPU=%d ms, CPU/GPU ratio: %f",time_cpu,time_gpu,CPU_GPU_ratio);
|
|
//--- Sleep 10 seconds
|
|
Sleep(10000);
|
|
}
|
|
//+------------------------------------------------------------------+
|