Используете ли вы возможности OpenCL для ускорения расчетов? (и обсуждение применения в торговле) - страница 5

 
Yury Kirillov:

Попробуем для разминки решить следующую задачку:

Отправить в кернел массив из двух элементов, поменять значения элементов местами и вернуть обратно.



Второй вариант решения:

Основная программа.

//============================================================================================= MQL5 ===
//    LibreOCL v1.003 (MQL5)
//    Главный модуль обработки событий
//    Librecoin(c)2014-2017
//============================================================================================= MQL5 ===
//    REVIEWS
//------------------------------------------------------------------------------------------------------
// Пример программирования OpenCL.
//============================================================================================= MQL5 ===
//    IDEAS
//------------------------------------------------------------------------------------------------------
// Заносим два значения в кернел, меняем местами и возвращаем обратно.
//============================================================================================= MQL5 ===
//    PROPERTY
//------------------------------------------------------------------------------------------------------
#property copyright "Librecoin(c)2017"
#property version   "1.003"
#property strict
#resource "Kernels/LibreOCL_v1.003.cl" as string CL_Source//Код кернел-программ можно подключать как ресурс
//
//============================================================================================= MQL5 ===
// Script program start function  
//------------------------------------------------------------------------------------------------------
void OnStart(){
//----- Включатель отладочной печати
   bool  PrintDebugSelector=true;
//----- Исходный массив значений для перестановки
   double x[]={1111.1,9999.9}; 
//----- Распечатаем исходные значения элементов массива
   Print("x[0]=",x[0]," x[1]=",x[1]);
//----- Хендлы для объектов OpenCL
   int h_CL_Context=INVALID_HANDLE;       //Хендл контекста
   int h_CL_Program=INVALID_HANDLE;       //Хендл программы
   int h_CL_Kernel=INVALID_HANDLE;        //Хендл кернела
   int h_CL_Buffer=INVALID_HANDLE;        //Хендл буфера
//----- Создание контекста (среды) для программы OpenCL (выбор девайса)
   {if((h_CL_Context=CLContextCreate(CL_USE_ANY))==INVALID_HANDLE)         //CL_USE_ANY - использовать любое доступное устройство с поддержкой OpenCL
   {
      ShutDown(h_CL_Context,h_CL_Program,h_CL_Kernel,h_CL_Buffer);
      return;
   }}//if((h_CL_Context=CLContextCreate(CL_USE_ANY))==INVALID_HANDLE)
//----- Создание в контексте программы на основе кода в строке CL_Source
   string BuildLog="";                    //Лог компиляции
   {if((h_CL_Program=CLProgramCreate(h_CL_Context,CL_Source,BuildLog))==INVALID_HANDLE)//В третьем параметре - лог компиляции
   {
      ShutDown(h_CL_Context,h_CL_Program,h_CL_Kernel,h_CL_Buffer,BuildLog,PrintDebugSelector);
      return;
   }}//if((h_CL_Program=CLProgramCreate(h_CL_Context,CL_Source,BuildLog))==INVALID_HANDLE)
//----- Создание кернела для расчета значений функции от двух переменных
   {if((h_CL_Kernel=CLKernelCreate(h_CL_Program,"Exch"))==INVALID_HANDLE)//Имя функции ("Exch") должно соответствовать имени в программной строке CL_Source
   {
      ShutDown(h_CL_Context,h_CL_Program,h_CL_Kernel,h_CL_Buffer);
      return;
   }}//if((h_CL_Kernel=CLKernelCreate(h_CL_Program,"Exch"))==INVALID_HANDLE)
//----- Создание буфера OpenCL для получения значений функции
   {if((h_CL_Buffer=CLBufferCreate(h_CL_Context,ArraySize(x)*sizeof(double),CL_MEM_READ_WRITE))==INVALID_HANDLE)
   {
      ShutDown(h_CL_Context,h_CL_Program,h_CL_Kernel,h_CL_Buffer);
      return;
   }}//if((h_CL_Buffer=CLBufferCreate(h_CL_Context,ArraySize(x)*sizeof(double),CL_MEM_READ_WRITE))==INVALID_HANDLE)
//----- Записываем исходные значения в буфер
   {if(CLBufferWrite(h_CL_Buffer,x)<=0)
   {
      ShutDown(h_CL_Context,h_CL_Program,h_CL_Kernel,h_CL_Buffer);
      return;
   }}//if(CLBufferWrite(h_CL_Buffer,x)<=0)
//----- Передаём значения буфера по хендлу h_CL_Buffer в кернел
   {if(!CLSetKernelArgMem(h_CL_Kernel,0,h_CL_Buffer))
   {
      ShutDown(h_CL_Context,h_CL_Program,h_CL_Kernel,h_CL_Buffer);
      return;
   }}//if(CLSetKernelArgMem(h_CL_Kernel,0,h_CL_Buffer))
//----- Запускаем выполнение кернела
   {if(!CLExecute(h_CL_Kernel))
   {
      ShutDown(h_CL_Context,h_CL_Program,h_CL_Kernel,h_CL_Buffer);
      return;
   }}//if(!CLExecute(h_CL_Kernel))
//----- Считываем полученные значения в массив x
   Print("Из буфера прочитано ",CLBufferRead(h_CL_Buffer,x)," элементов");
//----- Распечатываем полученные значения элементов массива
   Print("x[0]=",x[0]," x[1]=",x[1]);
//----- Удаляем объекты OpenCL
      ShutDown(h_CL_Context,h_CL_Program,h_CL_Kernel,h_CL_Buffer);
   return;
}//OnStart()
//
//============================================================================================= MQL5 ===
// ShutDown() function  
//------------------------------------------------------------------------------------------------------
void ShutDown(
                        int      &i_CL_Context,
                        int      &i_CL_Program,
                        int      &i_CL_Kernel,
                        int      &i_CL_Buffer,
               const    string   i_BuildLog              =  "",
               const    bool     i_PrintDebugSelector    =  false
             )
{
//----- Build Log Print
   {if((i_PrintDebugSelector)&&(i_BuildLog!=""))
   {
      string LogLines[];
      StringSplit(i_BuildLog,'\n',LogLines);
      int LogLinesCount=ArraySize(LogLines);
      {for(int i=0; i<LogLinesCount; i++)
      {
         Print(LogLines[i]);
      }}//for(int i=0; i<LogLinesCount; i++)
   }}//if((i_PrintDebugSelector)&&(i_BuildLog!=""))
//----- Remove buffer
   {if(i_CL_Buffer!=INVALID_HANDLE)
   {
      CLBufferFree(i_CL_Buffer);
      i_CL_Buffer=INVALID_HANDLE;
   }}//if(i_CL_Buffer!=INVALID_HANDLE)
//---- Remove kernel
   {if(i_CL_Kernel!=INVALID_HANDLE)
   {
      CLKernelFree(i_CL_Kernel);
      i_CL_Kernel=INVALID_HANDLE;
   }}//if(i_CL_Kernel!=INVALID_HANDLE)
//----- Remove program
   {if(i_CL_Program!=INVALID_HANDLE)
   {
      CLProgramFree(i_CL_Program);
      i_CL_Program=INVALID_HANDLE;
   }}//if(m_program!=INVALID_HANDLE)
//----- Remove context
   {if(i_CL_Context!=INVALID_HANDLE)
   {
      CLContextFree(i_CL_Context);
      i_CL_Context=INVALID_HANDLE;
   }}//if(m_context!=INVALID_HANDLE)
}//ShutDown()
//             

Код кернел-программы, подключенный к основной программе как ресурс.

//============================================================================================= MQL5 ===
//    LibreOCL v1.002 (MQL5)
//    Модуль кернел-функций для OpenCL
//    Librecoin(c)2014-2017
//------------------------------------------------------------------------------------------------------
__kernel void Exch(global double *ix)
{
   double z;
   z=ix[0];
   ix[0]=ix[1];
   ix[1]=z;
}//Exch()
//
 

