English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
preview
ONNX modellerini sınıflara sarma

ONNX modellerini sınıflara sarma

MetaTrader 5Örnekler | 18 Ocak 2024, 15:51
176 0
MetaQuotes
MetaQuotes

Giriş

Bir önceki makalede, oylama sınıflandırıcısını ayarlamak için iki ONNX modeli kullandık. Kaynak metnin tamamı tek bir MQ5 dosyası olarak düzenlenmiştir. Kodun tamamı fonksiyonlara bölünmüştür. Peki ya modelleri değiştirmeye çalışırsak? Ya da başka bir model eklersek? Orijinal metin daha da büyüyecektir. Nesne yönelimli yaklaşımı deneyelim.


1. Hangi modelleri kullanacağız?

Önceki oylama sınıflandırıcısında, bir sınıflandırma modeli ve bir regresyon modeli kullandık. Regresyon modelinde, öngörülen fiyat hareketi (aşağı, yukarı, değişmez) yerine, sınıfı hesaplamak için kullanılan öngörülen fiyatı elde ederiz. Ancak, bu durumda, sınıfa göre bir olasılık dağılımımız yoktur, bu da "yumuşak oylama" olarak adlandırılan duruma izin vermez.

3 adet sınıflandırma modeli hazırladık. “MQL5'te ONNX modellerinin nasıl bir araya getirileceğine dair bir örnek” makalesinde iki model zaten kullanılmıştır. İlk model (regresyon) bir sınıflandırma modeline dönüştürülmüştür. Eğitim 10 OHLC fiyatından oluşan bir seri üzerinde gerçekleştirilmiştir. İkinci model ise sınıflandırma modelidir. Eğitim 63 Kapanış fiyatından oluşan bir seri üzerinde gerçekleştirilmiştir.

Son olarak, bir model daha vardır. Sınıflandırma modeli, 30 Kapanış fiyatı serisi ve ortalama alma periyotları 21 ve 34 olan iki basit hareketli ortalama serisi üzerinde eğitilmiştir. Hareketli ortalamaların Kapanış grafiği ile ve kendi aralarında çaprazlaması hakkında herhangi bir varsayımda bulunmadık - tüm modeller ağ tarafından katmanlar arasında katsayı matrisleri şeklinde hesaplanacak ve hatırlanacaktır.

Tüm modeller MetaQuotes-Demo sunucu verileri, EURUSD D1 üzerinde 2010.01.01 - 2023.01.01 tarihleri arasında eğitilmiştir. Her üç model için eğitim komut dosyaları Python'da yazılmıştır ve bu makaleye eklenmiştir. Okuyucunun dikkatini makalemizin ana konusundan uzaklaştırmamak için kaynak kodlarını burada vermeyeceğiz.


2. Tüm modeller için tek bir temel sınıf gereklidir

Üç model bulunmaktadır. Her biri, girdi verilerinin büyüklüğü ve hazırlanması açısından diğerlerinden farklıdır. Tüm modeller aynı arayüze sahiptir. Tüm modellerin sınıfları aynı temel sınıftan kalıtılmalıdır.

Temel sınıfı tanımlayalım.

//+------------------------------------------------------------------+
//|                                            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:
   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_handle=INVALID_HANDLE;
      m_symbol=symbol;
      m_period=period;
      m_next_bar=0;
      m_class_delta=class_delta;
     }

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

   //+------------------------------------------------------------------+
   //| 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(void)
     {
      return(DBL_MAX);
     }

   //+------------------------------------------------------------------+
   //| Predict class (regression -> classification)                     |
   //+------------------------------------------------------------------+
   virtual int PredictClass(void)
     {
      double predicted_price=PredictPrice();
      if(predicted_price==DBL_MAX)
         return(-1);

      int    predicted_class=-1;
      double last_close=iClose(m_symbol,m_period,1);
      //--- classify predicted price movement
      double delta=last_close-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;
        }

      //--- return predicted class
      return(predicted_class);
     }
  };
//+------------------------------------------------------------------+

Temel sınıf hem regresyon hem de sınıflandırma modelleri için kullanılabilir. Yalnızca alt sınıfta uygun metodu uygulamamız gerekir - PredictPrice veya PredictClass.

Temel sınıf, modelin çalışacağı sembol zaman dilimini belirler (modelin eğitildiği veriler). Temel sınıf ayrıca modeli kullanan Uzman Danışmanın gerekli sembol zaman diliminde çalıştığını kontrol eder ve modeli çalıştırmak için bir ONNX oturumu oluşturur. Temel sınıf yalnızca yeni bir çubuğun başlangıcında çalışma sağlar.


3. Birinci model sınıfı

İlk modelimiz model.eurusd.D1.10.class.onnx olarak adlandırılır ve EURUSD D1 üzerinde 10 OHLC fiyatı serisi üzerinde eğitilmiş bir sınıflandırma modelidir.

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

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

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

