English 中文 Deutsch 日本語
preview
Внедрение в MQL5 практических модулей из других языков (Часть 02): Создание библиотеки REQUESTS, как в Python

Внедрение в MQL5 практических модулей из других языков (Часть 02): Создание библиотеки REQUESTS, как в Python

MetaTrader 5Интеграция |
341 0
Omega J Msigwa
Omega J Msigwa

Разделы


Введение

Возможность отправлять HTTP-запросы в интернет непосредственно из MetaTrader 5 — одно из лучших свойств языка программирования MQL5 за всю его историю. Благодаря этой возможности трейдеры могут взаимодействовать со своими внешними веб-сайтами, серверами, торговыми приложениями и т. д.

Это позволяет нам выполнять внутри торговой платформы практически любые действия: например, получать данные из внешних источников, отправлять торговые уведомления коллегам и многое другое.

Это свойство стало возможным благодаря функции WebRequest, доступной в языке MQL5, что позволяет нам выполнять любые действия на основе HTTP, такие как:

  • Отправка POST-запросов для передачи информации на внешние серверы.
  • Получение информации из интернета с помощью знаменитого GET-запроса.
  • Отправка PATCH-запросов в интернет для изменения информации в базе данных сервера.
  • Отправка PUT-запросов в интернет для обновления значений, хранящихся в базе данных сервера.

Вот лишь некоторые примеры HTTP-действий.

Однако эта единственная функция порой может быть слишком сложной, и она не очень удобна в использовании.

Отправка простого веб-запроса для выполнения любого из упомянутых выше действий требует значительных усилий, что усугубляется необходимостью учитывать HTTP-методы, заголовки и многое другое. Не говоря уже о том, что вам нужно будет вручную прописать процесс обработки данных, которые вы хотите отправить или получить. 

Если вы когда-либо в своей деятельности в качестве программиста использовали платформы для разработки приложений интернета (веб-фреймворки) или модули для решения подобных задач, вы могли заметить, что большинство фреймворков за пределами MQL5 способно обрабатывать большинство основных задач и операций, которые функция WebRequest в MQL5 не выполняет.

Один из таких модулей — это requests из языка программирования Python.

Модуль Requests, прозванный HTTP for Humans (HTTP для людей):

Это простая, но элегантная библиотека для работы с HTTP, которая позволяет программистам чрезвычайно легко отправлять запросы по протоколу HTTP/1.1.

Благодаря этой библиотеке разработчикам, использующим Python, не нужно вручную добавлять параметры запроса в URL-адреса или кодировать данные PUT и POST с помощью form-encode, а также совершать многие другие действия, поскольку все хорошо продумано и упрощено даже для разработчиков, не очень подкованных в плане техники.

В этой статье мы предполагаем описать реализацию аналогичного модуля с похожими функциями, синтаксисом и возможностями. Надеюсь, это позволит упростить и сделать более удобным выполнение веб-запросов в MQL5, как и в Python.


Выполнение веб-запроса

Это основная функциональность модуля requests. Функция request — это та, которая отправляет и получает всевозможную информацию в различных форматах из интернета.

Прежде чем имитировать метод, похожий на предлагаемый модулем requests в Python, давайте сначала рассмотрим эту функцию.

Метод request в Python выглядит следующим образом.

def request(
    method: str | bytes,
    url: str | bytes,
    *,
    params: _Params | None = ...,
    data: _Data | None = ...,
    headers: _HeadersMapping | None = ...,
    cookies: CookieJar | _TextMapping | None = ...,
    files: _Files | None = ...,
    auth: _Auth | None = ...,
    timeout: _Timeout | None = ...,
    allow_redirects: bool = ...,
    proxies: _TextMapping | None = ...,
    hooks: _HooksInput | None = ...,
    stream: bool | None = ...,
    verify: _Verify | None = ...,
    cert: _Cert | None = ...,
    json: Any | None = None
) -> Response

Эта функция принимает несколько аргументов для HTTP-запроса к веб-серверу. Начнем с того, что зададим несколько параметров: метод, URL, данные, заголовки, таймаут и параметры JSON.

CResponse CSession::request(const string method, //HTTP method GET, POST, etc
                             const string url, //endpoint url
                             const string data = "", //The data you want to send if the method is POST or PUT
                             const string headers = "", //HTTP headers
                             const int timeout = 5000, //Request timeout (milliseconds)
                             const bool is_json=true) //Checks whether the given data is in JSON format
  {
   char data_char[];
   char result[];
   string result_headers;
   string temp_data = data;
   
   CResponse response; //a structure containing various response fields

//--- Managing the headers

   string temp_headers = m_headers;
   if (headers != "") // If the user provided additional headers, append them
      temp_headers += headers;

//--- Updating the headers with the information received
   
   if(is_json) //If the information parsed is 
     {
         //--- Convert dictionary to JSON string
         
         CJAVal js(NULL, jtUNDEF);
         bool b = js.Deserialize(data, CP_UTF8);
         
         string json;
         js.Serialize(json); //Get the serialized Json outcome
         temp_data = json; //Assign the resulting serialized Json to the temporary data array
      
         //--- Set "Content-Type: application/json"
            
         temp_headers = UpdateHeader(temp_headers, "Content-Type", "application/json");
         if (MQLInfoInteger(MQL_DEBUG))
           printf("%s: %s",__FUNCTION__,temp_headers);
     }
    else
      {
         temp_headers = UpdateHeader(temp_headers, headers);
         if (MQLInfoInteger(MQL_DEBUG))
           printf("%s: %s",__FUNCTION__,temp_headers);
      }
     
//--- Convert data to byte array (for POST, PUT, etc.)

   if (StringToCharArray(temp_data, data_char, 0, StringLen(temp_data), CP_UTF8)<0) //Convert the data in a string format to a uchar
      {
         printf("%s, Failed to convert data to a Char array. Error = %s",__FUNCTION__,ErrorDescription(GetLastError()));
         return response;
      }

//--- Perform the WebRequest

   uint start = GetTickCount(); //starting time of the request
      
   int status = WebRequest(method, url, temp_headers, timeout, data_char, result, result_headers); //trigger a webrequest function
   if(status == -1)
     {
      PrintFormat("WebRequest failed with error %s", ErrorDescription(GetLastError()));
      response.status_code = 0;
      return response;
     }

//--- Fill the response struct

   response.elapsed = (GetTickCount() - start);
   
   string results_string = CharArrayToString(result);
   response.text = results_string;
   
   CJAVal js;
                                  
   if (!js.Deserialize(result))
      if (MQLInfoInteger(MQL_DEBUG))
         printf("Failed to serialize data received from WebRequest");
         
   response.json = js;
   
   response.cookies = js["cookies"].ToStr();
   
   response.status_code = status;
   ArrayCopy(response.content, result);
   response.headers = result_headers;
   response.url = url;
   response.ok = (status >= 200 && status < 400);
   response.reason = WebStatusText(status); // a custom helper for translating status codes

   return response;
  }

Функция request в Python предоставляет два варианта передачи данных в веб-запрос с использованием двух разных аргументов: аргумент data для передачи всех данных, не являющихся JSON, и аргумент json для передачи данных в формате JSON.

Поскольку оба аргумента предоставляют информацию, которая должна быть передана в запрос, а для отправки данных можно использовать только один аргумент, то вы можете отправлять либо необработанные данные (HTML, простой текст и т. д.), либо данные в формате JSON..

Таким образом, функция в Python определяет тип предоставленных данных (JSON или другой) и корректирует их заголовки в соответствии с заголовками, заданными пользователем. Например, при предоставлении данных в формате JSON он добавляет или изменяет заголовок Content-Type: application/json.

Хотя в функции MQL5 можно было бы использовать оба аргумента, я считаю эту идею слишком запутанной и добавляющей ненужную сложность. Таким образом, функция в нашем классе MQL5 принимает только один аргумент с именем data для отправки данных в интернет, а логический аргумент с именем is_json отвечает за различение информации, полученной в переменной с именем data (между JSON и другими типами) внутри функции.

С другой стороны, когда аргумент is_json установлен на true, функция добавляет или изменяет полученные заголовки со значением (Content-Type: application/json). Но перед этим полученные данные из аргумента data перед отправкой в интернет сериализуются в правильный формат JSON.

//--- Updating the headers with the information received
   
   if(is_json) //If the information parsed is 
     {
         //--- Convert dictionary to JSON string
         
         CJAVal js(NULL, jtUNDEF);
         bool b = js.Deserialize(data, CP_UTF8);
         
         string json;
         js.Serialize(json); //Get the serialized Json outcome
         temp_data = json; //Assign the resulting serialized Json to the temporary data array
      
         //--- Set "Content-Type: application/json"
            
         temp_headers = UpdateHeader(temp_headers, "Content-Type", "application/json");
         if (MQLInfoInteger(MQL_DEBUG))
           printf("%s: %s",__FUNCTION__,temp_headers);
     }
    else
      {
         temp_headers = UpdateHeader(temp_headers, headers);
         if (MQLInfoInteger(MQL_DEBUG))
           printf("%s: %s",__FUNCTION__,temp_headers);
      }

Метод request, который модуль requests предлагает в Python, возвращает множество переменных в зависимости от HTTP-Response и содержит информацию о состоянии запроса, полученных данных, ошибках и многом другом.

import requests

r = requests.get('https://api.github.com/events')

# Print the raw response
print("Raw response:", r)

# Status code
print("Status Code:", r.status_code)

# Reason phrase
print("Reason:", r.reason)

