English 中文 Español Deutsch 日本語 Português
preview
Как разработать агент обучения с подкреплением на MQL5 с интеграцией RestAPI (Часть 3): Создание автоматических ходов и тестовых скриптов на MQL5

Как разработать агент обучения с подкреплением на MQL5 с интеграцией RestAPI (Часть 3): Создание автоматических ходов и тестовых скриптов на MQL5

MetaTrader 5Примеры | 30 апреля 2024, 12:34
734 0
Jonathan Pereira
Jonathan Pereira

Введение

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

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

Руководство по установке и внедрению

Предварительные требования:

  • Python 3.6 или выше.
  • На компьютере установлен MetaTrader 5.
  • В Windows убедитесь, что выполнение скриптов разрешено. При необходимости запустите Set-ExecutionPolicy RemoteSigned в PowerShell от имени администратора, чтобы разрешить выполнение скрипта.

Этапы установки и внедрения:

  1. Загружаем и распаковываем проект — после загрузки проекта статьи распаковываем файлы в выбранную папку.
  2. Копируем его в папку Experts — перемещаем папку, которую извлекли, в папку 'Experts' в терминале MetaTrader.
  3. Открываем папку в терминале:
    • В Windows это можно сделать, найдя "Command Prompt" или "PowerShell" в меню "Пуск", открыв программу и используя команду cd folder_path для перехода к соответствующей папке проекта.
    • В MacOS или Linux откроем "Терминал" и выполним команду cd folder_path.
  4. Создаем виртуальную среду — открываем папку с проектом в терминале, запускаем python -m venv env, чтобы создать виртуальную среду.
  5. Активируем виртуальную среду — в Windows запускаем команду env\Scripts\activate. В MacOS или Linux выполняем команду source env/bin/activate.
  6. Устанавливаем зависимости — после включения виртуальной среды запускаем pip install -r requirements.txt.

Выполнение проекта:

  • Чтобы запустить API игры "крестики-нолики", открываем терминал в папке с проектом, запускаем python AppTicTacToe.py.
  • Для выполнения в MetaTrader открываем MetaEditor, переходим в меню Инструменты > Параметры > Компиляторы. Вставляем путь к папке "scripts" виртуальной среды в "External compile location", нажимаем кнопку compile и/или перетаскиваем скрипт на график.
  • Доступ к пользовательскому интерфейсу Swagger: переходим по адресу localhost:8000/docs в браузере, чтобы взаимодействовать с API через пользовательский интерфейс Swagger.

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

Статья состоит из 3 частей:

  1. Развитие автоматических ходов в игре "крестики-нолики" — подробно описывается процесс модификации игры "крестики-нолики" с учетом логики автоматических ходов, включая использованные методы программирования и возникшие трудности.
  2. Создание тестовых скриптов на языке MQL5 — изучение процесса разработки модульных тестов на MQL5 с акцентом на способы проверки взаимодействия между MQL5 и REST API.
  3. Практические и интеграционные проверки — практическая демонстрация интеграции внедренных улучшений, включая проверки и оценку результатов.

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

Таким образом, разработка агента на MQL5, взаимодействующего с игрой в "крестики-нолики", становится следующим логическим шагом. Данный агент сможет имитировать реального пользователя, выполняя движения и реагируя на действия в игре, тем самым создавая тестовую среду, приближенную к реальности. Эта стратегия позволяет нам не только проверить функциональность игры и API, но и изучить (и улучшить) алгоритмы принятия решений в автоматических играх, обеспечивая более сложный и увлекательный игровой опыт.

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


 


Разработка автоматических ходов

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

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

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

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

Инициализация игры:

def __init__(self):
    self.board = [[' ' for _ in range(3)] for _ in range(3)]
    self.player_turn = True

В этом разделе игра начинается с пустого игрового поля (self.board), а переменная self.player_turn указывает на ход игрока. Минималистичный дизайн обеспечивает идеальную отправную точку для интеграции логики автоматизированной игры без усложнения существующего кода.

