English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
preview
ONNX modellerinin regresyon metrikleri kullanılarak değerlendirilmesi

ONNX modellerinin regresyon metrikleri kullanılarak değerlendirilmesi

MetaTrader 5Örnekler | 18 Ocak 2024, 15:53
332 0
MetaQuotes
MetaQuotes

Giriş

Regresyon, etiketlenmemiş bir örnekten gerçek değeri tahmin etme görevidir. Regresyonun iyi bilinen bir örneği, büyüklük, ağırlık, renk, berraklık gibi özelliklere dayalı olarak bir elmasın değerinin tahmin edilmesidir.

Regresyon metrikleri, regresyon modeli tahminlerinin doğruluğunu değerlendirmek için kullanılır. Benzer algoritmalara rağmen, regresyon metrikleri anlamsal olarak benzer kayıp fonksiyonlarından farklıdır. Aralarındaki farkı anlamak önemlidir. Aşağıdaki şekilde formüle edilebilir:

  • Kayıp fonksiyonu, bir model oluşturma problemini bir optimizasyon problemine indirgediğimiz anda ortaya çıkar. Genellikle iyi özelliklere sahip olması istenir (örn. türevlenebilirlik).

  • Bir metrik, genellikle model parametrelerine değil, yalnızca tahmin edilen değerlere bağlı olan harici bir objektif kalite kriteridir.


MQL5'te regresyon metrikleri

MQL5 dili aşağıdaki metriklere sahiptir:

  • Hataların mutlak değerlerinin ortalaması (Mean Absolute Error, MAE)
  • Hataların karelerinin ortalaması (Mean Squared Error, MSE)
  • Hataların karelerinin ortalamasının karekökü (Root Mean Squared Error, RMSE)
  • R-kare (R-squared, R2)
  • Yüzde olarak MAE (Mean Absolute Percentage Error, MAPE)
  • Yüzde olarak MSE (Mean Squared Percentage Error, MSPE)
  • Logaritmik ölçekte hesaplanan RMSE (Root Mean Squared Logarithmic Error, RMSLE)

MQL5'te regresyon metriklerinin sayısının artırılması beklenmektedir.


Regresyon metriklerinin kısa özellikleri

MAE, mutlak hatayı (tahmin edilen sayının gerçek sayıdan ne kadar farklı olduğunu) hesaplar. Hata, amaç fonksiyonunun değeri ile aynı birimde ölçülür. Hata değeri, olası değerler aralığına göre yorumlanır. Örneğin, hedef değerler 1 ila 1.5 aralığındaysa, 10 değerindeki MAE çok büyük bir hatadır; 10000...15000 aralığı için ise oldukça kabul edilebilirdir. Geniş bir değer dağılımına sahip tahminleri değerlendirmek için uygun değildir.

MSE'de, kare alma nedeniyle her hatanın kendi ağırlığı vardır. Bu nedenle tahmin ve gerçeklik arasındaki büyük farklılıklar çok daha belirgindir.

RMSE, MSE ile aynı avantajlara sahiptir, ancak hata, amaç fonksiyonunun değerleriyle aynı birimde ölçüldüğü için anlaşılması daha kolaydır. Anomalilere ve uç değerlere karşı çok hassastır. MAE ve RMSE, bir tahmin kümesindeki hata varyasyonunu belirlemek için birlikte kullanılabilir. RMSE her zaman MAE'den büyük veya MAE'ye eşittir. Aralarındaki fark ne kadar büyükse, örneklemdeki bireysel hataların yayılımı da o kadar büyük olur. RMSE = MAE ise, tüm hatalar aynı büyüklüğe sahiptir.

R2 - belirlilik katsayısı, iki rastgele değişken arasındaki ilişkinin gücünü gösterir. Modelin açıklayabildiği veri çeşitliliğinin payının belirlenmesine yardımcı olur. Model her zaman doğru tahminde bulunursa, metrik 1 olur. Önemsiz model için bu değer 0'dır. Model veri eğilimini takip etmezken, model önemsiz olandan daha kötü tahmin yaparsa metrik değeri negatif olabilir.

MAPE - boyutu yoktur ve yorumlanması çok kolaydır. Hem ondalık hem de yüzde olarak ifade edilebilir. MQL5'te ondalık sayılarla ifade edilir. Örneğin, 0.1 değeri hatanın gerçek değerin %10'u kadar olduğunu gösterir. Bu metriğin arkasındaki fikir, göreceli sapmalara karşı duyarlılıktır. Gerçek ölçü birimleriyle çalışmanız gereken görevler için uygun değildir.

MSPE, MSE'nin ağırlıklandırılmış bir versiyonu olarak düşünülebilir; burada ağırlık, gözlemlenen değerin karesiyle ters orantılıdır. Dolayısıyla, gözlemlenen değerler arttıkça hata azalma eğilimi gösterir.

RMSLE, gerçek değerler birkaç büyüklük mertebesine yayıldığında kullanılır. Tanım gereği, tahmin edilen ve gerçek gözlemlenen değerler negatif olamaz.

Yukarıdaki tüm metriklerin hesaplanmasına yönelik algoritmalar VectorRegressionMetric.mqh kaynak dosyasında sağlanmaktadır.


ONNX modelleri

Önceki günlük çubuklarından günün kapanış fiyatını (EURUSD, D1) tahmin eden 4 regresyon modeli kullandık. Bu modelleri daha önceki makalelerde ele almıştık: "ONNX modellerini sınıflara sarma", "MQL5'te ONNX modellerinin nasıl bir araya getirileceğine dair bir örnek" ve "MQL5'te ONNX modelleri nasıl kullanılır?". Bu nedenle, modelleri eğitmek için kullanılan kuralları burada tekrar etmeyeceğiz. Tüm modelleri eğitmek için kullanılan komut dosyaları, bu makaleye ekli zip arşivinin Python alt klasöründe yer almaktadır. Eğitilmiş onnx modelleri - model.eurusd.D1.10, model.eurusd.D1.30, model.eurusd.D1.52 ve model.eurusd.D1.63 de burada yer almaktadır.


ONNX modellerini sınıflara sarma

Bir önceki makalede, ONNX modelleri için temel sınıfı ve sınıflandırma modelleri için türetilmiş sınıfları gösterdik. Temel sınıfı daha esnek hale getirmek için bazı küçük değişiklikler uyguladık.

//+------------------------------------------------------------------+
//|                                            ModelSymbolPeriod.mqh |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+

//--- price movement prediction
#define PRICE_UP   0
#define PRICE_SAME 1
#define PRICE_DOWN 2

