English Deutsch 日本語
preview
Разработка инструментария для анализа движения цен (Часть 9): Внешние библиотеки

Разработка инструментария для анализа движения цен (Часть 9): Внешние библиотеки

MetaTrader 5Торговые системы |
50 0
Christian Benjamin
Christian Benjamin

Введение

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

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

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

Давайте посмотрим, как мы подойдем к решению этой задачи:



Обзор стратегии

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

1. Советник > Python:

  • Советник собирает максимумы, минимумы, открытия, закрытия и объемы предыдущего дня за 10 дней. 
  • Отправляет данные на сервер Python. 
  • Форматирует данные в строку CSV и отправьте ее с помощью HTTP-запроса POST на сервер Python.

2. Python:

  • Python получает данные и обрабатывает полученные данные с помощью библиотек, таких как Pandas. 
  • Анализирует данные, чтобы сгенерировать торговый сигнал, среднюю цену и объем, а затем создает объяснение.

3. Python > советник:

  • Python отправляет сгенерированный сигнал, среднюю цену, объем и объяснение обратно в советник через HTTP-ответ.

4. Советник:

  • Советник получает и анализирует ответ, извлекает сигнал, среднюю цену, средний объем и объяснение из ответа. 
  • Если сигнал отличается, обновляет график с учетом нового сигнала и отображает его.

Для более подробного понимания обратимся к следующей диаграмме.


Поток интеграции

Рис 1. Логическая схема



Python

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

Рассмотрим установку Python, создание скрипта и его запуск шаг за шагом.

  • Загрузите установщик Python на официальном сайте Python
  • Запустите установщик

Важно: обязательно установите флажок Add Python to PATH (добавить Python в PATH), прежде чем кликнуть Install Now (установить сейчас). Это упрощает запуск Python из командной строки.

  •  Завершите установку

Установщик начнет процесс установки. Дождитесь окончания. После завершения установки нажмите Close (закрыть).

  •  Проверьте установку

Откройте командную строку (нажмите Windows + R, введите cmd и нажмите Enter). Введите python --version и нажмите Enter. Если Python установлен правильно, вы должны увидеть версию Python (например, Python 3.x.x).

После успешной установки Python, теперь стоит рассмотреть возможность установки Flask и Pandas. Flask — это легкий веб-фреймворк для Python, используемый для разработки веб-приложений. Он разработан с упором на простоту, гибкость и удобство использования. Flask используется для настройки простого веб-сервера, обеспечивающего взаимодействие между MQL5-советником и инструментами анализа данных Python. Советник отправляет данные во Flask (через HTTP-запросы), который обрабатывает данные с помощью библиотек Python, в данном случае Pandas, и возвращает торговый сигнал советнику.

Чтобы установить Flask и Pandas с помощью командной строки, выполните следующие действия:

Откройте командную строку

  • Нажмите Windows + R, введите cmd и нажмите Enter.

Убедитесь, что установлен pip (установщик пакетов Python)

  • Сначала проверьте, установлен ли pip, выполнив:

pip --version

  • Если pip установлен, вы увидите номер версии. Если не установлен, выполните следующие шаги для установки. PIP (Python Package Installer) обычно устанавливается автоматически вместе с Python. Если его нет, загрузите get-pip.py и запустите его с помощью команды get-pip.py.

Установите Flask

  • Чтобы установить Flask, выполните следующую команду в командной строке:

pip install Flask

  • Дождитесь окончания установки. Flask будет установлен и готов к использованию.

Установите Pandas

  • Чтобы установить Pandas, выполните эту команду:

pip install pandas

  • Аналогично дождитесь завершения установки.

Проверьте установку

  • После установки обоих пакетов вы можете проверить установку, выполнив следующие команды:

python -c "import flask; print(flask.__version__)"

python -c "import pandas; print(pandas.__version__)"

  • Это должно вывести на экран установленные версии Flask и Pandas.

Теперь вы можете приступить к созданию скрипта Python. Лично я предпочитаю использовать для этой задачи Notepad++. Чтобы создать скрипт, откройте Notepad++, создайте новый файл и установите язык Python, выбрав его в меню Language (язык). Готовый скрипт сохраните в каталоге, который легко найти. Обязательно сохраните файл с расширением .py, которое идентифицирует его как скрипт Python.

