모델 실행

MQL5에서 ONNX 모델을 실행하려면 다음과 같은 3단계를 거치세요:

  1. 다음을 사용하여 *.onnx 파일에서 모델을 로드합니다.OnnxCreate 함수 또는 배열OnnxCreateFromBuffer.
  2. 다음을 사용하여 입력 및 출력 데이터 쉐이프 지정OnnxSetInputShape와OnnxSetOutputShape 함수.
  3. OnnxRun함수를 사용하여 모델을 실행합니다. 관련 입력 및 출력 매개변수에 전달합니다.
  4. 필요한 경우 다음을 사용하여 모델 작업을 종료할 수 있습니다.OnnxRelease 함수.

 

ONNX 모델을 생성할 때 https://github.com/microsoft/onnxruntime/blob/rel-1.14.0/docs/OperatorKernels.md에 설명된 현재 제한 사항 및 금지 사항을 고려해야 합니다.

이러한 제한 사항의 일부 예는 다음과 같습니다:

Operation

지원되는 데이터 유형

ReduceSum

tensor(double), tensor(float), tensor(int32), tensor(int64)

Mul

tensor(bfloat16), tensor(double), tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)

 

아래는 공개 프로젝트의 MQL5 코드 예제입니다.ONNX.Price.Prediction.

const long   ExtOutputShape[] = {1,1};    // 모델의 출력 쉐이프
const long   ExtInputShape [] = {1,10,4}; // 모델의 입력 쉐이프
#resource "Python/model.onnx" as uchar ExtModel[]// 자원으로서의 모델
/+------------------------------------------------------------------+
//| 프로그램 시작 함수 스크립트                                        |
/+------------------------------------------------------------------+
int OnStart(void)
  {
   matrix rates;
//--- 10개 바
   if(!rates.CopyRates("EURUSD",PERIOD_H1,COPY_RATES_OHLC,2,10))
      return(-1);
//--- 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;
//--- 모델 생성
   long 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);
     }
//--- 정규화된 입력 데이터를 부동 소수점 유형으로 변환
   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());
      OnnxRelease(handle);
      return(-1);
     }
//--- 모델의 출력 값을 로그에 출력
   Print(y_norm);
//--- 역변환을 수행하여 예상 가격을 얻습니다.
   double y_pred=y_norm[0]*s[3]+m[3];
   Print("price predicted:",y_pred);
//--- 작업 완료
   OnnxRelease(handle);
   return(0);
  }

스크립트 실행 예:

ONNX: Creating and using per session threadpools since use_per_session_threads_ is true
ONNX: Dynamic block base set to 0
ONNX: Initializing session.
ONNX: Adding default CPU execution provider.
ONNX: Total shared scalar initializer count: 0
ONNX: Total fused reshape node count: 0
ONNX: Total shared scalar initializer count: 0
ONNX: Total fused reshape node count: 0
ONNX: Use DeviceBasedPartition as default
ONNX: Saving initialized tensors.
ONNX: Done saving initialized tensors
ONNX: Session successfully initialized.
[0.28188983]
predicted 1.0559258806393044

MetaTrader 5 터미널은 계산을 위한 최적의 executor를 선택했습니다 —ONNX Runtime Execution Provider. 이 예에서 모델은 CPU에서 실행되었습니다.

이전 10개 바의 값을 기반으로 괜찮은 레벨의 종가 예측의 백분율을 계산하도록 스크립트를 수정해 보겠습니다.

#resource "Python/model.onnx" as uchar ExtModel[]// 자원으로서의 모델
 