//+------------------------------------------------------------------+
//| Base class for models based on trained symbol and period         |
//+------------------------------------------------------------------+
class CModelSymbolPeriod
  {
protected:
   string            m_name;             // model name
   long              m_handle;           // created model session handle
   string            m_symbol;           // symbol of trained data
   ENUM_TIMEFRAMES   m_period;           // timeframe of trained data
   datetime          m_next_bar;         // time of next bar (we work at bar begin only)
   double            m_class_delta;      // delta to recognize "price the same" in regression models

public:
   //+------------------------------------------------------------------+
   //| Constructor                                                      |
   //+------------------------------------------------------------------+
   CModelSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES period,const double class_delta=0.0001)
     {
      m_name="";
      m_handle=INVALID_HANDLE;
      m_symbol=symbol;
      m_period=period;
      m_next_bar=0;
      m_class_delta=class_delta;
     }

   //+------------------------------------------------------------------+
   //| Destructor                                                       |
   //+------------------------------------------------------------------+
   ~CModelSymbolPeriod(void)
     {
      Shutdown();
     }

   //+------------------------------------------------------------------+
   //|                                                                  |
   //+------------------------------------------------------------------+
   string GetModelName(void)
     {
      return(m_name);
     }

   //+------------------------------------------------------------------+
   //| virtual stub for Init                                            |
   //+------------------------------------------------------------------+
   virtual bool Init(const string symbol, const ENUM_TIMEFRAMES period)
     {
      return(false);
     }

   //+------------------------------------------------------------------+
   //| Check for initialization, create model                           |
   //+------------------------------------------------------------------+
   bool CheckInit(const string symbol, const ENUM_TIMEFRAMES period,const uchar& model[])
     {
      //--- check symbol, period
      if(symbol!=m_symbol || period!=m_period)
        {
         PrintFormat("Model must work with %s,%s",m_symbol,EnumToString(m_period));
         return(false);
        }

      //--- create a model from static buffer
      m_handle=OnnxCreateFromBuffer(model,ONNX_DEFAULT);
      if(m_handle==INVALID_HANDLE)
        {
         Print("OnnxCreateFromBuffer error ",GetLastError());
         return(false);
        }

      //--- ok
      return(true);
     }

   //+------------------------------------------------------------------+
   //| Release ONNX session                                             |
   //+------------------------------------------------------------------+
   void Shutdown(void)
     {
      if(m_handle!=INVALID_HANDLE)
        {
         OnnxRelease(m_handle);
         m_handle=INVALID_HANDLE;
        }
     }

   //+------------------------------------------------------------------+
   //| Check for continue OnTick                                        |
   //+------------------------------------------------------------------+
   virtual bool CheckOnTick(void)
     {
      //--- check new bar
      if(TimeCurrent()<m_next_bar)
         return(false);
      //--- set next bar time
      m_next_bar=TimeCurrent();
      m_next_bar-=m_next_bar%PeriodSeconds(m_period);
      m_next_bar+=PeriodSeconds(m_period);

      //--- work on new day bar
      return(true);
     }

   //+------------------------------------------------------------------+
   //| virtual stub for PredictPrice (regression model)                 |
   //+------------------------------------------------------------------+
   virtual double PredictPrice(datetime date)
     {
      return(DBL_MAX);
     }

   //+------------------------------------------------------------------+
   //| Predict class (regression ~> classification)                     |
   //+------------------------------------------------------------------+
   virtual int PredictClass(datetime date,vector& probabilities)
     {
      date-=date%PeriodSeconds(m_period);
      double predicted_price=PredictPrice(date);
      if(predicted_price==DBL_MAX)
         return(-1);

      double last_close[2];
      if(CopyClose(m_symbol,m_period,date,2,last_close)!=2)
         return(-1);
      double prev_price=last_close[0];

      //--- classify predicted price movement
      int    predicted_class=-1;
      double delta=prev_price-predicted_price;
      if(fabs(delta)<=m_class_delta)
         predicted_class=PRICE_SAME;
      else
        {
         if(delta<0)
            predicted_class=PRICE_UP;
         else
            predicted_class=PRICE_DOWN;
        }

      //--- set predicted probability as 1.0
      probabilities.Fill(0);
      if(predicted_class<(int)probabilities.Size())
         probabilities[predicted_class]=1;
      //--- and return predicted class
      return(predicted_class);
     }
  };
//+------------------------------------------------------------------+

PredictPrice ve PredictClass metotlarına bir datetime parametresi ekledik, böylece yalnızca mevcut nokta için değil, zaman içerisindeki herhangi bir nokta için tahminler yapabiliriz. Bu, bir tahmin vektörü oluşturmak için faydalı olacaktır.


D1_10 model sınıfı

İlk modelimiz model.eurusd.D1.10.onnx olarak adlandırılır. EURUSD D1 üzerinde 10 OHLC fiyatı serisi üzerinde eğitilmiş regresyon modeli.
//+------------------------------------------------------------------+
//|                                             ModelEurusdD1_10.mqh |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#include "ModelSymbolPeriod.mqh"

#resource "Python/model.eurusd.D1.10.onnx" as uchar model_eurusd_D1_10[]

