Внедрение в MQL5 практических модулей из других языков (Часть 02): Создание библиотеки REQUESTS, как в Python
Разделы
- Введение
- Выполнение веб-запроса
- Разные веб-запросы в разных функциях
- Загрузка файлов в интернет
- Получение и загрузка файлов из интернета
- Обработка сессий и файлов cookie
- Базовая аутентификация
- Работа с параметрами URL-адреса
- Заключение
Введение
Возможность отправлять 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
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Автоматизация торговых стратегий на MQL5 (Часть 22): Создание системы зонального восстановления для трендовой торговли по индикатору Envelopes
Машинное обучение и Data Science (Часть 44): Прогнозирование OHLC-рядов Forex методом векторной авторегрессии (VAR)
Нейросети в трейдинге: Оптимизация Cross-Attention для анализа длинных последовательностей рынка (Окончание)
Возможности Мастера MQL5, которые вам нужно знать (Часть 72): Использование паттернов MACD и OBV с обучением с учителем
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования