preview
Разрабатываем менеджер терминалов (Часть 1): Постановка задачи

Разрабатываем менеджер терминалов (Часть 1): Постановка задачи

MetaTrader 5Трейдинг |
526 0
Yuriy Bykov
Yuriy Bykov

Введение

Если мы хотим использовать один советник на своём торговом счёте, то никаких проблем — запускаем терминал, ставим и ждём результат. Представим себе ситуацию, когда торговля идёт хорошо, и возникает желание попробовать подключить ещё одного или нескольких советников. Если они могут работать не мешая друг другу, то хорошо. Если нет — надо запускать для них отдельные копии терминала. Также они понадобятся, если нужно будет торговать на разных счетах.

Тут постепенно начинают возникать уже организационные и технические сложности. Как можно облегчить себе жизнь, обеспечив возможность удобного контроля за несколькими терминалами, на которых торгуют советники? Причём терминалы могут физически располагаться на разных компьютерах (серверах). Что для этого можно предпринять?

Раньше для чего-то подобного можно было использовать MultiTerminal. Но он позволял осуществлять на нескольких счетах только ручную торговлю. И только на MetaTrader 4. Потом он и вовсе перестал поддерживаться, а его аналог для MetaTrader 5 так и не вышел. Существующие сейчас сторонние инструменты предлагают лишь мониторинг, но не полноценное управление.

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


Архитектура

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

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

  2. Веб-сервер(ы) терминалов. Это компонент, который работает непосредственно на каждом компьютере, где установлены торговые терминалы. Для исполнения команд, полученных от главного веб-сервера, мониторинга состояния локально запущенных терминалов MetaTrader 5 и предоставления актуальной информации будем использовать Python с библиотекой MetaTrader 5.

  3. Хранилище данных. Для хранения информации о серверах, терминалах, счетах и их конфигурациях воспользуемся SQLite на начальном этапе. Это легковесная база данных, которая идеально подходит для прототипа и простых развёртываний. К тому же, к ней можно обращаться как из Python, так и из программ на MQL5, что открывает возможности для интеграции. В будущем, при росте нагрузки и распределённости системы, SQLite можно будет заменить на более мощную СУБД, например, PostgreSQL, но до этого ещё надо сначала дожить.

Возможно, нам понадобится ещё вспомогательный агент в самих терминалах — советник или сервис, точно пока не ясно.

Весь код будем размещать как публичный проект или проекты в хранилище MQL5 Algo Forge.


Намечаем путь

Задача, конечно, очень объёмная и поэтому требует определённых усилий, чтобы хотя бы начать работать над её решением. Но мы уже неоднократно пользовались простым принципом, который хорошо помогает в таких ситуациях. Одним из его названий можно считать такое: "Как съесть слона? — По кусочкам". Это означает, что любую сложную задачу нужно разбивать на маленькие, выполнимые части, и решать их поочерёдно, пока не будет достигнута общая цель. Это поможет избежать перегрузки, сохранить мотивацию и быстрее достичь результата. 

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

Давайте посмотрим, что нам для этого понадобится, и как этим можно воспользоваться для получения минимального жизнеспособного продукта (Minimum Viable Product, MVP).


Вспомним понятия

Мы упомянули, что будем разрабатывать веб-сервер. Так можно назвать приложение, которое ожидает поступления определённого вида запросов по сети и умеет на них отвечать, отправляя назад нужные данные. Множество видов запросов, которые сможет обрабатывать наш веб-сервер образуют его API.

Более строго, API (Application Programming Interface — программный интерфейс приложения) — это набор определённых правил, который позволяет одному приложению взаимодействовать с другим. Он определяет, каким образом и какие данные можно запрашивать или отправлять между программами, сервисами или компонентами системы. Более просто, API — это набор правил, по которому одна программа может обратиться к другой, чтобы обменяться данными.

Чтобы таким набором правил было удобно пользоваться, запросы и ответы должны соответствовать определённому формату, который будет строго документирован. То есть разработчики описывают, какие запросы доступны, какие параметры принимаются, и что возвращается в ответах.