//+------------------------------------------------------------------+
//| ONNX-model wrapper class                                         |
//+------------------------------------------------------------------+
class CModelEurusdD1_10 : public CModelSymbolPeriod
  {
private:
   int               m_sample_size;

public:
   //+------------------------------------------------------------------+
   //| Constructor                                                      |
   //+------------------------------------------------------------------+
   CModelEurusdD1_10(void) : CModelSymbolPeriod("EURUSD",PERIOD_D1)
     {
      m_name="D1_10";
      m_sample_size=10;
     }

   //+------------------------------------------------------------------+
   //| ONNX-model initialization                                        |
   //+------------------------------------------------------------------+
   virtual bool Init(const string symbol, const ENUM_TIMEFRAMES period)
     {
      //--- check symbol, period, create model
      if(!CModelSymbolPeriod::CheckInit(symbol,period,model_eurusd_D1_10))
        {
         Print("model_eurusd_D1_10 : initialization error");
         return(false);
        }

      //--- since not all sizes defined in the input tensor we must set them explicitly
      //--- first index - batch size, second index - series size, third index - number of series (OHLC)
      const long input_shape[] = {1,m_sample_size,4};
      if(!OnnxSetInputShape(m_handle,0,input_shape))
        {
         Print("model_eurusd_D1_10 : OnnxSetInputShape error ",GetLastError());
         return(false);
        }
   
      //--- since not all sizes defined in the output tensor we must set them explicitly
      //--- first index - batch size, must match the batch size of the input tensor
      //--- second index - number of predicted prices
      const long output_shape[] = {1,1};
      if(!OnnxSetOutputShape(m_handle,0,output_shape))
        {
         Print("model_eurusd_D1_10 : OnnxSetOutputShape error ",GetLastError());
         return(false);
        }
      //--- ok
      return(true);
     }

   //+------------------------------------------------------------------+
   //| Predict price                                                    |
   //+------------------------------------------------------------------+
   virtual double PredictPrice(datetime date)
     {
      static matrixf input_data(m_sample_size,4);    // matrix for prepared input data
      static vectorf output_data(1);                 // vector to get result
      static matrix  mm(m_sample_size,4);            // matrix of horizontal vectors Mean
      static matrix  ms(m_sample_size,4);            // matrix of horizontal vectors Std
      static matrix  x_norm(m_sample_size,4);        // matrix for prices normalize
   
      //--- prepare input data
      matrix rates;
      //--- request last bars
      date-=date%PeriodSeconds(m_period);
      if(!rates.CopyRates(m_symbol,m_period,COPY_RATES_OHLC,date-1,m_sample_size))
         return(DBL_MAX);
      //--- get series Mean
      vector m=rates.Mean(1);
      //--- get series Std
      vector s=rates.Std(1);
      //--- prepare matrices for prices normalization
      for(int i=0; i<m_sample_size; i++)
        {
         mm.Row(m,i);
         ms.Row(s,i);
        }
      //--- the input of the model must be a set of vertical OHLC vectors
      x_norm=rates.Transpose();
      //--- normalize prices
      x_norm-=mm;
      x_norm/=ms;
   
      //--- run the inference
      input_data.Assign(x_norm);
      if(!OnnxRun(m_handle,ONNX_NO_CONVERSION,input_data,output_data))
         return(DBL_MAX);

      //--- denormalize the price from the output value
      double predicted=output_data[0]*s[3]+m[3];
      //--- return prediction
      return(predicted);
     }
  };
//+------------------------------------------------------------------+

Bu model, MQL5\Shared Projects\ONNX.Price.Prediction adlı herkese açık projede yayınlanan ilk modelimize benzerdir.

10 OHLC fiyatından oluşan seri, eğitim sırasında olduğu gibi normalleştirilmelidir, yani serideki ortalama fiyattan sapma, serideki standart sapmaya bölünür. Böylece, seriyi ortalaması 0 ve yayılımı 1 olan belirli bir aralığa koyuyoruz, bu da eğitim sırasında yakınsamayı iyileştirir.


D1_30 model sınıfı

İkinci model model.eurusd.D1.30.onnx olarak adlandırılır. EURUSD D1 üzerinde eğitilen regresyon modeli, 30 Kapanış fiyatı ve ortalama alma periyotları 21 ve 34 olan iki basit hareketli ortalama serisine dayanmaktadır.

//+------------------------------------------------------------------+
//|                                             ModelEurusdD1_30.mqh |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#include "ModelSymbolPeriod.mqh"

#resource "Python/model.eurusd.D1.30.onnx" as uchar model_eurusd_D1_30[]

//+------------------------------------------------------------------+
//| ONNX-model wrapper class                                         |
//+------------------------------------------------------------------+
class CModelEurusdD1_30 : public CModelSymbolPeriod
  {
private:
   int               m_sample_size;
   int               m_fast_period;
   int               m_slow_period;
   int               m_sma_fast;
   int               m_sma_slow;

public:
   //+------------------------------------------------------------------+
   //| Constructor                                                      |
   //+------------------------------------------------------------------+
   CModelEurusdD1_30(void) : CModelSymbolPeriod("EURUSD",PERIOD_D1)
     {
      m_name="D1_30";
      m_sample_size=30;
      m_fast_period=21;
      m_slow_period=34;
      m_sma_fast=INVALID_HANDLE;
      m_sma_slow=INVALID_HANDLE;
     }

   //+------------------------------------------------------------------+
   //| ONNX-model initialization                                        |
   //+------------------------------------------------------------------+
   virtual bool Init(const string symbol, const ENUM_TIMEFRAMES period)
     {
      //--- check symbol, period, create model
      if(!CModelSymbolPeriod::CheckInit(symbol,period,model_eurusd_D1_30))
        {
         Print("model_eurusd_D1_30 : initialization error");
         return(false);
        }

      //--- since not all sizes defined in the input tensor we must set them explicitly
      //--- first index - batch size, second index - series size, third index - number of series (Close, MA fast, MA slow)
      const long input_shape[] = {1,m_sample_size,3};
      if(!OnnxSetInputShape(m_handle,0,input_shape))
        {
         Print("model_eurusd_D1_30 : OnnxSetInputShape error ",GetLastError());
         return(false);
        }
   
      //--- since not all sizes defined in the output tensor we must set them explicitly
      //--- first index - batch size, must match the batch size of the input tensor
      //--- second index - number of predicted prices
      const long output_shape[] = {1,1};
      if(!OnnxSetOutputShape(m_handle,0,output_shape))
        {
         Print("model_eurusd_D1_30 : OnnxSetOutputShape error ",GetLastError());
         return(false);
        }
      //--- indicators
      m_sma_fast=iMA(m_symbol,m_period,m_fast_period,0,MODE_SMA,PRICE_CLOSE);
      m_sma_slow=iMA(m_symbol,m_period,m_slow_period,0,MODE_SMA,PRICE_CLOSE);
      if(m_sma_fast==INVALID_HANDLE || m_sma_slow==INVALID_HANDLE)
        {
         Print("model_eurusd_D1_30 : cannot create indicator");
         return(false);
        }
      //--- ok
      return(true);
     }

   //+------------------------------------------------------------------+
   //| Predict price                                                    |
   //+------------------------------------------------------------------+
   virtual double PredictPrice(datetime date)
     {
      static matrixf input_data(m_sample_size,3);    // matrix for prepared input data
      static vectorf output_data(1);                 // vector to get result
      static matrix  x_norm(m_sample_size,3);        // matrix for prices normalize
      static vector  vtemp(m_sample_size);
      static double  ma_buffer[];
   
      //--- request last bars
      date-=date%PeriodSeconds(m_period);
      if(!vtemp.CopyRates(m_symbol,m_period,COPY_RATES_CLOSE,date-1,m_sample_size))
         return(DBL_MAX);
      //--- get series Mean
      double m=vtemp.Mean();
      //--- get series Std
      double s=vtemp.Std();
      //--- normalize
      vtemp-=m;
      vtemp/=s;
      x_norm.Col(vtemp,0);
      //--- fast sma
      if(CopyBuffer(m_sma_fast,0,date-1,m_sample_size,ma_buffer)!=m_sample_size)
         return(-1);
      vtemp.Assign(ma_buffer);
      m=vtemp.Mean();
      s=vtemp.Std();
      vtemp-=m;
      vtemp/=s;
      x_norm.Col(vtemp,1);
      //--- slow sma
      if(CopyBuffer(m_sma_slow,0,date-1,m_sample_size,ma_buffer)!=m_sample_size)
         return(-1);
      vtemp.Assign(ma_buffer);
      m=vtemp.Mean();
      s=vtemp.Std();
      vtemp-=m;
      vtemp/=s;
      x_norm.Col(vtemp,2);
   
      //--- run the inference
      input_data.Assign(x_norm);
      if(!OnnxRun(m_handle,ONNX_NO_CONVERSION,input_data,output_data))
         return(DBL_MAX);

      //--- denormalize the price from the output value
      double predicted=output_data[0]*s+m;
      //--- return prediction
      return(predicted);
     }
  };
