English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
preview
Un esempio di come assemblare i modelli ONNX in MQL5

Un esempio di come assemblare i modelli ONNX in MQL5

MetaTrader 5Apprendimento automatico |
670 7
MetaQuotes
MetaQuotes

Introduzione

Per un trading stabile, di solito si raccomanda di diversificare sia gli strumenti negoziati che le strategie di trading. Lo stesso vale per i modelli di apprendimento automatico: è più facile creare diversi modelli semplici che uno complesso. Ma può essere difficile assemblare questi modelli in un unico modello ONNX.

Tuttavia, è possibile combinare diversi modelli ONNX addestrati in un unico programma MQL5. In questo articolo prenderemo in considerazione uno degli assemblaggi chiamato classificatore di voto. Vi mostreremo come sia facile implementare un tale assemblaggio.


Modelli per il progetto

Per il nostro esempio, utilizzeremo due semplici modelli: un modello di previsione dei prezzi a regressione e un modello di previsione del movimento dei prezzi a classificazione. La differenza principale tra i modelli è che la regressione prevede la quantità, mentre la classificazione prevede la classe.

Il primo modello è quello della regressione.

Viene addestrato utilizzando i dati EURUSD D1 dal 2003 alla fine del 2022. L'addestramento viene effettuato utilizzando serie di 10 prezzi OHLC. Per migliorare l'addestrabilità del modello, normalizziamo i prezzi e dividiamo il prezzo medio della serie per la deviazione standard della serie. In questo modo, mettiamo una serie in un certo intervallo con una media di 0 e uno spread di 1, che migliora la convergenza durante l'addestramento.

Di conseguenza, il modello dovrebbe prevedere il prezzo di chiusura del giorno successivo.

Il modello è molto semplice. Viene fornito solo a scopo dimostrativo.

# Copyright 2023, MetaQuotes Ltd.
# https://www.mql5.com

from datetime import datetime
import MetaTrader5 as mt5
import tensorflow as tf
import numpy as np
import pandas as pd
import tf2onnx
from sklearn.model_selection import train_test_split
from tqdm import tqdm
from sys import argv

if not mt5.initialize():
    print("initialize() failed, error code =",mt5.last_error())
    quit()

# we will save generated onnx-file near the our script
data_path=argv[0]
last_index=data_path.rfind("\\")+1
data_path=data_path[0:last_index]
print("data path to save onnx model",data_path)

# input parameters
inp_model_name = "model.eurusd.D1.10.onnx"
inp_history_size = 10
inp_start_date = datetime(2003, 1, 1, 0)
inp_end_date = datetime(2023, 1, 1, 0)

# get data from client terminal
eurusd_rates = mt5.copy_rates_range("EURUSD", mt5.TIMEFRAME_D1, inp_start_date, inp_end_date)
df = pd.DataFrame(eurusd_rates)


#
# collect dataset subroutine
#
def collect_dataset(df: pd.DataFrame, history_size: int):
    """
    Collect dataset for the following regression problem:
    - input: history_size consecutive H1 bars;
    - output: close price for the next bar.

    :param df: D1 bars for a range of dates
    :param history_size: how many bars should be considered for making a prediction
    :return: features and labels
    """
    n = len(df)
    xs = []
    ys = []
    for i in tqdm(range(n - history_size)):
        w = df.iloc[i: i + history_size + 1]

        x = w[['open', 'high', 'low', 'close']].iloc[:-1].values
        y = w.iloc[-1]['close']
        xs.append(x)
        ys.append(y)

    X = np.array(xs)
    y = np.array(ys)
    return X, y
###


# get prices
X, y = collect_dataset(df, history_size=inp_history_size)

# normalize prices
m = X.mean(axis=1, keepdims=True)
s = X.std(axis=1, keepdims=True)
X_norm = (X - m) / s
y_norm = (y - m[:, 0, 3]) / s[:, 0, 3]