Перейдём к несколько более сложной задаче.

Попробуем максимально перенести в кернел расчет (пока без распараллеливания и оптимизации) следующего индикатора:

//============================================================================================= MQL5 ===
//    LibreFEI v1.005 (MQL5)
//    Главный модуль обработки событий
//    Librecoin(c)2014-2017
//============================================================================================= MQL5 ===
//    REVIEWS
//------------------------------------------------------------------------------------------------------
//    Fourier Extrapolator Adaptive - экстраполятор фурье творческая переработка.
//============================================================================================= MQL5 ===
//    IDEAS
//------------------------------------------------------------------------------------------------------
// 12.12.2017 Идея:  расчетную часть выполнить с использованием OpenCL
//============================================================================================= MQL5 ===
//    PROPERTY
//------------------------------------------------------------------------------------------------------
#define     ver            "1.005"
#property   copyright      "Librecoin(c)2014-2017, gpwr(c)2008-2010"
#property   link           "https://www.mql5.com/ru/users/kirillovyv"
#property   strict
#property   description    "**************************************************"
#property   description    "  Indicator LibreFEI v"+ver+" Lite (MQL5)" 
#property   description    "  Extrapolator by trigonometric (multitone) model" 
#property   description    "  From Russia with Love!  :-)"
#property   description    "  https://www.mql5.com/ru/users/kirillovyv"
#property   description    "  Based from: gpwr(c)2008-2010, neoclassic(c)2009"
#property   description    "**************************************************"
#property   version        ver
const       string         vers  =  "LibreFEI v"+ver;    //Version
//----- indicator property
#property indicator_chart_window
#property indicator_buffers 4
#property indicator_plots   2
//============================================================================================= MQL5 ===
//    INTERFACE
//------------------------------------------------------------------------------------------------------
input int      Npast          =  650;           //Past bars, to which trigonometric series is fitted
input int      Nfut           =  20;            //Predicted future bars
input int      Nharm          =  9;             //Min Narmonics in model
input double   FreqTOL        =  0.0000001;     //Tolerance of frequency calculations
input int      StartBar       =  15;            //С какого бара начинаем
input int      MSTimerSet     =  500;           //Установка таймера xxx миллисекунд
input int      nTickDelay     =  5;             //Интервал пропуска тиков для тестирования
input ulong    IterLimit      =  60;            //Iteration limit для Freq
input bool     CommentOn      =  false;         //Вывод комментариев на экран
input bool     PrintOn        =  false;         //Печать комментариев в журнал
//============================================================================================= MQL5 ===
//    Global variable definition
//------------------------------------------------------------------------------------------------------
bool     TimeInterrupt;
int      nTickSumm;
//----- indicator buffers
double   pv[];                                  //0 Отображаемый буфер истории PAST
double   fv[];                                  //1 Отображаемый буфер прогноза FUTURE
double   pc[];                                  //2 Расчетный буфер истории PAST
double   fc[];                                  //3 Расчетныйбуфер прогноза FUTURE
//----- Буфер расчетного параметра
double   xc[];                                  //Буфер расчетного параметра
//
//datetime xTime                =  D'2017.09.13 21:57:59';//Время начала вывода протоколов
//datetime xTimeStop            =  D'2017.09.13 23:55:55';//Время окончания вывода протоколов
//
//============================================================================================= MQL5 ===
// OnInit() -  Custom indicator initialization function
//------------------------------------------------------------------------------------------------------
int OnInit()
{
//----- initialize global variables
   TimeInterrupt=true;
   nTickSumm=0;
//----- indicator parametrs
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
   IndicatorSetString(INDICATOR_SHORTNAME,"LibreFEI");
//----- indicator buffers mapping
   //Прошлое - буфер отображения PAST
   ArraySetAsSeries(pv,true);
   ArrayInitialize(pv,EMPTY_VALUE);
   SetIndexBuffer(0,pv,INDICATOR_DATA);
   PlotIndexSetString(0,PLOT_LABEL,"Past"); 
   PlotIndexSetInteger(0,PLOT_DRAW_TYPE,DRAW_LINE); 
   PlotIndexSetInteger(0,PLOT_LINE_STYLE,STYLE_SOLID);
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,2);
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,clrBlue);
   //Будущее - буфер отображения FUTURE
   ArraySetAsSeries(fv,true);
   ArrayInitialize(fv,EMPTY_VALUE);
   SetIndexBuffer(1,fv,INDICATOR_DATA);
   PlotIndexSetString(1,PLOT_LABEL,"Future");    
   PlotIndexSetInteger(1,PLOT_DRAW_TYPE,DRAW_LINE); 
   PlotIndexSetInteger(1,PLOT_LINE_STYLE,STYLE_SOLID);
   PlotIndexSetInteger(1,PLOT_LINE_WIDTH,2);
   PlotIndexSetInteger(1,PLOT_LINE_COLOR,clrRed);
   PlotIndexSetInteger(1,PLOT_SHIFT,Nfut);                  //future data vector i=0..Nfut; Nfut corresponds to bar=StartBar
   //Прошлое - буфер расчета PAST
   ArraySetAsSeries(pc,true);
   ArrayInitialize(pc,EMPTY_VALUE);
   SetIndexBuffer(2,pc,INDICATOR_CALCULATIONS);
   //Будущее - буфер расчета FUTURE
   ArraySetAsSeries(fc,true);//false
   ArrayInitialize(fc,EMPTY_VALUE);
   SetIndexBuffer(3,fc,INDICATOR_CALCULATIONS);
   //Буфер расчетного параметра
   ArrayResize(xc,Npast+1);
//----- Настройки таймера и глобальных счетчиков
   {if(!MQLInfoInteger(MQL_TESTER))//Не тестирование
   { 
      int err=-1;
      int count=50;
      {while((err!=0)&&(count>0))
      {
         ResetLastError();
         EventSetMillisecondTimer(MSTimerSet);              //Установка таймера XXX миллисекунд
         err=GetLastError();
         {if(err!=0)
         {
            Sleep(50);
         }}//if(err!=0)
         count--;
      }}//while((err!=0)&&(count>0))
   }}//if(!MQLInfoInteger(MQL_TESTER))