//+------------------------------------------------------------------+

Önceki sınıfta olduğu gibi, CheckInit temel sınıf metodu Init metodunda çağrılır. Temel sınıf metodunda, ONNX modeli için bir oturum oluşturulur ve girdi ve çıktı tensörlerinin büyüklükleri açıkça ayarlanır.

PredictPrice metodu, önceki 30 Kapanış fiyatından ve hesaplanan hareketli ortalamalardan oluşan bir seri sağlar. Veriler eğitimde olduğu gibi aynı şekilde normalleştirilir.

Model, "ONNX modellerini sınıflara sarma" makalesi için geliştirilmiş ve bu makale için sınıflandırmadan regresyona dönüştürülmüştür.


D1_52 model sınıfı

Üçüncü model model.eurusd.D1.52.onnx olarak adlandırılır. EURUSD D1 üzerinde 52 Kapanış fiyatı serisi üzerinde eğitilmiş regresyon modeli.

//+------------------------------------------------------------------+
//|                                             ModelEurusdD1_52.mqh |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#include "ModelSymbolPeriod.mqh"

#resource "Python/model.eurusd.D1.52.onnx" as uchar model_eurusd_D1_52[]

//+------------------------------------------------------------------+
//| ONNX-model wrapper class                                         |
//+------------------------------------------------------------------+
class CModelEurusdD1_52 : public CModelSymbolPeriod
  {
private:
   int               m_sample_size;

public:
   //+------------------------------------------------------------------+
   //| Constructor                                                      |
   //+------------------------------------------------------------------+
   CModelEurusdD1_52(void) : CModelSymbolPeriod("EURUSD",PERIOD_D1,0.0001)
     {
      m_name="D1_52";
      m_sample_size=52;
     }

   //+------------------------------------------------------------------+
   //| ONNX-model initialization                                        |
   //+------------------------------------------------------------------+
   virtual bool Init(const string symbol, const ENUM_TIMEFRAMES period)
     {
      //--- check symbol, period, create model
      if(!CModelSymbolPeriod::CheckInit(symbol,period,model_eurusd_D1_52))
        {
         Print("model_eurusd_D1_52 : initialization error");
         return(false);
        }

      //--- since not all sizes defined in the input tensor we must set them explicitly
      //--- first index - batch size, second index - series size, third index - number of series (only Close)
      const long input_shape[] = {1,m_sample_size,1};
      if(!OnnxSetInputShape(m_handle,0,input_shape))
        {
         Print("model_eurusd_D1_52 : OnnxSetInputShape error ",GetLastError());
         return(false);
        }
   
      //--- since not all sizes defined in the output tensor we must set them explicitly
      //--- first index - batch size, must match the batch size of the input tensor
      //--- second index - number of predicted prices (we only predict Close)
      const long output_shape[] = {1,1};
      if(!OnnxSetOutputShape(m_handle,0,output_shape))
        {
         Print("model_eurusd_D1_52 : OnnxSetOutputShape error ",GetLastError());
         return(false);
        }
      //--- ok
      return(true);
     }

   //+------------------------------------------------------------------+
   //| Predict price                                                    |
   //+------------------------------------------------------------------+
   virtual double PredictPrice(datetime date)
     {
      static vectorf output_data(1);            // vector to get result
      static vector  x_norm(m_sample_size);     // vector for prices normalize
   
      //--- set date to day begin
      date-=date%PeriodSeconds(m_period);
      //--- check for calculate min and max
      double price_min=0;
      double price_max=0;
      GetMinMaxClose(date,price_min,price_max);
      //--- check for normalization possibility
      if(price_min>=price_max)
         return(DBL_MAX);
      //--- request last bars
      if(!x_norm.CopyRates(m_symbol,m_period,COPY_RATES_CLOSE,date-1,m_sample_size))
         return(DBL_MAX);
      //--- normalize prices
      x_norm-=price_min;
      x_norm/=(price_max-price_min);
      //--- run the inference
      if(!OnnxRun(m_handle,ONNX_DEFAULT,x_norm,output_data))
         return(DBL_MAX);

      //--- denormalize the price from the output value
      double predicted=output_data[0]*(price_max-price_min)+price_min;
      //--- return prediction
      return(predicted);
     }

private:
   //+------------------------------------------------------------------+
   //| Get minimal and maximal Close for last 52 weeks                  |
   //+------------------------------------------------------------------+
   void GetMinMaxClose(const datetime date,double& price_min,double& price_max)
     {
      static vector close;

      close.CopyRates(m_symbol,m_period,COPY_RATES_CLOSE,date,m_sample_size*7+1);
      price_min=close.Min();
      price_max=close.Max();
     }
  };
//+------------------------------------------------------------------+

Modeli sunmadan önce yapılan fiyat normalleştirmesi öncekilerden farklıdır. Eğitim sırasında MinMaxScaler kullanılmıştır. Bu nedenle, tahmin tarihinden önceki 52 haftalık dönem için minimum ve maksimum fiyatları alırız.

Model, "MQL5'te ONNX modelleri nasıl kullanılır?" makalesinde anlatılana benzerdir.


D1_63 model sınıfı

Son olarak, dördüncü model model.eurusd.D1.63.onnx olarak adlandırılır. EURUSD D1 üzerinde 63 Kapanış fiyatı serisi üzerinde eğitilmiş regresyon modeli.

//+------------------------------------------------------------------+
//|                                             ModelEurusdD1_63.mqh |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#include "ModelSymbolPeriod.mqh"

