ストラテジーテスターーでのモデルの検証

金融市場での運用のために作成されたモデルは、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;   // 成功した予測のカウンタ
//+------------------------------------------------------------------+
//| エキスパート初期化関数                                                |
//+------------------------------------------------------------------+
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);
 }
//+------------------------------------------------------------------+
//| エキスパート初期化解除関数                                             |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
 {
//--- モデル操作を完成する
  OnnxRelease(handle);
//--- 予測統計を計算して出力する
  PrintFormat("Successfull predictions = %.2f %%",confirmed*100./double(predictions));
 }
//+------------------------------------------------------------------+
//| エキスパートティック関数                                                 |
//+------------------------------------------------------------------+
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=0; i<10; i++)
    {
    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時間枠で指定します。これは、モデルが訓練されたデータです。コードは新しいバーの出現を確認するため、ティックモデリングモードは無視できます。 

バックテストの設定

 

実行して、テスト操作ログで結果を確認します。2022年には予測の50%強が正しかったことが示されています。

テスト操作ログ

 

予備的なモデルのテストで満足のいく結果が得られた場合は、このモデルに基づいて本格的な取引戦略の作成を開始できます。