# URL (final URL after redirects)
print("URL:", r.url)

# Headers (dictionary)
print("Headers:")

#... other responses

Для достижения этой цели необходима аналогичная структура в нашем классе MQL5.

Внутри файлаrequests.mqh ниже приведен класс CResponse.

struct CResponse
  {
   int               status_code; // HTTP status code (e.g., 200, 404)
   string            text;        // Raw response body as string

   CJAVal            json;        // Parses response as JSON
   uchar             content[];   // Raw bytes of the response
   string            headers;     // Dictionary of response headers
   string            cookies;     // Cookies set by the server
   string            url;         // Final URL after redirects
   bool              ok;          // True if status_code < 400
   uint              elapsed;     // Time taken for the response in ms
   string            reason;      // Text reason (e.g., "OK", "Not Found")
  };

Это структура, которую функция request возвращает внутри класса CSession, — обсудим это через секунду.

Для справки: ниже приведен табличный список всех переменных и содержащейся в них информации внутри класса CResponse.

Переменная Тип данных Описание
status_code int Возвращаемый сервером код состояния HTTP (например, 200 = OK, 404 = Not Found и т. д.).
text string  Полный ответ в виде необработанной строки (например, HTML, JSON или текст).
json CJAVal Подвергнутый парсингу JSON-объект из тела ответа, если процесс сериализации прошел успешно.
content[] uchar Массив байтов в исходном виде, содержащий тело ответа (полезно для бинарных ответов).
headers  string  Словарь, содержащий заголовки HTTP-ответов. При желании его можно преобразовать в формат JSON.
cookies string  Файлы cookie, установленные сервером (извлечены из заголовков Set-cookies, если таковые имеются).
url string  Итоговый URL-адрес после любых перенаправлений.
ok bool Становится true, если код состояния < 400, то есть в процессе не произошло ошибок со стороны клиента или сервера.
elapsed uint  Время в миллисекундах, необходимое для выполнения запроса.
reason string  Код состояния HTTP в текстовом формате — удобочитаемый для человека.

Ниже описано, как использовать функцию request.

Чтобы такой пример работал на вашем компьютере, убедитесь, что вы добавили https://httpbin.org (тестовый URL-адрес) в список разрешенных URL-адресов в MetaTrader 5.

(a) Отправка данных в формате JSON

#include <requests.mqh>
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
     
     string json = "{\"username\": \"omega\", \"password\": \"secret123\"}";
     
     CResponse response = CSession::request("POST","https://httpbin.org/post", json, NULL, 5000, true);     
      
      Print("Status Code: ", response.status_code);
      Print("Reason: ", response.reason);
      Print("URL: ", response.url);
      Print("OK: ", (string)response.ok);
      Print("Elapsed Time (ms): ", response.elapsed);
      
      Print("Headers:\n", response.headers);
      Print("Cookies: ", response.cookies);
      Print("Response: ",response.text);
      Print("JSON:\n", response.json["url"].ToStr());
 }

Результаты.

JF      0       08:10:33.226    Requests test (XAUUSD,D1)       CSession::request: Content-Type: application/json
GF      0       08:10:33.226    Requests test (XAUUSD,D1)       
MI      0       08:10:34.578    Requests test (XAUUSD,D1)       Status Code: 200
PS      0       08:10:34.578    Requests test (XAUUSD,D1)       Reason: OK
LH      0       08:10:34.578    Requests test (XAUUSD,D1)       URL: https://httpbin.org/post
HP      0       08:10:34.578    Requests test (XAUUSD,D1)       OK: true
IF      0       08:10:34.578    Requests test (XAUUSD,D1)       Elapsed Time (ms): 1343
HO      0       08:10:34.578    Requests test (XAUUSD,D1)       Headers:
QE      0       08:10:34.578    Requests test (XAUUSD,D1)       Date: Fri, 04 Jul 2025 05:10:35 GMT
MG      0       08:10:34.578    Requests test (XAUUSD,D1)       Content-Type: application/json
HQ      0       08:10:34.578    Requests test (XAUUSD,D1)       Content-Length: 619
IH      0       08:10:34.578    Requests test (XAUUSD,D1)       Connection: keep-alive
JL      0       08:10:34.578    Requests test (XAUUSD,D1)       Server: gunicorn/19.9.0
QD      0       08:10:34.578    Requests test (XAUUSD,D1)       Access-Control-Allow-Origin: *
IO      0       08:10:34.578    Requests test (XAUUSD,D1)       Access-Control-Allow-Credentials: true
PI      0       08:10:34.578    Requests test (XAUUSD,D1)       
GO      0       08:10:34.578    Requests test (XAUUSD,D1)       Cookies: 
HH      0       08:10:34.578    Requests test (XAUUSD,D1)       Response: {
QL      0       08:10:34.578    Requests test (XAUUSD,D1)         "args": {}, 
FK      0       08:10:34.578    Requests test (XAUUSD,D1)         "data": "{\"username\":\"omega\",\"password\":\"secret123\"}", 
MN      0       08:10:34.578    Requests test (XAUUSD,D1)         "files": {}, 
RH      0       08:10:34.578    Requests test (XAUUSD,D1)         "form": {}, 
OP      0       08:10:34.578    Requests test (XAUUSD,D1)         "headers": {
CH      0       08:10:34.578    Requests test (XAUUSD,D1)           "Accept": "*/*", 
GM      0       08:10:34.578    Requests test (XAUUSD,D1)           "Accept-Encoding": "gzip, deflate", 
HQ      0       08:10:34.578    Requests test (XAUUSD,D1)           "Accept-Language": "en;q=0.5", 
GH      0       08:10:34.578    Requests test (XAUUSD,D1)           "Content-Length": "43", 
IR      0       08:10:34.578    Requests test (XAUUSD,D1)           "Content-Type": "application/json", 
EI      0       08:10:34.578    Requests test (XAUUSD,D1)           "Host": "httpbin.org", 
NH      0       08:10:34.578    Requests test (XAUUSD,D1)           "User-Agent": "MetaTrader 5 Terminal/5.5120 (Windows NT 10.0.19045; x64)", 
HK      0       08:10:34.578    Requests test (XAUUSD,D1)           "X-Amzn-Trace-Id": "Root=1-6867624b-422e528808290adf61a651a3"
IN      0       08:10:34.578    Requests test (XAUUSD,D1)         }, 
GD      0       08:10:34.578    Requests test (XAUUSD,D1)         "json": {
CN      0       08:10:34.578    Requests test (XAUUSD,D1)           "password": "secret123", 
KD      0       08:10:34.578    Requests test (XAUUSD,D1)           "username": "omega"
QM      0       08:10:34.578    Requests test (XAUUSD,D1)         }, 
EJ      0       08:10:34.578    Requests test (XAUUSD,D1)         "origin": "197.250.227.26", 
FQ      0       08:10:34.578    Requests test (XAUUSD,D1)         "url": "https://httpbin.org/post"
EG      0       08:10:34.578    Requests test (XAUUSD,D1)       }
PR      0       08:10:34.578    Requests test (XAUUSD,D1)       
NF      0       08:10:34.578    Requests test (XAUUSD,D1)       JSON:
CR      0       08:10:34.578    Requests test (XAUUSD,D1)       https://httpbin.org/post

(b) Отправка данных, не являющихся JSON-данными

Рассмотрим данные формы в качестве примера.

#include <requests.mqh>
CSession requests;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
     
     string form_data = "username=omega&password=secret123"; //mimicking how the final form data is collected in the web
     
     CResponse response = CSession::post("https://httpbin.org/post", form_data, "Content-Type: application/x-www-form-urlencoded", 5000, false);
      
      Print("Status Code: ", response.status_code);
      Print("Reason: ", response.reason);
      Print("URL: ", response.url);
      Print("OK: ", (string)response.ok);
      Print("Elapsed Time (ms): ", response.elapsed);
      
      Print("Headers:\n", response.headers);
      Print("Cookies: ", response.cookies);
      Print("Response: ",response.text);
      Print("JSON:\n", response.json["url"].ToStr());
 }

Результаты.