#resource "Python/model.eurusd.D1.63.onnx" as uchar model_eurusd_D1_63[]

//+------------------------------------------------------------------+
//| ONNX-model wrapper class                                         |
//+------------------------------------------------------------------+
class CModelEurusdD1_63 : public CModelSymbolPeriod
  {
private:
   int               m_sample_size;

public:
   //+------------------------------------------------------------------+
   //| Constructor                                                      |
   //+------------------------------------------------------------------+
   CModelEurusdD1_63(void) : CModelSymbolPeriod("EURUSD",PERIOD_D1)
     {
      m_name="D1_63";
      m_sample_size=63;
     }

   //+------------------------------------------------------------------+
   //| ONNX-model initialization                                        |
   //+------------------------------------------------------------------+
   virtual bool Init(const string symbol, const ENUM_TIMEFRAMES period)
     {
      //--- check symbol, period, create model
      if(!CModelSymbolPeriod::CheckInit(symbol,period,model_eurusd_D1_63))
        {
         Print("model_eurusd_D1_63 : initialization error");
         return(false);
        }

      //--- since not all sizes defined in the input tensor we must set them explicitly
      //--- first index - batch size, second index - series size
      const long input_shape[] = {1,m_sample_size};
      if(!OnnxSetInputShape(m_handle,0,input_shape))
        {
         Print("model_eurusd_D1_63 : OnnxSetInputShape error ",GetLastError());
         return(false);
        }
   
      //--- since not all sizes defined in the output tensor we must set them explicitly
      //--- first index - batch size, must match the batch size of the input tensor
      //--- second index - number of predicted prices
      const long output_shape[] = {1,1};
      if(!OnnxSetOutputShape(m_handle,0,output_shape))
        {
         Print("model_eurusd_D1_63 : OnnxSetOutputShape error ",GetLastError());
         return(false);
        }
      //--- ok
      return(true);
     }

   //+------------------------------------------------------------------+
   //| Predict price                                                    |
   //+------------------------------------------------------------------+
   virtual double PredictPrice(datetime date)
     {
      static vectorf input_data(m_sample_size);  // vector for prepared input data
      static vectorf output_data(1);             // vector to get result
   
      //--- request last bars
      date-=date%PeriodSeconds(m_period);
      if(!input_data.CopyRates(m_symbol,m_period,COPY_RATES_CLOSE,date-1,m_sample_size))
         return(DBL_MAX);
      //--- get series Mean
      float m=input_data.Mean();
      //--- get series Std
      float s=input_data.Std();
      //--- normalize prices
      input_data-=m;
      input_data/=s;
   
      //--- run the inference
      if(!OnnxRun(m_handle,ONNX_NO_CONVERSION,input_data,output_data))
         return(DBL_MAX);

      //--- denormalize the price from the output value
      double predicted=output_data[0]*s+m;
      //--- return prediction
      return(predicted);
     }
  };
//+------------------------------------------------------------------+

PredictPrice metodu, önceki 63 Kapanış fiyatından oluşan bir seri sağlar. Veriler, birinci ve ikinci modellerde olduğu gibi aynı şekilde normalleştirilir.

Model, "MQL5'te ONNX modellerinin nasıl bir araya getirileceğine dair bir örnek" makalesi için halihazırda geliştirilmiştir.


Tüm modelleri tek bir komut dosyasında birleştirme. Gerçeklik, tahminler ve regresyon metrikleri

Regresyon metriklerini uygulamak için belirli sayıda tahmin yapmalı (vector_pred) ve aynı tarihler için gerçek verileri almalıyız (vector_true).

Tüm modellerimiz aynı temel sınıftan türeyen sınıflara sarıldığından, hepsini bir kerede değerlendirebiliriz.

Komut dosyası çok basittir.

//+------------------------------------------------------------------+
//|                                    ONNX.eurusd.D1.4M.Metrics.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

#define MODELS 4
#include "ModelEurusdD1_10.mqh"
#include "ModelEurusdD1_30.mqh"
#include "ModelEurusdD1_52.mqh"
#include "ModelEurusdD1_63.mqh"

#property script_show_inputs
input datetime InpStartDate = D'2023.01.01';
input datetime InpStopDate  = D'2023.01.31';

CModelSymbolPeriod *ExtModels[MODELS];

struct PredictedPrices
  {
   string            model;
   double            pred[];
  };
PredictedPrices ExtPredicted[MODELS];

double ExtClose[];

struct Metrics
  {
   string            model;
   double            mae;
   double            mse;
   double            rmse;
   double            r2;
   double            mape;
   double            mspe;
   double            rmsle;
  };
Metrics ExtMetrics[MODELS];

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- init section
   if(!Init())
      return;

//--- predictions test loop
   datetime dates[];
   if(CopyTime(_Symbol,_Period,InpStartDate,InpStopDate,dates)<=0)
     {
      Print("Cannot get data from ",InpStartDate," to ",InpStopDate);
      return;
     }
   for(uint n=0; n<dates.Size(); n++)
      GetPredictions(dates[n]);
      
   CopyClose(_Symbol,_Period,InpStartDate,InpStopDate,ExtClose);
   CalculateMetrics();