В нашем проекте мы будем отправлять HTTP-запросы на веб-сервер и получать в ответ либо данные в формате JSON, либо текст веб-страницы формате HTML.

Любой HTTP-запрос состоит из следующих частей:

  1. Метод (например, GET, POST, PUT, DELETE) — определяет действие. Ещё его могут называть "глагол";
  2. URL — адрес ресурса на сервере (например, /start );
  3. Заголовки (headers) — метаданные запроса (например, Content-Type , Authorization);
  4. Тело запроса (body) — данные, отправляемые на сервер (например, JSON или данные из формы на веб-странице).

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

Например, запросы, основным результатом которых будет получение от сервера некоторой информации, обычно начинаются со слова GET. Поэтому их так называют: GET-запросы. Если же запрос должен передать на сервер какие-то данные для сохранения на сервере, то обычно используется глагол POST или PUT. Однако, подчеркнём ещё раз, что выбор лежит на разработчике. Можно для выполнения всех запросов использовать только метод GET, например. Или только POST.

Следующая часть — URL — конкретизирует запрос, позволяя веб-серверу понять, что от него требуется. URL, адресованные определённому веб-серверу, обычно указываются без имени этого веб-сервера, то есть начиная с символа слеша "/", обозначающего корневую папку в дереве ресурсов. URL может состоять из нескольких частей, разделяемых прямыми слешами "/".

Если мы договариваемся для выполнения какого-то конкретного действия веб-сервера отправлять ему запрос с определённым глаголом и URL, то говорят, что мы определили "конечную точку" (endpoint) или "маршрут" (route).

Например, так может выглядеть конечная точка, которая должна заставлять веб-сервер возвращать HTML-страницу с названием проекта и его кратким описанием: 

GET /

А так можно выбрать конечную точку для получения от веб-сервера списка всех запущенных на нём экземпляров MetaTrader 5 в формате JSON:

GET /instances

Для некоторых конечных точек нам может понадобиться передавать дополнительные параметры. В этом случае описание названий и возможных значений каждого параметра должно быть где-то обязательно сделано. Параметры могут передаваться или в составе URL, как его часть, или в заголовках, или в теле запроса. 

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

GET /instance/<name>

Здесь <name> — это изменяемая часть запроса, в которую подставляется имя нужного экземпляра перед отправкой.

Совокупность всех выбранных конечных точек (маршрутов) с их детальным описанием как раз и будет образовывать API нашего веб-сервера.

Существуют разные виды API. Тот, что мы планируем использовать в данном проекте, называется REST API (от Representational State Transfer Application Programming Interface). Это архитектурный стиль взаимодействия между клиентом и сервером через интернет с использованием стандартных HTTP-запросов. Ему как раз свойственно то, что мы собираемся использовать:

  • Состояние не хранится на сервере. Каждый запрос содержит всю необходимую информацию для формирования ответа, поэтому серверу нет необходимости "помнить" цепочку прошлых обращений. Однако, это не означает, что сервер не может сохранять у себя никакой информации, полученной в ходе обработки прошлых запросов. Это основная отличительная особенность такого API.

  • HTTP-методы как вид действия. В REST API, как правило, используются разные названия методов HTTP-запросов для разных операций с единицами данных на сервере: GET — для получения данных, POST — для создания новых записей, PUT / PATCH — для обновления существующих и DELETE — для удаления. Но это лишь рекомендация.

  • Ресурсная структураВсе данные, которыми обладает сервер, представляются в виде ресурсов с уникальными URL. Например, как мы упоминали выше:

    • /instances — список всех терминалов,
    • /instance/4428341 — информация о конкретном терминале с названием 4428341.

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

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

В создании такой программы мы тоже воспользуемся двумя уже готовыми решениями:

  • Uvicorn — сервер для Python, который быстро и эффективно обрабатывает HTTP-запросы с поддержкой асинхронности. Он используется для запуска веб-приложений, созданных в том числе с помощью FastAPI;
  • FastAPI — фреймворк, который помогает описывать логику приложения (обработку запросов для всех конечных точек).