//-----   
   return(INIT_SUCCEEDED);
}//OnInit()
//
//============================================================================================= MQL5 ===
// OnDeinit()  -  Custom indicator iteration function                              |
//------------------------------------------------------------------------------------------------------
void OnDeinit(const int reason){
   Comment("");
   return;
}//OnDeinit()
//
//============================================================================================= MQL5 ===
//    OnTimer()
//------------------------------------------------------------------------------------------------------
void OnTimer(){
   TimeInterrupt=true;
   nTickSumm=0;
}//OnTimer()
//
//============================================================================================= MQL5 ===
//    OnCalculate()  -     Custom indicator iteration function
//------------------------------------------------------------------------------------------------------
int OnCalculate(const int        rates_total,      
                const int        prev_calculated,
                const datetime&  time[],
                const double&    open[],
                const double&    high[],
                const double&    low[],
                const double&    close[],
                const long&      tick_volume[],
                const long&      volume[],
                const int&       spread[])
{
//----- Check for insufficient data
   {if(rates_total<Npast+StartBar+1)
   {
      {if(PrintOn)
      {
         Print("Error: not enough bars in history!"
               +" Total="+IntegerToString(rates_total)
               +" needed="+IntegerToString(Npast+StartBar+1));
      }}//if(PrintOn)
      return(0);
   }}//if(rates_total<Npast)
//----- Проверка необходимости пересчета по тикам
   {if(MQLInfoInteger(MQL_TESTER))
   {
      nTickSumm++;
      {if(MathMod(nTickSumm,nTickDelay)<1.0)
      {
         nTickSumm=0;
         TimeInterrupt=true;
      }}//if(MathMod(nTickSumm,7)<1.0)
   }}//if(MQLInfoInteger(MQL_TESTER))
//----- Проверка необходимости пересчета по таймеру
   {if(rates_total<=prev_calculated)//размер входных таймсерий меньше или равен, чем ранее обработано (обычно размер входных на предшествующем тике)
   {//Изменений нет - проверяем таймер
      {if(!TimeInterrupt)//если нет прерывания от msec таймера
      {
         return(rates_total);                                  //Сваливаем, ибо нет изменений и прерывания таймера
      }else{//есть прерывание таймера - сбрасываем и выполняем расчет
         TimeInterrupt=false;
      }}//if(!TimeInterrupt)
   }}//if(rates_total<=prev_calculated)
//----- Определение серийности массивов данных
   ArraySetAsSeries(open,true);
   ArraySetAsSeries(close,true);
   ArraySetAsSeries(high,true);
   ArraySetAsSeries(low,true);
   ArraySetAsSeries(spread,true);
//----- Заполнение исходного массива для рассчета
   {for(int i=0;i<Npast+1;i++)
   {
      xc[i]=close[i+StartBar];
   }}//for(int i=0;Npast+1;i++)
   Calc_Fourier(xc,pc,fc,Npast,Nharm);
//----- Перекладка массивов для отображения
   //Заполнение исходного массива для рассчета прогноза
   {for(int i=0;i<Npast;i++)
   {
      xc[i]=close[i];
   }}//for(int i=0;i<Npast;i++)
//----- Расчет и вывод индикаторных буферов и справочной информации
   {if(CommentOn)
   {
      Comment( "LibreFEI"+" "+
               string(TimeCurrent())+" "+
               "ST="+IntegerToString(StartBar)+" "+
               "NF="+IntegerToString(Nfut)+" "+
               "NP="+IntegerToString(Npast)+" "+
               "NH="+IntegerToString(Nharm)+" "
             );
   }}//if(CommentOn)
   {if(PrintOn)
   {
      Print(   string(TimeCurrent())+" "+
               "NP="+IntegerToString(Npast)+" "+
               "NH="+IntegerToString(Nharm)+" "
            );
   }}//if(PrintOn)
   PlotIndexSetInteger(0,PLOT_DRAW_TYPE,DRAW_NONE);   //pv
   PlotIndexSetInteger(1,PLOT_DRAW_TYPE,DRAW_NONE);   //fv
   PlotIndexSetInteger(2,PLOT_DRAW_TYPE,DRAW_NONE); 
   PlotIndexSetInteger(3,PLOT_DRAW_TYPE,DRAW_NONE); 
   ArrayInitialize(pv,EMPTY_VALUE);
   ArrayInitialize(fv,EMPTY_VALUE);
   ArrayCopy(pv,pc,0,0,Npast+StartBar+1);
   {for(int i=0;i<=Nfut;i++) 
   {
      fv[Nfut-i]=fc[i];
   }}//for(int i=0;i<=Nfut;i++)  
   PlotIndexSetInteger(0,PLOT_DRAW_TYPE,DRAW_LINE); //pv
   PlotIndexSetInteger(1,PLOT_DRAW_TYPE,DRAW_LINE); //fv
   PlotIndexSetInteger(2,PLOT_DRAW_TYPE,DRAW_LINE); 
   PlotIndexSetInteger(3,PLOT_DRAW_TYPE,DRAW_LINE); 
   ChartRedraw(ChartID());
//-----
   return(rates_total);
}//OnCalculate()
//  
//============================================================================================= MQL5 ===
//    Calc_Fourier()    -     Calc_Fourier
//------------------------------------------------------------------------------------------------------
void Calc_Fourier(double &x[],double &p[],double &f[],int iNpast,int iNharm){
//-----
      //----- initialize indicator buffers to EMPTY_VALUE
      ArrayInitialize(p,EMPTY_VALUE);
      ArrayInitialize(f,EMPTY_VALUE);
      //----- Find average of past values
      double av=0.0;
      //Заполнение исходного массива для рассчета и накопление суммы для вычисления среднего 
      {for(int i=0;i<iNpast;i++)
      {
         av=av+x[i];
      }}//for(int i=0;i<Npast;i++)
      //Рассчет среднего
      av=av/iNpast;
      //----- initialize model outputs
      {for(int i=0;i<iNpast;i++)
      {
         p[i]=av;                           //Прошлое заполняем средним значением от [0] на максимальную глубину
      }}//for(int i=0;i<iNpast;i++)
      {for(int i=0;i<=Nfut;i++)
      {
         f[i]=av;                           //Будущее заполняем средним значением от [0] на глубину Nfut
      }}//for(int i=0;i<iNpast;i++)
      //----- fit trigonometric model and calculate predictions
      double w,m,c,s;
      {for(int harm=1;harm<=iNharm;harm++)//Nharmm - раз прогоняемся в цикле
      {
         Freq(x,p,iNpast,w,m,c,s);
         double mcc=0.0;
         double ss=0.0;
         {for(int i=0;i<iNpast;i++) 
         {
            mcc=m+c*MathCos(w*i);
            ss=s*MathSin(w*i);
            p[i]+=mcc+ss;
            {if(i<=Nfut)
            {
               f[i]+=mcc-ss;
            }}//if(i<=Nfut)
         }}//for(int i=0;i<iNpast;i++)  
      }}//for(int harm=1;harm<=Nharmm;harm++)
      return;
}//Calc_Fourier()
//  
//============================================================================================= MQL5 ===
//    Freq()   -     Quinn and Fernandes algorithm for finding frequency
//------------------------------------------------------------------------------------------------------
void Freq(double& x[],double& ipc[],int n,double& w,double& m,double& c,double& s)
{
   double z[];
   ArrayResize(z,n);
   double alpha=0.0;
   double beta=2.0;
   z[0]=x[0]-ipc[0];
   ulong IterCount=0;
   {while((MathAbs(alpha-beta)>FreqTOL)&&(IterCount<IterLimit))
   {
      alpha=beta;
      z[1]=x[1]-ipc[1]+alpha*z[0];
      double num=z[0]*z[1];
      double den=z[0]*z[0];
      {for(int i=2;i<n;i++)
      {
         z[i]=x[i]-ipc[i]+alpha*z[i-1]-z[i-2];
         num+=z[i-1]*(z[i]+z[i-2]);
         den+=z[i-1]*z[i-1];
      }}//for(int i=2;i<n;i++)
      beta=num/den;
      IterCount++;
   }}//while(MathAbs(alpha-beta)>FreqTOL)
   w=MathArccos(beta/2.0);
   TrigFit(x,ipc,n,w,m,c,s);
}//Freq()
//
//============================================================================================= MQL5 ===
//    TrigFit()   -     Least-squares fitting of trigonometric series
//------------------------------------------------------------------------------------------------------
void TrigFit(double& x[],double& ipc[],int n,double w,double& m,double& c,double& s)
{
   double Sc =0.0;
   double Ss =0.0;
   double Scc=0.0;
   double Sss=0.0;
   double Scs=0.0;
   double Sx =0.0;
   double Sxc=0.0;
   double Sxs=0.0;
   {for(int i=0;i<n;i++)
   {
      double cos_w_i=MathCos(w*i);
      double sin_w_i=MathSin(w*i);
      double dx=x[i]-ipc[i];
      Sc +=cos_w_i;
      Ss +=sin_w_i;
      Scc+=cos_w_i*cos_w_i;
      Sss+=sin_w_i*sin_w_i;
      Scs+=cos_w_i*sin_w_i;
      Sx +=dx;
      Sxc+=dx*cos_w_i;
      Sxs+=dx*sin_w_i;
   }}//for(int i=0;i<n;i++)
   Sc /=n;
   Ss /=n;
   Scc/=n;
   Sss/=n;
   Scs/=n;
   Sx /=n;
   Sxc/=n;
   Sxs/=n;
   {if(w==0.0)
   {
      m=Sx;
      c=0.0;
      s=0.0;
   }else{
      // calculating a, b, and m
      double den=MathPow(Scs-Sc*Ss,2)-(Scc-Sc*Sc)*(Sss-Ss*Ss);
      c=((Sxs-Sx*Ss)*(Scs-Sc*Ss)-(Sxc-Sx*Sc)*(Sss-Ss*Ss))/den;
      s=((Sxc-Sx*Sc)*(Scs-Sc*Ss)-(Sxs-Sx*Ss)*(Scc-Sc*Sc))/den;
      m=Sx-c*Sc-s*Ss;
   }}//if(w==0.0)
   return;
}//TrigFit()
//
Файлы:
 
