dualea/Experts/Advisors/DualEA/Tests/Test_NativeModelPolicy.mq5
70 lines
4.1 KiB
MQL5
Princeec13
2026-10-28 00:31:51 -04:00
#property strict
#include "..\Include\ModelPredictor.mqh"
#include "..\Include\PolicyHttpBridge.mqh"
// Test-only identity graph: checks native inference and scaler plumbing.
// This fixture is not a trained trading model and is never installed in DualEA.
const uchar SyntheticModel[]={8,8,18,46,68,117,97,108,69,65,32,114,101,103,114,101,115,115,105,111,110,32,102,105,120,116,117,114,101,44,32,110,111,116,32,97,32,116,114,97,105,110,101,100,32,109,111,100,101,108,58,119,10,33,10,8,102,101,97,116,117,114,101,115,18,11,112,114,111,98,97,98,105,108,105,116,121,34,8,73,100,101,110,116,105,116,121,18,23,83,89,78,84,72,69,84,73,67,95,67,79,78,84,82,65,67,84,95,79,78,76,89,90,26,10,8,102,101,97,116,117,114,101,115,18,14,10,12,8,1,18,8,10,2,8,1,10,2,8,2,98,29,10,11,112,114,111,98,97,98,105,108,105,116,121,18,14,10,12,8,1,18,8,10,2,8,1,10,2,8,2,66,2,16,13};
int g_checks=0;
int g_failures=0;
void Check(bool passed,string name)
{
g_checks++;
Print("[NATIVE-CONTRACT] ",passed ? "PASS: " : "FAIL: ",name);
if(!passed) g_failures++;
}
bool WriteText(string path,string text)
{
int file=FileOpen(path,FILE_WRITE|FILE_BIN);
if(file==INVALID_HANDLE) return false;
uchar bytes[];
int length=StringToCharArray(text,bytes,0,WHOLE_ARRAY,CP_UTF8)-1;
bool ok=(FileWriteArray(file,bytes,0,length)==(uint)length);
FileClose(file);
return ok;
}
int OnInit()
{
FolderCreate("NativeContract");
string model_path="NativeContract\\synthetic_identity.onnx";
string config_path="NativeContract\\synthetic.ini";
int file=FileOpen(model_path,FILE_WRITE|FILE_BIN);
if(file==INVALID_HANDLE) return INIT_FAILED;
uint written=FileWriteArray(file,SyntheticModel,0,ArraySize(SyntheticModel));
FileClose(file);
Check(written==ArraySize(SyntheticModel),"write test-only model fixture");
Check(WriteText(config_path,"feature_count=2\nfeature_names=a|b\nscaler_mean=1|2\nscaler_scale=2|4\n"),"write UTF-8 INI fixture");
CModelPredictor predictor;
Check(!predictor.IsReady(),"new predictor is not ready");
Check(!predictor.Init("NativeContract\\absent.onnx","",config_path),"missing model fails initialization");
Check(!predictor.IsReady(),"missing model cannot mark predictor ready");
Check(predictor.Init(model_path,"",config_path),"native identity model initializes without DLL");
Check(predictor.FeatureCount()==2,"INI feature count is exact");
string names[];
predictor.GetFeatureNames(names);
Check(ArraySize(names)==2 && names[0]=="a" && names[1]=="b","feature order preserved");
double features[]={1.4,5.2};
double probability=predictor.Predict(features,2);
Check(MathAbs(probability-0.8)<0.00001,"raw features standardize to [0.2,0.8] and infer probability 0.8");
Check(predictor.Predict(features,1)<0,"wrong feature count returns failure sentinel");
features[0]=1.0e300;
Check(predictor.Predict(features,2)<0,"overflowing float input rejected");
predictor.Shutdown();
Check(!predictor.IsReady(),"shutdown releases native session");
Check(predictor.Predict(features,2)<0,"prediction after shutdown fails");
Check(WriteText(config_path,"feature_count=2\nfeature_names=a|b\nscaler_mean=1|2\nscaler_scale=2\n"),"write malformed metadata fixture");
Check(!predictor.Init(model_path,"",config_path),"inconsistent scaler length rejected");
Check(WriteText(config_path,"feature_count=2\nfeature_names=a|b\nscaler_mean=1|2\nscaler_scale=2|0\n"),"write zero-scale metadata fixture");
Check(!predictor.Init(model_path,"",config_path),"zero scaler denominator rejected");
CPolicyHttpBridge policy;
policy.Configure("NativeContract\\absent_policy.json",1);
if(MQLInfoInteger(MQL_TESTER))
{
Check(!policy.VerifyAccess("http://127.0.0.1:1/never-called"),"tester VerifyAccess returns without WebRequest");
Check(!policy.Pull("http://127.0.0.1:1/never-called"),"tester Pull returns without WebRequest");
}
PrintFormat("[NATIVE-CONTRACT] RESULT checks=%d failures=%d",g_checks,g_failures);
return g_failures==0 ? INIT_SUCCEEDED : INIT_FAILED;
}
void OnTick() {}
double OnTester() { return g_failures==0 ? (double)g_checks : -(double)g_failures; }