DD      0       08:20:01.411    Requests test (XAUUSD,D1)       Status Code: 200
IN      0       08:20:01.411    Requests test (XAUUSD,D1)       Reason: OK
EG      0       08:20:01.411    Requests test (XAUUSD,D1)       URL: https://httpbin.org/post
QM      0       08:20:01.411    Requests test (XAUUSD,D1)       OK: true
RI      0       08:20:01.411    Requests test (XAUUSD,D1)       Elapsed Time (ms): 1547
QR      0       08:20:01.411    Requests test (XAUUSD,D1)       Headers:
EH      0       08:20:01.411    Requests test (XAUUSD,D1)       Date: Fri, 04 Jul 2025 05:20:02 GMT
DL      0       08:20:01.411    Requests test (XAUUSD,D1)       Content-Type: application/json
MD      0       08:20:01.411    Requests test (XAUUSD,D1)       Content-Length: 587
PM      0       08:20:01.411    Requests test (XAUUSD,D1)       Connection: keep-alive
OK      0       08:20:01.411    Requests test (XAUUSD,D1)       Server: gunicorn/19.9.0
HS      0       08:20:01.411    Requests test (XAUUSD,D1)       Access-Control-Allow-Origin: *
PD      0       08:20:01.411    Requests test (XAUUSD,D1)       Access-Control-Allow-Credentials: true
IF      0       08:20:01.411    Requests test (XAUUSD,D1)       
RD      0       08:20:01.411    Requests test (XAUUSD,D1)       Cookies: 
QM      0       08:20:01.411    Requests test (XAUUSD,D1)       Response: {
HK      0       08:20:01.411    Requests test (XAUUSD,D1)         "args": {}, 
OR      0       08:20:01.411    Requests test (XAUUSD,D1)         "data": "", 
JE      0       08:20:01.411    Requests test (XAUUSD,D1)         "files": {}, 
RL      0       08:20:01.411    Requests test (XAUUSD,D1)         "form": {
DF      0       08:20:01.411    Requests test (XAUUSD,D1)           "password": "secret123", 
PM      0       08:20:01.411    Requests test (XAUUSD,D1)           "username": "omega"
RE      0       08:20:01.411    Requests test (XAUUSD,D1)         }, 
PL      0       08:20:01.411    Requests test (XAUUSD,D1)         "headers": {
DE      0       08:20:01.411    Requests test (XAUUSD,D1)           "Accept": "*/*", 
LP      0       08:20:01.411    Requests test (XAUUSD,D1)           "Accept-Encoding": "gzip, deflate", 
CF      0       08:20:01.411    Requests test (XAUUSD,D1)           "Accept-Language": "en;q=0.5", 
EK      0       08:20:01.411    Requests test (XAUUSD,D1)           "Content-Length": "33", 
EL      0       08:20:01.411    Requests test (XAUUSD,D1)           "Content-Type": "application/x-www-form-urlencoded", 
PH      0       08:20:01.411    Requests test (XAUUSD,D1)           "Host": "httpbin.org", 
GO      0       08:20:01.411    Requests test (XAUUSD,D1)           "User-Agent": "MetaTrader 5 Terminal/5.5120 (Windows NT 10.0.19045; x64)", 
FQ      0       08:20:01.411    Requests test (XAUUSD,D1)           "X-Amzn-Trace-Id": "Root=1-68676482-6439a0a071c275773681a193"
LM      0       08:20:01.411    Requests test (XAUUSD,D1)         }, 
JE      0       08:20:01.411    Requests test (XAUUSD,D1)         "json": null, 
LM      0       08:20:01.411    Requests test (XAUUSD,D1)         "origin": "197.250.227.26", 
KH      0       08:20:01.411    Requests test (XAUUSD,D1)         "url": "https://httpbin.org/post"
LN      0       08:20:01.411    Requests test (XAUUSD,D1)       }
IK      0       08:20:01.411    Requests test (XAUUSD,D1)       
CO      0       08:20:01.411    Requests test (XAUUSD,D1)       JSON:
NK      0       08:20:01.411    Requests test (XAUUSD,D1)       https://httpbin.org/post

Отлично! Нам удалось отправить два разных типа данных, используя одну и ту же функцию веб-запроса.

Обратите внимание, что при отправке данных не в формате JSON (в данном случае, данных формы) я явно указываю "Content-type" в аргументе headers функции request, чтобы учесть данные формы.

Таким образом, если вы не отправляете данные в формате JSON, которые автоматически сериализуются, и соответствующий HTTP-заголовок для размещения этого типа данных автоматически не обновляется, необходимо явно указать Content-type, чтобы он соответствовал типу данных, которые вы хотите отправить.

Для получения более подробной информации читайте -> https://beeceptor.com/docs/concepts/content-type/index.html

Теперь эта функция request способна отправлять все виды HTTP-запросов аналогично встроенной функции MQL5. Это ее приблизительное продолжение.

Поскольку эта функция такая гибкая, ее использование становится сложным и чревато ошибками. Предположим, вы хотите отправить GET-запрос, чтобы получить некоторую информацию из интернета.

Всем известно, что отправлять данные с помощью GET-запроса нецелесообразно, поскольку изначально он не предназначен для этого. Чтобы уменьшить вероятность ошибок, модуль requests в языке Python содержит несколько высокоуровневых функций для отправки веб-запросов различных типов, которые учитывают потребности конкретного запроса.


Разные веб-запросы в разных функциях

На основе функции request, реализованной в предыдущем разделе, можно создать несколько функций для различных HTTP-действий следующим образом:

(a) Функция get 

static CResponse         get(const string url, const string headers = "", const int timeout = 5000)  
  {  
    return request("GET", url, "", headers, timeout, false);   
  }

Эта функция отправляет GET-запрос на указанный URL. При вызове этой функции данные на URL-адрес не отправляются, поскольку она предназначена только для получения информации.

Применение.

#include <requests.mqh>
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
      
      CResponse response = CSession::get("https://httpbin.org/get");
      
      Print("Status Code: ", response.status_code);
      Print("Reason: ", response.reason);
      Print("URL: ", response.url);
      Print("OK: ", (string)response.ok);
      Print("Elapsed Time (ms): ", response.elapsed);
      
      Print("Headers:\n", response.headers);
      Print("Cookies: ", response.cookies);
      Print("Response: ",response.text);
      Print("JSON:\n", response.json["url"].ToStr());
  }

Результаты.

LM      0       09:50:48.904    Requests test (XAUUSD,D1)       Status Code: 200
QF      0       09:50:48.904    Requests test (XAUUSD,D1)       Reason: OK
GQ      0       09:50:48.904    Requests test (XAUUSD,D1)       URL: https://httpbin.org/get
CD      0       09:50:48.904    Requests test (XAUUSD,D1)       OK: true
EQ      0       09:50:48.904    Requests test (XAUUSD,D1)       Elapsed Time (ms): 1782
KJ      0       09:50:48.904    Requests test (XAUUSD,D1)       Headers:
JQ      0       09:50:48.904    Requests test (XAUUSD,D1)       Date: Fri, 04 Jul 2025 06:50:49 GMT
JD      0       09:50:48.904    Requests test (XAUUSD,D1)       Content-Type: application/json
NL      0       09:50:48.904    Requests test (XAUUSD,D1)       Content-Length: 379
NE      0       09:50:48.904    Requests test (XAUUSD,D1)       Connection: keep-alive
MS      0       09:50:48.904    Requests test (XAUUSD,D1)       Server: gunicorn/19.9.0
NH      0       09:50:48.904    Requests test (XAUUSD,D1)       Access-Control-Allow-Origin: *
FL      0       09:50:48.904    Requests test (XAUUSD,D1)       Access-Control-Allow-Credentials: true
KM      0       09:50:48.904    Requests test (XAUUSD,D1)       
LL      0       09:50:48.904    Requests test (XAUUSD,D1)       Cookies: 
CE      0       09:50:48.904    Requests test (XAUUSD,D1)       Response: {
FS      0       09:50:48.904    Requests test (XAUUSD,D1)         "args": {}, 
DJ      0       09:50:48.904    Requests test (XAUUSD,D1)         "headers": {
PR      0       09:50:48.904    Requests test (XAUUSD,D1)           "Accept": "*/*", 
DF      0       09:50:48.904    Requests test (XAUUSD,D1)           "Accept-Encoding": "gzip, deflate", 
KO      0       09:50:48.904    Requests test (XAUUSD,D1)           "Accept-Language": "en;q=0.5", 
JL      0       09:50:48.904    Requests test (XAUUSD,D1)           "Host": "httpbin.org", 
QK      0       09:50:48.904    Requests test (XAUUSD,D1)           "User-Agent": "MetaTrader 5 Terminal/5.5120 (Windows NT 10.0.19045; x64)", 
JI      0       09:50:48.904    Requests test (XAUUSD,D1)           "X-Amzn-Trace-Id": "Root=1-686779c9-147d77346060e72a2fa2282f"
FH      0       09:50:48.904    Requests test (XAUUSD,D1)         }, 
RI      0       09:50:48.904    Requests test (XAUUSD,D1)         "origin": "197.250.227.26", 
CJ      0       09:50:48.904    Requests test (XAUUSD,D1)         "url": "https://httpbin.org/get"
PR      0       09:50:48.904    Requests test (XAUUSD,D1)       }
QG      0       09:50:48.904    Requests test (XAUUSD,D1)       
KK      0       09:50:48.904    Requests test (XAUUSD,D1)       JSON:
DQ      0       09:50:48.904    Requests test (XAUUSD,D1)       https://httpbin.org/get

Хотя функция get позволяет передавать заголовки в запрос HTTP, невозможно контролировать тип контента, получаемого от сервера, даже если вы установите для заголовков параметр Content-type.

(b) Функция post

static CResponse         post(const string url, const string data = "", const string headers = "", const int timeout = 5000, const bool is_json=true) 
  {
    return request("POST", url, data, headers, timeout, is_json);  
  }

Эта функция отправляет POST-запрос на указанный URL-адрес с опциональным набором данных. Аналогично функции request эта функция автоматически устанавливает Content-Type, когда аргумент is_json установлен на true.

Применение.

#include <requests.mqh>
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
      
      string json = "{\"username\": \"omega\", \"password\": \"secret123\"}";
      CResponse response = CSession::post("https://httpbin.org/post",json);
      
      Print("Status Code: ", response.status_code);
      Print("Reason: ", response.reason);
      Print("URL: ", response.url);
      Print("OK: ", (string)response.ok);
      Print("Elapsed Time (ms): ", response.elapsed);
      
      Print("Headers:\n", response.headers);
      Print("Cookies: ", response.cookies);
      Print("Response: ",response.text);
      Print("JSON:\n", response.json["url"].ToStr());    
 }

Результаты.