Yury Kirillov:

Перейдём к несколько более сложной задаче.

Попробуем максимально перенести в кернел расчет (пока без распараллеливания и оптимизации) следующего индикатора:

Просмотрел этот пример и не понял где собственно осуществляется перенос в кернел?

А если свернуть расчетные функции самого индикатора (которых может быть сколько угодно), и показать сам принцип переноса большого количества функций в кернел (OpenCL)?

Иначе говоря, среди функций которые нужно перенести, сложно найти сам код который переносит и понять главный принцип этого переноса.

Как его сформулировать?

Спасибо.

 
Реter Konow:

Просмотрел этот пример и не понял где собственно осуществляется перенос в кернел?

А если свернуть расчетные функции самого индикатора (которых может быть сколько угодно), и показать сам принцип переноса большого количества функций в кернел (OpenCL)?

Иначе говоря, среди функций которые нужно перенести, сложно найти сам код который переносит и понять главный принцип этого переноса.

Как его сформулировать?

Спасибо.


Это не решение, а собственно только постановка задачи. Ожидайте решения...

 
Yury Kirillov:

Это не решение, а собственно только постановка задачи. Ожидайте решения...

Ясно.
 

Перенос расчетов индикатора в кернел. Промежуточный вариант - показаны основные отличия.

Интерфейс.

Было:

//============================================================================================= MQL5 ===
//    INTERFACE
//------------------------------------------------------------------------------------------------------
input int      Npast          =  650;           //Past bars, to which trigonometric series is fitted
input int      Nfut           =  20;            //Predicted future bars
input int      Nharm          =  9;             //Min Narmonics in model
input double   FreqTOL        =  0.0000001;     //Tolerance of frequency calculations
input int      StartBar       =  15;            //С какого бара начинаем
input int      MSTimerSet     =  500;           //Установка таймера xxx миллисекунд
input int      nTickDelay     =  5;             //Интервал пропуска тиков для тестирования
input ulong    IterLimit      =  60;            //Iteration limit для Freq
input bool     CommentOn      =  false;         //Вывод комментариев на экран
input bool     PrintOn        =  false;         //Печать комментариев в журнал

Стало:

//============================================================================================= MQL5 ===
//    INTERFACE
//------------------------------------------------------------------------------------------------------
input int      Npast          =  650;           //Past bars, to which trigonometric series is fitted
input int      Nfut           =  20;            //Predicted future bars
input int      Nharm          =  9;             //Min Narmonics in model
input double   FreqTOL        =  0.0000001;     //Tolerance of frequency calculations
input int      StartBar       =  15;            //С какого бара начинаем
input int      MSTimerSet     =  500;           //Установка таймера xxx миллисекунд
input int      nTickDelay     =  5;             //Интервал пропуска тиков для тестирования
input ulong    IterLimit      =  60;            //Iteration limit для Freq
input bool     CommentOn      =  false;         //Вывод комментариев на экран
input bool     PrintOn        =  false;         //Печать комментариев в журнал
input bool     OCLSelector    =  true;          //Использовать OpenCL
Добавлен OCLSelector    для выбора варианта расчета: с использованием или без использования OpenCL.

Инициализация расчетных буферов.

Было:

   //Прошлое - буфер расчета PAST
   ArraySetAsSeries(pc,true);
   ArrayInitialize(pc,EMPTY_VALUE);
   SetIndexBuffer(2,pc,INDICATOR_CALCULATIONS);
   //Будущее - буфер расчета FUTURE
   ArraySetAsSeries(fc,true);//false
   ArrayInitialize(fc,EMPTY_VALUE);
   SetIndexBuffer(3,fc,INDICATOR_CALCULATIONS);
   //Буфер расчетного параметра
   ArrayResize(xc,Npast+1);
//----- Настройки таймера и глобальных счетчиков
   {if(!MQLInfoInteger(MQL_TESTER))//Не тестирование
   { 
      int err=-1;
      int count=50;
      {while((err!=0)&&(count>0))
      {
         ResetLastError();
         EventSetMillisecondTimer(MSTimerSet);              //Установка таймера XXX миллисекунд
         err=GetLastError();
         {if(err!=0)
         {
            Sleep(50);
         }}//if(err!=0)
         count--;
      }}//while((err!=0)&&(count>0))
   }}//if(!MQLInfoInteger(MQL_TESTER))
//-----   
   return(INIT_SUCCEEDED);

Стало:

   //Прошлое - буфер расчета PAST - разобраться с AsSeries(), сделать false
   ArraySetAsSeries(pc,false);
   ArrayInitialize(pc,EMPTY_VALUE);
   SetIndexBuffer(2,pc,INDICATOR_CALCULATIONS);
   //Будущее - буфер расчета FUTURE
   ArraySetAsSeries(fc,true);//false
   ArrayInitialize(fc,EMPTY_VALUE);
   SetIndexBuffer(3,fc,INDICATOR_CALCULATIONS);
   //Буфер расчетного параметра
   ArraySetAsSeries(xc,false);//Всегда!
   ArrayResize(xc,Npast+1);
//----- Настройки таймера и глобальных счетчиков
   {if(!MQLInfoInteger(MQL_TESTER))//Не тестирование
   { 
      int err=-1;
      int count=50;
      {while((err!=0)&&(count>0))
      {
         ResetLastError();
         EventSetMillisecondTimer(MSTimerSet);              //Установка таймера XXX миллисекунд
         err=GetLastError();
         {if(err!=0)
         {
            Sleep(50);
         }}//if(err!=0)
         count--;
      }}//while((err!=0)&&(count>0))
   }}//if(!MQLInfoInteger(MQL_TESTER))
