139 lines
4.0 KiB
Plaintext
139 lines
4.0 KiB
Plaintext
//+------------------------------------------------------------------+
|
|
//| MadTurtle_API.mqh - HTTP REST bridge to Python inference server |
|
|
//+------------------------------------------------------------------+
|
|
#ifndef MADTURTLE_API
|
|
#define MADTURTLE_API
|
|
|
|
#import "wininet.dll"
|
|
int InternetOpenW(string, int, string, string, int);
|
|
int InternetOpenUrlW(int, string, string, int, int, int);
|
|
int InternetReadFile(int, uchar &[], int, int &);
|
|
int InternetCloseHandle(int);
|
|
#import
|
|
|
|
// Timeout and buffer constants
|
|
#define MT5_API_TIMEOUT_MS 8000
|
|
#define MT5_API_BUFFER_SIZE 8192
|
|
|
|
// Server connection config
|
|
struct MadTurtleServerCfg {
|
|
string host;
|
|
int port;
|
|
string api_token;
|
|
int timeout_ms;
|
|
int retry_count;
|
|
bool use_ssl;
|
|
};
|
|
|
|
// API response container
|
|
struct MadTurtleAPIResponse {
|
|
int http_code;
|
|
string body;
|
|
bool success;
|
|
string error_msg;
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Initialize default server config |
|
|
//+------------------------------------------------------------------+
|
|
MadTurtleServerCfg MadTurtle_InitDefaultServer()
|
|
{
|
|
MadTurtleServerCfg cfg;
|
|
cfg.host = "127.0.0.1";
|
|
cfg.port = 8000;
|
|
cfg.api_token = "";
|
|
cfg.timeout_ms = MT5_API_TIMEOUT_MS;
|
|
cfg.retry_count = 2;
|
|
cfg.use_ssl = false;
|
|
return cfg;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Build full URL from path |
|
|
//+------------------------------------------------------------------+
|
|
string MadTurtle_BuildURL(const MadTurtleServerCfg &cfg, string path)
|
|
{
|
|
string proto = cfg.use_ssl ? "https" : "http";
|
|
return StringFormat("%s://%s:%d%s", proto, cfg.host, cfg.port, path);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| HTTP GET request |
|
|
//+------------------------------------------------------------------+
|
|
MadTurtleAPIResponse MadTurtle_HTTPGet(const MadTurtleServerCfg &cfg, string path)
|
|
{
|
|
MadTurtleAPIResponse resp;
|
|
resp.http_code = 0;
|
|
resp.success = false;
|
|
resp.body = "";
|
|
resp.error_msg = "";
|
|
|
|
int hInternet = InternetOpenW("MadTurtleEA/2.0", 1, NULL, NULL, 0);
|
|
if(hInternet == 0) {
|
|
resp.error_msg = "InternetOpenW failed";
|
|
return resp;
|
|
}
|
|
|
|
string url = MadTurtle_BuildURL(cfg, path);
|
|
int hUrl = InternetOpenUrlW(hInternet, url, NULL, 0, 0x04000000, 0);
|
|
if(hUrl == 0) {
|
|
InternetCloseHandle(hInternet);
|
|
resp.error_msg = "InternetOpenUrlW failed: " + IntegerToString(GetLastError());
|
|
return resp;
|
|
}
|
|
|
|
uchar buf[];
|
|
ArrayResize(buf, MT5_API_BUFFER_SIZE);
|
|
int bytesRead = 0;
|
|
string body = "";
|
|
|
|
while(true) {
|
|
int res = InternetReadFile(hUrl, buf, MT5_API_BUFFER_SIZE, bytesRead);
|
|
if(res == 0 || bytesRead == 0) break;
|
|
body += CharArrayToString(buf, 0, bytesRead, CP_UTF8);
|
|
}
|
|
|
|
resp.body = body;
|
|
resp.http_code = 200;
|
|
resp.success = (StringLen(body) > 0);
|
|
|
|
InternetCloseHandle(hUrl);
|
|
InternetCloseHandle(hInternet);
|
|
return resp;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Call inference server with feature vector (GET) |
|
|
//+------------------------------------------------------------------+
|
|
MadTurtleAPIResponse MadTurtle_GetSignal(const MadTurtleServerCfg &cfg, double &features[])
|
|
{
|
|
MadTurtleAPIResponse resp;
|
|
resp.http_code = 0;
|
|
resp.success = false;
|
|
resp.body = "";
|
|
resp.error_msg = "";
|
|
|
|
int n = ArraySize(features);
|
|
if(n == 0) {
|
|
resp.error_msg = "Empty feature vector";
|
|
return resp;
|
|
}
|
|
|
|
string qs = "?";
|
|
for(int i = 0; i < n; i++) {
|
|
if(i > 0) qs += "&";
|
|
qs += StringFormat("f%d=%.8f", i, features[i]);
|
|
}
|
|
|
|
resp = MadTurtle_HTTPGet(cfg, "/v1/signal" + qs);
|
|
|
|
for(int attempt = 1; attempt < cfg.retry_count && !resp.success; attempt++) {
|
|
Sleep(500);
|
|
resp = MadTurtle_HTTPGet(cfg, "/v1/signal" + qs);
|
|
}
|
|
|
|
return resp;
|
|
}
|
|
|
|
#endif // MADTURTLE_API
|