NK      0       15:32:13.093    Requests test (XAUUSD,D1)       Status Code: 200
OP      0       15:32:13.093    Requests test (XAUUSD,D1)       Reason: OK
KE      0       15:32:13.093    Requests test (XAUUSD,D1)       URL: https://httpbin.org/post
GR      0       15:32:13.093    Requests test (XAUUSD,D1)       OK: true
LD      0       15:32:13.093    Requests test (XAUUSD,D1)       Elapsed Time (ms): 1578
GL      0       15:32:13.093    Requests test (XAUUSD,D1)       Headers:
PK      0       15:32:13.093    Requests test (XAUUSD,D1)       Date: Fri, 04 Jul 2025 12:32:13 GMT
NR      0       15:32:13.093    Requests test (XAUUSD,D1)       Content-Type: application/json
GG      0       15:32:13.093    Requests test (XAUUSD,D1)       Content-Length: 619
JN      0       15:32:13.093    Requests test (XAUUSD,D1)       Connection: keep-alive
II      0       15:32:13.093    Requests test (XAUUSD,D1)       Server: gunicorn/19.9.0
RF      0       15:32:13.093    Requests test (XAUUSD,D1)       Access-Control-Allow-Origin: *
JR      0       15:32:13.093    Requests test (XAUUSD,D1)       Access-Control-Allow-Credentials: true
OK      0       15:32:13.093    Requests test (XAUUSD,D1)       
HQ      0       15:32:13.093    Requests test (XAUUSD,D1)       Cookies: 
GK      0       15:32:13.093    Requests test (XAUUSD,D1)       Response: {
RN      0       15:32:13.093    Requests test (XAUUSD,D1)         "args": {}, 
EN      0       15:32:13.093    Requests test (XAUUSD,D1)         "data": "{\"username\":\"omega\",\"password\":\"secret123\"}", 
NL      0       15:32:13.093    Requests test (XAUUSD,D1)         "files": {}, 
QJ      0       15:32:13.093    Requests test (XAUUSD,D1)         "form": {}, 
PS      0       15:32:13.093    Requests test (XAUUSD,D1)         "headers": {
DJ      0       15:32:13.093    Requests test (XAUUSD,D1)           "Accept": "*/*", 
HO      0       15:32:13.093    Requests test (XAUUSD,D1)           "Accept-Encoding": "gzip, deflate", 
GG      0       15:32:13.093    Requests test (XAUUSD,D1)           "Accept-Language": "en;q=0.5", 
HJ      0       15:32:13.093    Requests test (XAUUSD,D1)           "Content-Length": "43", 
JM      0       15:32:13.093    Requests test (XAUUSD,D1)           "Content-Type": "application/json", 
FK      0       15:32:13.093    Requests test (XAUUSD,D1)           "Host": "httpbin.org", 
MN      0       15:32:13.093    Requests test (XAUUSD,D1)           "User-Agent": "MetaTrader 5 Terminal/5.5120 (Windows NT 10.0.19045; x64)", 
IM      0       15:32:13.093    Requests test (XAUUSD,D1)           "X-Amzn-Trace-Id": "Root=1-6867c9cd-64a83cd77115a2575214fecd"
JS      0       15:32:13.093    Requests test (XAUUSD,D1)         }, 
HJ      0       15:32:13.093    Requests test (XAUUSD,D1)         "json": {
DL      0       15:32:13.093    Requests test (XAUUSD,D1)           "password": "secret123", 
LK      0       15:32:13.093    Requests test (XAUUSD,D1)           "username": "omega"
RS      0       15:32:13.093    Requests test (XAUUSD,D1)         }, 
FG      0       15:32:13.093    Requests test (XAUUSD,D1)         "origin": "197.250.227.26", 
EO      0       15:32:13.093    Requests test (XAUUSD,D1)         "url": "https://httpbin.org/post"
FE      0       15:32:13.093    Requests test (XAUUSD,D1)       }
OL      0       15:32:13.093    Requests test (XAUUSD,D1)       
MD      0       15:32:13.093    Requests test (XAUUSD,D1)       JSON:
DD      0       15:32:13.093    Requests test (XAUUSD,D1)       https://httpbin.org/post

(c) Функция put

Эта функция отправляет PUT-запрос для обновления ресурса по указанному URL-адресу с заданными данными.

static CResponse         put(const string url, const string data = "", const string headers = "", const int timeout = 5000, const bool is_json=true) 
  { 
    return request("PUT", url, data, headers, timeout, is_json);   
  }

Пример использования.

#include <requests.mqh>
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
           
      string json = "{\"username\": \"omega\", \"password\": \"secret123\"}";
      CResponse response = CSession::put("https://httpbin.org/put",json);
      
      Print("Status Code: ", response.status_code);
      Print("Reason: ", response.reason);
      Print("URL: ", response.url);
      Print("OK: ", (string)response.ok);
      Print("Elapsed Time (ms): ", response.elapsed);
      
      Print("Headers:\n", response.headers);
      Print("Cookies: ", response.cookies);
      Print("Response: ",response.text);
      Print("JSON:\n", response.json["url"].ToStr());
 }

Результаты.

#include <requests.mqh>
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
     
      string json = "{\"update\": true}";
      CResponse response = CSession::put("https://httpbin.org/put", json, "", 5000, true);
      
      Print("Reason: ", response.reason);
      Print("Response: ",response.text);
  }

Результаты.

MG      0       15:51:02.874    Requests test (XAUUSD,D1)       Reason: OK
EQ      0       15:51:02.874    Requests test (XAUUSD,D1)       Response: {
HG      0       15:51:02.874    Requests test (XAUUSD,D1)         "args": {}, 
JM      0       15:51:02.874    Requests test (XAUUSD,D1)         "data": "{\"update\":true}", 
LJ      0       15:51:02.874    Requests test (XAUUSD,D1)         "files": {}, 
CM      0       15:51:02.874    Requests test (XAUUSD,D1)         "form": {}, 
FE      0       15:51:02.874    Requests test (XAUUSD,D1)         "headers": {
RO      0       15:51:02.874    Requests test (XAUUSD,D1)           "Accept": "*/*", 
JI      0       15:51:02.874    Requests test (XAUUSD,D1)           "Accept-Encoding": "gzip, deflate", 
QL      0       15:51:02.874    Requests test (XAUUSD,D1)           "Accept-Language": "en;q=0.5", 
KE      0       15:51:02.874    Requests test (XAUUSD,D1)           "Content-Length": "15", 
LG      0       15:51:02.874    Requests test (XAUUSD,D1)           "Content-Type": "application/json", 
PL      0       15:51:02.874    Requests test (XAUUSD,D1)           "Host": "httpbin.org", 
KD      0       15:51:02.874    Requests test (XAUUSD,D1)           "User-Agent": "MetaTrader 5 Terminal/5.5120 (Windows NT 10.0.19045; x64)", 
KH      0       15:51:02.874    Requests test (XAUUSD,D1)           "X-Amzn-Trace-Id": "Root=1-6867ce36-76b6e4053cd661ec5e4faa1b"
HI      0       15:51:02.874    Requests test (XAUUSD,D1)         }, 
NG      0       15:51:02.874    Requests test (XAUUSD,D1)         "json": {
DQ      0       15:51:02.874    Requests test (XAUUSD,D1)           "update": true
PG      0       15:51:02.874    Requests test (XAUUSD,D1)         }, 
PS      0       15:51:02.874    Requests test (XAUUSD,D1)         "origin": "197.250.227.26", 
HD      0       15:51:02.874    Requests test (XAUUSD,D1)         "url": "https://httpbin.org/put"
RH      0       15:51:02.874    Requests test (XAUUSD,D1)       }
CI      0       15:51:02.874    Requests test (XAUUSD,D1)       

(d) Функция patch

static CResponse         patch(const string url, const string data = "", const string headers = "", const int timeout = 5000, const bool is_json=true) 
  { 
    return request("PATCH", url, data, headers, timeout, is_json); 
  }

Эта функция отправляет PATCH-запрос для частичного обновления ресурса по указанному URL-адресу с использованием предоставленных данных.

Пример использования.

#include <requests.mqh>
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
     
      string json = "{\"patched\": 1}";
      CResponse response = CSession::patch("https://httpbin.org/patch", json, "", 5000, true);
      
      Print("Reason: ", response.reason);
      Print("Response: ",response.text);   
  }

Результаты.

GR      0       16:33:45.258    Requests test (XAUUSD,D1)       Reason: OK
OF      0       16:33:45.258    Requests test (XAUUSD,D1)       Response: {
RR      0       16:33:45.258    Requests test (XAUUSD,D1)         "args": {}, 
GJ      0       16:33:45.258    Requests test (XAUUSD,D1)         "data": "{\"patched\":1}", 
NL      0       16:33:45.258    Requests test (XAUUSD,D1)         "files": {}, 
IK      0       16:33:45.258    Requests test (XAUUSD,D1)         "form": {}, 
HS      0       16:33:45.258    Requests test (XAUUSD,D1)         "headers": {
LE      0       16:33:45.258    Requests test (XAUUSD,D1)           "Accept": "*/*", 
HO      0       16:33:45.258    Requests test (XAUUSD,D1)           "Accept-Encoding": "gzip, deflate", 
OF      0       16:33:45.258    Requests test (XAUUSD,D1)           "Accept-Language": "en;q=0.5", 
CJ      0       16:33:45.258    Requests test (XAUUSD,D1)           "Content-Length": "13", 
RM      0       16:33:45.258    Requests test (XAUUSD,D1)           "Content-Type": "application/json", 
FK      0       16:33:45.258    Requests test (XAUUSD,D1)           "Host": "httpbin.org", 
MN      0       16:33:45.258    Requests test (XAUUSD,D1)           "User-Agent": "MetaTrader 5 Terminal/5.5120 (Windows NT 10.0.19045; x64)", 
GN      0       16:33:45.258    Requests test (XAUUSD,D1)           "X-Amzn-Trace-Id": "Root=1-6867d837-47b9eb772b7ec6300016aa79"
JS      0       16:33:45.258    Requests test (XAUUSD,D1)         }, 
HJ      0       16:33:45.258    Requests test (XAUUSD,D1)         "json": {
MR      0       16:33:45.258    Requests test (XAUUSD,D1)           "patched": 1
FH      0       16:33:45.258    Requests test (XAUUSD,D1)         }, 
RI      0       16:33:45.258    Requests test (XAUUSD,D1)         "origin": "197.250.227.26", 
KK      0       16:33:45.258    Requests test (XAUUSD,D1)         "url": "https://httpbin.org/patch"
DS      0       16:33:45.258    Requests test (XAUUSD,D1)       }

