Проверка модели в тестере стратегий

Модели для работы с финансовыми рынками можно проверять в тестере стратегий терминала MetaTrader 5. Это самый быстрый и удобный вариант, не требующий дополнительных усилий по эмуляции рыночного окружения и торговых условий.

Для проверки модели перепишем код из публичного проекта ONNX.Price.Prediction в советника. Это потребует небольших правок.

Создание модели перенесем в функцию OnInit, а завершение onnx-сессии в OnDeinit. Основной блок по работе с моделью поместим в обработчик OnTick.

Добавим также получение цены закрытия 2-х предыдущих баров, чтобы сравнивать актуальную цену закрытия и предсказание.

Код советника небольшой и читается просто.

 
const long   ExtInputShape [] = {1,10,4}; // форма входных данных модели
const long   ExtOutputShape[] = {1,1};    // форма выходных данных модели
#resource "Python/model.onnx" as uchar ExtModel[];// модель в виде ресурса
 
long handle;         // хендл модели
ulong predictions=0// счетчик предсказаний
ulong confirmed=0;   // счетчик успешных предсказаний
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- базовые проверки
   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);
     }
//--- создаём модель
   handle=OnnxCreateFromBuffer(ExtModel,ONNX_DEBUG_LOGS);
//--- укажем форму входных данных
   if(!OnnxSetInputShape(handle,0,ExtInputShape))
     {
      Print("OnnxSetInputShape failed, error ",GetLastError());
      OnnxRelease(handle);
      return(-1);
     }
//--- укажем форму выходных данных
   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)
  {
//--- завершили работу модели
   OnnxRelease(handle);
//--- посчитаем и выведем статистику предсказаний
   PrintFormat("Successfull predictions = %.2f %%",confirmed*100./double(predictions));
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   static datetime open_time=0;
   static double predict;
//--- проверим время открытия текущего бара
   datetime time=iTime(_Symbol,_Period,0);
   if(time==0)
     {
      PrintFormat("Failed to get Time(0), error %d"GetLastError());
      return;
     }
//--- если время открытия бара не изменилось, то выходим до следующего вызова OnTick
   if(time==open_time)
      return;
//--- получим цены закрытия 2-х последних завершенных баров
   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]; // предсказанное изменение цены
   double delta_actual=close[1]-close[0]; // действительное изменение цены
   if((delta_predict>0 && delta_actual>0) || (delta_predict<0 && delta_actual<0))
      confirmed++;
 
//--- вычислим на новом баре цену закрытия, чтобы проверить на следующем баре
   matrix rates;
//--- получаем 10 баров
   if(!rates.CopyRates("EURUSD",PERIOD_H1,COPY_RATES_OHLC,1,10))
      return;
//--- подаем на вход набор векторов 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);
//--- заполним матрицы нормировки
   for(int i=0i<10i++)
     {
      mm.Row(m,i);
      ms.Row(s,i);
     }
//--- нормируем входные данные
   x_norm-=mm;
   x_norm/=ms;
//--- конвертируем нормированные входные данные в тип float
   matrixf x_normf;
   x_normf.Assign(x_norm);
//--- сюда получим выходные данные модели - предсказание цены
   vectorf y_norm(1);
//--- запускаем модель
   if(!OnnxRun(handle,ONNX_DEBUG_LOGS | ONNX_NO_CONVERSION,x_normf,y_norm))
     {
      Print("OnnxRun failed, error ",GetLastError());
     }
//--- сделаем обратное преобразование для получения предсказанной цены и проверки на новом баре
   predict=y_norm[0]*s[3]+m[3];
   predictions++;  // увеличим счетчик предсказаний
   Print(predictions,". close prediction = ",predict);
//--- запомним время открытия бара для проверки на следующем тике
   open_time=time;
  }

Компилируем советника и запускаем тестирование на интервале 2022 года, указывем символ EURUSD и таймфрейм H1, на которых тренировалась модель. Режим моделирования тиков значения не имеет, так как в коде есть проверка появления нового бара.  

Настройки тестирования

 

Запускаем и получаем результат в журнале тестирования — чуть более 50% верных предсказаний за 2022 год.

Журнал тестирования

 

В случае, если результаты предварительной проверки модели удовлетворительны, можно приступать к написанию полноценной торговой стратегии с её использованием.