Скрипт Python

import pandas as pd
import flask
from flask import request, jsonify

app = flask.Flask(__name__)
app.config["DEBUG"] = True

@app.route('/analyze', methods=['POST'])
def analyze_csv():
    try:
        # Read CSV data from the POST request
        csv_data = request.data.decode('utf-8')

        # Write the CSV data to a file (optional, for debugging)
        with open('received_data.csv', 'w') as file:
            file.write(csv_data)

        # Load the CSV data into a DataFrame
        from io import StringIO
        data = StringIO(csv_data)
        df = pd.read_csv(data)

        # Ensure the CSV has the correct columns
        required_columns = ['date', 'prev_high', 'prev_low', 'prev_open', 'prev_close', 'prev_volume']
        for column in required_columns:
            if column not in df.columns:
                return jsonify({"error": f"Missing column: {column}"}), 400

        # Print the received metrics for debugging
        print("Received metrics:")
        print(df)

        # Perform analysis (Example: Calculate average price and volume)
        df['average_price'] = (df['prev_high'] + df['prev_low'] + df['prev_open'] + df['prev_close']) / 4
        average_price = df['average_price'].mean()  # Average of all the average prices
        average_volume = df['prev_volume'].mean()  # Average volume

        # Print the computed averages
        print(f"Average Price: {average_price}")
        print(f"Average Volume: {average_volume}")

        # Create a trading signal based on a simple rule
        last_close = df['prev_close'].iloc[-1]
        if last_close > average_price:
            signal = "BUY"
            signal_explanation = f"The last close price ({last_close}) is higher than the average price ({average_price})."
        else:
            signal = "SELL"
            signal_explanation = f"The last close price ({last_close}) is lower than the average price ({average_price})."

        # Print the signal and explanation
        print(f"Generated Signal: {signal}")
        print(f"Signal Explanation: {signal_explanation}")

        # Return the signal as JSON
        return jsonify({
            "signal": signal,
            "average_price": average_price,
            "average_volume": average_volume,
            "signal_explanation": signal_explanation
        })

    except Exception as e:
        return jsonify({"error": str(e)}), 500

if __name__ == '__main__':
    app.run(host='189.7.6.8', port=5877)

Чтобы запустить скрипт, откройте командную строку на вашем компьютере.

Выполните команду:

cd C:\Users\pathway to your python script folder

А затем - команду:

python filename.py

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

 Running on http://189.7.6.8:5877


Основные функции

Initialization (OnInit)

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

int OnInit()
{
   Print("Expert initialized. Ready to send data to Python.");
   return(INIT_SUCCEEDED);
}

Возвращаемое значение INIT_SUCCEEDED означает, что инициализация прошла успешно.

Deinitialization (OnDeinit)

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

void OnDeinit(const int reason)
{
   Print("Expert deinitialized.");
}

OnTick (Core Functionality)

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

void OnTick()
{
   // Check if enough time has passed since the last signal update
   if(TimeCurrent() - lastSignalTime < signalInterval)
   {
      return;  // Skip if it's too soon to update
   }

   // Collect data and prepare CSV for Python
   string csvData = "date,prev_high,prev_low,prev_open,prev_close,prev_volume\n";

   // Get the previous trend data for the last `trendDays`
   for(int i = 1; i <= 10; i++)  // You can adjust the trendDays here
   {
      datetime prevDate = iTime(Symbol(), PERIOD_D1, i);
      double prevHigh = iHigh(Symbol(), PERIOD_D1, i);
      double prevLow = iLow(Symbol(), PERIOD_D1, i);
      double prevOpen = iOpen(Symbol(), PERIOD_D1, i);
      double prevClose = iClose(Symbol(), PERIOD_D1, i);
      long prevVolume = iVolume(Symbol(), PERIOD_D1, i);

      csvData += StringFormat("%s,%.5f,%.5f,%.5f,%.5f,%ld\n",
                              TimeToString(prevDate, TIME_DATE | TIME_MINUTES),
                              prevHigh, prevLow, prevOpen, prevClose, prevVolume);
   }

   // Save data to CSV file
   string fileName = StringFormat("%s_analytics.csv", Symbol());
   int fileHandle = FileOpen(fileName, FILE_WRITE | FILE_CSV | FILE_ANSI);
   if(fileHandle != INVALID_HANDLE)
   {
      FileWriteString(fileHandle, csvData);
      FileClose(fileHandle);
      Print("CSV file created: ", fileName);
   }
}