public:
   //+------------------------------------------------------------------+
   //| Constructor                                                      |
   //+------------------------------------------------------------------+
   CModelEurusdD1_10Class(void) : CModelSymbolPeriod("EURUSD",PERIOD_D1)
     {
      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_class))
        {
         Print("model_eurusd_D1_10_class : 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_class : 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 classes (up, same or down)
      const long output_shape[] = {1,3};
      if(!OnnxSetOutputShape(m_handle,0,output_shape))
        {
         Print("model_eurusd_D1_10_class : OnnxSetOutputShape error ",GetLastError());
         return(false);
        }
      //--- ok
      return(true);
     }

   //+------------------------------------------------------------------+
   //| Predict class                                                    |
   //+------------------------------------------------------------------+
   virtual int PredictClass(void)
     {
      static matrixf input_data(m_sample_size,4);    // matrix for prepared input data
      static vectorf output_data(3);                 // 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
      if(!rates.CopyRates(m_symbol,m_period,COPY_RATES_OHLC,1,m_sample_size))
         return(-1);
      //--- 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(-1);
      //--- evaluate prediction
      return(int(output_data.ArgMax()));
     }
  };
//+------------------------------------------------------------------+

Yukarıda da belirtildiği gibi: "Üç model bulunmaktadır. Her biri, girdi verilerinin büyüklüğü ve hazırlanması açısından diğerlerinden farklıdır.” Sadece iki metodu yeniden tanımladık - Init ve PredictClass. Aynı metotlar diğer iki model için diğer iki sınıfta yeniden tanımlanacaktır.

Init metodu, ONNX modelimiz için bir oturumun oluşturulduğu ve girdi ve çıktı tensörlerinin büyüklüklerinin açıkça ayarlandığı CheckInit temel sınıf metodunu çağırır. Burada koddan çok yorum vardır.

PredictClass metodu, modeli eğitirken kullanılan girdi verisi hazırlama işleminin aynısını sağlar. Girdi, normalleştirilmiş OHLC fiyatlarının bir matrisidir.


4. Nasıl çalıştığını kontrol edelim

Sınıfımızın performansını test etmek için çok kompakt bir Uzman Danışman oluşturuldu.

//+------------------------------------------------------------------+
//|                                    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_10Class.mqh"
#include <Trade\Trade.mqh>

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

CModelEurusdD1_10Class ExtModel;
CTrade                 ExtTrade;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   if(!ExtModel.Init(_Symbol,_Period))
      return(INIT_FAILED);
//---
   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
   int predicted_class=ExtModel.PredictClass();
//--- 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);
     }
  }
//+------------------------------------------------------------------+

Model 2023'e kadar olan fiyat verileriyle eğitildiğinden, testi 1 Ocak 2023'ten itibaren başlatalım.

Test ayarları

Sonuç aşağıda gösterilmektedir:

Test sonuçları

Gördüğümüz gibi, model tamamen işlevseldir.


5. İkinci model sınıfı

İkinci model model.eurusd.D1.30.class.onnx olarak adlandırılır. EURUSD D1 üzerinde eğitilen sınıflandırma modeli, 30 Kapanış fiyatı ve ortalama alma periyotları 21 ve 34 olan iki basit hareketli ortalama serisinden oluşmaktadır.

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

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

//+------------------------------------------------------------------+
//| ONNX-model wrapper class                                         |
//+------------------------------------------------------------------+
class CModelEurusdD1_30Class : 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_30Class(void) : CModelSymbolPeriod("EURUSD",PERIOD_D1)
     {
      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_class))
        {
         Print("model_eurusd_D1_30_class : 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_class : 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 classes (up, same or down)
      const long output_shape[] = {1,3};
      if(!OnnxSetOutputShape(m_handle,0,output_shape))
        {
         Print("model_eurusd_D1_30_class : 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_class : cannot create indicator");
         return(false);
        }
      //--- ok
      return(true);
     }

   //+------------------------------------------------------------------+
   //| Predict class                                                    |
   //+------------------------------------------------------------------+
   virtual int PredictClass(void)
     {
      static matrixf input_data(m_sample_size,3);    // matrix for prepared input data
      static vectorf output_data(3);                 // 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
      if(!vtemp.CopyRates(m_symbol,m_period,COPY_RATES_CLOSE,1,m_sample_size))
         return(-1);
      //--- 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,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,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(-1);
      //--- evaluate prediction
      return(int(output_data.ArgMax()));
     }
  };
//+------------------------------------------------------------------+

Ö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.

PredictClass 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.

Bu modelin nasıl çalıştığını görelim. Bunu yapmak için, test Uzman Danışmanının sadece iki dizgesini değiştirelim.