//----- Подготовительные операции OpenCL
   {if(OCLSelector)
   {   
      //----- Включатель отладочной печати
      PrintDebugSelector=true;
      //----- Хендлы для объектов OpenCL
      h_CL_Context=INVALID_HANDLE;       //Хендл контекста
      h_CL_Program=INVALID_HANDLE;       //Хендл программы
      h_CL_Kernel=INVALID_HANDLE;        //Хендл кернела
      //----- Определение числа буферов под переменные
      ArrayResize(h_CL_Buffers,5);//x,ipc,im,ic,is
      ArrayFill(h_CL_Buffers,0,ArraySize(h_CL_Buffers),INVALID_HANDLE);
      //----- Создание контекста (среды) для программы OpenCL (выбор девайса)
      ResetLastError();
      {if((h_CL_Context=CLContextCreate(CL_USE_ANY))==INVALID_HANDLE)                     //CL_USE_ANY - использовать любое доступное устройство с поддержкой OpenCL
      {
         Print("OpenCL not found, error:",GetLastError());
         ShutDown(h_CL_Context,h_CL_Program,h_CL_Kernel,h_CL_Buffers);
         return(INIT_FAILED);
      }else{
         Print("OpenCL found, Хендл на контекст OpenCL:",h_CL_Context," Error:",GetLastError());
      }}//if((h_CL_Context=CLContextCreate(CL_USE_ANY))==INVALID_HANDLE)
      //----- Создание в контексте программы на основе кода в строке CL_Source
      string BuildLog="";                    //Лог компиляции
      ResetLastError();
      {if((h_CL_Program=CLProgramCreate(h_CL_Context,CL_Source,BuildLog))==INVALID_HANDLE)//В третьем параметре - лог компиляции
      {
         Print("OpenCL program create failed, error:",GetLastError()," BuildLog=",BuildLog);
         ShutDown(h_CL_Context,h_CL_Program,h_CL_Kernel,h_CL_Buffers,BuildLog,PrintDebugSelector);
         return(INIT_FAILED);
      }else{
         Print("OpenCL program create, Хендл программы OpenCL:",h_CL_Program," Error:",GetLastError());
      }}//if((h_CL_Program=CLProgramCreate(h_CL_Context,CL_Source,BuildLog))==INVALID_HANDLE)
      //----- Создание кернела для расчета значений функции от двух переменных
      string CL_Kernel_Name="TrigFit_OCL";                                                //Задание имени кернела - задать вручную
      ResetLastError();
      {if((h_CL_Kernel=CLKernelCreate(h_CL_Program,CL_Kernel_Name))==INVALID_HANDLE)      //Имя функции должно соответствовать имени в программной строке CL_Source
      {
         Print("OpenCL kernel create failed, error:",GetLastError());
         ShutDown(h_CL_Context,h_CL_Program,h_CL_Kernel,h_CL_Buffers);
         return(INIT_FAILED);
      }else{
         Print("OpenCL kernel create, Хендл кернела OpenCL:",h_CL_Kernel," Error:",GetLastError());
      }}//if((h_CL_Kernel=CLKernelCreate(h_CL_Program,"Exch"))==INVALID_HANDLE)
      //----- Создание буферов
      //----- Создание буфера[0] OpenCL для значений x[]
      ResetLastError();
      {if((h_CL_Buffers[0]=CLBufferCreate(h_CL_Context,Npast*sizeof(double),CL_MEM_READ_WRITE))==INVALID_HANDLE)//__global double *x,
      {
         Print("OpenCL buffer create failed, error:",GetLastError());
         ShutDown(h_CL_Context,h_CL_Program,h_CL_Kernel,h_CL_Buffers);
         return(INIT_FAILED);
      }else{
         Print("OpenCL buffer create, Хендл буфера OpenCL:",h_CL_Buffers[0]," Error:",GetLastError());
      }}//if((h_CL_Buffer=CLBufferCreate(h_CL_Context,ArraySize(x)*sizeof(double),CL_MEM_READ_WRITE))==INVALID_HANDLE)
      //----- Создание буфера[1] OpenCL для значений ipc[] - переделать, только при изменении размерности массива
      ResetLastError();
      {if((h_CL_Buffers[1]=CLBufferCreate(h_CL_Context,Npast*sizeof(double),CL_MEM_READ_WRITE))==INVALID_HANDLE)//__global double *ipc,
      {
         Print("OpenCL buffer create failed, error:",GetLastError());
         ShutDown(h_CL_Context,h_CL_Program,h_CL_Kernel,h_CL_Buffers);
         return(INIT_FAILED);
      }else{
         Print("OpenCL buffer create, Хендл буфера OpenCL:",h_CL_Buffers[1]," Error:",GetLastError());
      }}//if((h_CL_Buffer=CLBufferCreate(h_CL_Context,ArraySize(x)*sizeof(double),CL_MEM_READ_WRITE))==INVALID_HANDLE)
      //----- Создание буфера[2] OpenCL для значений im[]
      ResetLastError();
      {if((h_CL_Buffers[2]=CLBufferCreate(h_CL_Context,sizeof(double),CL_MEM_READ_WRITE))==INVALID_HANDLE)//__global double *m,
      {
         Print("OpenCL buffer create failed, error:",GetLastError());
         ShutDown(h_CL_Context,h_CL_Program,h_CL_Kernel,h_CL_Buffers);
         return(INIT_FAILED);
      }else{
         Print("OpenCL buffer create, Хендл буфера OpenCL:",h_CL_Buffers[2]," Error:",GetLastError());
      }}//if((h_CL_Buffer=CLBufferCreate(h_CL_Context,ArraySize(x)*sizeof(double),CL_MEM_READ_WRITE))==INVALID_HANDLE)
      //----- Создание буфера[3] OpenCL для значений ic[]
      ResetLastError();
      {if((h_CL_Buffers[3]=CLBufferCreate(h_CL_Context,sizeof(double),CL_MEM_READ_WRITE))==INVALID_HANDLE)//__global double *c,
      {
         Print("OpenCL buffer create failed, error:",GetLastError());
         ShutDown(h_CL_Context,h_CL_Program,h_CL_Kernel,h_CL_Buffers);
         return(INIT_FAILED);
      }else{
         Print("OpenCL buffer create, Хендл буфера OpenCL:",h_CL_Buffers[3]," Error:",GetLastError());
      }}//if((h_CL_Buffer=CLBufferCreate(h_CL_Context,ArraySize(x)*sizeof(double),CL_MEM_READ_WRITE))==INVALID_HANDLE)
      //----- Создание буфера[4] OpenCL для значений is[]
      ResetLastError();
      {if((h_CL_Buffers[4]=CLBufferCreate(h_CL_Context,sizeof(double),CL_MEM_READ_WRITE))==INVALID_HANDLE)//__global double *s,
      {
         Print("OpenCL buffer create failed, error:",GetLastError());
         ShutDown(h_CL_Context,h_CL_Program,h_CL_Kernel,h_CL_Buffers);
         return(INIT_FAILED);
      }else{
         Print("OpenCL buffer create, Хендл буфера OpenCL:",h_CL_Buffers[4]," Error:",GetLastError());
      }}//if((h_CL_Buffer=CLBufferCreate(h_CL_Context,ArraySize(x)*sizeof(double),CL_MEM_READ_WRITE))==INVALID_HANDLE)
   }else{
   
   }}//if(OCLSelector)
//----- Выход тут   
   return(INIT_SUCCEEDED);

Перенос расчетных массивов в индикаторные.

Было:

  ArrayCopy(pv,pc,0,0,Npast+StartBar+1);

Стало:

   //ArrayCopy(pv,pc,0,0,Npast+StartBar+1); - Если один массив AsSeries, а второй нет, то разворачивает
   {for(int i=0;i<=Npast+StartBar;i++) 
   {
      pv[i]=pc[i];
   }}//for(int i=0;i<=Npast+StartBar;i++) 

Расчет по Куину-Фернандесу.

Было:

//============================================================================================= MQL5 ===
//    Freq()   -     Quinn and Fernandes algorithm for finding frequency
//------------------------------------------------------------------------------------------------------
void Freq(double& x[],double& ipc[],int n,double& w,double& m,double& c,double& s)
{
   double z[];
   ArrayResize(z,n);
   double alpha=0.0;
   double beta=2.0;
   z[0]=x[0]-ipc[0];
   ulong IterCount=0;
   {while((MathAbs(alpha-beta)>FreqTOL)&&(IterCount<IterLimit))
   {
      alpha=beta;
      z[1]=x[1]-ipc[1]+alpha*z[0];
      double num=z[0]*z[1];
      double den=z[0]*z[0];
      {for(int i=2;i<n;i++)
      {
         z[i]=x[i]-ipc[i]+alpha*z[i-1]-z[i-2];
         num+=z[i-1]*(z[i]+z[i-2]);
         den+=z[i-1]*z[i-1];
      }}//for(int i=2;i<n;i++)
      beta=num/den;
      IterCount++;
   }}//while(MathAbs(alpha-beta)>FreqTOL)
   w=MathArccos(beta/2.0);
   TrigFit(x,ipc,n,w,m,c,s);
}//Freq()

