Discussion of article "How to use ONNX models in MQL5" - page 2

 
Vladimir #:
Nice article. The Prediction Graph on Testing Data is disappointing. You might as well skip all that DNN modeling/training and simply use a prediction of the next price equal to the last know price. I bet the prediction accuracy of such trivial model will be higher that using your DNN model. I suggest to compare those two accuracies and show them here. In general, using DNN to predict prices is a bad idea. They are better suited for classification of the price patterns (e.g., buy, sell, hold). Also, the number of weights in your DNN is astronomical. It must be overfitting.

Thank you Vladimir.
Just for discussion, when time permitted, I would modify this model to do classification for comparison.

Please let me know if you have ideas.

Vladimir
Vladimir
  • 2022.04.30
  • www.mql5.com
Trader's profile
 
const long input_shape[] = {1, input_count};
const long output_shape[] = {1, output_count};

The tutorial gives a input of one batch  SAMPLE_SIZE number of close inputs, you want one batch of input_count inputs.

Also your model doesn't use floats as inputs, but doubles, 

Moderator's note: This post is out of sequence due to posts below been moved from another topic. Please see post below.

 

Can We Troubleshoot this ONNX Model Together?

Hello MQL5 community, I've been trying to follow this tutorial on how to use ONNX in your EA's. In the tutorial a neural network was the model of choice, I've used a gradient boosted tree. 

I built the model using the InterpretML Python package, and exported it to ONNX using ebm2onnx.

I'll summaries the process by which the model was trained.

1) The model was trained on 5 inputs, OHLC and Height, Height is calculated as ((H + L) / 2) - C. 

2) The model is a binary classifier, aiming to classify the next candle as either UP (1) or DOWN (0).

Model Training Data

The data used to train the model.

3) The model was then exported to ONNX format 

ONNX Representation

ONNX model representation.


To get the model to work, I deviated from the code in the tutorial and kept editing the code to try make the ONNX model work, but now I really don't know what I'm doing wrong. I keep getting an error that the handle for the model is invalid.

I have attached the MQL5 code below.

I'll now summaries the steps that I took in my code that deviate from what is in the tutorial, and I'll explain why I deviated from the tutorial as well

1) LINE 57: Setting Model Input Shape. 
In the tutorial 3 dimensions were used to set the input and output shape i.e. {1,SAMPLE_SIZE,1}; However when I followed that approach I kept getting an error, specifically error 5808. After the usual trail and error process I realized that if I used only 1 dimension, the number of inputs, the error went away. 

2) LINE 68: Setting Model Output Shape.

Same logic as above.

The other deviations I made do not affect the model, for example I kept track of time using logic I found more intuitive than the logic implemented in the tutorial. I didn't need to normalize inputs because it's a tree-based model. 


If you can spot other errors I have made , I'd appreciate your insight.

//+------------------------------------------------------------------+
//|                                                         ONNX.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
//Meta properties
#property copyright "Gamuchirai Zororo Ndawana"
#property link      "https://www.mql5.com"
#property version   "1.00"

//Trade Library
#include <Trade\Trade.mqh>

//Reading our ONNX model and storing it into a data array
#resource "\\Files\\Python\\Volatility_75_EBM.onnx" as uchar ExtModel[]

//Custom keyword definitions
#define  SAMPLE_SIZE 998
#define  PRICE_UP 1
#define  PRICE_DOWN 0

//Global variables
long     ExtHandle = INVALID_HANDLE;
int      ExtPredictedClass = -1;
datetime ExtNextBar = 0;
datetime ExtNextMinute =0;
float    ExtMin = 0;
float    ExtMax = 0;
double   min_volume;
CTrade   ExtTrade;

//Inputs
int input lot_mutliple = 1; //How many time greater than minimum lot should we enter?