#include "ModelEurusdD1_30Class.mqh"
#include <Trade\Trade.mqh>

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

CModelEurusdD1_30Class ExtModel;
CTrade                 ExtTrade;

Test parametreleri aynıdır.

İkinci model test sonuçları

Modelin çalıştığını görüyoruz.


6. Üçüncü model sınıfı

Son model model.eurusd.D1.63.class.onnx olarak adlandırılır. EURUSD D1 üzerinde 63 Kapanış fiyatı serisi üzerinde eğitilen sınıflandırma modeli.

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

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

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

public:
   //+------------------------------------------------------------------+
   //| Constructor                                                      |
   //+------------------------------------------------------------------+
   CModelEurusdD1_63Class(void) : CModelSymbolPeriod("EURUSD",PERIOD_D1,0.0001)
     {
      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_class))
        {
         Print("model_eurusd_D1_63_class : 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_class : 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 classes (up, same or down)
      const long output_shape[] = {1,3};
      if(!OnnxSetOutputShape(m_handle,0,output_shape))
        {
         Print("model_eurusd_D1_63_class : OnnxSetOutputShape error ",GetLastError());
         return(false);
        }
      //--- ok
      return(true);
     }

   //+------------------------------------------------------------------+
   //| Predict class                                                    |
   //+------------------------------------------------------------------+
   virtual int PredictClass(void)
     {
      static vectorf input_data(m_sample_size);  // vector for prepared input data
      static vectorf output_data(3);             // vector to get result
   
      //--- request last bars
      if(!input_data.CopyRates(m_symbol,m_period,COPY_RATES_CLOSE,1,m_sample_size))
         return(-1);
      //--- 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(-1);
      //--- evaluate prediction
      return(int(output_data.ArgMax()));
     }
  };
//+------------------------------------------------------------------+

Bu, üç model arasında en basit olanıdır. PredictClass metodunun kodunun bu kadar kompakt olmasının nedeni budur.

Uzman Danışmandaki iki dizgeyi tekrar değiştirelim.

#include "ModelEurusdD1_63Class.mqh"
#include <Trade\Trade.mqh>

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

CModelEurusdD1_63Class ExtModel;
CTrade                 ExtTrade;

Testi aynı ayarlarla başlatalım.

Üçüncü model test sonuçları

Model çalışıyor.



7. Tüm modelleri tek bir Uzman Danışmanda birleştirme. Sert oylama

Her üç model de çalışma kapasitelerini göstermiştir. Şimdi onların çabalarını birleştirmeye çalışalım. Modellerin oylamasını ayarlayalım.

İleri bildiriler ve tanımlar

#include "ModelEurusdD1_10Class.mqh"
#include "ModelEurusdD1_30Class.mqh"
#include "ModelEurusdD1_63Class.mqh"
#include <Trade\Trade.mqh>

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

CModelSymbolPeriod *ExtModels[3];
CTrade              ExtTrade;

OnInit fonksiyonu

int OnInit()
  {
   ExtModels[0]=new CModelEurusdD1_10Class;
   ExtModels[1]=new CModelEurusdD1_30Class;
   ExtModels[2]=new CModelEurusdD1_63Class;

   for(long i=0; i<ExtModels.Size(); i++)
      if(!ExtModels[i].Init(_Symbol,_Period))
         return(INIT_FAILED);
//---
   return(INIT_SUCCEEDED);
  }

OnTick fonksiyonu

void OnTick()
  {
   for(long i=0; i<ExtModels.Size(); i++)
      if(!ExtModels[i].CheckOnTick())
         return;

//--- predict next price movement
   int returned[3]={0,0,0};
//--- collect returned classes
   for(long i=0; i<ExtModels.Size(); i++)
     {
      int pred=ExtModels[i].PredictClass();
      if(pred>=0)
         returned[pred]++;
     }
//--- get one prediction for all models
   int predicted_class=-1;
//--- count votes for predictions
   for(int n=0; n<3; n++)
     {
      if(returned[n]>=2)
        {
         predicted_class=n;
         break;
        }
     }

//--- check trading according to prediction
   if(predicted_class>=0)
      if(PositionSelect(_Symbol))
         CheckForClose(predicted_class);
      else
         CheckForOpen(predicted_class);
  }

Oy çoğunluğu <toplam oy sayısı>/2 + 1 denklemine göre hesaplanır. Toplam 3 oy için çoğunluk 2 oydur. Bu, "sert oylama" olarak adlandırılan bir durumdur.

Aynı ayarlarla test sonucu.

Sert oylama test sonuçları

Her üç modelin çalışmasını, yani kârlı ve kârsız işlemlerin sayısını ayrı ayrı hatırlayalım. İlk model - 11 : 3, ikinci model - 6 : 1, üçüncü model - 16 : 10.