Отображение игрового поля:

def print_board(self):
    for row in self.board:
        print("|".join(row))
        print("-" * 5)
Метод print_board обрабатывает отображение игрового поля. То, как представлено состояние игры, имеет решающее значение для поддержания удобства и понимания игры, особенно после внедрения автоматических ходов.


Проверка победителя:

 def check_winner(self):
     for i in range(3):
         if self.board[i][0] == self.board[i][1] == self.board[i][2] != ' ':
             return self.board[i][0]
         if self.board[0][i] == self.board[1][i] == self.board[2][i] != ' ':
             return self.board[0][i]
     if self.board[0][0] == self.board[1][1] == self.board[2][2] != ' ':
         return self.board[0][0]
     if self.board[0][2] == self.board[1][1] == self.board[2][0] != ' ':
         return self.board[0][2]
     return None

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

Выполнение ходов:

 def make_move(self, row, col):
     if self.board[row][col] == ' ':
         if self.player_turn:
             self.board[row][col] = 'X'
         else:
             self.board[row][col] = 'O'
         self.player_turn = not self.player_turn
     else:
         print("Недопустимый ход. Попробуйте еще раз.")

Метод make_move отвечает за ходы игроков. Реализация автоматических перемещений потребует модификации данного метода для эффективного переключения между ручными и автоматическими ходами.


Выполнение автоматических ходов:

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

def machine_move(self):
    for i in range(3):
        for j in range(3):
            if self.board[i][j] == ' ':
                # First try to find a winning move for 'O'
                self.board[i][j] = 'O'
                if self.check_winner() == 'O':
                    return (i, j)  # Return position for win
                self.board[i][j] = ' '

                # Then try to block a winning move for 'X'
                self.board[i][j] = 'X'
                if self.check_winner() == 'X':
                    self.board[i][j] = 'O'  # Block the player's win
                    return (i, j)
                self.board[i][j] = ' '

    # If there are no winning moves, randomly choose a free position
    available_moves = self.available_moves()
    if available_moves:
        move = random.choice(available_moves)
        self.board[move["row"]][move["col"]] = 'O'
        return (move["row"], move["col"])



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

def available_moves(self):
    moves = []
    for i in range(3):
        for j in range(3):
            if self.board[i][j] == ' ':
                moves.append({"row": i, "col": j})
    return moves


Благодаря этим изменениям игра в "крестики-нолики" становится интереснее. Она остается простой, но теперь в ней существует дополнительный элемент неожиданности и стратегии благодаря автоматическим ходам. И это делает игру еще более увлекательной.

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

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

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

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

Ниже приведен полный код игры:

class TicTacToe:

    def __init__(self):
        self.board = [[' ' for _ in range(3)] for _ in range(3)]
        self.player_turn = True

    def print_board(self):
        for row in self.board:
            print("|".join(row))
            print("-" * 5)
        print(f"Player {self.player_turn}'s turn")

    def check_winner(self):
        for i in range(3):
            if self.board[i][0] == self.board[i][1] == self.board[i][2] != ' ':
                return self.board[i][0]
            if self.board[0][i] == self.board[1][i] == self.board[2][i] != ' ':
                return self.board[0][i]
        if self.board[0][0] == self.board[1][1] == self.board[2][2] != ' ':
            return self.board[0][0]
        if self.board[0][2] == self.board[1][1] == self.board[2][0] != ' ':
            return self.board[0][2]
        return None

    def machine_move(self):
        for i in range(3):
            for j in range(3):
                if self.board[i][j] == ' ':
                    self.board[i][j] = 'O'
                    if self.check_winner() == 'O':
                        return (i, j)
                    self.board[i][j] = ' '
                    self.board[i][j] = 'X'
                    if self.check_winner() == 'X':
                        self.board[i][j] = 'O'
                        return (i, j)
                    self.board[i][j] = ' '

        for i in range(3):
            for j in range(3):
                if self.board[i][j] == ' ':
                    self.board[i][j] = 'O'
                    return (i, j)


    def available_moves(self):
        moves = []
        for i in range(3):
            for j in range(3):
                if self.board[i][j] == ' ':
                    moves.append({"row": i, "col": j})
        return moves