# split data to train and test sets
X_train, X_test, y_train, y_test = train_test_split(X_norm, y_norm, test_size=0.2, random_state=0)

# define model
model = tf.keras.Sequential([
    tf.keras.layers.LSTM(64, input_shape=(inp_history_size, 4)),
    tf.keras.layers.BatchNormalization(),
    tf.keras.layers.Dropout(0.1),
    tf.keras.layers.Dense(32, activation='relu'),
    tf.keras.layers.BatchNormalization(),
    tf.keras.layers.Dropout(0.1),
    tf.keras.layers.Dense(32, activation='relu'),
    tf.keras.layers.Dense(1)
])

model.compile(optimizer='adam', loss='mse', metrics=['mae'])

# model training for 50 epochs
lr_reduction = tf.keras.callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.1, patience=3, min_lr=0.000001)
history = model.fit(X_train, y_train, epochs=50, verbose=2, validation_split=0.15, callbacks=[lr_reduction])

# model evaluation
test_loss, test_mae = model.evaluate(X_test, y_test)
print(f"test_loss={test_loss:.3f}")
print(f"test_mae={test_mae:.3f}")

# save model to onnx
output_path = data_path+inp_model_name
onnx_model = tf2onnx.convert.from_keras(model, output_path=output_path)
print(f"saved model to {output_path}")

# finish
mt5.shutdown()
Si presume che il nostro modello di regressione venga eseguito, il prezzo previsto risultante dovrebbe essere trasformato nelle seguenti classi: il prezzo scende, il prezzo non cambia, il prezzo sale. Ciò è necessario in modo da organizzare il classificatore del voto.

Il secondo modello è quello di classificazione.

È stato addestrato su EURUSD D1 dal 2010 alla fine del 2022. L'addestramento viene effettuato utilizzando una serie di 63 prezzi di chiusura. All'uscita deve essere definita una delle tre classi: il prezzo scenderà, il prezzo rimarrà entro 10 punti o il prezzo salirà. È a causa della seconda classe che abbiamo dovuto addestrare il modello utilizzando i dati a partire dal 2010 - prima di allora, nel 2009, i mercati sono passati da una precisione a 4 cifre a una a 5 cifre. Così, un vecchio punto è diventato dieci nuovi punti.

Come nel modello precedente, il prezzo è normalizzato. La normalizzazione è la stessa: dividiamo la deviazione dal prezzo medio della serie per la deviazione standard della serie. L'idea di questo modello è stata descritta nell'articolo “Financial timeseries forecasting with MLP in Keras" (in Russo). Anche questo modello è stato progettato solo a scopo dimostrativo.

# Copyright 2023, MetaQuotes Ltd.
# https://www.mql5.com
#
# Classification model
# 0,0,1 - predict price down
# 0,1,0 - predict price same
# 1,0,0 - predict price up
#

from datetime import datetime
import MetaTrader5 as mt5
import tensorflow as tf
import numpy as np
import pandas as pd
import tf2onnx
from sklearn.model_selection import train_test_split
from tqdm import tqdm
from keras.models import Sequential
from keras.layers import Dense, Activation,Dropout, BatchNormalization, LeakyReLU
from keras.optimizers import SGD
from keras import regularizers
from sys import argv

# initialize MetaTrader 5 client terminal
if not mt5.initialize():
    print("initialize() failed, error code =",mt5.last_error())
    quit()

# we will save the generated onnx-file near the our script
data_path=argv[0]
last_index=data_path.rfind("\\")+1
data_path=data_path[0:last_index]
print("data path to save onnx model",data_path)

# input parameters
inp_model_name = "model.eurusd.D1.63.onnx"
inp_history_size = 63
inp_start_date = datetime(2010, 1, 1, 0)
inp_end_date = datetime(2023, 1, 1, 0)

# get data from the client terminal
eurusd_rates = mt5.copy_rates_range("EURUSD", mt5.TIMEFRAME_D1, inp_start_date, inp_end_date)
df = pd.DataFrame(eurusd_rates)