#define TESTS 10000  // 테스트 데이터세트의 수
/+------------------------------------------------------------------+
//| 프로그램 시작 함수 스크립트                                        |
/+------------------------------------------------------------------+
int OnStart()
  {
//--- 모델 생성
   long session_handle=OnnxCreateFromBuffer(ExtModel,ONNX_DEBUG_LOGS);
   if(session_handle==INVALID_HANDLE)
     {
      Print("Cannot create model. Error ",GetLastError());
      return(-1);
     }
 
//--- 입력 텐서 크기가 모델에 대해 정의되어 있지 않으므로 명시적으로 지정합니다.
//--- 첫 번째 인덱스는 배치 크기, 두 번째 인덱스는 시리즈 크기, 세 번째 인덱스는 시리즈 수(OHLC)
   const long input_shape[]={1,10,4};
   if(!OnnxSetInputShape(session_handle,0,input_shape))
     {
      Print("OnnxSetInputShape error ",GetLastError());
      return(-2);
     }
 
//--- 출력 텐서 크기가 모델에 개해 정의되어 있지 않으므로 명시적으로 지정합니다.
//--- 첫 번째 인덱스는 배치 크기이며 입력 텐서의 배치 크기와 일치해야 합니다.
//--- 두 번째 인덱스는 예상 가격들의 수입니다(여기서는 종가만 예측됨).
   const long output_shape[]={1,1};
   if(!OnnxSetOutputShape(session_handle,0,output_shape))
     {
      Print("OnnxSetOutputShape error ",GetLastError());
      return(-3);
     }
//--- 테스트 실행
   vector closes(TESTS);      // 검증 가격을 저장할 벡터
   vector predicts(TESTS);    // 구한 예측들을 저장할 벡터
   vector prev_closes(TESTS); // 이어지는 가격들을 저장할 벡터
 
   matrix rates;              // OHLC 시리즈를 얻기 위한 행렬
matrixsplitted[2];// 시리즈를 테스트와 검증으로 나누는 두 부분 행렬
   ulong  parts[]={10,1};     // 나누어진 부분 행렬�l 크기
 
//--- 이전 바부터 시작
   for(int i=1; i<=TESTS; i++)
     {
      //--- 11개의 바를 얻음
      rates.CopyRates("EURUSD",PERIOD_H1,COPY_RATES_OHLC,i,11);
//--- 행렬을 테스트와 검증으로 나눕니다.
      rates.Vsplit(parts,splitted);
//--- 유효성 검증 매트릭스에서 종가를 가져옵니다.
      closes[i-1]=splitted[1][3][0];
//--- 테스트된 시리즈의 마지막 종가
      prev_closes[i-1]=splitted[0][3][9];
 
//--- 10개의 바의 테스트 매트릭스를 테스팅에 제출
      predicts[i-1]=PricePredictionTest(session_handle,splitted[0]);
//--- 런타임 에러
      if(predicts[i-1]<=0)
        {
         OnnxRelease(session_handle);
         return(-4);
        }
     }
//--- 작업 완료
   OnnxRelease(session_handle);
//--- 가격 움직임이 올바르게 예측되었는지를 평가
   int    right_directions=0;
   vector delta_predicts=prev_closes-predicts;
   vector delta_actuals=prev_closes-closes;
 
   for(int i=0; i<TESTS; i++)
      if((delta_predicts[i]>0 && delta_actuals[i]>0) || (delta_predicts[i]<0 && delta_actuals[i]<0))
         right_directions++;
   PrintFormat("right direction predictions = %.2f%%",(right_directions*100.0)/double(TESTS));
//--- 
   return(0);
  }
/+------------------------------------------------------------------+
//| 데이터 준비하고 모델 실행                                          |
/+------------------------------------------------------------------+
double PricePredictionTest(const long session_handle,matrix& rates)
  {
   static matrixf input_data(10,4); // 변환된 입력을 위한 행렬
   static vectorf output_data(1);   // 결과를 받을 벡터
   static matrix mm(10,4);          //수평 벡터의 행렬 Mean
   static matrix ms(10,4);          // 수평 벡터의 Std
 
//--- OHLC 수직 벡터 세트가 모델에 입력되어야 합니다.
   matrix x_norm=rates.Transpose();
//--- 가격 정규화
   vector m=x_norm.Mean(0);
   vector s=x_norm.Std(0);
   for(int i=0; i<10; i++)
     {
      mm.Row(m,i);
      ms.Row(s,i);
     }
   x_norm-=mm;
   x_norm/=ms;
 
//--- 모델 실행
   input_data.Assign(x_norm);
   if(!OnnxRun(session_handle,ONNX_DEBUG_LOGS,input_data,output_data))
     {
      Print("OnnxRun error ",GetLastError());
      return(0);
     }
//--- 출력 값에서 가격을 비정규화
   double y_pred=output_data[0]*s[3]+m[3];
 
   return(y_pred);
  }

스크립트 실행: 예측 정확도는 약 51%입니다.

ONNX: Creating and using per session threadpools since use_per_session_threads_ is true
ONNX: Dynamic block base set to 0
ONNX: Initializing session.
ONNX: Adding default CPU execution provider.
ONNX: Total shared scalar initializer count: 0
ONNX: Total fused reshape node count: 0
ONNX: Total shared scalar initializer count: 0
ONNX: Total fused reshape node count: 0
ONNX: Use DeviceBasedPartition as default
ONNX: Saving initialized tensors.
ONNX: Done saving initialized tensors
ONNX: Session successfully initialized.
올바른 방향 예측 = 51.34%