Фреймворк — это, как правило, готовый исходный код, содержащий реализацию типовых действий, которые могут понадобится разработчикам при работе над своими проектами. Чем фреймворк отличается от библиотеки? Пожалуй, только тем, что применение кода из фреймворка обладает большей ограниченностью сценариев, то есть фреймворк задаёт более чёткие рамки того, как надо вести разработку.


Использование FastAPI

Общие принципы разработки с использованием фреймворка FastAPI можно изложить так:

  • Веб-приложение состоит из набора функций — обработчиков запросов к каждой конечной точке. Они могут быть как синхронными, так и асинхронными. Разработчик пишет только их.
  • Над каждым обработчиком стоит декоратор, выполняющий роль привязки данной функции к конкретной конечной точке. В нём (декораторе) указывается соответствующий HTTP-метод, URL и другие необходимые параметры.
  • В функции можно получить параметры из тела запроса, заголовков, URL и т.д., используя специальные типы из фреймворка FastAPI (например, Form, Query, Path, Body).
  • Функция возвращает ответ, который FastAPI автоматически преобразует в JSON или в HTML.

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


Создаём первый вариант веб-сервера

Для работы над проектом мы создали новый пустой репозиторий mt5-manager в хранилище MQL5 Algo Forge. Клонируем его в любую удобную папку и добавим новый файл нашего веб-приложения main.py:

mt5-manager/

└── main.py                 # Основной файл FastAPI

Для работы с выбранным фреймворком и сервером нам понадобится установить необходимые модули Python, используя менеджер pip:

pip install fastapi uvicorn jinja2 psutil

Начнём составлять список нужных конечных точек (маршрутов). Добавим в него пока что один маршрут:

# Метод URL Описание, параметры Формат
ответа 
1 GET / Отображает главную страницу с веб-интерфейсом для управления экземплярами MetaTrader 5
Пока что пусть отображается только заголовок с названием проекта.
HTML

Создадим минимальное веб-приложение, обрабатывающее этот маршрут. Для этого в самом начале выполним импорт из фреймворка FastAPI главного класса приложения. Этот класс так и называется — FastAPI:

from fastapi import FastAPI

Затем создадим объект этого класса. Это будет объект нашего веб-приложения. Назовём его, например, app:

app = FastAPI()

Добавим функцию с именем index(), которая будет возвращать заголовок первого уровня с названием проекта. Сделаем её асинхронной, добавив ключевое слово async:

async def index():
    return '<h1>MT5 Manager</h1>'

Теперь осталось сделать последний, но очень важный шаг — добавить связующий декоратор. Но сначала, давайте немного подробнее поясним, что это такое.

Декораторы в Python — это функции, которые модифицируют поведение других функций (или классов), не изменяя их код напрямую. Модификация выполняется за счёт создания новой функции, которая внутри себя как-то использует исходную функцию. Если эту новую функцию далее сохранить под именем исходной, то все дальнейшие вызовы будут адресованы уже к модифицированной функции. Таким образом можно добавлять дополнительную логику (например, проверку, логирование, кеширование) перед или после выполнением кода исходной основной функции. 

Чтобы применить декоратор к функции надо либо вызвать его напрямую:

# Исходная функция
def my_function():
    pass

# Вызываем функцию-декоратор, передавая ей исходную функцию
# Возвращаемую новую функцию запоминаем под тем же именем
my_function = my_decorator(my_function)

Либо, что всегда и используется, просто указать имя нужного декоратора перед заголовком функции с символом @ вначале:

# Создание новой функции с применённым декоратором my_decorator
@my_decorator
def my_function():
    pass

Добавим теперь нужный нам декоратор:

@app.get('/')
async def index():
    return '<h1>MT5 Manager</h1>'

То есть @app.get('/') — это декоратор, который указывает FastAPI, что функция index() должна обрабатывать GET-запросы по пути /.