Она также выполняет следующие операции:

  • Проверка интервала сигнала: : Советник сначала проверяет, прошло ли достаточно времени с момента последнего обновления сигнала, используя TimeCurrent(). В противном случае обработка будет пропущена.
  • Сбор данных: Советник собирает рыночные данные за последние 10 дней (или больше, если вы измените значение в цикле), включая: максимум, минимум, открытие, закрытие и объем предыдущего дня.
  • Форматирование данных: Затем он форматирует эти данные в CSV для легкой передачи на сервер Python. 
  • Сохранение CSV-файла: Данные сохраняются в виде CSV-файла с именем <symbol>_analytics.csv. Если создание и запись файла прошли успешно, выводится сообщение об успешном завершении.

HTTP-запрос к серверу Python (WebRequest)

string headers = "Content-Type: application/json\r\n";
char result[];
string resultHeaders;
int responseCode = WebRequest(
    "POST",                  // HTTP method
    pythonUrl,               // URL
    headers,                 // Custom headers
    timeout,                 // Timeout in milliseconds
    data,                    // Data to send
    result,                  // Response content
    resultHeaders            // Response headers
);

if(responseCode == 200)
{
    string response = CharArrayToString(result);
    Print("Received response: ", response);
}
else
{
    Print("Error: HTTP request failed with code ", responseCode);
}

После подготовки данных в формате CSV советник отправляет эти данные на сервер Python через HTTP POST.

  • Headers: Заголовок Content-Type установлен на application/json, который сообщает серверу, что отправляемые данные имеют формат JSON.
  • WebRequest: Функция WebRequest используется для отправки HTTP-запроса POST на сервер Python. Функция возвращает:

1) responseCode: Код ответа HTTP (например, 200 при успешном завершении).

2) result: Содержимое ответа сервера (обычно результаты анализа).

WebRequest

Рис 2. Схема WebRequest

  • Если запрос успешен (responseCode == 200), содержимое ответа преобразуется из массива символов в строку, и выводится сообщение об успешном выполнении. При неудачном запросе отображается сообщение об ошибке.

Анализ и отображение ответа

if(responseCode == 200)
{
    string signal = "";
    string avgPrice = "";
    string avgVolume = "";
    string explanation = "";

    // Extract signal, avgPrice, avgVolume, and explanation from the response
    int signalStart = StringFind(response, "\"signal\":");
    int signalEnd = StringFind(response, "\"average_price\":");
    int explanationStart = StringFind(response, "\"signal_explanation\":");
    int avgPriceStart = StringFind(response, "\"average_price\":");
    int avgVolumeStart = StringFind(response, "\"average_volume\":");

    if(signalStart != -1 && signalEnd != -1)
    {
        signal = StringSubstr(response, signalStart + 10, signalEnd - signalStart - 12);
    }

    if(explanationStart != -1)
    {
        explanation = StringSubstr(response, explanationStart + 23, StringFind(response, "\"", explanationStart + 23) - (explanationStart + 23));
    }

    if(avgPriceStart != -1)
    {
        avgPrice = StringSubstr(response, avgPriceStart + 16, StringFind(response, "\"", avgPriceStart + 16) - (avgPriceStart + 16));
    }

    if(avgVolumeStart != -1)
    {
        avgVolume = StringSubstr(response, avgVolumeStart + 18, StringFind(response, "\"", avgVolumeStart + 18) - (avgVolumeStart + 18));
    }

    // Update the chart if the signal has changed
    if(signal != lastSignal)
    {
        lastSignal = signal;
        lastSignalTime = TimeCurrent();  // Update last signal time
        string receivedSummary = "Signal: " + signal + "\n" +
                                 "Avg Price: " + avgPrice + "\n" +
                                 "Avg Volume: " + avgVolume + "\n" +
                                 "Explanation: " + explanation;
        Print("Received metrics and signal: ", receivedSummary);
        Comment(receivedSummary);  // Display it on the chart
    }
}

 Получив ответ от сервера Python, советник анализирует ответ для извлечения ключевых данных, таких как:

  • Signal - торговый сигнал (например, buy или sell).
  • Avg Price - средняя цена, полученная в результате анализа.
  • Avg Volume - средний объем сделок.
  • Explanation - объяснение причины возникновения сигнала.