#
# collect dataset subroutine
#
def collect_dataset(df: pd.DataFrame, history_size: int):
    """
    Collect dataset for the following regression problem:
    - input: history_size consecutive H1 bars;
    - output: close price for the next bar.

    :param df: H1 bars for a range of dates
    :param history_size: how many bars should be considered for making a prediction
    :return: features and labels
    """
    n = len(df)
    xs = []
    ys = []
    for i in tqdm(range(n - history_size)):
        w = df.iloc[i: i + history_size + 1]
        x = w[['close']].iloc[:-1].values

        delta = x[-1] - w.iloc[-1]['close']
        if np.abs(delta)<=0.0001:
           y = 0, 1, 0
        else:
           if delta<0:
              y = 1, 0, 0
           else:
              y = 0, 0, 1

        xs.append(x)
        ys.append(y)

    X = np.array(xs)
    Y = np.array(ys)
    return X, Y
###


# get prices
X, Y = collect_dataset(df, history_size=inp_history_size)

# normalize prices
m = X.mean(axis=1, keepdims=True)
s = X.std(axis=1, keepdims=True)
X_norm = (X - m) / s

# split data to train and test sets
X_train, X_test, Y_train, Y_test = train_test_split(X_norm, Y, test_size=0.1, random_state=0)

# define model
model = Sequential()
model.add(Dense(64, input_dim=inp_history_size, activity_regularizer=regularizers.l2(0.01)))
model.add(BatchNormalization())
model.add(LeakyReLU())
model.add(Dropout(0.3))
model.add(Dense(16, activity_regularizer=regularizers.l2(0.01)))
model.add(BatchNormalization())
model.add(LeakyReLU())
model.add(Dense(3))
model.add(Activation('softmax'))

opt = SGD(learning_rate=0.01, momentum=0.9)
model.compile(optimizer=opt, loss='categorical_crossentropy', metrics=['accuracy'])

# model training for 300 epochs
lr_reduction = tf.keras.callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.9, patience=5, min_lr=0.00001)
history = model.fit(X_train, Y_train, epochs=300, validation_data=(X_test, Y_test), shuffle = True, batch_size=128, verbose=2, callbacks=[lr_reduction])

# model evaluation
test_loss, test_accuracy = model.evaluate(X_test, Y_test)
print(f"test_loss={test_loss:.3f}")
print(f"test_accuracy={test_accuracy:.3f}")

# save model to onnx
output_path = data_path+inp_model_name
onnx_model = tf2onnx.convert.from_keras(model, output_path=output_path)
print(f"saved model to {output_path}")

# finish
mt5.shutdown()
I modelli sono stati addestrati con dati fino alla fine del 2022, lasciando così il periodo per dimostrare il loro funzionamento nel tester di strategie.


Un Assemblaggio di Modelli ONNX nell’Expert Advisor MQL5

Di seguito viene presentato un semplice Expert Advisor per dimostrare le possibilità di assemblaggio dei modelli. I principi principali dell'uso dei modelli ONNX in MQL5 sono stati descritti nella seconda parte dell'articolo precedente.

Dichiarazioni e definizioni avanzate

#include <Trade\Trade.mqh>

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

#resource "Python/model.eurusd.D1.10.onnx" as uchar ExtModel1[]
#resource "Python/model.eurusd.D1.63.onnx" as uchar ExtModel2[]

#define SAMPLE_SIZE1 10
#define SAMPLE_SIZE2 63

long     ExtHandle1=INVALID_HANDLE;
long     ExtHandle2=INVALID_HANDLE;
int      ExtPredictedClass1=-1;
int      ExtPredictedClass2=-1;
int      ExtPredictedClass=-1;
datetime ExtNextBar=0;
CTrade   ExtTrade;

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

