策略测试中的模型验证

为金融市场操作创建的模型可以在 MetaTrader 5程序端策略测试部分进行验证。这是最快、最方便的选项,无需额外模拟市场环境和交易条件。

若要测试模型,需要根据公共项目ONNX.Price.Prediction的代码创建一个EA交易程序。这将需要进行一些编辑。

将模型创建移至OnInit函数。onnx会话将在OnDeinit中关闭。将主要模型操作块定位到OnTick处理程序。

此外,添加获取前两个柱形图的收盘价,需要与实际收盘价和预测收盘价进行比较。

Expert Advisor 代码小且易于阅读。

 
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;   // 成功预测计数器
//+------------------------------------------------------------------+
//| EA交易初始化函数                                                   |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| EA交易去初始化函数                                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- 完成模型操作
   OnnxRelease(handle);
//--- 计算和输出预测统计
   PrintFormat("Successfull predictions = %.2f %%",confirmed*100./double(predictions));
  }
//+------------------------------------------------------------------+
//| EA报价函数                                                        |
//+------------------------------------------------------------------+
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;
//--- 获取最后两个已完成柱形图的收盘价
   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]; // predicted price change
   double delta_actual=close[1]-close[0]; // actual price change
   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;
//--- 将标准化输入数据转换为浮点类型
   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;
  }

编译EA交易,并在2022年期间运行测试。使用H1时间周期指定EURUSD,这是训练模型的数据。可以忽略报价建模模式,因为代码检查的是新柱形图的出现。 

回测设置

 

运行并在测试日志中查看结果。它表明略高于50%的预测在2022年是正确的。

测试日志

 

如果初步模型测试产生令人满意的结果,您可以开始基于此模型编写完整的交易策略。