Соберём всё вместе в файле main.py:

# Импортируем нужные классы из библиотек
from fastapi import FastAPI

# Создаём объект приложения
app = FastAPI()

# Обработчик GET-запросов по адресу / (корневой каталог)
@app.get('/')
async def index():
    return '<h1>MT5 Manager</h1>'

Минимальное веб-приложение готово к запуску. Теперь нам понадобится обратиться к серверу Uvicorn, запустив его в консоли с указанием нашего веб-приложения как источника правил обработки запросов:

uvicorn main:app --reload --no-use-colors

Здесь main:app означает, что наше веб-приложение находится в файле с именем main.py в текущей папке, а объект приложения в исходном коде называется app. Параметр --reload заставляет автоматически перезапускать сервер при внесении изменений в исходный код веб-приложения. Параметр --no-use-colors отключает использование вывода текста в консоли с применением разных цветов (нужен если сервер запускается в консоли, которая это не поддерживает).

После запуска мы увидим примерно следующее:

По умолчанию веб-сервер будет использовать порт 8000, поэтому, чтобы увидеть результат его работы, зайдём в браузер по адресу http://127.0.0.1:8000. Вот что получится:

Как видно, на странице действительно показывается тот текст, который мы возвращаем из функции index(). Но только браузер почему-то не воспринимает HTML-теги заголовка, показывая их просто как часть текста страницы. Всё в порядке, так и должно быть. Дело в том, что по умолчанию сервер отдаёт результат, сопровождая его информацией, что это JSON-код. Поэтому браузер и не стал разбирать полученный текст как HTML-код. Сейчас мы это исправим.

Импортируем ещё один класс из фреймворка FastAPI, который является представлением ответа сервера в формате HTML. В строке применения декоратора добавим дополнительный параметр response_class, через который передадим имя класса HTMLResponse.

# Импортируем нужные классы из библиотек
from fastapi import FastAPI
from fastapi.responses import HTMLResponse

# Создаём объект приложения
app = FastAPI()

# Обработчик GET-запросов по адресу / (корневой каталог)
@app.get('/', response_class=HTMLResponse)
async def index():
    return '<h1>MT5 Manager</h1>'

Теперь строка, возвращаемая из нашей исходной функции, будет использоваться для создания объекта класса HTMLResponse. Именно объект такого класса будет возвращаться при вызове преобразованной декоратором функции.

После сохранения этих изменений, запущенный ранее сервер Uvicorn автоматически перезагрузится, и мы увидим в браузере ожидаемую картину:

Первая версия готова, теперь можно подумать и о расширении списка обрабатываемых маршрутов.


Добавляем запуск/остановку терминала

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

C:/Program Files/MetaTrader 5/terminal64.exe

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

# Метод URL Описание, параметры Формат
ответа 
1 GET / Отображает главную страницу с веб-интерфейсом для управления экземплярами MetaTrader 5
Пока что пусть отображается только заголовок с названием проекта.
HTML
POST /start  Запускает экземпляр терминала MetaTrader 5 по установленному пути. JSON
3 POST
/stop  Останавливает запущенный процесс MetaTrader 5 JSON

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

Импортируем ещё один класс из фреймворка:

from fastapi.responses import HTMLResponse, JSONResponse

Теперь его можно использовать по аналогии с тем, как мы использовали класс HTMLResponse, или выполняя явное создание объекта нужного класса при возврате значения из обработчика маршрута. Покажем ниже, как выглядит второй вариант.

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

# Обработчик POST /start - запуск терминала
@app.post('/start')
async def start_instance():
    result = start_mt5()
    return JSONResponse(result)

# Обработчик POST /stop - остановка терминала
@app.post('/stop', response_class=JSONResponse)
async def stop_instance():
    result = stop_mt5()
    return JSONResponse(result)

Функции start_mt5() и stop_mt5() мы напишем чуть ниже. По названию понятно, что именно в них будет располагаться код, отвечающий за непосредственный запуск или остановку терминала MetaTrader 5.