(e) Функция delete

static CResponse         delete_(const string url, const string headers = "", const int timeout = 5000, const bool is_json=true) 
  {  
    return request("DELETE", url, "", headers, timeout, is_json);   
  }

Эта функция отправляет DELETE-запрос для удаления ресурса по указанному URL-адресу. Тело запроса не используется.

Пример использования.

#include <requests.mqh>
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
     
      CResponse response = CSession::delete_("https://httpbin.org/delete", "", 5000, true);
      
      Print("Reason: ", response.reason);
      Print("Response: ",response.text);
 }

Результаты.

ML      0       16:43:03.046    Requests test (XAUUSD,D1)       Reason: OK
EL      0       16:43:03.046    Requests test (XAUUSD,D1)       Response: {
HH      0       16:43:03.046    Requests test (XAUUSD,D1)         "args": {}, 
OR      0       16:43:03.046    Requests test (XAUUSD,D1)         "data": "", 
JD      0       16:43:03.046    Requests test (XAUUSD,D1)         "files": {}, 
ER      0       16:43:03.046    Requests test (XAUUSD,D1)         "form": {}, 
DK      0       16:43:03.046    Requests test (XAUUSD,D1)         "headers": {
PR      0       16:43:03.046    Requests test (XAUUSD,D1)           "Accept": "*/*", 
LG      0       16:43:03.046    Requests test (XAUUSD,D1)           "Accept-Encoding": "gzip, deflate", 
KO      0       16:43:03.046    Requests test (XAUUSD,D1)           "Accept-Language": "en;q=0.5", 
QQ      0       16:43:03.046    Requests test (XAUUSD,D1)           "Content-Length": "0", 
HE      0       16:43:03.046    Requests test (XAUUSD,D1)           "Content-Type": "application/json", 
LS      0       16:43:03.046    Requests test (XAUUSD,D1)           "Host": "httpbin.org", 
GF      0       16:43:03.046    Requests test (XAUUSD,D1)           "User-Agent": "MetaTrader 5 Terminal/5.5120 (Windows NT 10.0.19045; x64)", 
JK      0       16:43:03.046    Requests test (XAUUSD,D1)           "X-Amzn-Trace-Id": "Root=1-6867da67-1926ebf246353ab24461aed9"
LK      0       16:43:03.046    Requests test (XAUUSD,D1)         }, 
FL      0       16:43:03.046    Requests test (XAUUSD,D1)         "json": null, 
PG      0       16:43:03.046    Requests test (XAUUSD,D1)         "origin": "197.250.227.26", 
PO      0       16:43:03.046    Requests test (XAUUSD,D1)         "url": "https://httpbin.org/delete"
HE      0       16:43:03.046    Requests test (XAUUSD,D1)       }
QL      0       16:43:03.046    Requests test (XAUUSD,D1)       


Загрузка файлов в интернет

Модуль requests в языке Python значительно упрощает обмен файлами и получение их из интернета, в отличие от встроенной функции для веб-запросов в MQL5.

Возможность отправлять файлы в интернет является необходимым условием эффективной коммуникации в современном мире. Нам часто бывает нужно отправить скриншоты графиков, чтобы показать прогресс в торговле, а иногда продемонстрировать торговые стратегии и некоторые визуальные сигналы непосредственно на графике MetaTrader 5.

Это самая сложная часть в наших занятиях на тему CSession-MQL5, потому что нам нужно учитывать типы файлов, которые пользователи могут загружать в интернет, и применять правильное кодирование к извлеченной непосредственно из файлов двоичной информации. Кроме того, нам необходимы правильные HTTP-заголовки для каждого типа файлов.

CResponse CSession::request(const string method,
                             const string url,
                             const string data,
                             const string &files[],
                             const string headers = "",
                             const int timeout = 5000,
                             const bool is_json=true)
 {
   char result[];
   string result_headers;
   string temp_headers = m_headers;
   string boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW"; //for setting boundaries between data types and files in the form data
   CArrayChar final_body; //Final body uchar array

   CResponse response; //a structure containing various response fields

   // Append user headers
   if (headers != "")
      temp_headers += headers;

   bool use_multipart = ArraySize(files) > 0; //Check if files are attached 

//--- Create a multi part request

   if (use_multipart) // If multipart, assemble full body (JSON + files)
    {
      temp_headers = UpdateHeader(temp_headers, "Content-Type", "multipart/form-data; boundary=" + boundary + "\r\n"); //Update the headers

      //--- JSON part (or form data)
      if (StringLen(data) > 0)
      {
         string json_data = "";
         if (is_json) //if Json data is given alongside the files 
          {
            CJAVal js(NULL, jtUNDEF);
            if (js.Deserialize(data, CP_UTF8))
               js.Serialize(json_data); //Serialize the JSON data
          }

         string json_part = "--" + boundary + "\r\n";
         json_part += "Content-Disposition: form-data; name=\"metadata\"\r\n";
         json_part += "Content-Type: application/json\r\n\r\n";
         json_part += json_data + "\r\n";

         char json_bytes[];
         StringToCharArray(json_part, json_bytes, 0, StringLen(json_part), CP_UTF8);
         
         final_body.AddArray(json_bytes);
      }

      //--- File parts
      for (uint i = 0; i < files.Size(); i++)
       {
         string filename = GetFileName(files[i]);
         
         char file_data[]; //for storing the file data in binary format

         int file_handle = FileOpen(filename, FILE_BIN | FILE_SHARE_READ); // Read the file in binary format
         if (file_handle == INVALID_HANDLE)
          {
            printf("func=%s line=%d, Failed to read the file '%s'. Error = %s",__FUNCTION__,__LINE__,filename,ErrorDescription(GetLastError()));
            continue; //skip to the next file if the current file is invalid
          }

         int fsize = (int)FileSize(file_handle);
         ArrayResize(file_data, fsize);
         if (FileReadArray(file_handle, file_data, 0, fsize)==0)
           {
              printf("func=%s line=%d, No data found in the file '%s'. Error = %s",__FUNCTION__,__LINE__,filename,ErrorDescription(GetLastError()));
              FileClose(file_handle);
              continue; //skip to the next file if the current file is invalid
           }    
           
         FileClose(file_handle); //close the current file

         //--- Append files header and content type as detected to the request
        
         string file_part = "--" + boundary + "\r\n";
         file_part += StringFormat("Content-Disposition: form-data; name=\"file\"; filename=\"%s\"\r\n", filename);
         file_part += StringFormat("Content-Type: %s\r\n\r\n", GuessContentType(filename));
         
         char file_header[];
         StringToCharArray(file_part, file_header, 0, StringLen(file_part), CP_UTF8); //UTF-8 Encoding is a must
         
         final_body.AddArray(file_header); //Add the file header
         final_body.AddArray(file_data); //Add the file in binary format, the actual file 
         
         //--- append the new line — critical for HTTP form parsing.
         
         final_body.Add('\r');
         final_body.Add('\n');
      }

      //--- Final boundary
      string closing = "--" + boundary + "--\r\n";
      char closing_part[];
      StringToCharArray(closing, closing_part);
      
      final_body.AddArray(closing_part);
    }
   else // no files attached
    {
      //--- If it's just JSON or plain form data
      string body_data = data;
      if (is_json)
       {
         CJAVal js(NULL, jtUNDEF);
         if (js.Deserialize(data, CP_UTF8))
            js.Serialize(body_data);

         temp_headers = UpdateHeader(temp_headers, "Content-Type", "application/json");
       }
      else
         temp_headers = UpdateHeader(temp_headers, headers);
      
      //---
      
      char array[];      
      StringToCharArray(body_data, array, 0, StringLen(body_data), CP_UTF8); //Use UTF-8 similar requests in Python, This is very crucial
      final_body.AddArray(array);
    }
   
   char final_body_char_arr[];
   CArray2Array(final_body, final_body_char_arr);
   
   if (MQLInfoInteger(MQL_DEBUG))
     Print("Final body:\n",CharArrayToString(final_body_char_arr, 0 , final_body.Total(), CP_UTF8));
   
//--- Send the request

   uint start = GetTickCount(); //starting time of the request
   int status = WebRequest(method, url, temp_headers, timeout, final_body_char_arr, result, result_headers); //trigger a webrequest function

   if(status == -1)
     {
      PrintFormat("WebRequest failed with error %s", ErrorDescription(GetLastError()));
      response.status_code = 0;
      return response;
     }

//--- Fill the response struct

   response.elapsed = GetTickCount() - start;
   response.text = CharArrayToString(result);
   response.status_code = status;
   response.headers = result_headers;
   response.url = url;
   response.ok = (status >= 200 && status < 400);
   response.reason = WebStatusText(status);
   ArrayCopy(response.content, result);

//---

   CJAVal js;
   if (js.Deserialize(response.text))
      response.json = js;

   return response;
 }