//--- deinit section
   Deinit();
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool Init()
  {
   ExtModels[0]=new CModelEurusdD1_10;
   ExtModels[1]=new CModelEurusdD1_30;
   ExtModels[2]=new CModelEurusdD1_52;
   ExtModels[3]=new CModelEurusdD1_63;

   for(long i=0; i<ExtModels.Size(); i++)
     {
      if(!ExtModels[i].Init(_Symbol,_Period))
        {
         Deinit();
         return(false);
        }
     }

   for(long i=0; i<ExtModels.Size(); i++)
      ExtPredicted[i].model=ExtModels[i].GetModelName();

   return(true);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Deinit()
  {
   for(uint i=0; i<ExtModels.Size(); i++)
      delete ExtModels[i];
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void GetPredictions(datetime date)
  {
//--- collect predicted prices
   for(uint i=0; i<ExtModels.Size(); i++)
      ExtPredicted[i].pred.Push(ExtModels[i].PredictPrice(date));
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CalculateMetrics()
  {
   vector vector_pred,vector_true;
   vector_true.Assign(ExtClose);

   for(uint i=0; i<ExtModels.Size(); i++)
     {
      ExtMetrics[i].model=ExtPredicted[i].model;
      vector_pred.Assign(ExtPredicted[i].pred);
      ExtMetrics[i].mae  =vector_pred.RegressionMetric(vector_true,REGRESSION_MAE);
      ExtMetrics[i].mse  =vector_pred.RegressionMetric(vector_true,REGRESSION_MSE);
      ExtMetrics[i].rmse =vector_pred.RegressionMetric(vector_true,REGRESSION_RMSE);
      ExtMetrics[i].r2   =vector_pred.RegressionMetric(vector_true,REGRESSION_R2);
      ExtMetrics[i].mape =vector_pred.RegressionMetric(vector_true,REGRESSION_MAPE);
      ExtMetrics[i].mspe =vector_pred.RegressionMetric(vector_true,REGRESSION_MSPE);
      ExtMetrics[i].rmsle=vector_pred.RegressionMetric(vector_true,REGRESSION_RMSLE);
     }

   ArrayPrint(ExtMetrics);
  }
//+------------------------------------------------------------------+

Komut dosyasını EURUSD D1 grafiğinde çalıştıralım ve tarihleri 1 Ocak ile 31 Ocak 2023 arasında ayarlayalım. Ne görüyoruz?

    [model]   [mae]   [mse]  [rmse]     [r2]  [mape]  [mspe] [rmsle]
[0] "D1_10" 0.00381 0.00003 0.00530  0.77720 0.00356 0.00002 0.00257
[1] "D1_30" 0.01809 0.00039 0.01963 -2.05545 0.01680 0.00033 0.00952
[2] "D1_52" 0.00472 0.00004 0.00642  0.67327 0.00440 0.00004 0.00311
[3] "D1_63" 0.00413 0.00003 0.00559  0.75230 0.00385 0.00003 0.00270

Negatif R-kare değeri ikinci satırda hemen göze çarpmaktadır. Bu, modelin çalışmadığı anlamına gelir. Tahmin grafiklerine bakmak ilginç olacaktır.

Dört model tahmini

D1_30 grafiğini gerçek Kapanış fiyatlarından ve diğer tahminlerden çok uzakta görüyoruz. Bu modele ilişkin metriklerin hiçbiri cesaret verici değildir. MAE, 1809 fiyat noktasının tahmin doğruluğunu gösteriyor! Bununla birlikte, modelin başlangıçta bir önceki makale için bir regresyon modeli değil, bir sınıflandırma modeli olarak geliştirildiğini unutmayın. Örnek oldukça nettir.

Diğer modelleri ayrı ayrı ele alalım.

Analiz için ilk aday D1_10'dur

    [model]   [mae]   [mse]  [rmse]     [r2]  [mape]  [mspe] [rmsle]
[0] "D1_10" 0.00381 0.00003 0.00530  0.77720 0.00356 0.00002 0.00257

Şimdi bu model tarafından tahmin edilen fiyatların grafiğine bakalım.

D1_10 tahmin

RMSLE metriği pek anlamlı değildir, çünkü 1.05 ile 1.09 arasındaki fark bir büyüklük mertebesinden çok daha azdır. MAPE ve MSPE metrikleri, EURUSD döviz kurunun bire yakın olması nedeniyle MAE ve MSE'ye yakın değerlere sahiptir. Ancak, yüzde sapmaları hesaplarken, mutlak sapmaları hesaplarken mevcut olmayan bir nüans vardır.

MAPE = |(y_true-y_pred)/y_true|

if y_true = 10 and y_pred = 5
MAPE = 0.5

if y_true = 5 and y_pred = 10
MAPE = 1.0

Başka bir deyişle, bu metrik (MSPE gibi) asimetriktir. Bu, tahminin gerçekten daha yüksek olduğu durumda daha büyük bir hata elde edeceğimiz anlamına gelir.

Tamamen metodolojik amaçlarla, yani MQL5'te ONNX modelleriyle nasıl çalışabileceğinizi göstermek için bir araya getirilen basit model için R-kare metriğinin iyi sonucu elde edilmiştir.


İkinci aday - D1_63

    [model]   [mae]   [mse]  [rmse]     [r2]  [mape]  [mspe] [rmsle]
[3] "D1_63" 0.00413 0.00003 0.00559  0.75230 0.00385 0.00003 0.00270

D1_63 tahmin

Tahmin, görsel olarak bir öncekine çok benzemektedir. Metrik değerler bu benzerliği doğruluyor.

[0] "D1_10" 0.00381 0.00003 0.00530  0.77720 0.00356 0.00002 0.00257
[3] "D1_63" 0.00413 0.00003 0.00559  0.75230 0.00385 0.00003 0.00270

Şimdi bu modellerden hangisinin aynı dönemde sınayıcıda daha iyi performans göstereceğini göreceğiz.


Şimdi D1_52 için

    [model]   [mae]   [mse]  [rmse]     [r2]  [mape]  [mspe] [rmsle]
[2] "D1_52" 0.00472 0.00004 0.00642  0.67327 0.00440 0.00004 0.00311

Bunu sadece R-kare değeri 0.5'ten büyük olduğu için dikkate alıyoruz.

D1_52 tahmin

Tahmin edilen fiyatların neredeyse tamamı, en kötü durumumuzda olduğu gibi Kapanış grafiğinin altındadır. Önceki iki modelle karşılaştırılabilir metrik değerlere rağmen, bu model herhangi bir iyimserlik uyandırmamaktadır. Bunu bir sonraki paragrafta kontrol edeceğiz.


ONNX modellerini sınayıcıda çalıştırma

Aşağıda modellerimizi sınayıcıda kontrol etmek için çok basit bir Uzman Danışman verilmiştir.

//+------------------------------------------------------------------+
//|                                    ONNX.eurusd.D1.Prediction.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright   "Copyright 2023, MetaQuotes Ltd."
#property link        "https://www.mql5.com"
#property version     "1.00"

#include "ModelEurusdD1_10.mqh"
#include "ModelEurusdD1_30.mqh"
#include "ModelEurusdD1_52.mqh"
#include "ModelEurusdD1_63.mqh"
#include <Trade\Trade.mqh>

input double InpLots = 1.0;    // Lots amount to open position

//CModelEurusdD1_10 ExtModel;
//CModelEurusdD1_30 ExtModel;
CModelEurusdD1_52 ExtModel;
//CModelEurusdD1_63 ExtModel;
CTrade            ExtTrade;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   if(!ExtModel.Init(_Symbol,_Period))
      return(INIT_FAILED);
   Print("model ",ExtModel.GetModelName());
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   ExtModel.Shutdown();
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(!ExtModel.CheckOnTick())
      return;

//--- predict next price movement
   vector prob(3);
   int    predicted_class=ExtModel.PredictClass(TimeCurrent(),prob);
   Print("predicted class ",predicted_class);
//--- check trading according to prediction
   if(predicted_class>=0)
      if(PositionSelect(_Symbol))
         CheckForClose(predicted_class);
      else
         CheckForOpen(predicted_class);
  }
//+------------------------------------------------------------------+
//| Check for open position conditions                               |
//+------------------------------------------------------------------+
void CheckForOpen(const int predicted_class)
  {
   ENUM_ORDER_TYPE signal=WRONG_VALUE;
//--- check signals
   if(predicted_class==PRICE_DOWN)
      signal=ORDER_TYPE_SELL;    // sell condition
   else
     {
      if(predicted_class==PRICE_UP)
         signal=ORDER_TYPE_BUY;  // buy condition
     }

//--- open position if possible according to signal
   if(signal!=WRONG_VALUE && TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
     {
      double price=SymbolInfoDouble(_Symbol,(signal==ORDER_TYPE_SELL) ? SYMBOL_BID : SYMBOL_ASK);
      ExtTrade.PositionOpen(_Symbol,signal,InpLots,price,0,0);
     }
  }
//+------------------------------------------------------------------+
//| Check for close position conditions                              |
//+------------------------------------------------------------------+
void CheckForClose(const int predicted_class)
  {
   bool bsignal=false;
//--- position already selected before
   long type=PositionGetInteger(POSITION_TYPE);
//--- check signals
   if(type==POSITION_TYPE_BUY && predicted_class==PRICE_DOWN)
      bsignal=true;
   if(type==POSITION_TYPE_SELL && predicted_class==PRICE_UP)
      bsignal=true;

//--- close position if possible
   if(bsignal && TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
     {
      ExtTrade.PositionClose(_Symbol,3);
      //--- open opposite
      CheckForOpen(predicted_class);
     }
  }
//+------------------------------------------------------------------+

Gerçekten de, D1_52 modeline göre, yalnızca bir satış işlemi açıldı ve bu modele göre trend, tüm test dönemi boyunca değişmedi.

D1_52 testi


2023.06.09 16:18:31.967 Symbols EURUSD: symbol to be synchronized
2023.06.09 16:18:31.968 Symbols EURUSD: symbol synchronized, 3720 bytes of symbol info received
2023.06.09 16:18:32.023 History EURUSD: load 27 bytes of history data to synchronize in 0:00:00.001
2023.06.09 16:18:32.023 History EURUSD: history synchronized from 2011.01.03 to 2023.04.07
2023.06.09 16:18:32.124 History EURUSD,Daily: history cache allocated for 283 bars and contains 260 bars from 2022.01.03 00:00 to 2022.12.30 00:00
2023.06.09 16:18:32.124 History EURUSD,Daily: history begins from 2022.01.03 00:00
2023.06.09 16:18:32.126 Tester  EURUSD,Daily (MetaQuotes-Demo): 1 minutes OHLC ticks generating
2023.06.09 16:18:32.126 Tester  EURUSD,Daily: testing of Experts\article_2\ONNX.eurusd.D1.Prediction.ex5 from 2023.01.01 00:00 to 2023.02.01 00:00 started with inputs:
2023.06.09 16:18:32.126 Tester    InpLots=1.0
2023.06.09 16:18:32.161 ONNX    api version 1.16.0 initialized
2023.06.09 16:18:32.180 ONNX.eurusd.D1.Prediction (EURUSD,D1)   2023.01.01 00:00:00   model D1_52
2023.06.09 16:18:32.194 ONNX.eurusd.D1.Prediction (EURUSD,D1)   2023.01.02 07:02:00   predicted class 2
2023.06.09 16:18:32.194 Trade   2023.01.02 07:02:00   instant sell 1 EURUSD at 1.07016 (1.07016 / 1.07023 / 1.07016)
2023.06.09 16:18:32.194 Trades  2023.01.02 07:02:00   deal #2 sell 1 EURUSD at 1.07016 done (based on order #2)
2023.06.09 16:18:32.194 Trade   2023.01.02 07:02:00   deal performed [#2 sell 1 EURUSD at 1.07016]
2023.06.09 16:18:32.194 Trade   2023.01.02 07:02:00   order performed sell 1 at 1.07016 [#2 sell 1 EURUSD at 1.07016]
2023.06.09 16:18:32.195 ONNX.eurusd.D1.Prediction (EURUSD,D1)   2023.01.02 07:02:00   CTrade::OrderSend: instant sell 1.00 EURUSD at 1.07016 [done at 1.07016]
2023.06.09 16:18:32.196 ONNX.eurusd.D1.Prediction (EURUSD,D1)   2023.01.03 00:00:00   predicted class 2
2023.06.09 16:18:32.199 ONNX.eurusd.D1.Prediction (EURUSD,D1)   2023.01.04 00:00:00   predicted class 2
2023.06.09 16:18:32.201 ONNX.eurusd.D1.Prediction (EURUSD,D1)   2023.01.05 00:00:30   predicted class 2
2023.06.09 16:18:32.203 ONNX.eurusd.D1.Prediction (EURUSD,D1)   2023.01.06 00:00:00   predicted class 2
2023.06.09 16:18:32.206 ONNX.eurusd.D1.Prediction (EURUSD,D1)   2023.01.09 00:02:00   predicted class 2
2023.06.09 16:18:32.208 ONNX.eurusd.D1.Prediction (EURUSD,D1)   2023.01.10 00:00:00   predicted class 2
2023.06.09 16:18:32.210 ONNX.eurusd.D1.Prediction (EURUSD,D1)   2023.01.11 00:00:00   predicted class 2
2023.06.09 16:18:32.213 ONNX.eurusd.D1.Prediction (EURUSD,D1)   2023.01.12 00:00:00   predicted class 2
2023.06.09 16:18:32.215 ONNX.eurusd.D1.Prediction (EURUSD,D1)   2023.01.13 00:00:00   predicted class 2
2023.06.09 16:18:32.217 ONNX.eurusd.D1.Prediction (EURUSD,D1)   2023.01.16 00:03:00   predicted class 2
2023.06.09 16:18:32.220 ONNX.eurusd.D1.Prediction (EURUSD,D1)   2023.01.17 00:00:00   predicted class 2
2023.06.09 16:18:32.222 ONNX.eurusd.D1.Prediction (EURUSD,D1)   2023.01.18 00:00:30   predicted class 2
2023.06.09 16:18:32.224 ONNX.eurusd.D1.Prediction (EURUSD,D1)   2023.01.19 00:00:00   predicted class 2
2023.06.09 16:18:32.227 ONNX.eurusd.D1.Prediction (EURUSD,D1)   2023.01.20 00:00:30   predicted class 2
2023.06.09 16:18:32.229 ONNX.eurusd.D1.Prediction (EURUSD,D1)   2023.01.23 00:02:00   predicted class 2
2023.06.09 16:18:32.231 ONNX.eurusd.D1.Prediction (EURUSD,D1)   2023.01.24 00:00:00   predicted class 2
2023.06.09 16:18:32.234 ONNX.eurusd.D1.Prediction (EURUSD,D1)   2023.01.25 00:00:00   predicted class 2
2023.06.09 16:18:32.236 ONNX.eurusd.D1.Prediction (EURUSD,D1)   2023.01.26 00:00:00   predicted class 2
2023.06.09 16:18:32.238 ONNX.eurusd.D1.Prediction (EURUSD,D1)   2023.01.27 00:00:00   predicted class 2
2023.06.09 16:18:32.241 ONNX.eurusd.D1.Prediction (EURUSD,D1)   2023.01.30 00:03:00   predicted class 2
2023.06.09 16:18:32.243 ONNX.eurusd.D1.Prediction (EURUSD,D1)   2023.01.31 00:00:00   predicted class 2
2023.06.09 16:18:32.245 Trade   2023.01.31 23:59:59   position closed due end of test at 1.08621 [#2 sell 1 EURUSD 1.07016]
2023.06.09 16:18:32.245 Trades  2023.01.31 23:59:59   deal #3 buy 1 EURUSD at 1.08621 done (based on order #3)
2023.06.09 16:18:32.245 Trade   2023.01.31 23:59:59   deal performed [#3 buy 1 EURUSD at 1.08621]
2023.06.09 16:18:32.245 Trade   2023.01.31 23:59:59   order performed buy 1 at 1.08621 [#3 buy 1 EURUSD at 1.08621]
2023.06.09 16:18:32.245 Tester  final balance 8366.00 USD
2023.06.09 16:18:32.249 Tester  EURUSD,Daily: 123499 ticks, 22 bars generated. Environment synchronized in 0:00:00.043. Test passed in 0:00:00.294 (including ticks preprocessing 0:00:00.016).

Önceki bölümde de belirtildiği üzere, D1_52 modeli iyimserlik uyandırmamaktadır. Bu durum test sonuçlarıyla da teyit edilmiştir.

Sadece iki satırlık kodu değiştirelim.

#include "ModelEurusdD1_10.mqh"
#include "ModelEurusdD1_30.mqh"
#include "ModelEurusdD1_52.mqh"
#include "ModelEurusdD1_63.mqh"
#include <Trade\Trade.mqh>

input double InpLots = 1.0;    // Lots amount to open position

CModelEurusdD1_10 ExtModel;
//CModelEurusdD1_30 ExtModel;
//CModelEurusdD1_52 ExtModel;
//CModelEurusdD1_63 ExtModel;
CTrade            ExtTrade;

Ve test için D1_10 modelini başlatalım.

D1_10 test sonuçları

Sonuçlar iyidir. Test grafiği de umut vericidir.

D1_10 test grafiği


İki satırlık kodu tekrar düzeltelim ve D1_63 modelini test edelim.

D1_63 test sonuçları

Grafik:

D1_63 test grafiği

Test grafiği D1_10 modelinden çok daha kötüdür.

D1_10 ve D1_63 modellerini karşılaştırdığımızda, ilk modelin ikincisinden daha iyi regresyon metriklerine sahip olduğunu görebiliriz. Sınayıcı da aynı şeyi gösteriyor.

Önemli not: Makalede kullanılan modellerin yalnızca MQL5 dilini kullanarak ONNX modelleriyle nasıl çalışılacağını göstermek için sunulduğunu lütfen unutmayın. Uzman Danışman, gerçek hesaplarda ticaret yapmak için tasarlanmamıştır.


Sonuç

Fiyat tahmin modellerini değerlendirmek için en uygun metrik R-kare değeridir. MAE - RMSE - MAPE metriklerinin bir arada değerlendirilmesi çok faydalı olabilir. RMSLE metriği fiyat tahmini görevlerinde dikkate alınmayabilir. Bazı değişikliklerle aynı model olsa bile, değerlendirme için birkaç modele sahip olmak çok yararlıdır.

Ciddi bir araştırma için 22 değerlik bir örneklemin yetersiz olduğunun farkındayız, ancak amacımız istatistiksel bir çalışma yapmak değildi. Bunun yerine, sadece bir kullanım örneği sunduk.


MetaQuotes Ltd tarafından Rusçadan çevrilmiştir.
Orijinal makale: https://www.mql5.com/ru/articles/12772

Ekli dosyalar |
MQL5.zip (1005.2 KB)
Popülasyon optimizasyon algoritmaları: İstilacı yabancı ot optimizasyonu (Invasive Weed Optimization, IWO) Popülasyon optimizasyon algoritmaları: İstilacı yabancı ot optimizasyonu (Invasive Weed Optimization, IWO)
Yabancı otların çok çeşitli koşullarda hayatta kalma konusundaki şaşırtıcı yeteneği, güçlü bir optimizasyon algoritması için bir fikir haline gelmiştir. IWO, daha önce incelenenler arasındaki en iyi algoritmalardan biridir.
ONNX modellerini sınıflara sarma ONNX modellerini sınıflara sarma
Nesne yönelimli programlama, okunması ve değiştirilmesi kolay olan daha kompakt bir kod oluşturulmasını sağlar. Burada üç ONNX modeli için örneğe bir göz atacağız.
Fractals göstergesine dayalı bir ticaret sistemi nasıl geliştirilir? Fractals göstergesine dayalı bir ticaret sistemi nasıl geliştirilir?
En popüler teknik göstergelere dayalı ticaret sistemleri tasarladığımız serimizin yeni makalesindeyiz. Bu makalede Fractals göstergesini ve ona dayalı olarak MetaTrader 5 terminalinde yürütülecek bir ticaret sisteminin nasıl geliştirileceğini öğreneceğiz.
MQL5'te matrisler ve vektörler: Aktivasyon fonksiyonları MQL5'te matrisler ve vektörler: Aktivasyon fonksiyonları
Burada makine öğreniminin sadece bir yönünü - aktivasyon fonksiyonlarını - açıklayacağız. Yapay sinir ağlarında, bir nöron aktivasyon fonksiyonu, bir girdi sinyalinin veya bir dizi girdi sinyalinin değerlerine dayalı olarak bir çıktı sinyali değerini hesaplar. Sürecin iç işleyişini derinlemesine inceleyeceğiz.