Funzione OnInit

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   if(_Symbol!="EURUSD" || _Period!=PERIOD_D1)
     {
      Print("model must work with EURUSD,D1");
      return(INIT_FAILED);
     }

//--- create first model from static buffer
   ExtHandle1=OnnxCreateFromBuffer(ExtModel1,ONNX_DEFAULT);
   if(ExtHandle1==INVALID_HANDLE)
     {
      Print("First model OnnxCreateFromBuffer error ",GetLastError());
      return(INIT_FAILED);
     }
//--- 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_shape1[] = {1,SAMPLE_SIZE1,4};
   if(!OnnxSetInputShape(ExtHandle1,0,input_shape1))
     {
      Print("First model OnnxSetInputShape error ",GetLastError());
      return(INIT_FAILED);
     }
   
//--- 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_shape1[] = {1,1};
   if(!OnnxSetOutputShape(ExtHandle1,0,output_shape1))
     {
      Print("First model OnnxSetOutputShape error ",GetLastError());
      return(INIT_FAILED);
     }

//--- create second model from static buffer
   ExtHandle2=OnnxCreateFromBuffer(ExtModel2,ONNX_DEFAULT);
   if(ExtHandle2==INVALID_HANDLE)
     {
      Print("Second model OnnxCreateFromBuffer error ",GetLastError());
      return(INIT_FAILED);
     }
  
//--- 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_shape2[] = {1,SAMPLE_SIZE2};
   if(!OnnxSetInputShape(ExtHandle2,0,input_shape2))
     {
      Print("Second model OnnxSetInputShape error ",GetLastError());
      return(INIT_FAILED);
     }

//--- 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_shape2[] = {1,3};
   if(!OnnxSetOutputShape(ExtHandle2,0,output_shape2))
     {
      Print("Second model OnnxSetOutputShape error ",GetLastError());
      return(INIT_FAILED);
     }
//--- ok
   return(INIT_SUCCEEDED);
  }

Lo eseguiremo solo con EURUSD, D1. Questo perché utilizziamo i dati del simbolo/periodo corrente, mentre i modelli vengono addestrati utilizzando i prezzi giornalieri.

I modelli sono inclusi nell'Expert Advisor come risorse.

È importante definire esplicitamente le forme dei dati di ingresso e di uscita.

Funzione OnTick

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- check new bar
   if(TimeCurrent()<ExtNextBar)
      return;
//--- set next bar time
   ExtNextBar=TimeCurrent();
   ExtNextBar-=ExtNextBar%PeriodSeconds();
   ExtNextBar+=PeriodSeconds();

//--- predict price movement
   Predict();
//--- check trading according to prediction
   if(ExtPredictedClass>=0)
      if(PositionSelect(_Symbol))
         CheckForClose();
      else
         CheckForOpen();
  }

Tutte le operazioni di trading vengono effettuate solo all'inizio della giornata.

Funzione di previsione

//+------------------------------------------------------------------+
//| Voting classification                                            |
//+------------------------------------------------------------------+
void Predict(void)
  {
//--- evaluate first model
   ExtPredictedClass1=PredictPrice(ExtHandle1,SAMPLE_SIZE1);
//--- evaluate second model
   ExtPredictedClass2=PredictPriceMovement(ExtHandle2,SAMPLE_SIZE2);
//--- vote
   if(ExtPredictedClass1==ExtPredictedClass2)
      ExtPredictedClass=ExtPredictedClass1;
   else
      ExtPredictedClass=-1;
  }

Una classe si considera selezionata quando entrambi i modelli hanno ricevuto la stessa classe. Si tratta di una votazione a maggioranza. E poiché ci sono solo due modelli nel gruppo, il voto a maggioranza significa "unanime".

Previsione del prezzo di chiusura di giornata dai 10 prezzi OHLC precedenti