int OnInit()
  {
   //Check if the symbol and time frame conform to training conditions
   if(_Symbol != "Volatility 75 Index" || _Period != PERIOD_M1)
       {
            Comment("Model must be used with the Volatility 75 Index on the 1 Minute Chart");
            return(INIT_FAILED);
       }
    
    //Create an ONNX model from our data array
    ExtHandle = OnnxCreateFromBuffer(ExtModel,ONNX_DEFAULT);
    Print("ONNX Create from buffer status ",ExtHandle);
    
    //Checking if the handle is valid
    if(ExtHandle == INVALID_HANDLE)
      {
            Comment("ONNX create from buffer error ", GetLastError());
            return(INIT_FAILED);
      }
   
   //Set input shape
   long input_count = OnnxGetInputCount(ExtHandle);   
   const long input_shape[] = {input_count};
   Print("Total model inputs : ",input_count);
   if(!OnnxSetInputShape(ExtHandle,0,input_shape))
      {
            Comment("ONNX set input shape error ", GetLastError());
            OnnxRelease(ExtHandle);
            return(INIT_FAILED);
      }
      
   //Set output shape
   long output_count = OnnxGetOutputCount(ExtHandle);
   const long output_shape[] = {output_count};
   Print("Total model outputs : ",output_count);
   if(!OnnxSetOutputShape(ExtHandle,0,output_shape))
      {
            Comment("ONNX set output shape error ", GetLastError());
            OnnxRelease(ExtHandle);
            return(INIT_FAILED);
      }
    
    //Get the minimum trading volume allowed  
    min_volume = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);  
    return(INIT_SUCCEEDED);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   if(ExtHandle != INVALID_HANDLE)
      {
         OnnxRelease(ExtHandle);
         ExtHandle = INVALID_HANDLE;
      }
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   //Time trackers
   static datetime time_stamp;
   datetime time = iTime(_Symbol,PERIOD_M1,0);
      
    //Check new bar
     if(time_stamp != time)
      {
         time_stamp = time;
         
         PredictedPrice();
         Print("Predicted class: ",ExtPredictedClass);
         
         if(ExtPredictedClass == PRICE_UP || ExtPredictedClass == PRICE_DOWN)
            if(PositionSelect(_Symbol))
               CheckForClose();
            if(PositionsTotal() == 0)
               CheckForOpen();
      }
   
  }
//+------------------------------------------------------------------+

void CheckForOpen(void)
   {
      ENUM_ORDER_TYPE signal = WRONG_VALUE;
      
      //Check signals
      if(ExtPredictedClass == PRICE_DOWN)
         {
            signal = ORDER_TYPE_SELL;
         }
         
      else if(ExtPredictedClass == PRICE_UP)
         {
            signal = ORDER_TYPE_BUY;
         }
         
      if(signal != WRONG_VALUE && TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
         {
            double price, sl = 0 , tp = 0;
            double bid = SymbolInfoDouble(_Symbol,SYMBOL_BID);
            double ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
            
            if(signal == ORDER_TYPE_SELL)
               {
                  price = bid;
               }
               
           else
               {
                  price = ask;
               }
               
            Print("Opening a new position: ",signal);  
            ExtTrade.PositionOpen(_Symbol,signal,min_volume,price,0,0);
         }
   }
   
void CheckForClose(void)
   {
      bool bsignal = false;
      
      long type = PositionGetInteger(POSITION_TYPE);
      
      if(type == POSITION_TYPE_BUY && ExtPredictedClass == PRICE_DOWN)
         bsignal = true;
         
      if(type == POSITION_TYPE_SELL && ExtPredictedClass == PRICE_UP)
         bsignal = true;
         
         if(bsignal && TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
            {
                  ExtTrade.PositionClose(_Symbol,3);
                  CheckForOpen();
            }
   }
   
 void PredictedPrice(void)
   {
      vectorf output_data(1);
      float   open  = float(iOpen(_Symbol,PERIOD_M1,1));
      float   high  = float(iHigh(_Symbol,PERIOD_M1,1));
      float   low   = float(iLow(_Symbol,PERIOD_M1,1));
      float   close = float(iClose(_Symbol,PERIOD_M1,1));
      float   height =  float((((high + low) / 2) - close));
      Print("Current open ",open);
      Print("Current high ",high);
      Print("Current low ",low);
      Print("Current close ",close);
      Print("Current height ",height);
      vectorf input_data = {open,high,low,close,height};
      
      Print("Input vector: ",input_data);
      
       if(!OnnxRun(ExtHandle,ONNX_NO_CONVERSION,input_data,output_data))
         {
            Print("ONNX run error : ",GetLastError());
            OnnxRelease(ExtHandle);
         }
        
       int predicted = int(output_data[0]);
       
       Print("Model prediction: ",predicted);
       Print(output_data);
       
       if(predicted == 1)
         {
            ExtPredictedClass = PRICE_UP;
         }
         
       else if(predicted == 0)
         {
            ExtPredictedClass = PRICE_DOWN;
         }
         
         Comment("Model Prediction: ", ExtPredictedClass);
   }



Forum on trading, automated trading systems and testing trading strategies

Discussion of article "How to use ONNX models in MQL5"

Stian Andreassen, 2023.12.08 20:51

const long input_shape[] = {1, input_count};
const long output_shape[] = {1, output_count};

The tutorial gives a input of one batch  SAMPLE_SIZE number of close inputs, you want one batch of input_count inputs.

Also your model doesn't use floats as inputs, but doubles, 



Thank you for sharing Sitan, I've applied what you pointed out but the error is still there


  One batch of input_count

One batch of input_count inputs.

Set input to double

Set input to double

Error message

Error message.


Files:
 
amuchirai Zororo Ndawana #:

Can We Troubleshoot this ONNX Model Together?

Hello MQL5 community, I've been trying to follow this tutorial on how to use ONNX in your EA's. In the tutorial a neural network was the model of choice, I've used a gradient boosted tree. 

I built the model using the InterpretML Python package, and exported it to ONNX using ebm2onnx.

I'll summaries the process by which the model was trained.

1) The model was trained on 5 inputs, OHLC and Height, Height is calculated as ((H + L) / 2) - C. 

2) The model is a binary classifier, aiming to classify the next candle as either UP (1) or DOWN (0).