Как и в случае с предыдущей функцией request, для выполнения какого-либо запроса к интернету эта функция решает аналогичную задачу, но способна обнаруживать файлы, предоставленные пользователем в качестве аргумента функции, и встраивать их в HTTP-запрос.

Когда массив файлов пуст, т.е. пользователь не предоставляет никаких файлов. Описанная выше функция выполняет обычный HTTP-запрос, как обсуждалось ранее, но после получения файлов она обновляет заголовок HTTP, преобразуя его в содержимое типа multipart/form-data, что позволяет HTTP-запросу различать типы предоставленных информации и данных.

temp_headers = UpdateHeader(temp_headers, "Content-Type", "multipart/form-data; boundary=" + boundary + "\r\n"); //Update the headers

Массив final_body отвечает за объединение всех данных (содержимого и файлов) в одну символьную (char) переменную, аналогично тому, как это делает форма в интернете. Это делается внутри цикла, который перебирает массив, содержащий все файлы, которые вы хотите отправить на сервер одновременно.

      //--- File parts
      for (uint i = 0; i < files.Size(); i++)
       {
         string filename = GetFileName(files[i]);
         
         char file_data[]; //for storing the file data in binary format

         int file_handle = FileOpen(filename, FILE_BIN | FILE_SHARE_READ); // Read the file in binary format
         if (file_handle == INVALID_HANDLE)
          {
            printf("func=%s line=%d, Failed to read the file '%s'. Error = %s",__FUNCTION__,__LINE__,filename,ErrorDescription(GetLastError()));
            continue; //skip to the next file if the current file is invalid
          }

         int fsize = (int)FileSize(file_handle);
         ArrayResize(file_data, fsize);
         if (FileReadArray(file_handle, file_data, 0, fsize)==0)
           {
              printf("func=%s line=%d, No data found in the file '%s'. Error = %s",__FUNCTION__,__LINE__,filename,ErrorDescription(GetLastError()));
              FileClose(file_handle);
              continue; //skip to the next file if the current file is invalid
           }    
           
         FileClose(file_handle); //close the current file

         //--- Append files header and content type as detected to the request
        
         string file_part = "--" + boundary + "\r\n";
         file_part += StringFormat("Content-Disposition: form-data; name=\"file\"; filename=\"%s\"\r\n", filename);
         file_part += StringFormat("Content-Type: %s\r\n\r\n", GuessContentType(filename));
         
         char file_header[];
         StringToCharArray(file_part, file_header, 0, StringLen(file_part), CP_UTF8); //UTF-8 Encoding is a must
         
         final_body.AddArray(file_header); //Add the file header
         final_body.AddArray(file_data); //Add the file in binary format, the actual file 
         
         //--- append the new line — critical for HTTP form parsing.
         
         final_body.Add('\r');
         final_body.Add('\n');
      }

Это позволит отправлять на сервер файлы различных типов (видео, изображения, документы Microsoft и т. д.) с помощью одной этой функции.

ФункцияGuessContentType определяет тип файла на основе его расширения и возвращает правильный Content-type для добавления в заголовок HTTP multipart-form.

string CSession::GuessContentType(string filename)
{
   StringToLower(filename); // Normalize for case-insensitivity

   if(StringFind(filename, ".txt")   >= 0) return "text/plain";
   if(StringFind(filename, ".json")  >= 0) return "application/json";
   if(StringFind(filename, ".xml")   >= 0) return "application/xml";
   //... other files

   //--- Images
   if(StringFind(filename, ".png")   >= 0) return "image/png";
   if(StringFind(filename, ".jpg")   >= 0 || StringFind(filename, ".jpeg") >= 0) return "image/jpeg";
   if(StringFind(filename, ".gif")   >= 0) return "image/gif";
   //...etc

   //--- Audio
   if(StringFind(filename, ".mp3")   >= 0) return "audio/mpeg";
   if(StringFind(filename, ".wav")   >= 0) return "audio/wav";
   if(StringFind(filename, ".ogg")   >= 0) return "audio/ogg";

   //--- Video
   if(StringFind(filename, ".mp4")   >= 0) return "video/mp4";
   if(StringFind(filename, ".avi")   >= 0) return "video/x-msvideo";
   if(StringFind(filename, ".mov")   >= 0) return "video/quicktime";
   if(StringFind(filename, ".webm")  >= 0) return "video/webm";
   if(StringFind(filename, ".mkv")   >= 0) return "video/x-matroska";

   //--- Applications
   if(StringFind(filename, ".pdf")   >= 0) return "application/pdf";
   if(StringFind(filename, ".zip")   >= 0) return "application/zip";
   //... etc

   //--- Microsoft Office
   if(StringFind(filename, ".doc")   >= 0) return "application/msword";
   if(StringFind(filename, ".docx")  >= 0) return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
   if(StringFind(filename, ".xls")   >= 0) return "application/vnd.ms-excel";   
   //...etc

   return "application/octet-stream"; // Default fallback
}

Пример использования.

Предположим, у нас есть изображение — скриншот графика MetaTrader 5, который мы хотим отправить на сервер.

Для удобной работы с этими файлами необходимо убедиться, что они находятся в MQL5 DataPath.

Воспользуемся сервером tempfiles.org в качестве конечной точки нашего API.

Повторюсь, чтобы это сработало, обязательно добавьте URL-адрес tempfiles.org в список разрешенных URL-адресов в MetaTrader 5;

#include <requests.mqh>
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
          
     string files[] = {"chart.jpg"};
     
     CResponse response = CSession::request("POST","https://tmpfiles.org/api/v1/upload","",files);
          
      Print("Status Code: ", response.status_code);
      Print("Reason: ", response.reason);
      Print("URL: ", response.url);
      Print("OK: ", (string)response.ok);
      Print("Elapsed Time (ms): ", response.elapsed);
      
      Print("Headers:\n", response.headers);
      Print("Cookies: ", response.cookies);
      Print("Response: ",response.text);
      Print("JSON:\n", response.json["url"].ToStr());
  }

Результаты.

CF      0       17:06:25.063    Requests test (XAUUSD,D1)       Status Code: 200
RL      0       17:06:25.063    Requests test (XAUUSD,D1)       Reason: OK
QM      0       17:06:25.063    Requests test (XAUUSD,D1)       URL: https://tmpfiles.org/api/v1/upload
FN      0       17:06:25.063    Requests test (XAUUSD,D1)       OK: true
OH      0       17:06:25.063    Requests test (XAUUSD,D1)       Elapsed Time (ms): 1594
FQ      0       17:06:25.063    Requests test (XAUUSD,D1)       Headers:
RN      0       17:06:25.063    Requests test (XAUUSD,D1)       Server: nginx/1.22.1
QO      0       17:06:25.063    Requests test (XAUUSD,D1)       Content-Type: application/json
KJ      0       17:06:25.063    Requests test (XAUUSD,D1)       Transfer-Encoding: chunked
CS      0       17:06:25.063    Requests test (XAUUSD,D1)       Connection: keep-alive
KE      0       17:06:25.063    Requests test (XAUUSD,D1)       Cache-Control: no-cache, private
RM      0       17:06:25.063    Requests test (XAUUSD,D1)       Date: Thu, 10 Jul 2025 14:06:25 GMT
DF      0       17:06:25.063    Requests test (XAUUSD,D1)       X-RateLimit-Limit: 60
GN      0       17:06:25.063    Requests test (XAUUSD,D1)       X-RateLimit-Remaining: 59
CN      0       17:06:25.063    Requests test (XAUUSD,D1)       Access-Control-Allow-Origin: *
NF      0       17:06:25.063    Requests test (XAUUSD,D1)       
ED      0       17:06:25.063    Requests test (XAUUSD,D1)       Cookies: 
RM      0       17:06:25.063    Requests test (XAUUSD,D1)       Response: {"status":"success","data":{"url":"http://tmpfiles.org/5459540/chart.png"}}
LS      0       17:06:25.063    Requests test (XAUUSD,D1)       JSON:
HJ      0       17:06:25.063    Requests test (XAUUSD,D1)       

После успешного выполнения POST-запроса, tempfiles.org возвращает JSON-ответ, содержащий URL-адрес конечной точки, где размещен файл. Мы можем перейти по этой ссылке и наблюдать в веб-браузере файл изображения.


Получение и загрузка файлов из интернета

Опять же, интернет предназначен для обмена различной информацией и файлами, и возможность получать различные файлы в формате MQL5 очень удобна, поскольку помогает получать данные в форматах CSV и Excel, получать обученные модели машинного обучения и их параметры в различных бинарных форматах и совершать множество иных действий.

Реализованная функция get уже способна это сделать, если предоставить ей правильную конечную точку API.

Например, давайте получим изображение из httpbin.org и сохраним его в пути передачи данных MQL5.

#include <requests.mqh>
CSession requests;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
      //--- Get the image file from the web
      CResponse response = requests.get("https://httpbin.org/image/jpeg");
 }

При успешном выполнении эта функция возвращает зашифрованный файл изображения или данные (в двоичном формате). 

Этот файл находится в переменной CResponse::content.