Стало:

//============================================================================================= MQL5 ===
//    Freq()   -     Quinn and Fernandes algorithm for finding frequency
//------------------------------------------------------------------------------------------------------
void Freq(double& x[],double& ipc[],int n,double& w,double& m,double& c,double& s)
{
   double z[];
   ArrayResize(z,n);
   double alpha=0.0;
   double beta=2.0;
   z[0]=x[0]-ipc[0];
   ulong IterCount=0;
   {while((MathAbs(alpha-beta)>FreqTOL)&&(IterCount<IterLimit))
   {
      alpha=beta;
      z[1]=x[1]-ipc[1]+alpha*z[0];
      double num=z[0]*z[1];
      double den=z[0]*z[0];
      {for(int i=2;i<n;i++)
      {
         z[i]=x[i]-ipc[i]+alpha*z[i-1]-z[i-2];
         num+=z[i-1]*(z[i]+z[i-2]);
         den+=z[i-1]*z[i-1];
      }}//for(int i=2;i<n;i++)
      beta=num/den;
      IterCount++;
   }}//while(MathAbs(alpha-beta)>FreqTOL)
   w=MathArccos(beta/2.0);
   ////----- Сравнение расчетов
   //double m1,c1,s1;
   //m1=m;c1=c;s1=s;
   //TrigFitOCL(x,ipc,n,w,m,c,s);
   //Print("1. m=",DoubleToString(m,8)," c=",DoubleToString(c,8)," s=",DoubleToString(s,8));
   //m=m1;c=c1;s=s1;
   //TrigFit(x,ipc,n,w,m,c,s);
   //Print("2. m=",DoubleToString(m,8)," c=",DoubleToString(c,8)," s=",DoubleToString(s,8));
   {if(OCLSelector)
   {   
      TrigFitOCL(x,ipc,n,w,m,c,s);
   }else{
      TrigFit(x,ipc,n,w,m,c,s);
   }}//if(OCLSelector)
}//Freq()

Добавлена функция TrigFitOCL():

//============================================================================================= MQL5 ===
//    TrigFitOCL()   -     Least-squares fitting of trigonometric series
//------------------------------------------------------------------------------------------------------
void TrigFitOCL(double& x[],double& ipc[],int n,double w,double& m,double& c,double& s)
{
//----- Транзитные переменные
double   im[1];//2 для m
double   ic[1];//3 для c
double   is[1];//4 для s
   im[0]=m;
   ic[0]=c;
   is[0]=s;
//----- Устанавливаем в качестве 0-го параметра функции OpenCL (кернела) буфер по хендлу h_CL_Buffers[0]
   ResetLastError();
   {if(!CLSetKernelArgMem(h_CL_Kernel,0,h_CL_Buffers[0]))
   {
      Print("OpenCL set buffer failed, error:",GetLastError());
      ShutDown(h_CL_Context,h_CL_Program,h_CL_Kernel,h_CL_Buffers);
      return;
   }else{
      //Print("OpenCL set buffer, Error:",GetLastError());
   }}//if(CLSetKernelArgMem(h_CL_Kernel,0,h_CL_Buffer))
//----- Устанавливаем в качестве 1-го параметра функции OpenCL (кернела) буфер по хендлу h_CL_Buffers[1]
   ResetLastError();
   {if(!CLSetKernelArgMem(h_CL_Kernel,1,h_CL_Buffers[1]))
   {
      Print("OpenCL set buffer failed, error:",GetLastError());
      ShutDown(h_CL_Context,h_CL_Program,h_CL_Kernel,h_CL_Buffers);
      return;
   }else{
      //Print("OpenCL set buffer, Error:",GetLastError());
   }}//if(CLSetKernelArgMem(h_CL_Kernel,0,h_CL_Buffer_ipc))
//----- Устанавливаем в качестве 2-го параметра функции OpenCL (кернела) значение переменной n
   ResetLastError();
   {if(!CLSetKernelArg(h_CL_Kernel,2,n))
   {
      Print("OpenCL set buffer failed, error:",GetLastError());
      ShutDown(h_CL_Context,h_CL_Program,h_CL_Kernel,h_CL_Buffers);
      return;
   }else{
      //Print("OpenCL set buffer, Error:",GetLastError());
   }}//if(CLSetKernelArgMem(h_CL_Kernel,0,h_CL_Buffer_ipc))
//----- Устанавливаем в качестве 3-го параметра функции OpenCL (кернела) значение переменной w
   ResetLastError();
   {if(!CLSetKernelArg(h_CL_Kernel,3,w))
   {
      Print("OpenCL set buffer failed, error:",GetLastError());
      ShutDown(h_CL_Context,h_CL_Program,h_CL_Kernel,h_CL_Buffers);
      return;
   }else{
      //Print("OpenCL set buffer, Error:",GetLastError());
   }}//if(CLSetKernelArgMem(h_CL_Kernel,0,h_CL_Buffer_ipc))
//----- Устанавливаем в качестве 4-го параметра функции OpenCL (кернела) буфер по хендлу h_CL_Buffers[2]
   ResetLastError();
   {if(!CLSetKernelArgMem(h_CL_Kernel,4,h_CL_Buffers[2]))
   {
      Print("OpenCL set buffer failed, error:",GetLastError());
      ShutDown(h_CL_Context,h_CL_Program,h_CL_Kernel,h_CL_Buffers);
      return;
   }else{
      //Print("OpenCL set buffer, Error:",GetLastError());
   }}//if(CLSetKernelArgMem(h_CL_Kernel,0,h_CL_Buffer_ipc))
//----- Устанавливаем в качестве 5-го параметра функции OpenCL (кернела) буфер по хендлу h_CL_Buffers[3]
   ResetLastError();
   {if(!CLSetKernelArgMem(h_CL_Kernel,5,h_CL_Buffers[3]))
   {
      Print("OpenCL set buffer failed, error:",GetLastError());
      ShutDown(h_CL_Context,h_CL_Program,h_CL_Kernel,h_CL_Buffers);
      return;
   }else{
      //Print("OpenCL set buffer, Error:",GetLastError());
   }}//if(CLSetKernelArgMem(h_CL_Kernel,0,h_CL_Buffer_ipc))
//----- Устанавливаем в качестве 6-го параметра функции OpenCL (кернела) буфер по хендлу h_CL_Buffers[4]
   ResetLastError();
   {if(!CLSetKernelArgMem(h_CL_Kernel,6,h_CL_Buffers[4]))
   {
      Print("OpenCL set buffer failed, error:",GetLastError());
      ShutDown(h_CL_Context,h_CL_Program,h_CL_Kernel,h_CL_Buffers);
      return;
   }else{
      //Print("OpenCL set buffer, Error:",GetLastError());
   }}//if(!CLSetKernelArgMem(h_CL_Kernel,6,h_CL_Buffers[4]))
//----- Записываем исходные значения x[] в буфер по хендлу h_CL_Buffers[0]
   ResetLastError();
   uint nElementsWrite=CLBufferWrite(h_CL_Buffers[0],x,0,0,n);
   {if(nElementsWrite<(uint)n)
   {
      Print("OpenCL buffer x write failed, nElementsWrite=",nElementsWrite," error:",GetLastError());
      ShutDown(h_CL_Context,h_CL_Program,h_CL_Kernel,h_CL_Buffers);
      return;
   }else{
      //Print("OpenCL buffer write, nElementsWrite=",nElementsWrite," error:",GetLastError());
   }}//if(nElementsWrite<=0)
//----- Записываем исходные значения ipc[] в буфер по хендлу h_CL_Buffers[1]
   ResetLastError();
   nElementsWrite=CLBufferWrite(h_CL_Buffers[1],ipc,0,0,n);
   {if(nElementsWrite<(uint)n)
   {
      Print("OpenCL buffer ipc write failed, nElementsWrite=",nElementsWrite," error:",GetLastError());
      ShutDown(h_CL_Context,h_CL_Program,h_CL_Kernel,h_CL_Buffers);
      return;
   }else{
      //Print("OpenCL buffer write, nElementsWrite=",nElementsWrite," error:",GetLastError());
   }}//if(nElementsWrite<=0)
//----- Записываем исходное значение m в буфер по хендлу h_CL_Buffers[2]
   ResetLastError();
   nElementsWrite=CLBufferWrite(h_CL_Buffers[2],im,0,0,1);
   {if(nElementsWrite<1)
   {
      Print("OpenCL buffer write failed, nElementsWrite=",nElementsWrite," error:",GetLastError());
      ShutDown(h_CL_Context,h_CL_Program,h_CL_Kernel,h_CL_Buffers);
      return;
   }else{
      //Print("OpenCL buffer write, nElementsWrite=",nElementsWrite," error:",GetLastError());
   }}//if(nElementsWrite<=0)
//----- Записываем исходное значение c в буфер по хендлу h_CL_Buffers[3]
   ResetLastError();
   nElementsWrite=CLBufferWrite(h_CL_Buffers[3],ic,0,0,1);
   {if(nElementsWrite<1)
   {
      Print("OpenCL buffer write failed, nElementsWrite=",nElementsWrite," error:",GetLastError());
      ShutDown(h_CL_Context,h_CL_Program,h_CL_Kernel,h_CL_Buffers);
      return;
   }else{
      //Print("OpenCL buffer write, nElementsWrite=",nElementsWrite," error:",GetLastError());
   }}//if(nElementsWrite<=0)
//----- Записываем исходное значение s в буфер по хендлу h_CL_Buffers[4]
   ResetLastError();
   nElementsWrite=CLBufferWrite(h_CL_Buffers[4],is,0,0,1);
   {if(nElementsWrite<1)
   {
      Print("OpenCL buffer write failed, nElementsWrite=",nElementsWrite," error:",GetLastError());
      ShutDown(h_CL_Context,h_CL_Program,h_CL_Kernel,h_CL_Buffers);
      return;
   }else{
      //Print("OpenCL buffer write, nElementsWrite=",nElementsWrite," error:",GetLastError());
   }}//if(nElementsWrite<=0)
//----- Запускаем выполнение кернела
   ResetLastError();
   {if(!CLExecute(h_CL_Kernel))
   {
      Print("OpenCL execute failed, error:",GetLastError());
      ShutDown(h_CL_Context,h_CL_Program,h_CL_Kernel,h_CL_Buffers);
      return;
   }else{
      //Print("OpenCL execute, error:",GetLastError());
   }}//if(!CLExecute(h_CL_Kernel))
//----- Считываем полученные значения в массивы
   //Print("Из буфера прочитано ",CLBufferRead(h_CL_Buffers[0],x,0,0,5)," элементов");
   CLBufferRead(h_CL_Buffers[0],x,0,0,n);
   //Print("Из буфера прочитано ",CLBufferRead(h_CL_Buffers[1],ipc,0,0,3)," элементов");
   CLBufferRead(h_CL_Buffers[1],ipc,0,0,n);
   //Print("Из буфера прочитано ",CLBufferRead(h_CL_Buffers[2],im,0,0,1)," элементов");
   CLBufferRead(h_CL_Buffers[2],im,0,0,1);
   m=im[0];
   //Print("Из буфера прочитано ",CLBufferRead(h_CL_Buffers[3],ic,0,0,1)," элементов");
   CLBufferRead(h_CL_Buffers[3],ic,0,0,1);
   c=ic[0];
   //Print("Из буфера прочитано ",CLBufferRead(h_CL_Buffers[4],is,0,0,1)," элементов");
   CLBufferRead(h_CL_Buffers[4],is,0,0,1);
   s=is[0];
 return;
}//TrigFitOCL()