//+------------------------------------------------------------------+
//| Predict next price (first model)                                 |
//+------------------------------------------------------------------+
int PredictPrice(const long handle,const int sample_size)
  {
   static matrixf input_data(sample_size,4);    // matrix for prepared input data
   static vectorf output_data(1);               // vector to get result
   static matrix  mm(sample_size,4);            // matrix of horizontal vectors Mean
   static matrix  ms(sample_size,4);            // matrix of horizontal vectors Std
   static matrix  x_norm(sample_size,4);        // matrix for prices normalize

//--- prepare input data
   matrix rates;
//--- request last bars
   if(!rates.CopyRates(_Symbol,_Period,COPY_RATES_OHLC,1,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<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(handle,ONNX_NO_CONVERSION,input_data,output_data))
      return(-1);
//--- denormalize the price from the output value
   double predicted=output_data[0]*s[3]+m[3];
//--- classify predicted price movement
   int    predicted_class=-1;
   double delta=rates[3][sample_size-1]-predicted;
   if(fabs(delta)<=0.0001)
      predicted_class=PRICE_SAME;
   else
     {
      if(delta<0)
         predicted_class=PRICE_UP;
      else
         predicted_class=PRICE_DOWN;

     }

   return(predicted_class);
  }

I dati di input devono essere preparati seguendo le stesse regole che valgono per l'addestramento del modello. Dopo l'esecuzione del modello, il valore risultante viene riconvertito in prezzo. La classe viene calcolata in base alla differenza tra l'ultimo prezzo di chiusura della serie e il prezzo risultante.

La previsione del movimento dei prezzi si basa su una serie di 63 prezzi di chiusura giornalieri:

//+------------------------------------------------------------------+
//| Predict price movement (second model)                            |
//+------------------------------------------------------------------+
int PredictPriceMovement(const long handle,const int sample_size)
  {
   static vectorf input_data(sample_size);    // vector for prepared input data
   static vectorf output_data(3);             // vector to get result

//--- request last bars
   if(!input_data.CopyRates(_Symbol,_Period,COPY_RATES_CLOSE,1,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(handle,ONNX_NO_CONVERSION,input_data,output_data))
      return(-1);
//--- evaluate prediction
   return(int(output_data.ArgMax()));
  }

I prezzi sono normalizzati secondo le stesse regole del primo modello. Tuttavia, questa volta il codice è più compatto perché l'input è un vettore e non una matrice. La classe viene selezionata in base al valore massimo delle tre probabilità.

La strategia di trading è semplice. Le operazioni di trading vengono effettuate all'inizio di ogni giornata. Se la previsione è "il prezzo salirà", compriamo; se è "il prezzo scenderà", vendiamo.

//+------------------------------------------------------------------+
//| Check for open position conditions                               |
//+------------------------------------------------------------------+
void CheckForOpen(void)
  {
   ENUM_ORDER_TYPE signal=WRONG_VALUE;
//--- check signals
   if(ExtPredictedClass==PRICE_DOWN)
      signal=ORDER_TYPE_SELL;    // sell condition
   else
     {
      if(ExtPredictedClass==PRICE_UP)
         signal=ORDER_TYPE_BUY;  // buy condition
     }

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

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


Abbiamo addestrato il nostro modello con i dati fino all'inizio del 2023. Quindi, impostiamo l'intervallo del test dall'inizio dell'anno.

Impostazioni del test

Ecco i risultati dei test basati sui dati dall'inizio dell'anno.

Risultati del test dell’Expert Advisor


Sarebbe interessante conoscere i risultati dei test per ogni singolo modello.

Per farlo, modifichiamo il codice sorgente dell’EA come segue:

enum EnModels
  {
   USE_FIRST_MODEL,    // Use first model only
   USE_SECOND_MODEL,   // Use second model only
   USE_BOTH_MODELS     // Use both models
  };
input EnModels InpModels = USE_BOTH_MODELS;  // Models using
input double   InpLots   = 1.0;              // Lots amount to open position

...

//+------------------------------------------------------------------+
//| Voting classification                                            |
//+------------------------------------------------------------------+
void Predict(void)
  {
//--- evaluate first model
   if(InpModels==USE_BOTH_MODELS || InpModels==USE_FIRST_MODEL)
      ExtPredictedClass1=PredictPrice(ExtHandle1,SAMPLE_SIZE1);
//--- evaluate second model
   if(InpModels==USE_BOTH_MODELS || InpModels==USE_SECOND_MODEL)
      ExtPredictedClass2=PredictPriceMovement(ExtHandle2,SAMPLE_SIZE2);

//--- check predictions
   switch(InpModels)
     {
      case USE_FIRST_MODEL :
         ExtPredictedClass=ExtPredictedClass1;
         break;
      case USE_SECOND_MODEL :
         ExtPredictedClass=ExtPredictedClass2;
         break;
      case USE_BOTH_MODELS :
         if(ExtPredictedClass1==ExtPredictedClass2)
            ExtPredictedClass=ExtPredictedClass1;
         else
            ExtPredictedClass=-1;
     }
  }

Abilitare il parametro "Usa solo il primo modello".

Impostazioni dell’Expert Advisor per utilizzare solo il primo modello

Risultati del test del primo modello

Risultati del test del primo modello


Verifichiamo ora il secondo modello. Ecco i risultati del test del secondo modello.

Risultati del test del secondo modello

Il secondo modello si è rivelato molto più resistente del primo. I risultati confermano la teoria secondo cui i modelli deboli devono stare in gruppo. Tuttavia, questo articolo non riguardava la teoria dell'assemblaggio, ma l'applicazione pratica.

Nota importante: Notare che i modelli utilizzati nell'articolo sono presentati solo per dimostrare come lavorare con i modelli ONNX utilizzando il linguaggio MQL5. L'Expert Advisor non è destinato al trading su conti reali.



Conclusioni

Abbiamo presentato un esempio molto semplice ma illustrativo di un assemblaggio di due modelli ONNX. Il numero di modelli utilizzati contemporaneamente è limitato e non può superare i 256 modelli. Tuttavia, anche l'utilizzo di più di due modelli richiederà un approccio diverso nella programmazione dell'Expert Advisor, ovvero una programmazione orientata agli oggetti.

Ma questo è un argomento per un altro articolo.

Tradotto dal russo da MetaQuotes Ltd.
Articolo originale: https://www.mql5.com/ru/articles/12433

File allegati |
MQL5.zip (105.08 KB)
Ultimi commenti | Vai alla discussione (7)
mysticsoul
mysticsoul | 12 apr 2023 a 12:49

Ho impostato la stessa data e le stesse impostazioni, ma i risultati sono stati diversi. Qualcuno sa perché?

Risultati del test del primo modello


Risultati del primo test del modello


Risultati del test del secondo modello


risultati del test del secondo modello
Slava
Slava | 12 apr 2023 a 15:06
mysticsoul #: Ho impostato la stessa data e le stesse impostazioni, ma i risultati sono stati diversi. Qualcuno sa perché?

Potrebbe essere dovuto al fatto che il vostro server di trading non è MetaQuotes-Demo.

Rasoul Mojtahedzadeh
Rasoul Mojtahedzadeh | 12 apr 2023 a 23:04
mysticsoul #:

Ho impostato la stessa data e le stesse impostazioni, ma i risultati sono stati diversi. Qualcuno sa perché?

Risultati del test del primo modello

Risultati del secondo modello
Potrebbe essere dovuto a una differenza nell'inizializzazione del peso dei modelli. Purtroppo non utilizzano la tecnica del "seeding everything" per rendere i loro risultati riproducibili.
linfo2
linfo2 | 13 apr 2023 a 20:33

Innanzitutto, grazie mille per aver messo insieme questo documento, è bello guardare in diverse direzioni. È facile da seguire e ben strutturato.

Per quanto mi riguarda, ottengo percentuali di successo simili e un numero di operazioni leggermente inferiore con il conto demo, ma quando utilizzo il conto demo di meta trader. Con il mio conto di trading si opera solo una volta. Presumo che sia il fuso orario del broker, il mio broker è in Australia (GMT+10). La prima transazione dal conto demo è; Core 1 2023.01.02 07:02:00 deal #2 sell 1 EURUSD at 1.07016 done(based on order #2)

La prima transazione dal mio Broker Australia (GMT+10) è; Core 1 2023.01.03 00:00:00 failed market sell 1 EURUSD [Mercato chiuso] e non so esattamente come risolverlo. Forse l'intero modello dipende dal fuso orario. Se così fosse i tempi dovrebbero essere espressi in ore intere, ma come fa la transazione iniziale 2023.01.02 07:02:00 a diventare 2023.01.03 00:00:00?

Apprezzerei qualsiasi suggerimento sulla causa di questo problema.



Too Chee Ng
Too Chee Ng | 19 nov 2023 a 19:28
Slava #:
servizio commerciale

Lo stesso, riesco a riprodurre risultati molto simili con i file onnx originali sul mio conto MetaQuates-Demo.

Poi, riesco a riaddestrare le ML di Python fino al completamento, anche se con i seguenti avvertimenti/errori che possono essere ignorati:

D:\MT5 Demo1\MQL5\Experts\article_12433\Python>python ONNX.eurusd.D1.10.Training.py
2023-11-19 18:07:38.169418: W tensorflow/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'cudart64_110.dll'; dlerror: cudart64_110.dll not found
2023-11-19 18:07:38.169664: I tensorflow/stream_executor/cuda/cudart_stub.cc:29] Ignore above cudart dlerror if you do not have a GPU set up on your machine.
data path to save onnx model
100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 5187/5187 [00:00<00:00, 6068.93it/s]
2023-11-19 18:07:40.434910: W tensorflow/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'nvcuda.dll'; dlerror: nvcuda.dll not found
2023-11-19 18:07:40.435070: W tensorflow/stream_executor/cuda/cuda_driver.cc:263] failed call to cuInit: UNKNOWN ERROR (303)
2023-11-19 18:07:40.437138: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:169] retrieving CUDA diagnostic information for host: WIN-SSPXX7BO0B0
2023-11-19 18:07:40.437323: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:176] hostname: WIN-SSPXX7BO0B0
2023-11-19 18:07:40.437676: I tensorflow/core/platform/cpu_feature_guard.cc:193] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX AVX2
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
Epoch 1/50
111/111 - 1s - loss: 1.6160 - mae: 0.9378 - val_loss: 2.7602 - val_mae: 1.3423 - lr: 0.0010 - 1s/epoch - 12ms/step
Epoch 2/50
111/111 - 0s - loss: 1.4932 - mae: 0.8952 - val_loss: 2.4339 - val_mae: 1.2412 - lr: 0.0010 - 287ms/epoch - 3ms/step
...