Но сначала мы создадим константу с полным путём к запускаемому файлу терминала и словарь для хранения информации о запущенном процессе:

# Путь к запускаемому файлу терминала
MT5_PATH = 'C:/Program Files/MetaTrader 5/terminal64.exe'

# Словарь для хранения информации о запущенном терминале
instances = {}

Для функции запуска терминала нам пригодится библиотека subprocess, поэтому подключим её вначале, а затем уже реализуем саму функцию start_mt5(). Запуск реализуем пока через вызов функции Popen(), которой надо передать список аргументов командной строки запуска. У нас этот список будет состоять из единственного элемента — полного пути к файлу терминала MetaTrader 5.

import subprocess

# Запуск терминала
def start_mt5():
    # Запускаем новый процесс
    process = subprocess.Popen([MT5_PATH])

    # Идентификатор запущенного процесса
    pid = process.pid

    # Запоминаем идентификатор и статус процесса
    instances['default'] = {'pid': pid, 'status': 'running'}
    
    # Возвращаем результат - успешный запуск
    return {'instance': 'default', 'pid': pid}

Использование такого способа запуска позволяет сейчас более легко реализовать функцию остановки терминала. Так как при запуске мы запоминаем идентификатор нового процесса (pid), то для его остановки мы можем воспользоваться библиотекой psutil, в которой есть класс представления запущенных процессов. В функции stop_mt5() мы создаёт объект этого класса по идентификатору нужного процесса и затем останавливаем его, вызывая метод terminate().

Если всё в порядке, то возвращаем информацию об успешной остановке, иначе — о том, что процесс не найден.

import psutil

# Остановка терминала
def stop_mt5():
    # Если ранее терминал был запущен 
    if 'default' in instances:
        # Берём идентификатор его процесса
        pid = instances['default']['pid']
        try:
            # Получаем объект процесса терминала
            p = psutil.Process(pid)

            # Останавливаем процесс
            p.terminate()

            # Удаляем информацию о запущенном ранее процессе
            del instances['default']

            # Возвращаем результат - успешная остановка
            return {'status': 'stopped', 'instance': 'default'}
        except psutil.NoSuchProcess:
            # Если процесс не найден, то
            # удаляем информацию о запущенном ранее процессе
            del instances['default']
    
    # Возвращаем результат - процесс не найден
    return {'status': 'not found', 'instance': 'default'}

Сохраним сделанные изменения в файле main.py и посмотрим, как можно протестировать добавленную функциональность.


Документация и тестирование

Если первый маршрут мы вполне можем протестировать, просто указав нужный URL в адресной строке, то второй и третий так протестировать не получится. Это связано с тем, что при отправке запроса из адресной строки браузер всегда использует GET-запросы. А нам теперь нужно проверить, как работают конечные точки, до которых можно достучаться только POST-запросом. К счастью, фреймворк нам поможет и в этом случае.

FastAPI автоматически генерирует интерактивную документацию API на основе декораторов и аннотаций типов в коде. Также FastAPI включает встроенную поддержку Swagger UI (Swagger или OpenAPI — это стандарт описания REST API), которая позволяет просматривать и тестировать все конечные точки прямо в браузере. Это очень удобно, особенно если мы будем впоследствии использовать этот API в других веб-приложениях.

Для получения доступа к этому инструменту, достаточно после запуска приложения веб-сервера открыть страницу по адресу http://127.0.0.1:8000/docs. Хотя мы сами не добавляли такую конечную точку, она доступна в любом веб-приложении, созданном с использованием фреймворка FastAPI.

При заходе на эту страницу, мы увидим список всех конечных точек (маршрутов) нашего веб-сервера, которые были добавлены в веб-приложении:

Каждый маршрут можно раскрыть и увидеть список параметров с описаниями, формат ответа. У наших маршрутов пока параметров нет, поэтому мы видим пока только "No parameters":

Но самое интересное, это конечно же возможность вручную послать запрос к каждой конечной точке и посмотреть результат. Для этого нажмем в открытом маршруте на кнопку "Try it out" и затем на появившуюся кнопку "Execute".