Добавлена функция ShutDown():

//============================================================================================= MQL5 ===
// ShutDown() function  
//------------------------------------------------------------------------------------------------------
void ShutDown(
                        int      &i_CL_Context,
                        int      &i_CL_Program,
                        int      &i_CL_Kernel,
                        int      &i_CL_Buffers[],
               const    string   i_BuildLog              =  "",
               const    bool     i_PrintDebugSelector    =  false
             )
{
//----- Build Log Print
   {if((i_PrintDebugSelector)&&(i_BuildLog!=""))
   {
      string LogLines[];
      StringSplit(i_BuildLog,'\n',LogLines);
      int LogLinesCount=ArraySize(LogLines);
      {for(int i=0; i<LogLinesCount; i++)
      {
         Print(LogLines[i]);
      }}//for(int i=0; i<LogLinesCount; i++)
   }}//if((i_PrintDebugSelector)&&(i_BuildLog!=""))
//----- Remove buffer
   {for(int i=0;i<=ArraySize(i_CL_Buffers)-1;i++)
   {
      {if(i_CL_Buffers[i]!=INVALID_HANDLE)
      {
         CLBufferFree(i_CL_Buffers[i]);
         i_CL_Buffers[i]=INVALID_HANDLE;
      }}//if(i_CL_Buffers[i]=INVALID_HANDLE)
   }}//for(i=0;i<=ArraySize(i_CL_Buffers);i++)
//----- Remove kernel
   {if(i_CL_Kernel!=INVALID_HANDLE)
   {
      CLKernelFree(i_CL_Kernel);
      i_CL_Kernel=INVALID_HANDLE;
   }}//if(i_CL_Kernel!=INVALID_HANDLE)
//----- Remove program
   {if(i_CL_Program!=INVALID_HANDLE)
   {
      CLProgramFree(i_CL_Program);
      i_CL_Program=INVALID_HANDLE;
   }}//if(m_program!=INVALID_HANDLE)
//----- Remove context
   {if(i_CL_Context!=INVALID_HANDLE)
   {
      CLContextFree(i_CL_Context);
      i_CL_Context=INVALID_HANDLE;
   }}//if(m_context!=INVALID_HANDLE)
}//ShutDown()

Добавлен ресурс:

#resource "Kernels/LibreFEI_v1.006.cl" as string CL_Source//Код кернел-программ можно подключать как ресурс

Полные тексты - во вложении.

Файлы:
 
Yury Kirillov:

Перенос расчетов индикатора в кернел. Промежуточный вариант - показаны основные отличия.

Интерфейс.

Было:

Стало:

Инициализация расчетных буферов.

Было:


Стало:

Перенос расчетных массивов в индикаторные.

Было:

Стало:

Расчет по Куину-Фернандесу.

Было:

Стало:

Добавлена функция TrigFitOCL():

Добавлена функция ShutDown():

Добавлен ресурс:

Полные тексты - во вложении.

А Вы можете изложить основные правила и функции переноса расчетов в кернел?

Иначе получается гора кода из которой трудно извлечь смысл осуществляемых действий.

Спасибо.

 
Реter Konow:

А Вы можете изложить основные правила и функции переноса расчетов в кернел?

Иначе получается гора кода из которой трудно извлечь смысл осуществляемых действий.

Спасибо.


1. В данном случае предпринималась просто попытка переноса кода функции 

TrigFit()

из MQL в среду исполнения OpenCL.

Никакая оптимизация и распараллеливание не производились.

2. Код самих исполняемых функций для MQL и OpenCL практически идентичен.

MQL (в теле программы):