Теперь, когда мы реализовали автоматические движения в игре "крестики-нолики" на Python, задача состоит в том, чтобы интегрировать эту функциональность с нашим FastAPI API. Данный шаг необходим для обеспечения эффективного и бесшовного взаимодействия между игрой и бэкендом, что открывает путь для будущих интеграций, таких как внедрение MQL5-агента.

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


Шаги по адаптации FastAPI API к автоматическим ходам
  1. Улучшение управления ходами. API должен правильно определить, чья очередь играть — игрока или машины. После каждого хода игрока API должен проверить, наступил ли ход машины. Если да, нужно активировать логику автоматического хода.

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

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

  4. Управление результатами игры. API должен уметь определять окончание игры (будь то победа или ничья) и сообщать об этом соответствующим образом. Очень важно, чтобы API предоставлял четкую информацию о победителе игры или объявлял ничью, если победа невозможна.

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


Пример реализации в API

Чтобы учесть данные изменения, мы изменим функцию play в API:

@app.post("/play/{game_id}/")
def play(game_id: int, move: PlayerMove):
    game = games.get(game_id)
    if not game:
        raise HTTPException(status_code=404, detail="Game not found")

    board = game.board
    if board[move.row][move.col] == ' ':
        board[move.row][move.col] = 'X'
    else:
        raise HTTPException(status_code=400, detail="Invalid move")

    player_move = {"row": move.row, "col": move.col, "symbol": 'X'}

    winner = game.check_winner()
    machine_move_result = None

    if not winner:
        game.player_turn = not game.player_turn
        if not game.player_turn:
            move_result = game.machine_move()
            if move_result:
                row, col = move_result
                machine_move_result = {"row": row, "col": col, "symbol": 'O'}
                winner = game.check_winner()
            game.player_turn = not game.player_turn

    return {
        "board": board,
        "player_move": player_move,
        "machine_move": machine_move_result,
        "winner": winner,
        "available_moves": game.available_moves()
    }


Реализация функциональности автоматических ходов в игре "крестики-нолики" на Python, а также адаптация FastAPI API для поддержки этой функциональности, важны для создания полноценной интерактивной игровой системы. Теперь, когда API настроен на работу с автоматическим ходами, игроки могут взаимодействовать с игрой более динамично. Когда игрок делает ход, API проверяет, наступила ли очередь машины играть, и, если да, то активирует логику автоматического хода. Это создает непрерывный интерактивный игровой процесс, в котором человек соревнуется за победу с искусственным интеллектом.

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


Создание тестовых скриптов на языке MQL5

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

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

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


Структура тестов


Тестовый код в MQL5 организован в трех основных файлах:

  1. Tests.mqh — содержит функции проверки.
  2. Request.mqh — обрабатывает HTTP-запросы.
  3. Tests.mq5 — основной скрипт, запускающий тесты.