Görünüşe göre sert oylamanın yardımıyla sonucu iyileştirdik - 16 : 4. Ancak elbette tam raporlara ve test grafiklerine bakmamız gerekiyor.


8. Yumuşak oylama

Yumuşak oylamanın sert oylamadan farkı, dikkate alınan oy sayısı değil, her üç modelden her üç sınıfın olasılıklarının toplamı olmasıdır. Sınıf en yüksek olasılığa göre seçilir.

Yumuşak oylamayı sağlamak için bazı değişikliklerin yapılması gerekmektedir.

Temel sınıfta:

   //+------------------------------------------------------------------+
   //| Predict class (regression -> classification)                     |
   //+------------------------------------------------------------------+
   virtual int PredictClass(vector& probabilities)
     {
...
      //--- 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);
     }

Alt sınıflarda:

   //+------------------------------------------------------------------+
   //| Predict class                                                    |
   //+------------------------------------------------------------------+
   virtual int PredictClass(vector& probabilities)
     {
...
      //--- evaluate prediction
      probabilities.Assign(output_data);
      return(int(output_data.ArgMax()));
     }

Uzman Danışmanda:

#include "ModelEurusdD1_10Class.mqh"
#include "ModelEurusdD1_30Class.mqh"
#include "ModelEurusdD1_63Class.mqh"
#include <Trade\Trade.mqh>

enum EnVotes
  {
   Two=2,    // Two votes
   Three=3,  // Three votes
   Soft=4    // Soft voting
  };

input double  InpLots  = 1.0;    // Lots amount to open position
input EnVotes InpVotes = Two;    // Votes to make trade decision

CModelSymbolPeriod *ExtModels[3];
CTrade              ExtTrade;
void OnTick()
  {
   for(long i=0; i<ExtModels.Size(); i++)
      if(!ExtModels[i].CheckOnTick())
         return;

//--- predict next price movement
   int    returned[3]={0,0,0};
   vector soft=vector::Zeros(3);
//--- collect returned classes
   for(long i=0; i<ExtModels.Size(); i++)
     {
      vector prob(3);
      int    pred=ExtModels[i].PredictClass(prob);
      if(pred>=0)
        {
         returned[pred]++;
         soft+=prob;
        }
     }
//--- get one prediction for all models
   int predicted_class=-1;
//--- soft or hard voting
   if(InpVotes==Soft)
      predicted_class=(int)soft.ArgMax();
   else
     {
      //--- count votes for predictions
      for(int n=0; n<3; n++)
        {
         if(returned[n]>=InpVotes)
           {
            predicted_class=n;
            break;
           }
        }
     }

//--- check trading according to prediction
   if(predicted_class>=0)
      if(PositionSelect(_Symbol))
         CheckForClose(predicted_class);
      else
         CheckForOpen(predicted_class);
  }

Test ayarları aynıdır. Girdilerde yumuşak oylamayı seçelim.

Girdi ayarları

Sonuç aşağıdaki gibidir:

Yumuşak oylama test sonuçları

Kârlı işlemler - 15, kârsız işlemler - 3. Parasal açıdan da sert oylamanın yumuşak oylamadan daha iyi olduğu ortaya çıkmıştır.


Oy birliği ile, yani oy sayısı 3 olan bir oylamanın sonucuna bakalım.

Oy birliği test sonuçları

Çok temkinli bir ticaret. Kârlı olmayan tek işlem testin sonunda kapatılmıştır (belki de kârsız değildir).

Oy birliği test grafiği


Ö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ç

Bu makalede, nesne yönelimli programlamanın program yazmayı nasıl kolaylaştırdığını gösterdik. Modellerin tüm karmaşıklıkları sınıflarında gizlidir (modeller örnek olarak sunduğumuzdan çok daha karmaşık olabilir). "Karmaşıklığın" geri kalanı OnTick fonksiyonunun 45 dizgesinde yer almaktadır.


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

Ekli dosyalar |
MQL5.zip (190.3 KB)
ONNX modellerinin regresyon metrikleri kullanılarak değerlendirilmesi ONNX modellerinin regresyon metrikleri kullanılarak değerlendirilmesi
Regresyon, etiketlenmemiş bir örnekten gerçek değeri tahmin etme görevidir. Regresyon metrikleri, regresyon modeli tahminlerinin doğruluğunu değerlendirmek için kullanılır.
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.
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.
MQL5'te ONNX modellerinin nasıl bir araya getirileceğine dair bir örnek MQL5'te ONNX modellerinin nasıl bir araya getirileceğine dair bir örnek
Açık sinir ağı santrali (Open Neural Network eXchange, ONNX), sinir ağlarını temsil etmek için oluşturulmuş açık bir formattır. Bu makalede, bir Uzman Danışmanda aynı anda iki ONNX modelinin nasıl kullanılacağını göstereceğiz.