void TrigFit(
               double   &x[],
               double   &ipc[],
               int      n,
               double   w,
               double   &m,
               double   &c,
               double   &s
               )
{
   double Sc =0.0;
   double Ss =0.0;
   double Scc=0.0;
   double Sss=0.0;
   double Scs=0.0;
   double Sx =0.0;
   double Sxc=0.0;
   double Sxs=0.0;
   {for(int i=0;i<n;i++)
   {
      double cos_w_i=cos(w*i);
      double sin_w_i=sin(w*i);
      double dx=x[i]-ipc[i];
      Sc +=cos_w_i;
      Ss +=sin_w_i;
      Scc+=cos_w_i*cos_w_i;
      Sss+=sin_w_i*sin_w_i;
      Scs+=cos_w_i*sin_w_i;
      Sx +=dx;
      Sxc+=dx*cos_w_i;
      Sxs+=dx*sin_w_i;
   }}//for(int i=0;i<n;i++)
   Sc /=n;
   Ss /=n;
   Scc/=n;
   Sss/=n;
   Scs/=n;
   Sx /=n;
   Sxc/=n;
   Sxs/=n;
   {if(w==0.0)
   {
      m=Sx;
      c=0.0;
      s=0.0;
   }else{
      // calculating a, b, and m
      double den=pow(Scs-Sc*Ss,2)-(Scc-Sc*Sc)*(Sss-Ss*Ss);
      c=((Sxs-Sx*Ss)*(Scs-Sc*Ss)-(Sxc-Sx*Sc)*(Sss-Ss*Ss))/den;
      s=((Sxc-Sx*Sc)*(Scs-Sc*Ss)-(Sxs-Sx*Ss)*(Scc-Sc*Sc))/den;
      m=Sx-c*Sc-s*Ss;
   }}//if(w==0.0)
   return;
}//TrigFit()


OpenCL (файл LibreFEI_v1.006.cl):

kernel void TrigFit_OCL(
                          global double   *x,
                          global double   *ipc,
                                 int      n,
                                 double   w,
                          global double   *m,
                          global double   *c,
                          global double   *s
                          )
{
   double Sc =0.0;
   double Ss =0.0;
   double Scc=0.0;
   double Sss=0.0;
   double Scs=0.0;
   double Sx =0.0;
   double Sxc=0.0;
   double Sxs=0.0;
   {for(int i=0;i<n;i++)
   {
      double cos_w_i=cos(w*i);
      double sin_w_i=sin(w*i);
      double dx=x[i]-ipc[i];
      Sc +=cos_w_i;
      Ss +=sin_w_i;
      Scc+=cos_w_i*cos_w_i;
      Sss+=sin_w_i*sin_w_i;
      Scs+=cos_w_i*sin_w_i;
      Sx +=dx;
      Sxc+=dx*cos_w_i;
      Sxs+=dx*sin_w_i;
   }}//for(int i=0;i<n;i++)
   Sc /=n;
   Ss /=n;
   Scc/=n;
   Sss/=n;
   Scs/=n;
   Sx /=n;
   Sxc/=n;
   Sxs/=n;
   {if(w==0.0)
   {
      m[0]=Sx;
      c[0]=0.0;
      s[0]=0.0;
   }else{
      // calculating a, b, and m
      double den=pow(Scs-Sc*Ss,2)-(Scc-Sc*Sc)*(Sss-Ss*Ss);
      c[0]=((Sxs-Sx*Ss)*(Scs-Sc*Ss)-(Sxc-Sx*Sc)*(Sss-Ss*Ss))/den;
      s[0]=((Sxc-Sx*Sc)*(Scs-Sc*Ss)-(Sxs-Sx*Ss)*(Scc-Sc*Sc))/den;
      m[0]=Sx-c[0]*Sc-s[0]*Ss;
   }}//if(w==0.0)
}//TrigFit_OCL()

Поэтому основная задача заключалась в записи программы в кернел, передаче ей параметров, запуске программы и получению результатов её работы.

Подготовительные операции по настройке среды исполнения OpenCL являются однократно выполняемыми. Это:

1. Создание контекста (среды) для программы OpenCL (выбор устройства - видеокарта): CLContextCreate(CL_USE_ANY).

2. Создание в контексте (среде исполнения на устройстве) программы на основе кода передаваемого через строку CL_Source: CLProgramCreate(h_CL_Context,CL_Source,BuildLog).

3. Создание кернела для расчета значений функции: CLKernelCreate(h_CL_Program,CL_Kernel_Name).

4. Создание буферов для массивов передаваемых в кернел по ссылке и для возвращаемых значений: CLBufferCreate(h_CL_Context,Npast*sizeof(double),CL_MEM_READ_WRITE) и др.

 
Yury Kirillov:

1. В данном случае предпринималась просто попытка переноса кода функции 

TrigFit()

из MQL в среду исполнения OpenCL.

Никакая оптимизация и распараллеливание не производились.

2. Код самих исполняемых функций для MQL и OpenCL практически идентичен.

MQL (в теле программы):


OpenCL (файл LibreFEI_v1.006.cl):

Поэтому основная задача заключалась в записи программы в кернел, передаче ей параметров, запуске программы и получению результатов её работы.

Я предлагаю разобрать каждую функцию OpenCL. Что она делает, как и зачем. Все на практических примерах.

  1. CLHandleType         

    Возвращает тип OpenCL хендла в виде значения из перечисления ENUM_OPENCL_HANDLE_TYPE


  2. CLGetInfoInteger               

    Возвращает значение целочисленного свойства для OpenCL-объекта или устройства



  3. CLGetInfoString

    Возвращает строковое значение свойства для OpenCL-объекта или устройства


  4. CLContextCreate 

    Cоздает контекст OpenCL




  5. CLContextFree    

    Удаляет контекст OpenCL


  6. CLGetDeviceInfo 

    Получает свойство устройства из OpenCL драйвера


  7. CLProgramCreate 

    Создает OpenCL программу из исходного кода


  8. CLProgramFree  

    Удаляет OpenCL программу


  9. CLKernelCreate 

    Создает функцию запуска OpenCL


  10. CLKernelFree   

    Удаляет функцию запуска OpenCL


  11. CLSetKernelArg  

    Выставляет параметр для функции OpenCL


  12. CLSetKernelArgMem 

    Выставляет буфер OpenCL в качестве параметра функции OpenCL


  13. CLSetKernelArgMemLocal 

    Задаёт локальный буфер в качестве аргумента kernel-функции


  14. CLBufferCreate 

    Создает буфер OpenCL



  15. CLBufferFree 

    Удаляет буфер OpenCL


  16. CLBufferWrite 

    Записывает массив в буфер OpenCL и возвращает количество записанных элементов


  17. CLBufferRead  

    Читает буфер OpenCL в массив и возвращает количество прочитанных элементов



  18. CLExecute  

    Выполняет OpenCL программу



  19. CLExecutionStatus

    Возвращает состояние выполнения OpenCL программы





    Вот все функции. Необходимо простым и понятным языком описать для чего нужна каждая функция и привести маленький конкретный пример. Тогда все будет ясно.





 
Yury Kirillov:

Поэтому основная задача заключалась в записи программы в кернел, передаче ей параметров, запуске программы и получению результатов её работы.

Некоторые подготовительные операции по настройке среды исполнения OpenCL являются однократно выполняемыми. Это:



1. Создание контекста (среды) для программы OpenCL (выбор устройства - видеокарта): CLContextCreate(CL_USE_ANY).

2. Создание в контексте (среде исполнения на устройстве) программы на основе кода передаваемого через строку CL_Source: CLProgramCreate(h_CL_Context,CL_Source,BuildLog).

3. Создание кернела для расчета значений функции: CLKernelCreate(h_CL_Program,CL_Kernel_Name).

4. Создание буферов для массивов передаваемых в кернел по ссылке: CLBufferCreate(h_CL_Context,Npast*sizeof(double),CL_MEM_READ_WRITE) и др.

Хорошо. Подготовительные операции понятны.

Причина обращения: