- Общие принципы работы с локальными проектами
- План проекта веб-сервиса копирования сделок и сигналов
- Веб-сервер на основе nodejs
- Теоретические основы протокола WebSockets
- Серверная часть веб-сервисов на базе WebSocket-протокола
- Протокол WebSocket-ов на MQL5
- Клиентские программы эхо и чат-сервисов на MQL5
- Сервис торговых сигналов и тестовая веб-страница
- Клиентская программа сигнального сервиса на MQL5
Клиентские программы эхо и чат-сервисов на MQL5
Для подключения к эхо-сервису напишем простой скрипт MQL5/Experts/MQL5Book/p7/wsEcho/wsecho.mq5 (обратите внимание, что это именно скрипт, но мы расположили его внутри папки MQL5/Experts/MQL5Book/p7/, сделав её единым контейнером для MQL-программ, связанных с веб, поскольку все последующие примеры будут экспертами). Поскольку в данной главе мы рассматриваем создание комплексов программ в рамках проектов, оформим скрипт как часть mqproj-проекта, в который также включим и серверную составляющую.
Входные параметры скрипта позволяют указать адрес сервиса и текст сообщения. По умолчанию используется незащищенное соединение. Если сервер wsecho.js будет запущен с поддержкой TLS, нужно поменять протокол на защищенный wss. Имейте в виду, что установление защищенного соединения требует больше времени (например, пару секунд), чем обычного.
input string Server = "ws://localhost:9000/";
|
В функции OnStart создадим экземпляр WebSocket-клиента (wss) для заданного адреса и вызовем метод open. В случае успешного подключения мы ждем приветственного сообщения от сервиса с помощью вызова wss.readMessage в блокирующем режиме (ожидание до 5 секунд, по умолчанию). Мы использует автоуказатель для получаемого объекта, чтобы не вызывать в конце delete вручную.
void OnStart()
|
Напомним, что класс WebSocketClient содержит заглушки обработчиков событий, в том числе и простой метод onMessage, который распечатает приветствие в журнал.
Затем мы отправляем свое сообщение и снова ждем ответа от сервера. Эхо-сообщение также будет выведено в журнал.
Print("Sending message...");
|
В завершение мы закрываем соединение.
if(wss.isConnected())
|
На основе файла скрипта создадим файл проекта (wsecho.mqproj). Заполним в свойствах проекта номер версии (1.0), копирайт, и описание. Добавим в ветвь Settings and files серверные файлы эхо-сервиса (это, как минимум, станет напоминанием разработчику о наличии тестового сервера). После компиляции в иерархии появятся зависимости (заголовочные файлы).
Все должно выглядеть примерно как на скриншоте.
Проект эхо-сервиса, клиентский скрипт и сервер
Если бы скрипт располагался внутри папки Shared Projects, например, в MQL5/Shared Projects/MQL5Book/wsEcho/, то после успешной компиляции его ex5-файл был бы автоматически перемещен в папку MQL5/Scripts/Shared Projects/MQL5Book/wsEcho/, о чем была бы выведена соответствующая запись в журнал компиляции. Это стандартное поведение компиляции любых MQL-программ в разделяемых проектах.
Во всех примерах данной главы не забываем стартовать сервер, прежде чем тестировать MQL-скрипт. В данном случае выполняем команду: node.exe wsecho.js, находясь в папке Web.
Далее запустим скрипт wsecho.ex5. В журнале появятся записи о происходящих действиях, а также уведомления о сообщениях.
Opening...
|
Приведенные выше HTTP-заголовки — это ответ сервера в процессе "рукопожатия". Если заглянуть в окно консоли, где запущен сервер, обнаружим HTTP-заголовки, полученные сервером от нашего клиента.
Серверный журнал эхо-сервиса
Также здесь отмечено подключение пользователя, его сообщение и отключение.
Проделаем аналогичную работу для чат-сервиса: создадим WebSocket-клиент на MQL5, проект под него, и протестируем. На этот раз тип клиентской программы будет эксперт, потому что для чата необходима поддержка интерактивных событий от клавиатуры на графике. Эксперт прилагается к книге в папке MQL5/MQL5Book/p7/wsChat/wschat.mq5.
Для демонстрации технологии получения событий в методах-обработчиках определим собственный класс MyWebSocket, производный от WebSocketClient.
class MyWebSocket: public WebSocketClient<Hybi>
|
При получении сообщения мы будем выводить его не в журнал, а алертом, после чего объект следует удалить.
В глобальном контексте опишем объект нашего класса wss и строку message, где будет аккумулироваться ввод пользователя с клавиатуры.
MyWebSocket wss(Server);
|
Функция OnInit содержит необходимую подготовку, в частности запускает таймер и открывает соединение.
int OnInit()
|
Таймер нужен, чтобы проверять новые сообщений от других пользователей.
void OnTimer()
|
В обработчике OnChartEvent реагируем на нажатия клавиш: все буквенно-цифровые клавиши транслируются в символы и присоединяются к строке message. При необходимости можно нажать Backspace, чтобы удалить последний знак. Весь набранный текст обновляется в комментарии графика. Когда сообщение набрано полностью, нажатие Enter отправляет его на сервер.
void OnChartEvent(const int id, const long &lparam, const double &dparam,
|
Если ввести текст "long", программа отправит специально подготовленный довольно длинный текст. Если текст сообщения "bye", программа закрывает соединение. Также соединение закроется при выходе из программы.
void OnDeinit(const int)
|
Создадим под эксперт проект (файл wschat.mqproj), заполним его свойства и добавим серверную часть в ветвь Settings and files. На этот раз покажем, как файл проекта выглядит изнутри. В mqproj-файле ветвь Dependencies хранится в свойстве "files", а ветвь Settings and files — в свойстве "tester".
{ "platform" :"mt5", "program_type":"expert", "copyright" :"Copyright 2022, MetaQuotes Ltd.", "version" :"1.0", "description" :"WebSocket-client for chat-service.\r\nType and send text messages for all connected users.\r\nShow alerts with messages from others.", "optimize" :"1", "fpzerocheck" :"1", "tester_no_cache":"0", "tester_everytick_calculate":"0", "unicode_character_set":"0", "static_libraries":"0", "files": [ { "path":"wschat.mq5", "compile":true, "relative_to_project":true }, { "path":"MQL5\\Include\\MQL5Book\\ws\\wsclient.mqh", "compile":false, "relative_to_project":false }, { "path":"MQL5\\Include\\MQL5Book\\URL.mqh", "compile":false, "relative_to_project":false }, { "path":"MQL5\\Include\\MQL5Book\\ws\\wsframe.mqh", "compile":false, "relative_to_project":false }, { "path":"MQL5\\Include\\MQL5Book\\ws\\wstools.mqh", "compile":false, "relative_to_project":false }, { "path":"MQL5\\Include\\MQL5Book\\ws\\wsinterfaces.mqh", "compile":false, "relative_to_project":false }, { "path":"MQL5\\Include\\MQL5Book\\ws\\wsmessage.mqh", "compile":false, "relative_to_project":false }, { "path":"MQL5\\Include\\MQL5Book\\ws\\wstransport.mqh", "compile":false, "relative_to_project":false }, { "path":"MQL5\\Include\\MQL5Book\\ws\\wsprotocol.mqh", "compile":false, "relative_to_project":false }, { "path":"MQL5\\Include\\VirtualKeys.mqh", "compile":false, "relative_to_project":false } ], "tester": [ { "type":"file", "path":"..\\Web\\MQL5Book.crt", "relative_to_project":true }, { "type":"file", "path":"..\\Web\\MQL5Book.key", "relative_to_project":true }, { "type":"file", "path":"..\\Web\\wschat.htm", "relative_to_project":true }, { "type":"file", "path":"..\\Web\\wschat.js", "relative_to_project":true }, { "type":"file", "path":"..\\Web\\wschat_client.js", "relative_to_project":true } ] } |
Если бы эксперт находился внутри папки Shared Projects, например, в MQL5/Shared Projects/MQL5Book/wsChat/, после успешной компиляции его ex5-файл был бы автоматически перемещен в папку MQL5/Experts/Shared Projects/MQL5Book/wsChat/.
Стартуем сервер node.exe wschat.js. Теперь можно запустить пару копий эксперта на разных графиках. В принципе, сервис предполагает "общение" между разными терминалами и даже разными компьютерами, но никто не запрещает тестировать его из одного терминала.
Вот пример общения между чартами EURUSD и GBPUSD.
(EURUSD,H1)
|
Поскольку у нас сообщения рассылаются всем, включая отправителя, они задвоены в журнале, но на разных чартах.
Общение видно и на стороне сервера.
Серверный журнал чат-сервиса
Теперь у нас готова вся техническая составляющая для организации сервиса торговых сигналов.