entrambi gli script ML terminano con:

111/111 - 0 s - loss: 1.2812 - mae: 0.8145 - val_loss: 1.2598 - val_mae: 0.8142 - lr: 1.0000 e-06 - 366 ms/epoch - 3 ms/step
Epoch 50/50
111/111 - 0 s - loss: 1.3030 - mae: 0.8203 - val_loss: 1.2604 - val_mae: 0.8143 - lr: 1.0000 e-06 - 365 ms/epoch - 3 ms/step
33/33 [==============================] - 0 s 1 ms/step - loss: 1.1542 - mae: 0.7584
test_loss=1.154
test_mae=0.758
2023-11-19 18:07:57.480814: I tensorflow/core/grappler/devices.cc:66] Number of eligible GPUs (core count >= 8, compute capability >= 0.0): 0
2023-11-19 18:07:57.481315: I tensorflow/core/grappler/clusters/single_machine.cc:358] Starting new session
2023-11-19 18:07:57.560110: I tensorflow/core/grappler/devices.cc:66] Number of eligible GPUs (core count >= 8, compute capability >= 0.0): 0
2023-11-19 18:07:57.560380: I tensorflow/core/grappler/clusters/single_machine.cc:358] Starting new session
2023-11-19 18:07:57.611678: I tensorflow/compiler/mlir/mlir_graph_optimization_pass.cc:354] MLIR V1 optimization pass is not enabled
saved model to model.eurusd.D1.10.onnx
24/24 - 0 s - loss: 0.6618 - accuracy: 0.6736 - val_loss: 0.8993 - val_accuracy: 0.4759 - lr: 4.1746 e-05 - 37 ms/epoch - 2 ms/step
Epoch 300/300
24/24 - 0 s - loss: 0.6531 - accuracy: 0.6770 - val_loss: 0.8997 - val_accuracy: 0.4789 - lr: 4.1746 e-05 - 39 ms/epoch - 2 ms/step
11/11 [==============================] - 0 s 682 us/step - loss: 0.8997 - accuracy: 0.4789
test_loss=0.900
test_accuracy=0.479
2023-11-19 18:07:19.838160: I tensorflow/core/grappler/devices.cc:66] Number of eligible GPUs (core count >= 8, compute capability >= 0.0): 0
2023-11-19 18:07:19.838516: I tensorflow/core/grappler/clusters/single_machine.cc:358] Starting new session
2023-11-19 18:07:19.872285: I tensorflow/core/grappler/devices.cc:66] Number of eligible GPUs (core count >= 8, compute capability >= 0.0): 0
2023-11-19 18:07:19.872584: I tensorflow/core/grappler/clusters/single_machine.cc:358] Starting new session
saved model to model.eurusd.D1.63.onnx