Функция использует StringFind и StringSubstr для извлечения этих значений из строки ответа.

Если сигнал изменился с момента последнего обновления (signal != lastSignal):

1) Обновляются переменные lastSignal и lastSignalTime.

2) Отображается новый сигнал, средняя цена, объем и объяснение в виде комментария на графике с помощью функции Comment().

Обновление и отображение сигнала

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

if(signal != lastSignal)
{
    lastSignal = signal;
    lastSignalTime = TimeCurrent();  // Update last signal time
    string receivedSummary = "Signal: " + signal + "\n" +
                             "Avg Price: " + avgPrice + "\n" +
                             "Avg Volume: " + avgVolume + "\n" +
                             "Explanation: " + explanation;
    Print("Received metrics and signal: ", receivedSummary);
    Comment(receivedSummary);  // Display it on the chart
}

 Если сигнал изменился (т.е. отличается от предыдущего), советник:

  • Обновляет переменные lastSignal и lastSignalTime.
  • Создает строковую сводку, содержащую сигнал, среднюю цену, средний объем и пояснение.
  • Отображает сводку на графике в виде комментария и выводит ее в журнал.

CharArrayToString (Utility Function)

string CharArrayToString(char &arr[])
{
    string result = "";
    for(int i = 0; i < ArraySize(arr); i++)
    {
        result += StringFormat("%c", arr[i]);
    }
    return(result);
}

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

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


Результаты

Первый шаг — убедиться, что ваш скрипт Python запущен и активно прослушивает требуемый сервер. Подробные инструкции по настройке и запуску скрипта сморите в разделе Python выше. При активном прослушивании мы должны увидеть: 
Running on http://189.7.6.8:5877

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

В командной строке отобразится следующее:

189.7.6.8 - - [21/Jan/2025 10:53:44] "POST /analyze HTTP/1.1" 200 -
Received metrics:
                date  prev_high  prev_low  prev_open  prev_close  prev_volume
0   2025.01.20 00:00    868.761   811.734    826.389     863.078      83086.0
1   2025.01.19 00:00    856.104   763.531    785.527     826.394      82805.0
2   2025.01.18 00:00    807.400   752.820    795.523     785.531      82942.0
3   2025.01.17 00:00    886.055   790.732    868.390     795.546      83004.0
4   2025.01.16 00:00    941.334   864.202    932.870     868.393      83326.0
5   2025.01.15 00:00    943.354   870.546    890.620     932.876      83447.0
6   2025.01.14 00:00    902.248   848.496    875.473     890.622      83164.0
7   2025.01.13 00:00    941.634   838.520    932.868     875.473      82516.0
8   2025.01.12 00:00    951.350   868.223    896.455     932.883      83377.0
9   2025.01.11 00:00    920.043   857.814    879.103     896.466      83287.0
10               NaN        NaN       NaN        NaN         NaN          NaN

Приведенная выше информация будет использоваться pandas для анализа и генерации сигналов. Данные за десятый день показывают NaN, поскольку день еще не закрылся, а это значит, что анализ в первую очередь опирается на значения, полученные за предыдущие дни. Однако он также включает в себя текущие уровни цен десятого дня, которые являются неполными. Ниже вы можете ознакомиться с результатами регистрации и анализа, отображаемыми pandas в командной строке (CMD).

Average Price: 865.884525
Average Volume: 83095.4
Generated Signal: SELL
Signal Explanation: The last close price (nan) is lower than the average price (865.884525).

MetaTrader 5 отобразит следующее:

Начнем с проверки регистрации на вкладке "Эксперты". Ниже представлены результаты.