В результате мы увидим полученный от веб-сервера ответ с кодом 200 (OK) и информацию о запущенном экземпляре терминала MetaTrader 5 с идентификатором процесса pid=16480. Открыв диспетчер задач Windows на нашем компьютере, можно убедиться, что такой процесс действительно есть, и это именно терминал MetaTrader 5:

Если теперь сделать то же самое для маршрута POST /stop, то запущенный терминал прекратит свою работу, а веб-сервер пришлёт в ответ подтверждение:

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


Заключение

На этом мы приостановимся и посмотрим, что нам удалось сделать на пути к достижению поставленной цели. Мы успешно создали работающий прототип системы управления терминалами MetaTrader 5. Наш минимальный веб-сервер на FastAPI уже умеет запускать и останавливать терминал по обычному HTTP-запросу. Мы не только реализовали базовую логику, но и убедились в её работоспособности.

Этот MVP — критически важный первый шаг, который подтверждает правильность выбранного пути. Мы "откусили первый кусок от слона" и получили фундамент, на котором можно строить дальнейшую функциональность. Следующими логичными шагами станут:

  • Добавление возможности регистрировать несколько компьютеров с терминалами.
  • Создание интерфейса для привязки торговых счетов к конкретным серверам и терминалам.
  • Расширение API для получения детальной информации о статусе счетов, открытых позициях и работе советников.

Путь предстоит долгий, но первый шаг уже сделан.

Спасибо за внимание, до следующей встречи!


Содержание архива

#
Имя Версия Описание Последние изменения
  mt5-manager   Рабочая папка проекта веб-сервера терминалов  
1 main.py 1.00
Веб-приложение для веб-сервера терминалов
Часть 1
Прикрепленные файлы |
main.py (2.77 KB)
От начального до среднего уровня: Индикатор (II) От начального до среднего уровня: Индикатор (II)
В этой статье мы рассмотрим, как реализовать расчет скользящей средней и какие меры предосторожности следует предпринять при выполнении данного расчета. Мы также поговорим о перегрузке функции OnCalculate, чтобы знать, когда и как работать с той или иной моделью.
Генеративно-состязательные сети (GAN) для синтетических данных в сфере финансового моделирования (Часть 2): Создание синтетического символа для тестирования Генеративно-состязательные сети (GAN) для синтетических данных в сфере финансового моделирования (Часть 2): Создание синтетического символа для тестирования
В этой статье мы создаем синтетический символ с использованием генеративно-состязательной сети (GAN), которая включает в себя генерацию реалистичных финансовых данных, имитирующих поведение реальных рыночных инструментов, таких как EURUSD. Модель GAN изучает закономерности и волатильность на основе исторических рыночных данных и создает синтетические ценовые данные с аналогичными характеристиками.
Автоматизация торговых стратегий на MQL5 (Часть 11): Разработка многоуровневой системы сеточной торговли Автоматизация торговых стратегий на MQL5 (Часть 11): Разработка многоуровневой системы сеточной торговли
В настоящей статье мы разрабатываем советник многоуровневой системы сеточной торговли с использованием MQL5, уделяя особое внимание архитектуре и алгоритмам, лежащим в основе стратегий сеточной торговли. Мы изучим внедрение многоуровневой сетевой логики и методов управления рисками для работы в изменяющихся рыночных условиях. Наконец, приведём подробные объяснения и практические советы, которые помогут вам в создании, тестировании и совершенствовании автоматической торговой системы.
Алгоритм голубых обезьян — Blue Monkey (BM) Algorithm Алгоритм голубых обезьян — Blue Monkey (BM) Algorithm
В статье представлена реализация метаэвристического алгоритма Blue Monkey, основанного на моделировании социального поведения голубых мартышек. Рассматриваются ключевые механизмы алгоритма - групповая структура популяции, следование за локальными лидерами и обновление поколений через замену худших взрослых особей лучшими детёнышами, а также анализируются результаты тестирования.