The data used to train the model.

3) The model was then exported to ONNX format 

ONNX model representation.


To get the model to work, I deviated from the code in the tutorial and kept editing the code to try make the ONNX model work, but now I really don't know what I'm doing wrong. I keep getting an error that the handle for the model is invalid.

I have attached the MQL5 code below.

I'll now summaries the steps that I took in my code that deviate from what is in the tutorial, and I'll explain why I deviated from the tutorial as well

1) LINE 57: Setting Model Input Shape. 
In the tutorial 3 dimensions were used to set the input and output shape i.e. {1,SAMPLE_SIZE,1}; However when I followed that approach I kept getting an error, specifically error 5808. After the usual trail and error process I realized that if I used only 1 dimension, the number of inputs, the error went away. 

2) LINE 68: Setting Model Output Shape.

Same logic as above.

The other deviations I made do not affect the model, for example I kept track of time using logic I found more intuitive than the logic implemented in the tutorial. I didn't need to normalize inputs because it's a tree-based model. 


If you can spot other errors I have made , I'd appreciate your insight.





Thank you for sharing Sitan, I've applied what you pointed out but the error is still there


 

One batch of input_count inputs.

Set input to double

Error message.


It seems that MQL5 does not (or rather ONNXMLTools does not) yet support EBM's ONNX:

https://www.mql5.com/en/docs/onnx/onnx_conversion

If you refer to the ONNX attachments  (especially model.eurusd.D1.10.class.onnx which uses 4 inputs) from https://www.mql5.com/en/articles/12484; and use Netron (web version) to visualise the onnx files you will see the differences.

I think the following two articles would help you understand further too:

Regression models of the Scikit-learn Library and their export to ONNX

Classification models in the Scikit-Learn library and their export to ONNX

Wrapping ONNX models in classes
Wrapping ONNX models in classes
  • www.mql5.com
Object-oriented programming enables creation of a more compact code that is easy to read and modify. Here we will have a look at the example for three ONNX models.
 

Hi everybody,


We are trying to use a keras neural network with 11 predictors at one point in time (batch size 32) to make predictions on the XauUsd (where the output is a singular number between 0 and 1). Firstly, we load in from OnnxCreatefrombuffer (because OnnxCreate itself doesn't work for us), then we always get an error on the OnnxRun stage, where I have attached both errors below. Any help on what dimension to reshape to for the input, what format to put our predictor vector in (if it should be a vector at all?), or just any help or suggestions with syntax to help tackle these errors would be amazing. We have tried reshaping to all sorts of combinations of 32,1,11 vectors and no luck and really no idea with the next steps.. Thanks so much for anyone who can help !! Ben.

' error 5808'

' ONNX: input parameter #0 tensor has wrong dimension [0], try to use OnnxSetInputShape'

'ONNX: invalid input parameter #0 size, expected 1408 bytes instead of 480'

 

Hi, I try to use the

OnnxModelInfo.mq5

file script, but can't make it work, what am I doing wrong? this cant be so complicated!

I copy pasted the OnnxModelInfo script, and saved into de Files folder 

I have a onnx model (attached)

and when I compilate the script, 21 errors appear.

Can some one help me with this? Please

'element_type' - undeclared identifier  onnx read file.mq5      60      49
'element_type' - parameter for EnumToString must be an enumeration      onnx read file.mq5      60      49
'dimensions' - undeclared identifier    onnx read file.mq5      62      17
'dimensions' - undeclared identifier    onnx read file.mq5      64      37
'[' - array required    onnx read file.mq5      64      47
'dimensions' - undeclared identifier    onnx read file.mq5      65      51
'[' - array required    onnx read file.mq5      65      61
'dimensions' - undeclared identifier    onnx read file.mq5      66      33
'dimensions' - undeclared identifier    onnx read file.mq5      68      23
'[' - array required    onnx read file.mq5      68      33
'dimensions' - undeclared identifier    onnx read file.mq5      71      48
'[' - array required    onnx read file.mq5      71      58
'dimensions' - undeclared identifier    onnx read file.mq5      80      33
'dimensions' - undeclared identifier    onnx read file.mq5      82      35
'[' - array required    onnx read file.mq5      82      45
'dimensions' - undeclared identifier    onnx read file.mq5      100     28
';' - unexpected token  onnx read file.mq5      102     45
'<' - l-value required  onnx read file.mq5      100     17
cannot implicitly convert type 'string' to 'bool'       onnx read file.mq5      102     21
l-value required        onnx read file.mq5      102     20
'(' - unbalanced left parenthesis       onnx read file.mq5      100     9
empty controlled statement found        onnx read file.mq5      102     45
Files:
model.onnx  295 kb
Reason: