Verificação do modelo no testador de estratégia

Os modelos para mercados financeiros podem ser testados no testador de estratégias do terminal MetaTrader 5. Essa é a opção mais rápida e conveniente que não exige esforços adicionais para emular o ambiente de mercado e as condições de negociação.

Reescreveremos o código do projeto público ONNX.Price.Prediction no EA para verificar o modelo. Isso requer pequenas edições.

Transferimos a criação do modelo para a função OnInit e encerramos a sessão onnx em OnDeinit. Colocamos o bloco principal de manipulação do modelo no manipulador OnTick.

Também adicionamos uma função para obter o preço de fechamento das duas barras anteriores a fim de comparar o preço de fechamento real e a previsão.

O código do EA é pequeno e fácil de ler.

 
const long   ExtInputShape [] = {1,10,4}; // forma dos dados de entrada do modelo
const long   ExtOutputShape[] = {1,1};    // forma dos dados de saída do modelo
#resource "Python/model.onnx" as uchar ExtModel[];// modelo em forma de recurso
 
long handle;         // identificador do modelo
ulong predictions=0// contador de previsões
ulong confirmed=0;   // contador de previsões bem-sucedidas
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- verificações básicas
   if(_Symbol!="EURUSD")
     {
      Print("Symbol must be EURUSD, testing aborted");
      return(-1);
     }
   if(_Period!=PERIOD_H1)
     {
      Print("Timeframe must be H1, testing aborted");
      return(-1);
     }
//--- criamos o modelo
   handle=OnnxCreateFromBuffer(ExtModel,ONNX_DEBUG_LOGS);
//--- especificamos a forma dos dados de entrada
   if(!OnnxSetInputShape(handle,0,ExtInputShape))
     {
      Print("OnnxSetInputShape failed, error ",GetLastError());
      OnnxRelease(handle);
      return(-1);
     }
//--- especificamos a forma dos dados de saída
   if(!OnnxSetOutputShape(handle,0,ExtOutputShape))
     {
      Print("OnnxSetOutputShape failed, error ",GetLastError());
      OnnxRelease(handle);
      return(-1);
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- concluímos o trabalho do modelo
   OnnxRelease(handle);
//--- calculamos e exibimos estatísticas de previsão
   PrintFormat("Successfull predictions = %.2f %%",confirmed*100./double(predictions));
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   static datetime open_time=0;
   static double predict;
//--- verificamos o tempo de abertura da barra atual
   datetime time=iTime(_Symbol,_Period,0);
   if(time==0)
     {
      PrintFormat("Failed to get Time(0), error %d"GetLastError());
      return;
     }
//--- se o tempo de abertura da barra não muda, então saímos antes da próxima chamada OnTick
   if(time==open_time)
      return;
//--- obtemos os preços de fechamento das últimas 2 barras concluídas
   double close[];
   int recieved=CopyClose(_Symbol,_Period,1,2,close);
   if(recieved!=2)
     {
      PrintFormat("CopyClose(2 bars) failed, error %d",GetLastError());
      return;
     }
   double delta_predict=predict-close[0]; // movimento de preço previsto
   double delta_actual=close[1]-close[0]; // variação real de preços
   if((delta_predict>0 && delta_actual>0) || (delta_predict<0 && delta_actual<0))
      confirmed++;
 
//--- calculamos o preço de fechamento em uma nova barra para verificar na próxima barra
   matrix rates;
//--- obtemos 10 barras
   if(!rates.CopyRates("EURUSD",PERIOD_H1,COPY_RATES_OHLC,1,10))
      return;
//--- alimentamos com um conjunto de vetores OHLC
   matrix x_norm=rates.Transpose();
   vector m=x_norm.Mean(0);
   vector s=x_norm.Std(0);
   matrix mm(10,4);
   matrix ms(10,4);
//--- preenchemos matrizes de normalização
   for(int i=0i<10i++)
     {
      mm.Row(m,i);
      ms.Row(s,i);
     }
//--- normalizamos os dados de entrada
   x_norm-=mm;
   x_norm/=ms;
//--- convertemos dados de entrada normalizados em dados do tipo float
   matrixf x_normf;
   x_normf.Assign(x_norm);
//--- obtemos o resultado do modelo - a previsão de preço
   vectorf y_norm(1);
//--- iniciamos o modelo
   if(!OnnxRun(handle,ONNX_DEBUG_LOGS | ONNX_NO_CONVERSION,x_normf,y_norm))
     {
      Print("OnnxRun failed, error ",GetLastError());
     }
//--- realizamos uma transformação inversa para obter o preço previsto e verificamos em uma nova barra
   predict=y_norm[0]*s[3]+m[3];
   predictions++;  // aumentamos o contador de previsões
   Print(predictions,". close prediction = ",predict);
//--- memorizamos o tempo de abertura da barra para verificar no próximo tick
   open_time=time;
  }

Compilamos o Expert Advisor e começamos a testar no intervalo 2022, especificando o símbolo EURUSD e o período de tempo H1 com os quais o modelo foi treinado. O modo de simulação de ticks não importa, pois o código tem uma verificação do aparecimento de nova barra.  

Configurações de teste

 

Executamos e obtemos o resultado no log de teste – pouco mais de 50% das previsões corretas para 2022.

Log de teste

 

Se os resultados da verificação preliminar do modelo forem satisfatórios, podemos começar a escrever uma estratégia de negociação completa e usá-la.