
Добавляем пользовательскую LLM в торгового робота (Часть 5): Разработка и тестирование торговой стратегии с помощью LLM(IV) — Тестирование торговой стратегии
Содержание
- Содержание
- Введение
- Среда разработки в качестве примера
- Методы загрузки LLM в MQL5
- Преобразование модели GPT-2 в модель ONNX
- Разработка стратегии советника и функциональности сервера
- Создание службы вывода
- Клиент советника
- Тестирование на истории
- Заключение
Введение
В предыдущих статьях мы рассказали, как с помощью разных методов настраивать предварительно обученные модели GPT-2, чтобы GPT-2 выполнял задачи в соответствии с нашими пожеланиями, и сравнили эти методы по нескольким параметрам. Конечно, мы представили лишь несколько общеупотребимых методов, но это не значит, что только эти методы можно использовать для тонкой настройки моделей GPT-2. Вы можете попробовать настроить GPT-2, используя другие методы на основе нашего примера процесса внедрения, сравнить их и выбрать лучшую модель. Если по ходу дела у вас возникнут какие-либо проблемы, вы можете оставить комментарий в конце статьи.
Теперь наша точно настроенная модель GPT-2 имеет начальную возможность реализовывать простые количественные торговые стратегии. Поэтому в этой статье мы расскажем, как интегрировать нашу точно настроенную модель в количественную торговую стратегию. В примере использована модель GPT-2, настроенная в Adapter-tuning (Добавляем пользовательскую LLM в торгового робота (Часть 5): Разработка и тестирование торговой стратегии с помощью LLM (III) – Настройка адаптера). Таким образом, если не указано иное, все ссылки на GPT-2 в этой статье относятся к этой модели.
Однако следует отметить, что доработанная нами модель основана на ограниченных данных, предназначенных для демонстрационных целей, и не может работать в реальных торговых условиях. Без тестирования и оптимизации их не следует использовать напрямую в реальной торговле, что имеет первостепенное значение. Наш предыдущий код прогнозирования был выполнен в среде Python, но MQL5, как высокоинтегрированный язык программирования для платформы MetaTrader 5, предоставляет мощные инструменты для разработки советников. Поэтому для реализации автоматизированных количественных торговых стратегий нам необходимо вернуться в среду MQL5. В этой статье мы шаг за шагом осуществим этот процесс.
Давайте рассмотрим, как перенести эту обученную модель из среды Python в советник MQL5, запустив ее непосредственно на платформе MetaTrader 5 для поддержки принятия торговых решений в реальном времени.
Среда разработки в качестве примера
Давайте рассмотрим среду выполнения примеров кода, приведенных в этой статье. Конечно, это не означает, что ваша кодовая среда должна быть такой же, как моя, но если у вас возникнут проблемы при запуске кода, вы можете обратиться к моей конфигурации среды.
- Операционная система : Ubuntu 22.04.5 LTS (или соответствующая версия WSL)
- Версия Python: 3.10.14
- Необходимые библиотеки Python:
- torch-2.4.1
- numpy-1.26.3
- pandas-2.2.3
- transformers-4.45.1
- petf-0.13.0
- matplotlib-3.9.2
- onnx-1.17.0
- onnxconverter-common-1.14.0
- onnxruntime-1.20.1
- onnxruntime-tools-1.7.0
Перед тем, как перейти к следующему шагу, убедитесь, что вы обучили модель с помощью настройки адаптера (Adapter-tuning), как описано в предыдущей статье (поскольку размер модели превышает ограничение платформы, веса, которые я уже обучил, не могут быть загружены).
Методы загрузки LLM в MQL5
Чтобы интегрировать обученную модель GPT-2 в советник MQL5, первая проблема, которую нам необходимо решить, — как загрузить и запустить эту модель, которая по сути является обученной на Python моделью, в среде MQL5. Вот несколько возможных методов:
1. Конвертировать модель в ONNX и добавить ее в советник.
ONNX (Open Neural Network Exchange) — открытый формат представления нейронных сетей, обеспечивающий взаимодействие между различными фреймворками глубокого обучения. В предыдущей статье я рассказал, как интегрировать простые модели в советники с использованием ONNX (Разметка данных в анализе временных рядов (Часть 6):Применение и тестирование советника с помощью ONNX). Мы также можем преобразовать модель GPT-2 в формат ONNX, импортировать ее в советник и использовать встроенную библиотеку времени выполнения ONNX в MQL5 для вывода модели. В официальной документации по MQL5 можно найти больше информации о моделях ONNX (https://www.mql5.com/ru/docs/onnx).
- Преимущества:
- Высокая производительность: среда выполнения ONNX обычно оптимизирована под производительность, что обеспечивает относительно эффективный вывод в советнике.
- Высокая степень интеграции: MQL5 имеет встроенную поддержку ONNX, что устраняет необходимость во внешних программах или библиотеках.
- Независимость: преобразованная модель ONNX может работать независимо от среды Python.
- Недостатки:
- Сложность преобразования: преобразование сложных языковых моделей в формат ONNX может оказаться сложной задачей и потребовать решения проблем совместимости операторов.
- Сложность отладки: отладка моделей ONNX менее удобна, чем отладка моделей Python.
2. Прямой запуск скриптов вывода Python с помощью Winapi
MQL5 предоставляет доступ к WinAPI, что позволяет нам вызывать функцию WinExec() из kernel32.dll для выполнения внешних программ. Таким образом, мы можем использовать существующие скрипты Python для загрузки модели GPT-2 и выполнения вывода, а затем вызвать скрипт в советнике с помощью WinExec() и проанализировать его выходные результаты (в качестве альтернативы, функция ShellExecuteW() из shell32.dll также может обеспечить эту функциональность). Для реализации этого метода требуется определенный опыт разработки и знакомство с разработкой для Windows.
- Преимущества:
- Простота и непосредственность: не нужно преобразовывать модель, можно напрямую использовать существующий код Python.
- Гибкость: можно легко использовать богатые библиотеки и инструменты экосистемы Python.
- Недостатки:
- Снижение производительности: каждый вывод требует запуска нового процесса Python, что приводит к значительным вычислительным расходам и неэффективности.
- Зависимость: советник зависит от внешней среды Python и скриптов.
- Обмен данными: требует обработки обмена данными между MQL5 и Python, что увеличивает сложность.
- Безопасность: могут возникнуть различные непредвиденные ситуации, потенциально приводящие к сбоям.
Примечание: Этот метод настоятельно не рекомендуется! Я предлагаю это решение только для того, чтобы показать, что оно осуществимо и может быть использовано при тестировании или в контролируемых условиях. Не используйте его без достаточной уверенности.
3. Получение результатов вывода Python через сокетную связь
Аналогично второму методу, но с использованием Socket-связи вместо Winapi (на самом деле можно также использовать протокол HTTP, аналогичный HTTP-сервисам, предоставляемым основными фреймворками вывода, которые по сути являются тем же самым, что и Socket, и в этой статье он не будет обсуждаться далее). Конкретный метод реализации заключается в запуске сервера Socket на Python для загрузки модели и выполнения вывода, при этом советник выступает в качестве клиента, подключающегося к серверу, отправляющего входные данные и получающего результаты вывода.
- Преимущества:
- Лучшая производительность: Связь через сокеты может сократить накладные расходы на запуск процесса и является гораздо более безопасной.
- Гибкость: по-прежнему можно использовать преимущества Python.
- Недостатки:
- Сложность: Необходимо реализовать логику связи между сервером Socket и клиентом.
- Зависимость: Советник зависит от внешней среды Python и сервера Socket, что требует определенных знаний для настройки службы.
- Стабильность: Стабильность соединений сокетов может повлиять на работу советника.
Примечание: Конкретная реализация этого метода представлена в моей предыдущей статье. Если вам интересно, вы можете обратиться к статье: Разметка данных в анализе временных рядов (Часть 5):Применение и тестирование советника с помощью Socket.
Мы обсудили несколько различных методов преобразования. В настоящее время я по-прежнему склоняюсь к варианту преобразования модели GPT-2 в формат ONNX и ее интеграции в советник, поскольку это также может решить проблемы кроссплатформенности, а советник обеспечивает более высокую интеграцию и стабильность. Однако если параметры модели ONNX слишком велики, их невозможно запустить в MQL5 (например, наша текущая модель GPT-2 превышает лимит загрузки файла MQL5).
Еще одной сложной проблемой является решение проблемы токенизатора в модели трансформеров, поскольку такие модели, как GPT-2, поставляются с токенизатором для обработки входной информации, а для запуска модели GPT-2 в MQL5 нам необходимо построить токенизатор GPT-2 в MQL5, что является довольно трудоемкой задачей. Это сложно, но не невозможно. Тем не менее, ограничение размера загружаемого файла MQL5 представляет собой сложную для решения проблему.
Хотя я и пытался преобразовать его в формат INT8, он все равно превысил лимит и не смог быть загружен. Если квантовать в формате INT4, то, несмотря на то, что размер модели соответствует требованиям, MQL5 не поддерживает квантованные модели формата INT4! Поэтому нам остается только с сожалением отказаться от этого метода. Однако в этой статье я все же приведу пример того, как преобразовать нашу настроенную с помощью адаптера модель GPT-2 в формат ONNX, надеясь вскоре решить эту проблему!
В этой статье я в конечном итоге решил рассмотреть использование взаимодействия сокетов со службой вывода Python. Преимущество этого метода в том, что он может обеспечить безопасность данных и упростить реализацию нашего советника. В советнике нам нужно сосредоточиться только на нашей стратегии и торговой логике и не нужно рассматривать дополнительные вопросы интеграции модулей. Еще одним преимуществом этого метода является то, что если локально отсутствует соответствующая среда разработки модели (например, модель разрабатывается и обучается на удаленном устройстве), то даже если среда разработки несовместима с локальной средой, этот метод все равно можно использовать для разработки советника.
В целом, хотя этот метод может показаться технически сложным в реализации и требующим дополнительных знаний, он позволяет достичь высокой операционной эффективности и обеспечить независимость советника, что имеет решающее значение для эффективной торговой среды в реальном времени. Учитывая, что мы уже подробно обсуждали это в предыдущей статье, в этой статье не будут описываться подробности. Если у вас возникли вопросы по примерам кода, вы можете обратиться к подробному введению в предыдущей статье.
Преобразование модели GPT-2 в модель ONNX
В предыдущем разделе я описал различные проблемы, возникшие при конвертации настроенной модели GPT-2 в формат ONNX и использовании ее в MQL5. Тем не менее, я по-прежнему считаю, что это направление стоит попробовать, поэтому в этой статье я воспользуюсь дополнительным разделом, чтобы рассказать, как преобразовать эту персонализированную настроенную модель в формат ONNX, надеясь, что каждый сможет найти решение сложившейся ситуации. Если эта часть вам не интересна, вы можете пропустить этот раздел.
1. Методы преобразования моделей
Ⅰ. Прямое преобразование (https://github.com/rayhern/convert-gpt2-xl-to-onnx)
В этом репозитории GitHub представлен скрипт для прямого преобразования моделей GPT-2 на основе библиотеки transformers и экспортера torch.onnx от Hugging Face. Однако из-за длительного отсутствия поддержки со стороны автора он может иметь некоторые ограничения и может быть несовместим с последними версиями библиотеки transformers.
- Преимущества: Предоставляет относительно простой скрипт, который можно использовать напрямую; оптимизирован специально для преобразования модели GPT-2.
- Недостатки: Статус обслуживания этого репозитория может быть неясен, и он может быть несовместим с последними версиями transformers и применим только к определенным версиям моделей GPT-2.
Ⅱ. ONNX API от Microsoft (https://github.com/microsoft/onnxruntime-genai)
Библиотека onnxruntime-genai от Microsoft предоставляет набор API-интерфейсов преобразования и оптимизации ONNX для генеративных моделей ИИ.
- Преимущества: Оптимизирован для среды выполнения ONNX, повышает производительность вывода, поддерживается и обслуживается корпорацией Microsoft.
- Недостатки: Необходимо изучить API библиотеки onnxruntime-genai, который может оказаться более сложным по сравнению с другими методами.
Ⅲ. Использование torch.onnx для экспорта модели
PyTorch предоставляет встроенную функцию экспорта ONNX (`torch.onnx`), которая позволяет экспортировать модели PyTorch в формат ONNX.
- Преимущества: torch.onnx тесно интегрирован с фреймворком PyTorch, прост в использовании и является широко используемым инструментом экспорта ONNX.
- Недостатки: Может потребоваться решить некоторые проблемы совместимости операторов, особенно для новых или пользовательских операторов, а также вручную настроить некоторые параметры экспорта для обеспечения корректности и производительности модели.
Ⅳ. Использование transformers.onnx для преобразования модели
Библиотека transformers от Hugging Face предоставляет собственный инструмент конвертации ONNX (transformers.onnx), который может легко конвертировать модели из библиотеки transformers в формат ONNX.
- Преимущества: Простой и удобный в использовании, имеет простой интерфейс командной строки для легкого преобразования моделей, тесно интегрирован с библиотекой transformers, поддерживает несколько предварительно обученных моделей и активно поддерживается и обновляется командой Hugging Face.
- Недостатки: По сравнению с torch.onnx, transformers.onnx является относительно новым инструментом и может иметь проблемы с совместимостью.
Ⅴ. Использование Optimum
Optimum — это библиотека инструментов, созданная Hugging Face для оптимизации и ускорения моделей, которая также обеспечивает функциональность преобразования ONNX.
- Преимущества: Оптимизированная интеграция, позволяет сочетать преобразование ONNX с другими методами оптимизации (такими как квантизация, обрезка), поддерживается и обслуживается командой Hugging Face.
- Недостатки: Необходимо изучить использование библиотеки Optimum, что требует некоторой технической базы.
Эти методы преобразования имеют свои преимущества и недостатки. Вам не обязательно ограничиваться методом, описанным в этой статье, и вы можете выбрать подходящий метод, исходя из своих потребностей. В нашем примере будет использоваться библиотека transformers.onnx для преобразования модели GPT-2.
2. Преобразование модели GPT-2 в модель ONNX
Определив использование transformers.onnx для преобразования модели, мы предоставим подробный процесс преобразования.
Ⅰ. Установка зависимостей
Сначала убедитесь, что установлены библиотеки transformers и onnx. Если они не установлены, вы можете использовать следующую команду для их установки:
pip install transformers onnx
Если вам необходимо выполнить оптимизацию для конкретного оборудования, например, с использованием ускорения GPU, вам также необходимо установить onnxruntime-gpu:
pip install onnxruntime-gpu
Ⅱ. Команда преобразования
transformers.onnx предоставляет простой инструмент командной строки. Без особых требований использовать этот инструмент для преобразования моделей просто, достаточно выполнить следующую команду:
python -m transformers.onnx --model=path/to/your/tuned_model --feature=causal-lm-with-past path/to/save/onnx_model
Параметры этой команды:
- `python -m transformers.onnx`: вызвать инструмент transformers.onnx.
- `--model=path/to/your/tuned_model`: указать путь к настроенной модели GPT-2. В нашем примере это путь `gpt2_Adapter-tuning`.
- `--feature=causal-lm-with-past`: указать тип функциональности модели. Поскольку мы используем каузальную языковую модель и нам необходимо поддерживать past_key_values для повышения эффективности генерации, мы выбираем causal-lm-with-past.
- `path/to/save/onnx_model`: указать путь для сохранения модели ONNX. Например, мы можем установить его на gpt2_onnx.
Полный пример команды:
python -m transformers.onnx --model=gpt2_Adapter-tuning --feature=causal-lm-with-past gpt2_onnx
Запустите указанную выше команду в командной строке, transformers.onnx автоматически загрузит необходимые файлы конфигурации и преобразует модель в формат ONNX. После завершения преобразования вы увидите файл с именем model.onnx в указанном выходном каталоге (в данном случае gpt2_onnx), а также некоторые возможные файлы JSON, такие как config.json.
Однако если вам необходимо изменить некоторые настройки в процессе преобразования модели, чтобы они лучше соответствовали текущему варианту использования, этот инструмент явно не может удовлетворить наши потребности. Поэтому для сложных сценариев применения по-прежнему необходимо писать соответствующие скрипты для преобразования, чтобы иметь более точный контроль над формой экспортируемой модели.
Ⅲ. Скрипт преобразования
Чтобы преобразовать модель GPT-2, настроенную с помощью Adapter-Tuning, в процессе преобразования необходимо загрузить модуль адаптера и настройки, а также установить версию ONNX OP, чтобы избежать проблем с совместимостью. Далее мы будем шаг за шагом реализовывать соответствующие функции в соответствии с нашими потребностями.
Сначала мы импортируем необходимые библиотеки Python и классы Adapter() и GPT2LMHeadModelWithAdapters(). Эти классы были подробно представлены в предыдущей статье (Добавляем пользовательскую LLM в торгового робота (Часть 5): Разработка и тестирование торговой стратегии с помощью LLM (III) – Настройка адаптера). Вы можете выбрать прямой импорт из существующего скрипта, и здесь мы копируем эти классы в скрипт преобразования для лучшего понимания:
import os import logging from pathlib import Path from transformers.onnx import export, FeaturesManager from transformers import AutoConfig, AutoTokenizer, GPT2LMHeadModel, modeling_outputs from torch import nn import torch.nn.functional as F import onnx # Set up basic configuration for logging logging.basicConfig(level=logging.INFO) tokenizer = AutoTokenizer.from_pretrained('gpt2') # Define the Adapter class, which is a simple feed-forward network with dropout class Adapter(nn.Module): def __init__(self, in_features, bottleneck_features=64): super(Adapter, self).__init__() # Down projection layer self.down_project = nn.Linear(in_features, bottleneck_features) # Up projection layer self.up_project = nn.Linear(bottleneck_features, in_features) # Dropout layer for regularization self.dropout = nn.Dropout(0.1) # Initialize weights of the layers self.init_weights() def init_weights(self): # Initialize weights for down projection layer nn.init.normal_(self.down_project.weight, mean=0.0, std=0.02) nn.init.constant_(self.down_project.bias, 0) # Initialize weights for up projection layer nn.init.normal_(self.up_project.weight, mean=0.0, std=0.02) nn.init.constant_(self.up_project.bias, 0) def forward(self, hidden_states): # Apply down projection and ReLU activation hidden_states = self.down_project(hidden_states) hidden_states = F.relu(hidden_states) # Apply dropout hidden_states = self.dropout(hidden_states) # Apply up projection hidden_states = self.up_project(hidden_states) # Apply dropout again hidden_states = self.dropout(hidden_states) return hidden_states # Define the GPT2LMHeadModelWithAdapters class, which inherits from GPT2LMHeadModel # and adds adapter layers to each transformer layer class GPT2LMHeadModelWithAdapters(GPT2LMHeadModel): def __init__(self, config): super().__init__(config) # Create a list of adapter modules, one for each transformer layer self.adapters = nn.ModuleList([Adapter(config.n_embd) for _ in range(config.n_layer)]) def forward( self, input_ids=None, past_key_values=None, attention_mask=None, token_type_ids=None, position_ids=None, head_mask=None, inputs_embeds=None, encoder_hidden_states=None, encoder_attention_mask=None, labels=None, use_cache=None, output_attentions=None, output_hidden_states=None, return_dict=None, ): # Get the outputs from the transformer transformer_outputs = self.transformer( input_ids, past_key_values=past_key_values, attention_mask=attention_mask, token_type_ids=token_type_ids, position_ids=position_ids, head_mask=head_mask, inputs_embeds=inputs_embeds, encoder_hidden_states=encoder_hidden_states, encoder_attention_mask=encoder_attention_mask, use_cache=use_cache, output_attentions=output_attentions, output_hidden_states=output_hidden_states, return_dict=return_dict, ) hidden_states = transformer_outputs[0] # Apply each adapter to the hidden states for i, adapter in enumerate(self.adapters): hidden_states = hidden_states + adapter(hidden_states) # Get the logits for the language modeling head lm_logits = self.lm_head(hidden_states) # Compute loss if labels are provided loss = None if labels is not None: # Shift logits and labels for loss computation shift_logits = lm_logits[..., :-1, :].contiguous() shift_labels = labels[..., 1:].contiguous() # Flatten the logits and labels for cross-entropy loss loss_fct = nn.CrossEntropyLoss() loss = loss_fct(shift_logits.view(-1, shift_logits.size(-1)), shift_labels.view(-1)) # Return the outputs in the appropriate format if not return_dict: output = (lm_logits,) + transformer_outputs[1:] return ((loss,) + output) if loss is not None else output return modeling_outputs.CausalLMOutputWithCrossAttentions( loss=loss, logits=lm_logits, past_key_values=transformer_outputs.past_key_values, hidden_states=transformer_outputs.hidden_states, attentions=transformer_outputs.attentions, cross_attentions=transformer_outputs.cross_attentions, )
Далее нам необходимо загрузить настроенную модель GPT-2 и проконтролировать процесс конвертации модели. Мы используем функцию load_model_and_tokenizer() для загрузки точно настроенной модели GPT-2, функцию export_model_to_onnx() для преобразования модели в формат ONNX и функцию main() для управления всем процессом и путями ввода/вывода. Наконец, мы определяем функцию check_onnx() для проверки результатов экспорта и функцию quantization() для квантования. Покажем это на примере:
# Function to load the model and tokenizer def load_model_and_tokenizer(model_id): try: # Load the model configuration config = AutoConfig.from_pretrained(model_id) # Load the model model = GPT2LMHeadModelWithAdapters.from_pretrained(model_id) # Load the tokenizer # tokenizer = AutoTokenizer.from_pretrained('gpt2') return config, model,tokenizer except Exception as e: # Log any errors that occur during loading logging.error(f"Error loading model and tokenizer: {e}") raise # Function to export the model to ONNX format def export_model_to_onnx(model, config, tokenizer, output_path, opset): try: # Get the appropriate feature for the model model_type = config.model_type.replace("-", "_") feature = "causal-lm-with-past" # Get the ONNX configuration onnx_config_constructor = FeaturesManager.get_config(model_type, feature=feature) onnx_config = onnx_config_constructor(config) # Create the output directory if it doesn't exist if not os.path.exists(output_path.parent): os.makedirs(output_path.parent) # Export the model to ONNX export( model=model, config=onnx_config, opset=opset, output=output_path, preprocessor=tokenizer, ) # Log success message logging.info(f"Model successfully converted to ONNX and saved in {output_path}") except Exception as e: # Log any errors that occur during export logging.error(f"Error exporting model to ONNX: {e}") raise # Main function to orchestrate the process def main(): # Define the model ID, output path, and ONNX opset version model_id = "gpt2_Adapter-tuning" onnx_path = "./gpt2_onnx" out_path = Path(os.path.join(onnx_path, "gpt2_adapter_tuning.onnx")) opset = 14 # Load the model and tokenizer config, model, tokenizer = load_model_and_tokenizer(model_id) # Export the model to ONNX export_model_to_onnx(model, config, tokenizer, out_path, opset) def check_onnx(): # Check the ONNX model onnx_model = onnx.load("gpt2_onnx/gpt2_adapter_tuning.onnx") onnx.checker.check_model(onnx_model) print("ONNX model check passed!") def quantization(): from onnxruntime.quantization import quantize_dynamic, QuantType # load model model_path = "gpt2_onnx/gpt2_adapter_tuning.onnx" onnx_model = onnx.load(model_path) #dynamic quantize INT4 quantized_model_path = "gpt2_onnx/quantized_gpt2.onnx" quantize_dynamic(model_path, quantized_model_path, weight_type=QuantType.QUInt4) print(f"Save the quantized model to: {quantized_model_path}")
Реализация этой части кода не представляет никаких сложностей, и в коде имеются подробные комментарии, поэтому мы не будем ее подробно рассматривать. Мы обсудим только ключевые части кода:
- Для загрузки настроенной модели необходимо использовать класс модели с модулем Adapter:
model = GPT2LMHeadModelWithAdapters.from_pretrained(model_id)
- Пути к файлам должны быть преобразованы в формат путей, поддерживаемый transformers.onnx.export(), и не могут напрямую использоваться как строковые пути. Мы используем класс Path из библиотеки pathlib для преобразования:
out_path = Path(os.path.join(onnx_path, "gpt2_adapter_tuning.onnx"))
- Параметры tokenizer и preprocessor функции export() могут иметь только одно значение. В противном случае будет выдано сообщение об ошибке. Рекомендуется использовать preprocessor:
export(model=model, config=onnx_config, opset=opset, output=output_path, preprocessor=tokenizer)
- Определите версию opset, которая должна соответствовать версии opset, поддерживаемой MQL5, для корректной загрузки. Мы выбираем opset=14:
opset = 14
- Входной путь модели (т. е. папка, содержащая модель GPT-2, настроенную с помощью Adapter-Tuning) задается как папка gpt2_Adapter-tuning в текущем пути проекта, а выходной путь задается как папка gpt2_onnx в текущем пути проекта:
model_id = "gpt2_Adapter-tuning" onnx_path = "./gpt2_onnx"
- Функции check_onnx() и quantization() не являются обязательными и приведены для справки.
Конечно, это всего лишь базовый пример скрипта конверсии. Мы не установили более подробную информацию, такую как поддержка динамического ввода для последовательностей. Если вам необходим соответствующий функционал, добавьте соответствующие функции на основе примера скрипта.
Полный скрипт конвертации также приведен во вложении под названием torch2onnx.py.
Разработка стратегии советника и функциональности сервера
Определили режим работы советника. Далее нам необходимо указать план, чтобы определить, какие услуги предоставляет сервер и какие функции интегрирует клиент: клиент советника в основном отвечает за сбор данных и реализацию сделок; сервер Python получает данные, отправленные клиентом, вычисляет результаты вывода и отправляет результаты обратно клиенту; клиент советника и сервер Python взаимодействуют через сокет.
1. Стратегия советника
Далее мы разработаем торговую стратегию на основе результатов прогнозирования GPT-2. Поскольку цель данной статьи — продемонстрировать, как интегрировать модель GPT-2 в советник MQL5, в качестве примера мы создадим простую торговую стратегию. Следует подчеркнуть, что это простой пример стратегии, представленный исключительно в демонстрационных целях и не предназначенный для использования в реальной торговле. На практике необходимо разрабатывать более полные и надежные торговые стратегии, а также проводить тщательное тестирование и оценку рисков.
Логика стратегии советника:
- Получайте данные о цене закрытия последних 20 временных точек каждую минуту.
- Передайте данные на сервер и дождитесь, пока сервер пришлет результаты расчетов.
- Отправляйте ордера на торговлю на основе торговых сигналов, отправляемых сервером, без установки стоп-лосса или тейк-профита и всегда удерживая только один ордер.
2. Проектирование функций сервера
На стороне сервера нам необходимо реализовать основные функции получения данных от клиента советника, запуска вывода модели для получения результатов и расчета торговых сигналов, которые будут отправлены обратно клиенту на основе результатов вывода.
Функции на стороне сервера:
- Получение данных от клиента.
- Загрузка модели GPT-2 и токенизатора и поддержание модели постоянно наготове.
- Запустите вывод и рассчитайте разницу между текущей фактической ценой и средним значением прогнозируемой цены на основе результатов вывода. Если разница больше 0, подается сигнал на покупку; если меньше 0, подается сигнал на продажу; при 0 сигнал не подается.
- Решение о том, следует ли использовать CPU или GPU для вывода модели (в зависимости от режима, поддерживаемого текущим устройством).
Далее мы завершим реализацию соответствующего функционала.
Создание службы вывода
Подробное описание создания сервиса вывода я привел в предыдущей статье (Разметка данных в анализе временных рядов (Часть 5):Применение и тестирование советника с помощью Socket), где предоставлен используемый здесь скрипт server.py). Часть кода по-прежнему будет следовать основной логике скрипта server.py из предыдущей статьи, только адаптируя ее к нашей доработанной модели GPT-2 и внося некоторые другие оптимизации и улучшения.
Модифицированный код в основном имеет следующие изменения:
- Адаптирует вывод модели к модели GPT-2, внося существенные изменения в функцию eva().
- Оптимизирует логику рукопожатия Socket, добавив возможность повторного подключения клиента без перезапуска сервера после отключения, что более удобно для тестирования на истории и не требует перезапуска сервера после тестирования.
- Добавляет определение статуса клиентского соединения, чтобы избежать ненужной траты ресурсов.
- Избегает избыточной печати результатов, печатает результаты только тогда, когда изменяются результаты прогнозирования.
- Добавляет логику обработки ошибок, чтобы избежать сбоев сервера.
- Оптимизирует общую логику кода.
Что касается кода, то в этой статье не будут подробно рассматриваться детали, а будут рассмотрены только те части, которые необходимо изменить.
1. Импорт необходимых библиотек
Помимо импорта обычных необходимых библиотек, нам также необходимо импортировать классы Adapter и GPT2LMHeadModelWithAdapters, которые мы встроили в скрипт. Вы можете получить эти классы из моей предыдущей статьи о тонкой настройке GPT-2 или напрямую импортировать их из torch2onnx.py, предоставленного в этой статье. В примере кода выбран импорт двух классов напрямую из torch2onnx.py.
import socket from time import sleep import pandas as pd import numpy as np import warnings import base64 import hashlib import struct from torch2onnx import GPT2LMHeadModelWithAdapters,Adapter from transformers import AutoTokenizer import logging import torch from statistics import mean # Set logging and warning logging.basicConfig(level=logging.INFO) warnings.filterwarnings("ignore") # Set device dvc='cuda' if torch.cuda.is_available() else 'cpu' # Global model_id = "gpt2_Adapter-tuning" encoder_length=20 prediction_length=10 info_file="results.json" host="0.0.0.0" port=10055
2. Добавление логики загрузки модели GPT-2 в функцию load_model()
В исходном скрипте (server.py) для загрузки модели используется функция load_model(). Обратите внимание, что нам необходимо добавить сюда логику загрузки модели GPT-2, а также логику загрузки для токенизатора GPT-2.
# Function to loda model def load_model(): try: # Load the model model = GPT2LMHeadModelWithAdapters.from_pretrained(model_id).to(dvc) # Load the tokenizer tokenizer = AutoTokenizer.from_pretrained('gpt2') print("Model loaded!") return model,tokenizer except Exception as e: # Log any errors that occur during loading logging.error(f"Error loading model and tokenizer: {e}") raise
3. Добавление логики вывода модели GPT-2 в функцию eva()
def eva(msg,model,tokenizer): # Get the data msg=np.fromstring(msg, dtype=float, sep= ',').tolist() # Parse the data input_data=msg[-encoder_length:] # Create the prompt prompt = ' '.join(map(str, input_data)) # Generate the predication token=tokenizer.encode(prompt, return_tensors='pt').to(dvc) attention_mask = torch.ones_like(token).to(dvc) model.eval() generated = tokenizer.decode( model.generate( token, attention_mask=attention_mask, pad_token_id=tokenizer.eos_token_id, do_sample=True, max_length=200)[0], skip_special_tokens=True) generated_prices=generated.split('\n')[0] # Remove non-numeric formats def try_float(s): try: return float(s) except ValueError: return None generated_prices=generated_prices.split() generated_prices=list(map(try_float,generated_prices)) generated_prices = [f for f in generated_prices if f is not None] generated_prices=generated_prices[0:prediction_length] # Calculate and send the results last_price=input_data[-1] prediction_mean=mean(generated_prices) if (last_price-prediction_mean) >= 0: # print('Send sell.') return "sell" else: # print("Send buy.") return "buy"
Обратите внимание, что длина входных данных должна соответствовать формату данных, используемому при обучении модели GPT-2 с помощью Adapter-Tuning:
- input_data = msg[-encoder_length:]: взять последние 20 точек данных, отправленных клиентом, в качестве входных данных модели
- prompt = ' '.join(map(str, input_data)): преобразовать данные в строковый формат, а затем - в запрос
- token = tokenizer.encode(prompt, return_tensors='pt').to(dvc): использовать токенизатор предварительно обученной модели GPT-2 для кодирования подсказки и передачи ее на текущее поддерживаемое устройство (соответствующее устройству, используемому для вывода модели).
- attention_mask = torch.ones_like(token).to(dvc): определяет маску внимания для вывода модели
- model.generate(token, attention_mask=attention_mask, pad_token_id=tokenizer.eos_token_id, do_sample=True, max_length=200)[0]: запуск вывода модели
- generated = tokenizer.decode(model.generate(...), skip_special_tokens=True): декодировать результаты прогнозирования и настроить пропуск специальных токенов
- generated_prices = generated.split('\n')[0]: разделить декодированные результаты вывода
- try_float(s) : определить наличие элементов в результатах вывода, которые невозможно преобразовать в формат с плавающей точкой
- generated_prices = generated_prices.split(): разделить результаты прогнозирования пробелами и удалить разделители, которые невозможно преобразовать в числа
- generated_prices = list(map(try_float, generated_prices)): преобразовать все элементы в generated_prices в числа с плавающей точкой. Если есть элементы, которые невозможно преобразовать в числа, используйте функцию try_float(s), чтобы установить для них значение None
- generated_prices = [f для f в generated_prices, если f не равно None]: Обойти все элементы в generated_prices и удалить элементы, которые равны None
- generated_prices = generated_prices[0:prediction_length]: получить только первые 10 прогнозируемых значений в качестве справочных
- if (last_price - prediction_mean) >= 0: рассчитать разницу между последними данными, отправленными клиентом, и средним значением прогнозируемых значений. Если больше или равно 0, подать сигнал на продажу; если меньше 0, подать сигнал на покупку
Для вывода мы решили использовать библиотеку transformers. Вы также можете использовать скрипт torch2onnx.py, упомянутый ранее, для преобразования модели в формат ONNX и использовать библиотеку onnxruntime для вывода. В данной статье этот метод обсуждаться не будет.
4. Сервер
Вся функциональность сервера интегрирована в класс server_(), и общие изменения кода незначительны. Здесь мы не будем его подробно интерпретировать, а обсудим лишь те части, которые были изменены.
class server_: def __init__(self, host = host, port = port): self.sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM,) self.host = host self.port = port self.sk.bind((self.host, self.port)) self.re = '' self.model,self.tokenizer=load_model() self.stop=None self.sk.listen(1) self.sk_, self.ad_ = self.sk.accept() self.last_action=None print('server running:',self.sk_, self.ad_) def msg(self): self.re = '' wsk=False while True: sleep(0.5) if self.is_connected(): try: data = self.sk_.recv(2500) except Exception as e: break if not data: break if (data[1] & 0x80) >> 7: fin = (data[0] & 0x80) >> 7 # FIN bit opcode = data[0] & 0x0f # opcode masked = (data[1] & 0x80) >> 7 # mask bit mask = data[4:8] # masking key payload = data[8:] # payload data # print('fin is:{},opcode is:{},mask:{}'.format(fin,opcode,masked)) message = "" for i in range(len(payload)): message += chr(payload[i] ^ mask[i % 4]) data=message wsk=True else: data=data.decode("utf-8") if '\r\n\r\n' in data: self.handshake(data) data=data.split('\r\n\r\n',1)[1] if "stop" in data: self.stop=True break if len(data)<50: break self.re+=data bt=eva(self.re, self.model,self.tokenizer) bt=bytes(bt, "utf-8") # If the signal changes,then print the information if bt != self.last_action: if bt == b'buy': print('Send buy.') elif bt == b'sell': print('Send sell.') self.last_action = bt if wsk: tk=b'\x81' lgt=len(bt) tk+=struct.pack('B',lgt) bt=tk+bt self.sk_.sendall(bt) else: print("Disconnected!Try to connect the client...") try: # reconnect self.sk_.close() self.sk.listen(1) self.sk_, self.ad_ = self.sk.accept() print('Reconnected:', self.sk_, self.ad_) # handshake while True: sleep(0.5) data = self.sk_.recv(2500) data=data.decode("utf-8") if '\r\n\r\n' in data: self.handshake(data) break print("Reconnection succeed!") # # clean the socket # while True: # if not self.sk_.recv(2500): # break except Exception as e: print(f"Reconnection failed: {e}") return self.re def __del__(self): print("server closed!") self.sk.close() if self.sk_ is not None: self.sk_.close() self.ad_.close() def handshake(self,data): try: # Handshake key = data.split("\r\n")[4].split(": ")[1] GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" ac = base64.b64encode(hashlib.sha1((key+GUID).encode('utf-8')).digest()) response_tpl="HTTP/1.1 101 Switching Protocols\r\n" \ "Upgrade:websocket\r\n" \ "Connection: Upgrade\r\n" \ "Sec-WebSocket-Accept: %s\r\n" \ "WebSocket-Location: ws://%s/\r\n\r\n" response_str = response_tpl % (ac.decode('utf-8'), "127.0.0.1:10055") self.sk_.send(bytes(response_str, encoding='utf-8')) print('Handshake succeed!') except Exception as e: print(f"Connection failed: {e}") return None def is_connected(self): try: # Check remote # remote_addr = self.sk_.getpeername() data = self.sk_.recv(1, socket.MSG_PEEK) return True except socket.error: self.last_action=None return False
- Добавим функцию класса is_connected(self) для определения, находится ли клиент в сети.
- Добавим функцию класса handshake(self, data), чтобы интегрировать логику рукопожатия и избежать загромождения основной логики анализа.
- Добавьте член класса self.last_action, чтобы определить, изменился ли торговый сигнал. Печатайте результаты только при изменении торгового сигнала, чтобы избежать частой печати. При отключении клиента установите значение None, чтобы избежать отправки неверных сигналов при повторном подключении клиента.
Примечание: Наш адрес хоста установлен на "0.0.0.0", поскольку если он установлен на "127.0.0.1", удаленные клиенты, работающие на другом хосте, не смогут подключиться. Это означает, что если установить значение "0.0.0.0", то даже если сервер и клиент находятся не на одном хосте, они все равно смогут подключиться (клиенту советника необходимо установить правильный IP-адрес хоста).
Полный код находится в прикрепленном файле server.py. Когда сервер запущен, терминал выдает соответствующую информацию о его работе.
Клиент советника
Клиент в основном следует логике предыдущей статьи (конкретно упомянутой в предыдущей статье), с соответствующими изменениями в логике. В нем по-прежнему сохранены два метода совместимости сокетов (один с использованием Winapi для реализации WebSocket, другой с использованием встроенного модуля Socket в MQL5), чтобы избежать прерываний сигнала, вызванных невозможностью подключения встроенного в MQL5 Socket при особых обстоятельствах. Основная операционная логика заключается в инициализации сокета в функции OnInit(), обработке торговой логики в функции OnTick() и обработке отправки данных на сервер и получении результатов вывода каждый фиксированный момент времени в функции OnTimer().
1. Определяем константы
#include <WinAPI\winhttp.mqh> int sk=-1; string host="127.0.0.1"; int port= 10055; int data_len=100; string pre=NULL; HINTERNET ses_h,cnt_h,re_h,ws_h;
- sk: хэндл сокета.
- host и port: адрес сервера и порт для подключения.
- data_len: количество точек данных о ценах для отправки.
- pre: строка для хранения результатов прогнозирования.
- ses_h, cnt_h, re_h, ws_h: хэндл сеанса, хэндл соединения, хэндл запроса и хэндл WebSocket для WinHttp соответственно.
2. Инициализируем сокет
int OnInit() { //--- create timer EventSetTimer(60); ses_h=cnt_h=re_h=ws_h=NULL; //handshake ses_h=WinHttpOpen("MT5", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, NULL, NULL, 0); //Print(ses_h); if (ses_h==NULL){ Print("Http open failed!",string(kernel32::GetLastError())); return INIT_FAILED; } cnt_h=WinHttpConnect(ses_h, host, port, 0); //Print(cnt_h); if (cnt_h==NULL){ Print("Http connect failed!",string(kernel32::GetLastError())); return INIT_FAILED; } re_h=WinHttpOpenRequest(cnt_h, "GET", NULL, NULL, NULL, NULL, 0); if(re_h==NULL){ Print("Request open failed!",string(kernel32::GetLastError())); return INIT_FAILED; } uchar nullpointer[]= {}; if(!WinHttpSetOption(re_h,WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET,nullpointer,0)) { Print("Set web socket failed!",string(kernel32::GetLastError())); return INIT_FAILED; } bool br; br = WinHttpSendRequest( re_h, NULL, 0, nullpointer, 0, 0, 0); if (!br) { Print("send request failed!",string(kernel32::GetLastError())); return INIT_FAILED; } br=WinHttpReceiveResponse(re_h,nullpointer); if (!br) { Print("receive response failed!",string(kernel32::GetLastError())); return INIT_FAILED; } ulong nv=0; ws_h=WinHttpWebSocketCompleteUpgrade(re_h,nv); if (!ws_h) { Print("Web socket upgrade failed!",string(kernel32::GetLastError())); return INIT_FAILED; } else{ Print("Web socket connected!"); } WinHttpCloseHandle(re_h); re_h=NULL; sk=SocketCreate(); Print(sk); Print(GetLastError()); if (sk==INVALID_HANDLE) { Print("Failed to create socket"); //return INIT_FAILED; } if (!SocketConnect(sk,host, port,1000)) { Print("Failed to connect to built-in socket"); //return INIT_FAILED; } //--- return(INIT_SUCCEEDED); }
В части инициализации мы в основном реализуем инициализацию Winapi WebSocket и встроенного сокета в MQL5. Эта часть не претерпела существенных изменений по сравнению с содержанием предыдущей статьи, поэтому в данной статье она обсуждаться не будет.
3. Торговая стратегия
void OnTick() { //--- MqlTradeRequest request; MqlTradeResult result; //int x=SymbolInfoInteger(_Symbol,SYMBOL_FILLING_MODE); if (pre!=NULL) { //Print("The predicted value is:",pre); ulong numt=0; ulong tik=0; bool sod=false; ulong tpt=-1; ZeroMemory(request); numt=PositionsTotal(); //Print("All tickets: ",numt); if (numt>0) { tik=PositionGetTicket(numt-1); sod=PositionSelectByTicket(tik); tpt=PositionGetInteger(POSITION_TYPE);//ORDER_TYPE_BUY or ORDER_TYPE_SELL if (tik==0 || sod==false || tpt==0) return; } if (pre=="buy") { if (tpt==POSITION_TYPE_BUY) return; request.action=TRADE_ACTION_DEAL; request.symbol=Symbol(); request.volume=0.1; request.deviation=5; request.type_filling=ORDER_FILLING_IOC; request.type = ORDER_TYPE_BUY; request.price = SymbolInfoDouble(Symbol(), SYMBOL_ASK); if(tpt==POSITION_TYPE_SELL) { request.position=tik; Print("Close sell order."); } else{ Print("Open buy order."); } OrderSend(request, result); } else{ if (tpt==POSITION_TYPE_SELL) return; request.action = TRADE_ACTION_DEAL; request.symbol = Symbol(); request.volume = 0.1; request.type = ORDER_TYPE_SELL; request.price = SymbolInfoDouble(Symbol(), SYMBOL_BID); request.deviation = 5; //request.type_filling=SymbolInfoInteger(_Symbol,SYMBOL_FILLING_MODE); request.type_filling=ORDER_FILLING_IOC; if(tpt==POSITION_TYPE_BUY) { request.position=tik; Print("Close buy order."); } else{ Print("OPen sell order."); } OrderSend(request, result); } //is_pre=false; } pre=NULL; }
Мы интегрируем всю торговую стратегию в функцию OnTick(), чтобы сделать логику более понятной. При выполнении функции OnTick() проверяем, является ли глобальная переменная pre пустой. Если она не пустая, это означает, что от клиента отправлены результаты прогнозирования.
Затем отправим торговые запросы на основе результатов прогноза (buy или sell):
- При buy, открываем позицию, если нет существующей позиции, или закрываем существующий ордер на продажу.
- При sell открываем позицию, если нет существующей позиции, или закрываем существующий ордер на покупку.
Поддерживаем только один ордер на протяжении всего времени, не устанавливая тейк-профит или стоп-лосс, и управляем позицией только с помощью торговых сигналов.
4. Взаимодействие с сервером
void OnTimer() { //--- MqlTradeRequest request; MqlTradeResult result; char recv_data[5]; double priceData[100]; string dataToSend; char ds[]; int nc=CopyClose(Symbol(),0,0,data_len,priceData); for(int i=0;i<ArraySize(priceData);i++) dataToSend+=(string)priceData[i]+","; int dsl=StringToCharArray(dataToSend,ds); if (sk!=-1) { if (SocketIsWritable(sk)) { Print("Send data:",dsl); int ssl=SocketSend(sk,ds,dsl); } uint len=SocketIsReadable(sk); if (len) { int rsp_len=SocketRead(sk,recv_data,len,500); if(rsp_len>0) { string result=NULL; result+=CharArrayToString(recv_data,0,rsp_len); Print("The predicted value is:",result); if (StringFind(result,"buy")) { pre="buy"; } if (StringFind(result,"sell")){ pre="sell"; } } } } else { ulong send=0; if (ws_h) { send=WinHttpWebSocketSend(ws_h, WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE, ds, dsl); //Print("Send data failed!",string(kernel32::GetLastError())); if(!send) { ZeroMemory(recv_data); ulong rb=0; WINHTTP_WEB_SOCKET_BUFFER_TYPE st=-1; ulong get=WinHttpWebSocketReceive(ws_h,recv_data,ArraySize(recv_data),rb,st); if (!get) { pre=NULL; pre+=CharArrayToString(recv_data,0); Print("The predicted value is:",pre); } } } } }
Основная функция сервера — собрать 100 точек данных из текущего графика, отправить их на сервер и получить от сервера результаты вывода, а затем изменить глобальную переменную на основе результатов, чтобы гарантировать, что торговая стратегия выполняется в соответствии с результатами, предоставленными сервером. Здесь мы используем два метода подключения сокетов для реализации логики взаимодействия данных и автоматически выбираем подходящий метод на основе текущего типа подключенного сокета.
5. Освобождение ресурсов
void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); uchar stop[]; int ls=StringToCharArray("stop",stop); SocketSend(sk,stop,ls); SocketClose(sk); // close the websocket WinHttpSendRequest(re_h,NULL,0,stop,0,0,0); BYTE closearray[]= {}; ulong close=WinHttpWebSocketClose(ws_h, WINHTTP_WEB_SOCKET_SUCCESS_CLOSE_STATUS, closearray, 0); if(close) { Print("websocket close error "+string(kernel32::GetLastError())); if(re_h!=NULL) WinHttpCloseHandle(re_h); if(ws_h!=NULL) WinHttpCloseHandle(ws_h); if(cnt_h!=NULL) WinHttpCloseHandle(cnt_h); if(ses_h!=NULL) WinHttpCloseHandle(ses_h); } }
В функции OnDeinit() освободим связанные системные ресурсы и выполним восстановление ресурсов.
Поскольку процесс вывода модели GPT-2 не реализован в советнике, это делает логику нашего советника намного проще и лаконичнее. Обратите внимание, что мы не добавили логику управления рисками в советник, и полагаться исключительно на результаты вывода GPT-2 при принятии решения о том, удерживать или открывать позицию, является очень рискованным подходом. Еще раз обратите внимание, что этот пример советника не следует использовать для реальной торговли!
Полный код приведен во вложении к статье под названием gpt2_EA.mql5.
Тестирование на истории
Для оценки производительности советника мы можем провести тестирование на истории в тестере стратегий клиента MetaTrader 5. Мы выбираем соответствующий диапазон исторических данных, устанавливаем параметры тестирования на истории, а затем запускаем тестирование (поскольку наша модель gpt2 обучена на валютной паре NZDUSD, мы можем выбрать только валютную пару NZDUSD для тестирования)
Запускаем тестирование на истории:
После завершения тестирования на истории результаты следующие:
Вы можете проанализировать прибыльность советника, максимальную просадку, процент выигрышей и другие показатели, просмотрев отчет по тестированию на истории. Помните, что наша торговая стратегия проста, поэтому результаты тестирования на исторических данных неидеальны. Это в основном связано с тем, что наша стратегия не подвергалась какой-либо оптимизации параметров или контролю рисков, а процесс обучения и подготовки данных для модели имеют значительный потенциал оптимизации. В целом, эта работа требует большого терпения. Важно отметить, что из-за изменений рыночных условий и ограничений модели результаты тестирования на истории не могут гарантировать производительность советника в будущей реальной торговле, а ограничения модели также могут привести к нестабильным результатам прогнозирования.
Заключение
В этой статье мы продемонстрировали, как интегрировать модель GPT-2, настроенную на конкретные финансовые данные (валютной пары NZDUSD), в программу советника, систематически объяснив весь процесс от настройки модели и реализации логики вывода до настройки сервера и клиента и, наконец, интеграции торговых стратегий.
Важно подчеркнуть, что наша торговая стратегия относительно проста и предназначена только для демонстрационных целей. На практике необходимо разрабатывать более полные и надежные стратегии, такие как комбинирование нескольких технических индикаторов, учет настроений рынка, установка стоп-лосса и тейк-профита и т. д.
Кроме того, процесс обучения и подготовки данных для модели имеют значительный потенциал оптимизации, а изменения рыночных условий и ограничений модели могут привести к нестабильным результатам прогнозирования. Несмотря на это, значимость данной работы заключается в демонстрации потенциала больших языковых моделей в количественной торговле. Такие модели, как GPT-2, могут анализировать традиционные рыночные данные и обрабатывать новостные данные, данные социальных сетей и другие текстовые данные, обеспечивая более комплексный анализ настроений рынка, помогая трейдерам принимать более взвешенные решения. Такая кросс-модальная возможность отсутствует в традиционных финансовых моделях, и это область, которую нам необходимо изучить более подробно.
В следующей статье мы на примере продемонстрируем, как оптимизировать применение больших языковых моделей в количественной торговле.
Приложения:
Файлы | Описание |
---|---|
torch2onnx.py | Скрипт Python для преобразования модели GPT-2 в формат ONNX |
server.py | Скрипт Python для предоставления услуг и результатов вывода модели GPT-2 |
gpt2_EA.mq5 | Советник для тестирования результатов вывода моделей GPT-2 |
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/13506
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.




- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Ознакомьтесь с новой статьей: Интеграция собственных LLM в советник (часть 5): Разработка и тестирование торговой стратегии с помощью LLM(IV) - Тестирование торговой стратегии.
Автор: Yuqiang Pan