Successivamente ricompilo l'originale ONNX.Price.Prediction.2M.D1.mq5 per utilizzare i nuovi ML addestrati.

I risultati del backtest con lo stesso conto MetaQuates-Demo sono molto diversi da quelli originali, il che non è positivo.

Mi piacerebbe molto sapere cosa è andato storto?
Grazie mille.

Matrici e vettori in MQL5: Funzioni di attivazione Matrici e vettori in MQL5: Funzioni di attivazione
Qui descriveremo solo uno degli aspetti dell'apprendimento automatico - le funzioni di attivazione. Nelle reti neurali artificiali, una funzione di attivazione del neurone calcola il valore di un segnale di output in base ai valori di un segnale di input o di un insieme di segnali di input. Ci addentreremo nei meccanismi interni del processo.
Sviluppare un Expert Advisor di trading da zero (Parte 25): Fornire robustezza al sistema (II) Sviluppare un Expert Advisor di trading da zero (Parte 25): Fornire robustezza al sistema (II)
In questo articolo, faremo il passo finale verso le prestazioni dell'EA. Preparatevi quindi a una lunga lettura. Per rendere il nostro Expert Advisor affidabile, per prima cosa rimuoveremo dal codice tutto ciò che non fa parte del sistema di trading.
Implementare i modelli ONNX in classi Implementare i modelli ONNX in classi
La programmazione orientata agli oggetti consente di creare un codice più compatto che sia facile da leggere e da modificare. Qui di seguito vedremo l'esempio di tre modelli ONNX.
Sviluppare un Expert Advisor per il trading da zero (Parte 24): Fornire robustezza al sistema (I) Sviluppare un Expert Advisor per il trading da zero (Parte 24): Fornire robustezza al sistema (I)
In questo articolo renderemo il sistema più affidabile per garantire un utilizzo robusto e sicuro. Uno dei modi per raggiungere la robustezza desiderata è cercare di riutilizzare il codice il più possibile in modo che venga costantemente testato in casi differenti. Ma questo è solo uno dei modi. Un altro è usare l'OOP.