void OnStart()
  {
      //--- Get the image file from the web
      CResponse response = requests.get("https://httpbin.org/image/jpeg");
      
      //--- Saving an image received in binary format stored in response.content
      
      int handle = FileOpen("image.jpg", FILE_WRITE|FILE_BIN|FILE_SHARE_WRITE); //Open a .jpg file for writting an image to it
      if (handle == INVALID_HANDLE) //Check the handle
         {
            printf("Failed to open an Image. Error=%s",ErrorDescription(GetLastError()));
            return;
         }
         
      if (FileWriteArray(handle, response.content)==0) //write all binary data to a image.jpg file
         {
            printf("Failed to write an Image. Error=%s",ErrorDescription(GetLastError()));
            return;
         }
         
      FileClose(handle);
  }

Результаты.

Изображение, содержащее лису (или какое бы животное это ни было), хранится в папке MQL5/Files.


Обработка сессий и файлов cookie

Возможно, вы заметили, что все функции в классе CSession являются статическими, поэтому данный класс является "статическим".

class CSession
  {
protected:
   //.... other lines of code

public:
                     
                            CSession(const string headers, const string cookies=""); // Provides headers cookies persistance
                           ~CSession(void);
   
   static void SetCookie(const string cookie)
      {
         if (StringLen(m_cookies) > 0)
            m_cookies += "; ";
         m_cookies += cookie;
      }
      
   static void ClearCookies()
      {
         m_cookies = "";
      }
      
   static void              SetBasicAuth(const string username, const string password);
   
   //---
   
   static CResponse         request(const string method, const string url, const string data, const string &files[], const string headers = "", const int timeout = 5000, const bool is_json=true);
   
   // High-level request helpers
   static CResponse         get(const string url, const string headers = "", const int timeout = 5000)  
     {  
       string files[];
       return request("GET", url, "", files, headers, timeout, false);   
     }

     //... other functions
 }

Цель состоит в том, чтобы предоставить разработчикам возможность использовать библиотеку requests частично или полностью, имитируя работу модуля requests в языке Python.

(а) Использование всего объекта класса.

#include <requests.mqh>
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
     
     string headers = "Content-Type: application/json;";
     string cookies = "sessionid=abc123";
     
     CSession session(headers, cookies); //New session, class constructor calle with 
     CResponse response = session.get("https://httpbin.org/cookies"); //receive cookies from the server
        
      Print("HTTP response");  
      Print("--> Status Code: ", response.status_code);
      Print("--> Reason: ", response.reason);
      Print("--> URL: ", response.url);
      Print("--> OK: ", (string)response.ok);
      Print("--> Elapsed Time (ms): ", response.elapsed);
      
      Print("--> Headers:\n", response.headers);
      Print("--> Cookies: ", response.cookies);
      Print("--> Response text: ",response.text);
      Print("--> JSON:\n", response.json.ToStr());
}

Результаты.

DS      0       11:38:36.272    Requests test (XAUUSD,D1)       HTTP response
RI      0       11:38:36.272    Requests test (XAUUSD,D1)       --> Status Code: 200
KR      0       11:38:36.272    Requests test (XAUUSD,D1)       --> Reason: OK
NG      0       11:38:36.272    Requests test (XAUUSD,D1)       --> URL: https://httpbin.org/cookies
IF      0       11:38:36.272    Requests test (XAUUSD,D1)       --> OK: true
QQ      0       11:38:36.272    Requests test (XAUUSD,D1)       --> Elapsed Time (ms): 2141
IH      0       11:38:36.272    Requests test (XAUUSD,D1)       --> Headers:
FQ      0       11:38:36.272    Requests test (XAUUSD,D1)       Date: Sat, 12 Jul 2025 08:38:36 GMT
RE      0       11:38:36.272    Requests test (XAUUSD,D1)       Content-Type: application/json
FO      0       11:38:36.272    Requests test (XAUUSD,D1)       Content-Length: 49
DE      0       11:38:36.272    Requests test (XAUUSD,D1)       Connection: keep-alive
CR      0       11:38:36.272    Requests test (XAUUSD,D1)       Server: gunicorn/19.9.0
PK      0       11:38:36.272    Requests test (XAUUSD,D1)       Access-Control-Allow-Origin: *
HM      0       11:38:36.272    Requests test (XAUUSD,D1)       Access-Control-Allow-Credentials: true
QN      0       11:38:36.272    Requests test (XAUUSD,D1)       
DL      0       11:38:36.272    Requests test (XAUUSD,D1)       --> Cookies: 
LG      0       11:38:36.272    Requests test (XAUUSD,D1)       --> Response text: {
EP      0       11:38:36.272    Requests test (XAUUSD,D1)         "cookies": {
HJ      0       11:38:36.272    Requests test (XAUUSD,D1)           "sessionid": "abc123"
RN      0       11:38:36.272    Requests test (XAUUSD,D1)         }
DE      0       11:38:36.272    Requests test (XAUUSD,D1)       }
EM      0       11:38:36.272    Requests test (XAUUSD,D1)       
MD      0       11:38:36.272    Requests test (XAUUSD,D1)       --> JSON:
GH      0       11:38:36.272    Requests test (XAUUSD,D1)       

Использование целого класса посредством вызова конструктора класса и передачи заголовка и файлов cookie (необязательно) позволяет работать с глобальными значениями заголовков и использовать одни и те же файлы cookie во всех HTTP-запросах, которые будут выполняться с применением одного и того же экземпляра класса. Мы называем это HTTP-сессией.

(b) Использование функций из класса по отдельности

Для выполнения простых HTTP-запросов без нахождения в HTTP-сессии, то есть для управления всеми новыми HTTP-заголовками и файлами cookie без исключения.

Ниже описано, как использовать функции из класса CSession непосредственно, без создания экземпляра объекта класса.

#include <requests.mqh>
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
     
     CResponse response = CSession::get("https://httpbin.org/get"); //The get request 
        
      Print("HTTP response");  
      Print("--> Status Code: ", response.status_code);
      Print("--> Reason: ", response.reason);
      Print("--> URL: ", response.url);
      Print("--> OK: ", (string)response.ok);
      Print("--> Elapsed Time (ms): ", response.elapsed);
      
      Print("--> Headers:\n", response.headers);
      Print("--> Cookies: ", response.cookies);
      Print("--> Response text: ",response.text);
      Print("--> JSON:\n", response.json.ToStr());
 }


Базовая аутентификация

У всех функций в модуле requests языка Python есть возможность отправлять на сервер данные для базовой (простой) аутентификации.

import requests

response = requests.get("https://httpbin.org/headers", auth=("user", "pass"))
print(response.text)

Ниже представлен аналогичный функционал в нашем классе для языка MQL5.

void CSession::SetBasicAuth(const string username, const string password)
  {
   string credentials = username + ":" + password;
   string encoded = Base64Encode(credentials); //Encode the credentials
      
   m_headers = UpdateHeader(m_headers, "Authorization", "Basic " + encoded); //Update HTTP headers with the authentication information
  }

В отличие от модуля языка Python, где разработчики могут передавать эти параметры аутентификации непосредственно в функции, наш класс в MQL5 делает это немного иначе, позволяя пользователям передавать такие основные параметры аутентификации в отдельной функции.

Функция SetBasicAuth обновляет заголовки в классе, добавляя учетные данные для авторизации; эти значения будут доступны всем функциям, вызываемым впоследствии с использованием того же экземпляра класса.

#include <requests.mqh>
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
     
     CSession::SetBasicAuth("user", "pass");   //Sets authentication parameters to the HTTP header
     CResponse response = CSession::get("https://httpbin.org/headers"); //Get the headers from the server
     
      Print("HTTP response");  
      Print("--> Headers:\n", response.headers);
      Print("--> Response text: ",response.text);
 }

Результаты.

IE      0       14:23:23.885    Requests test (XAUUSD,D1)       HTTP response
FQ      0       14:23:23.885    Requests test (XAUUSD,D1)       --> Headers:
KI      0       14:23:23.885    Requests test (XAUUSD,D1)       Date: Sat, 12 Jul 2025 11:23:23 GMT
MM      0       14:23:23.885    Requests test (XAUUSD,D1)       Content-Type: application/json
HK      0       14:23:23.885    Requests test (XAUUSD,D1)       Content-Length: 385
IR      0       14:23:23.885    Requests test (XAUUSD,D1)       Connection: keep-alive
JJ      0       14:23:23.885    Requests test (XAUUSD,D1)       Server: gunicorn/19.9.0
IS      0       14:23:23.885    Requests test (XAUUSD,D1)       Access-Control-Allow-Origin: *
QE      0       14:23:23.885    Requests test (XAUUSD,D1)       Access-Control-Allow-Credentials: true
HF      0       14:23:23.885    Requests test (XAUUSD,D1)       
KG      0       14:23:23.885    Requests test (XAUUSD,D1)       --> Response text: {
KP      0       14:23:23.885    Requests test (XAUUSD,D1)         "headers": {
GH      0       14:23:23.885    Requests test (XAUUSD,D1)           "Accept": "*/*", 
CM      0       14:23:23.885    Requests test (XAUUSD,D1)           "Accept-Encoding": "gzip, deflate", 
DQ      0       14:23:23.885    Requests test (XAUUSD,D1)           "Accept-Language": "en;q=0.5", 
NE      0       14:23:23.885    Requests test (XAUUSD,D1)           "Authorization": "Basic dXNlcjpwYXNz", 
NS      0       14:23:23.885    Requests test (XAUUSD,D1)           "Cookie": "session=abc123;max-age=60;", 
KL      0       14:23:23.885    Requests test (XAUUSD,D1)           "Host": "httpbin.org", 
HK      0       14:23:23.885    Requests test (XAUUSD,D1)           "User-Agent": "MetaTrader 5 Terminal/5.5120 (Windows NT 10.0.19045; x64)", 
NI      0       14:23:23.885    Requests test (XAUUSD,D1)           "X-Amzn-Trace-Id": "Root=1-687245ab-2065056c28f0024b71a6446f"
GH      0       14:23:23.885    Requests test (XAUUSD,D1)         }
IF      0       14:23:23.885    Requests test (XAUUSD,D1)       }