2025.01.21 10:50:28.106 External Flow (Boom 300 Index,D1)       CSV file created: Boom 300 Index_analytics.csv
2025.01.21 10:50:28.161 External Flow (Boom 300 Index,D1)       Received response: {
2025.01.21 10:50:28.161 External Flow (Boom 300 Index,D1)         "average_price": 865.884525,
2025.01.21 10:50:28.161 External Flow (Boom 300 Index,D1)         "average_volume": 83095.4,
2025.01.21 10:50:28.161 External Flow (Boom 300 Index,D1)         "signal": "SELL",
2025.01.21 10:50:28.161 External Flow (Boom 300 Index,D1)         "signal_explanation": "The last close price (nan) is lower than the average price (865.884525)."

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

Отображение графика

Рис. 3. Отображаемый результат

Ниже представлен график прибыльной сделки, которую я разместил на основе сгенерированного сигнала и дополнительного анализа. Для большей наглядности торговля отображается на M1 (1 минута).

Прибыльная сделка

Рис 4. Размещенная сделка



Заключение

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

Дата Название инструмента  Описание Версия  Обновления  Примечания
01/10/24 Chart Projector Скрипт для наложения эффекта призрака на движение цены за предыдущий день. 1.0 Первоначальная версия Первый инструмент в Lynnchris Tools Chest
18/11/24 Analytical Comment Предоставляет информацию за предыдущий день в табличном формате, а также прогнозирует будущее направление рынка. 1.0 Первоначальная версия Второй инструмент в Lynnchris Tools Chest
27/11/24 Analytics Master Регулярное обновление рыночных показателей каждые два часа  1.01 Вторая версия Третий инструмент в Lynnchris Tools Chest
02/12/24 Analytics Forecaster  Регулярное обновление рыночных показателей каждые два часа с интеграцией с Telegram 1.1 Третья версия Инструмент номер 4
09/12/24 Volatility Navigator Советник анализирует рыночные условия с помощью полос Боллинджера, RSI и ATR. 1.0 Первоначальная версия Инструмент номер 5
19/12/24 Mean Reversion Signal Reaper  Анализирует рынок и генерирует сигналы, используя стратегию возврата к среднему  1.0  Первоначальная версия  Инструмент номер 6 
9/01/2025  Signal Pulse  Анализирует несколько таймфреймов 1.0  Первоначальная версия  Инструмент номер 7 
17/01/2025  Metrics Board  Панель с кнопкfvb для анализа  1.0  Первоначальная версия Инструмент номер 8 
21/01/2025 External Flow Аналитика с помощью внешних библиотек 1.0  Первоначальная версия Инструмент номер 9 

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

Прикрепленные файлы |
External_Flow.mq5 (6.72 KB)
DeepANALYTICS.py (2.48 KB)
Скрытые марковские модели для прогнозирования волатильности с учетом тренда Скрытые марковские модели для прогнозирования волатильности с учетом тренда
Скрытые марковские модели (СММ) — это мощный статистический инструмент, позволяющий выявлять скрытые состояния рынка на основе анализа наблюдаемых ценовых движений. В трейдинге СММ позволяют улучшить прогнозирование волатильности и применяются при разработке трендовых стратегий, моделируя изменения рыночных режимов. В этой статье мы представим пошаговый процесс разработки стратегии следования за трендом, которая использует СММ в качестве фильтра для прогнозирования волатильности.
Нейросети в трейдинге: От трансформеров к спайковым нейронам (SpikingBrain) Нейросети в трейдинге: От трансформеров к спайковым нейронам (SpikingBrain)
Фреймворк SpikingBrain демонстрирует уникальный подход к обработке данных: нейроны реагируют только на значимые события, эффективно фильтруя шум. Его событийная архитектура снижает вычислительные затраты, сохраняя ключевую информацию о движениях. Адаптивные пороги и возможность использования предварительно обученных модулей обеспечивают гибкость и масштабируемость модели.
Особенности написания экспертов Особенности написания экспертов
Написание и тестирование экспертов в торговой системе MetaTrader 4.
Торговый инструментарий MQL5 (Часть 7): Расширение EX5-библиотеки для управления историей функциями последнего отмененного отложенного ордера Торговый инструментарий MQL5 (Часть 7): Расширение EX5-библиотеки для управления историей функциями последнего отмененного отложенного ордера
Мы завершаем создание последнего модуля в EX5-библиотеке для управления историей (History Manager), сосредоточившись на функциях, отвечающих за обработку последнего отмененного отложенного ордера. Это позволит эффективно извлекать и хранить ключевые данные, связанные с отмененными отложенными ордерами с помощью MQL5.