Tests.mqh

  • Assert() — данная функция используется для проверки истинности определенного условия. Очень важно подтвердить ожидаемые результаты тестов.

    Код и объяснение:

    void Assert(bool condition, const string message) {
      if(!condition) {
        Print("Test error: ", message);
      }
    }

    Если условие, переданное в Assert, равно false, он выводит сообщение об ошибке. Это помогает быстро выявлять сбои в тестировании.

    • TestGameInitialisation() — проверяет инициализацию новой игры и убеждается в том, что API отвечает правильно.
    Код и объяснение:
    void TestGameInitialization() {
      string url = "http://localhost:8000/start-game/";
      string response;
      int result = Request("GET", response, url);
      Assert(result == 200, "Game initialization failed");
      Assert(StringLen(response) > 0, "game_id missing in game initialization response");
    }This function makes a GET request to start a game and checks if the response code is 200 (OK) and if 
    game_id is returned in the response.

      Данная функция выполняет GET-запрос для запуска игры и проверяет, является ли код ответа 200 (OK) и возвращается ли в ответе идентификатор game_id.


      • TestPlayerMove() — проверяет функциональность выполнения игроком правильного хода.

        Код и объяснение:

        // Test function to check player's move
        void TestPlayerMove()
          {
           string url = "http://localhost:8000/start-game/";
           string response;
           int result = -1;
           int game_id = -1;
        
           Request("GET", response, url);
        
           js.Deserialize(response);
           game_id = js["game_id"].ToStr();
        
        // Make a valid player move
           url = StringFormat("http://localhost:8000/play/%d/", game_id);
           string payload = "{\"row\": 0, \"col\": 0}";
           result = Request("POST", response, url, payload);
        
        // Check if the HTTP response code is 200 (OK)
           Assert(result == 200, "Player move failed");
        
        // Check if the response contains information about the player's move
        // (you can adjust this based on the actual response structure)
           Assert(StringFind(response, "player_move") != -1, "Player move response incomplete");
          }

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


        • TestInvalidPlayerMove() — проверяет ответ API на недействительное движение.

          Код и объяснение:

          // Test function to check an invalid player move
          void TestInvalidPlayerMove()
            {
             string url = "http://localhost:8000/start-game/";
             string response;
             int result = -1;
             int game_id = -1;
          
             Request("GET", response, url);
          
             js.Deserialize(response);
             game_id = js["game_id"].ToStr();
          
          // Make an invalid player move (e.g., on an occupied position)
             url = StringFormat("http://localhost:8000/play/%d/", game_id);
             string payload = "{\"row\": 0, \"col\": 0}";
             Request("POST", response, url, payload);
          
          //repeat
             payload = "{\"row\": 0, \"col\": 0}";
             result = Request("POST", response, url, payload);
          
          // Check if the HTTP response code is 400 (Bad Request)
             Assert(result == 400, "Invalid player move not handled correctly");
            }
            Данная функция пытается выполнить недопустимый ход (например, сыграть на уже занятой позиции) и проверяет, возвращает ли API код ошибки 400 (Bad Request).

            • TestPlayerWin() — моделирует последовательность ходов, которая приводит к победе игрока.

              Код и объяснение:
              // Test function to check player's victory
              void TestPlayerWin()
                {
                 string url = "http://localhost:8000/start-game/";
                 string response;
                 int result = -1;
                 int game_id = -1;
              
                 Request("GET", response, url);
              
                 js.Deserialize(response);
                 game_id = js["game_id"].ToStr();
              
              // Make moves for player X to win
                 url = StringFormat("http://localhost:8000/play/%d/", game_id);
              
                 string payload = "{\"row\": 0, \"col\": 0}";
                 result = Request("POST", response, url, payload);
                 Assert(result == 200, "Player X move 1 failed");
              
                 payload = "{\"row\": 0, \"col\": 2}";
                 result = Request("POST", response, url, payload);
                 Assert(result == 200, "Player X move 2 failed");
              
                 payload = "{\"row\": 2, \"col\": 2}";
                 result = Request("POST", response, url, payload);
                 Assert(result == 200, "Player X move 3 failed");
              
                 payload = "{\"row\": 1, \"col\": 2}";
                 result = Request("POST", response, url, payload);
                 Assert(result == 200, "Player X move 4 failed");
              
              // Check if the response contains information about the winner
                 js.Deserialize(response); // Deserialize the updated game state
              
              // Check if the HTTP response code is 200 (OK) after move 5
                 Assert(result == 200 && js["winner"].ToStr() == "X", "Player X victory failed");
              
                }

                Эта функция выполняет серию ходов, которые приведут к победе игрока, и также проверяет, правильно ли API распознает условие победы.

                • RunTests() — функция-агрегатор, которая выполняет все определенные тесты.
                Код и объяснение:
                  // Function to run all tests
                  void RunTests()
                    {
                     TestGameInitialization();
                     TestPlayerMove();
                     TestInvalidPlayerMove();
                     TestPlayerWin();
                    }

                  Данная функция просто вызывает все ранее определенные тестовые функции, что позволяет легко запустить все тесты сразу.

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


                  Изменения, внесенные в библиотеку Requests

                  У новой реализации библиотеки Requests есть улучшения, в основном направленные на гибкость и диагностику ошибок. Давайте рассмотрим основные изменения:

                  1. Включение параметра отладки:

                    • В предыдущих версиях библиотека не предусматривала опции отладки как таковой. Любой отладочный вывод необходимо было реализовать вручную.
                    • Реализации функций SendGetRequest и SendPostRequest теперь включают параметр отладки. Если данный параметр включен, он позволяет печатать отладочные данные, что облегчает отслеживание и поиск неисправностей.

                  2. Улучшена обработка ошибок:

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


                  Почему внесены эти изменения? Изменения в библиотеке Requests были вызваны необходимостью:

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


                  Влияние изменений

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


                  Изменение 1 — включение отладочного параметра

                  Предыдущая реализация SendGetRequest и SendPostRequest:

                  // Example of old SendGetRequest implementation
                  int SendGetRequest(const string url, const string query_param, string &out, string headers = "", const int timeout = 5000) {
                     // ... code ...
                     out = CharArrayToString(result, start_index, WHOLE_ARRAY, CP_UTF8);
                     return (0);
                  }
                  

                  Новая реализация с отладкой:

                  // Example of new SendGetRequest implementation
                  int SendGetRequest(const string url, const string query_param, string &out, string headers = "", const int timeout = 5000, bool debug=false) {
                     // ... code ...
                     out = CharArrayToString(result, start_index, WHOLE_ARRAY, CP_UTF8);
                     if(debug) {
                         Print(out);
                     }
                     return res;
                  }
                  

                  Новая реализация включает в себя параметр отладки. Если он равен true, функция выводит результат, облегчая отладку.


                  Изменение 2 — улучшение обработки ошибок

                  Прежняя реализация SendGetRequest и SendPostRequest:

                  // Example of old implementation of SendGetRequest
                  int SendGetRequest(const string url, const string query_param, string &out, string headers = "", const int timeout = 5000) {
                     // ... code ...
                     if(res == -1) {
                         return (_LastError);
                     } else {
                         // HTTP error handling
                         out = CharArrayToString(result, 0, WHOLE_ARRAY, CP_UTF8);
                         Print(out);
                         return (ERR_HTTP_ERROR_FIRST + res);
                     }
                  }
                  

                  Новая реализация с улучшенной обработкой ошибок:

                  // Example of new implementation of SendGetRequest
                  int SendGetRequest(const string url, const string query_param, string &out, string headers = "", const int timeout = 5000, bool debug=false) {
                     // ... code ...
                     if(res == -1) {
                         return (_LastError);
                     } else {
                         // HTTP error handling
                         out = CharArrayToString(result, 0, WHOLE_ARRAY, CP_UTF8);
                         if(debug) {
                             Print(out);
                         }
                         return res;
                     }
                  }
                  

                  В новой реализации обработка ошибок HTTP стала более точной, с возможностью выводить данные только при включенном режиме отладки.


                  Интеграция и практические тесты

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

                  Этапы интеграции

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

                  1. Обновление Библиотеки Requests. Во-первых, мы обновили библиотеку Requests, включив в нее реализованные улучшения. Это позволило наладить более эффективную связь и отлаживать проблемы более эффективно.

                  2. Адаптация игры "крестики-нолики". Важным шагом стала интеграция автоматических ходов в игру "крестики-нолики" на Python. Мы изменили код игры, чтобы он распознавал ход машины и активировал логику автоматических ходов.

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

                  Проведение тестов

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

                  1. Новый тест создания игры (Swagger и Test Script) — чтобы убедиться, что создание новой игры работает стабильно, мы проведем данный тест как через интерфейс Swagger, так и через наш автоматизированный тестовый скрипт. Это гарантирует, что функциональность будет доступна обоими способами.

                  2. Тестирование хода игрока (Swagger и Test Script) — функциональность выполнения игроком правильного хода будет протестирована как с помощью Swagger, так и с помощью тестового скрипта: это гарантирует, что взаимодействие игроков будет тщательно протестировано.

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

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

                  Результаты и оценка

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

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




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

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

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


                  Заключение

                  Данная статья, продолжающая серию статей о REST API, посвящена реализации и тестированию автоматических ходов в игре "крестики-нолики" на языке Python, интегрированной с разработкой MQL5-функций. Основная задача состояла в двух направлениях: улучшить игру "крестики-нолики" с помощью автономной игры и разработать модульные тесты на MQL5 для проверки взаимодействия с REST API. Интеграция данных функций не только улучшает саму игру, но и создает основу для более полных и эффективных тестов.

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

                  Что касается тестирования, то создание и реализация тестовых скриптов на MQL5 обеспечили надежную связь между MQL5-кодом и REST API. Тесты включали в себя инициализацию игры, выполнение правильных и неправильных ходов, а также проверку условий выигрыша: это необходимо для обеспечения надежности и стабильности системы.

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

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

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


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

                  Прикрепленные файлы |
                  Parte_03.zip (65.15 KB)
                  Нейросети — это просто (Часть 88): Полносвязный Энкодер временных рядов (TiDE) Нейросети — это просто (Часть 88): Полносвязный Энкодер временных рядов (TiDE)
                  Желание получить наиболее точные прогнозы толкает исследователей к усложнению моделей прогнозирования. Что в свою очередь ведет к увеличению затрат на обучение и обслуживание модели. Но всегда ли это оправдано? В данной статье я предлагаю вам познакомиться с алгоритмом, который использует простоту и скорость линейных моделей и демонстрирует результаты на уровне лучших с более сложной архитектурой.
                  Как добавить Trailing Stop по индикатору Parabolic SAR Как добавить Trailing Stop по индикатору Parabolic SAR
                  При создании торговой стратегии нам нужно проверить самые разные варианты защитных стопов. И тут напрашивается динамическое подтягивание уровня Stop Loss вслед за ценой. Наилучшим кандидатом для этого является индикатор Parabolic SAR —трудно придумать что-либо проще и нагляднее.
                  Разработка MQTT-клиента для MetaTrader 5: методология TDD (Часть 5) Разработка MQTT-клиента для MetaTrader 5: методология TDD (Часть 5)
                  Статья является пятой частью серии, описывающей этапы разработки нативного MQL5-клиента для протокола MQTT 5.0. В этой части мы опишем структуру пакетов PUBLISH - как мы устанавливаем их флаги публикации (Publish Flags), кодируем строки названий тем и устанавливаем идентификаторы пакетов, когда это необходимо.
                  Разметка данных в анализе временных рядов (Часть 5):Применение и тестирование советника с помощью Socket Разметка данных в анализе временных рядов (Часть 5):Применение и тестирование советника с помощью Socket
                  В этой серии статей представлены несколько методов разметки временных рядов, которые могут создавать данные, соответствующие большинству моделей искусственного интеллекта (ИИ). Целевая разметка данных может сделать обученную модель ИИ более соответствующей пользовательским целям и задачам, повысить точность модели и даже помочь модели совершить качественный скачок!