Работа с параметрами URL-адреса

Еще одна классная штука, которую умеет делать модуль requests в языке Python, заключается в том, что он обрабатывает полученный URL-адрес и его параметры перед отправкой окончательного веб-запроса.

import requests

response = requests.get("https://httpbin.org/get", params={"param1": "value1"})
print(response.url)

Результаты.

https://httpbin.org/get?param1=value1

В нашем классе MQL5 мы используем несколько иной подход. Вместо того чтобы передавать параметры URL-адреса всем функциям, что усложнит их работу, мы используем отдельную вспомогательную функцию, которая поможет создать окончательный URL-адрес с заданными параметрами, учитывая исходный URL-адрес и связанные с ним параметры.

#include <requests.mqh>
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
      string keys[]   = {"user", "id", "lang"};
      string values[] = {"omega", "123", "mql5 test"};
      
      string parent_url = "https://httpbin.org/get";
      string final_url =  CSession::BuildUrlWithParams(parent_url, keys, values); //builds a URL with the given parameters
      
      Print("final url: ",final_url);
 }

Результаты.

2025.07.12 15:41:57.924 Requests test (XAUUSD,D1)       final url: https://httpbin.org/get?user=omega&id=123&lang=mql5+test

После создания URL-адреса с соответствующими параметрами вы можете использовать его для выполнения HTTP-запросов к веб-ресурсам.

      CResponse response = CSession::get(final_url); //Get the headers from the server
     
      Print("HTTP response");  
      Print("--> Headers:\n", response.headers);
      Print("--> Response text: ",response.text);

Результаты.

JK      0       15:42:00.398    Requests test (XAUUSD,D1)       --> Headers:
QP      0       15:42:00.398    Requests test (XAUUSD,D1)       Date: Sat, 12 Jul 2025 12:41:59 GMT
QK      0       15:42:00.398    Requests test (XAUUSD,D1)       Content-Type: application/json
PM      0       15:42:00.398    Requests test (XAUUSD,D1)       Content-Length: 525
ED      0       15:42:00.398    Requests test (XAUUSD,D1)       Connection: keep-alive
FP      0       15:42:00.398    Requests test (XAUUSD,D1)       Server: gunicorn/19.9.0
MH      0       15:42:00.398    Requests test (XAUUSD,D1)       Access-Control-Allow-Origin: *
EK      0       15:42:00.398    Requests test (XAUUSD,D1)       Access-Control-Allow-Credentials: true
LM      0       15:42:00.398    Requests test (XAUUSD,D1)       
OI      0       15:42:00.398    Requests test (XAUUSD,D1)       --> Response text: {
RQ      0       15:42:00.398    Requests test (XAUUSD,D1)         "args": {
CR      0       15:42:00.398    Requests test (XAUUSD,D1)           "id": "123", 
KF      0       15:42:00.398    Requests test (XAUUSD,D1)           "lang": "mql5 test", 
HI      0       15:42:00.398    Requests test (XAUUSD,D1)           "user": "omega"
KP      0       15:42:00.398    Requests test (XAUUSD,D1)         }, 
MP      0       15:42:00.398    Requests test (XAUUSD,D1)         "headers": {
IH      0       15:42:00.398    Requests test (XAUUSD,D1)           "Accept": "*/*", 
QL      0       15:42:00.398    Requests test (XAUUSD,D1)           "Accept-Encoding": "gzip, deflate", 
JQ      0       15:42:00.398    Requests test (XAUUSD,D1)           "Accept-Language": "en;q=0.5", 
NF      0       15:42:00.398    Requests test (XAUUSD,D1)           "Cookie": "session=abc123;max-age=60;", 
KQ      0       15:42:00.398    Requests test (XAUUSD,D1)           "Host": "httpbin.org", 
HP      0       15:42:00.398    Requests test (XAUUSD,D1)           "User-Agent": "MetaTrader 5 Terminal/5.5120 (Windows NT 10.0.19045; x64)", 
ND      0       15:42:00.398    Requests test (XAUUSD,D1)           "X-Amzn-Trace-Id": "Root=1-68725817-67dc04cf43ac75b012094481"
KE      0       15:42:00.398    Requests test (XAUUSD,D1)         }, 
CQ      0       15:42:00.398    Requests test (XAUUSD,D1)         "origin": "197.250.227.235", 
MD      0       15:42:00.398    Requests test (XAUUSD,D1)         "url": "https://httpbin.org/get?user=omega&id=123&lang=mql5+test"
IK      0       15:42:00.398    Requests test (XAUUSD,D1)       }
LN      0       15:42:00.398    Requests test (XAUUSD,D1)       

Потрясающе! Сервер даже ответил нам, добавив ключ args в JSON-текст ответа, что указывает на успешное формирование URL-адреса с соответствующими параметрами.


Заключение

При наличии всех доступных общественности бесплатных знаний и информации с открытым исходным кодом в современном мире программирование не должно составить большого труда.

После того как я узнал, как работает модуль requestsв языке Python, мне удалось реализовать аналогичный модуль на MQL5, чтобы упростить отправку HTTP-запросов из MetaTrader 5 на внешние серверы.

Однако, хотя синтаксис и вызовы функций могут выглядеть похожими на те, что предлагаются в модуле requests языка Python, этот модуль MQL5 далек от завершения; нам необходимо тщательно его тестировать и постоянно улучшать, поэтому я создал репозиторий на Forge MQL5 (ссылка -> https://forge.mql5.io/omegajoctan/Requests).

Поэтому не стесняйтесь вносить изменения в код и делиться своими мыслями в разделе обсуждений.

Всем добра.


Таблица вложений

Имя файла Описание и использование
Include\errordescription.mqh Содержит описания всех кодов ошибок, генерируемых MQL5 и MetaTrader 5
Include\Jason.mqh Библиотека для сериализации и десериализации строк в формате, подобном JSON.
Include\requests.mqh Основной модуль, похожий на модуль requests из языка Python.
Scripts\Requests test.mq5 Основной скрипт для тестирования всех функций и методов, описанных в этой публикации.

Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/18728

Прикрепленные файлы |
Attachments.zip (17.51 KB)
Автоматизация торговых стратегий на MQL5 (Часть 22): Создание системы зонального восстановления для трендовой торговли по индикатору Envelopes Автоматизация торговых стратегий на MQL5 (Часть 22): Создание системы зонального восстановления для трендовой торговли по индикатору Envelopes
Мы разработаем систему зонального восстановления (Zone Recovery System), интегрированную со стратегией трендовой торговли на основе конвертов (Envelopes trend-trading strategy) на MQL5. Также мы опишем архитектуру использования индикаторов RSI и конвертов для инициирования сделок и управления зональным восстановлением с целью минимизации потерь. На практике и в ходе тестирования мы продемонстрируем, как создать эффективную автоматизированную торговую систему для динамичных рынков.
Машинное обучение и Data Science (Часть 44): Прогнозирование OHLC-рядов Forex методом векторной авторегрессии (VAR) Машинное обучение и Data Science (Часть 44): Прогнозирование OHLC-рядов Forex методом векторной авторегрессии (VAR)
В этом материале мы познакомимся с тем, как модели векторной авторегрессии (VAR) могут прогнозировать временные ряды значений OHLC (цены открытия, максимум, минимум и цена закрытия) на форексе Поговорим о том, как реализовать VAR-модели, обучать их и строить прогнозы в MetaTrader 5 в реальном времени, чтобы анализировать взаимозависимые движения валютных курсов для получения лучших результатов в трейдинге.
Нейросети в трейдинге: Оптимизация Cross-Attention для анализа длинных последовательностей рынка (Окончание) Нейросети в трейдинге: Оптимизация Cross-Attention для анализа длинных последовательностей рынка (Окончание)
В статье рассматривается практическая реализация архитектуры STCA с интеграцией механизмов OneTrans для совместной обработки временных рядов и контекстных признаков рынка. Описаны особенности построения модели, алгоритмы прямого прохода и накопления исторического состояния. Отдельное внимание уделено процессу обучения и результатам тестирования на реальных данных, демонстрирующим поведение модели в рыночных условиях.
Возможности Мастера MQL5, которые вам нужно знать (Часть 72): Использование паттернов MACD и OBV с обучением с учителем Возможности Мастера MQL5, которые вам нужно знать (Часть 72): Использование паттернов MACD и OBV с обучением с учителем
В продолжение нашей предыдущей статьи о паре индикаторов MACD и OBV, мы рассмотрим, как эту пару можно улучшить с помощью машинного обучения. MACD и OBV — это взаимодополняющая пара, отражающая тренд и объем. Наш подход к машинному обучению использует сверточную нейронную сеть (convolution neural network, CNN), которая задействует экспоненциальное ядро (Exponential kernel) для определения размеров своих ядер и каналов при настройке прогнозов этой пары индикаторов. Как обычно, это делается в пользовательском файле класса сигналов (signal class), который взаимодействует с Мастером MQL5 для создания советника.