Integrar seu próprio LLM em EA (Parte 5): Desenvolver e testar estratégia de trading com LLMs (IV) — Testar estratégia de trading
Índice
- Índice
- Introdução
- Ambiente de desenvolvimento para o exemplo deste artigo
- Métodos para carregar LLMs em MQL5
- Converter o modelo GPT-2 para o modelo ONNX
- Formulação da estratégia do EA e funcionalidade do servidor
- Criação do serviço de inferência
- Cliente EA
- Backtesting
- Conclusão
Introdução
Em artigos anteriores, apresentamos como ajustar modelos GPT-2 pré-treinados usando diferentes métodos para fazer com que o GPT-2 execute tarefas de acordo com nossos desejos, e comparamos esses métodos em várias dimensões. É claro que apresentamos apenas alguns métodos comumente usados, o que não significa que apenas esses métodos possam ser usados para ajustar modelos GPT-2. Você pode tentar ajustar o GPT-2 usando outros métodos com base no nosso processo de implementação de exemplo, compará-los e escolher um modelo melhor. Se você encontrar algum problema durante esse processo, pode deixar um comentário no final do artigo.
Agora, nosso modelo GPT-2 ajustado tem a capacidade inicial de executar estratégias simples de trading quantitativo. Portanto, este artigo apresentará como integrar nosso modelo ajustado à nossa estratégia de trading quantitativo. O modelo usado no exemplo é o modelo GPT-2 ajustado com Adapter-tuning (link específico do artigo: Integrate Your Own LLM into EA (Part 5): Develop and Test Trading Strategy with LLMs (III) – Adapter-Tuning). Assim, salvo indicação em contrário, todas as referências ao GPT-2 neste artigo referem-se a esse modelo.
No entanto, deve-se observar que o modelo que ajustamos é baseado em dados limitados para fins de demonstração e não pode lidar com ambientes reais de trading. Sem testes e otimizações, não o utilize diretamente em trading real, o que é de extrema importância. Nosso código de previsão anterior foi concluído no ambiente Python, mas o MQL5, como uma linguagem de programação altamente integrada para a plataforma MetaTrader 5, fornece ferramentas poderosas para desenvolver Expert Advisors (EAs). Portanto, para implementar estratégias automatizadas de trading quantitativo, precisamos retornar ao ambiente MQL5. Este artigo realizará esse processo passo a passo.
Vamos ver como migrar este modelo treinado do ambiente Python para o EA em MQL5, fazendo com que ele seja executado diretamente na plataforma MetaTrader 5 para dar suporte a decisões de trading em tempo real.
Ambiente de desenvolvimento para o exemplo deste artigo
Vamos apresentar o ambiente de execução para os exemplos de código fornecidos neste artigo. É claro que isso não significa que o seu ambiente de código deva ser o mesmo que o meu, mas se você encontrar problemas ao executar o código, pode consultar minha configuração de ambiente.
- Sistema operacional: Ubuntu 22.04.5 LTS (ou a versão correspondente do WSL)
- Versão do Python: 3.10.14
- Bibliotecas Python necessárias:
- 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
Observe que, antes de prosseguir para a próxima etapa, certifique-se de que você treinou um modelo usando Adapter-tuning conforme descrito no artigo anterior (como o tamanho do modelo excede o limite da plataforma, os pesos que já treinei não podem ser enviados).
Métodos para carregar LLMs em MQL5
Para integrar o modelo GPT-2 treinado ao EA em MQL5, o primeiro problema que precisamos resolver é como carregar e executar esse modelo, que essencialmente é um modelo treinado em Python, no ambiente MQL5. Aqui estão vários métodos viáveis:
1. Converter o modelo para ONNX e adicioná-lo ao EA
ONNX (Open Neural Network Exchange) é um formato aberto para representar redes neurais, permitindo interoperabilidade entre diferentes frameworks de deep learning. No meu artigo anterior, apresentei como integrar modelos simples em EAs usando ONNX (Data label for time series mining (Part 6): Apply and Test in EA Using ONNX). Também podemos converter o modelo GPT-2 para o formato ONNX, importá-lo para o EA e usar a biblioteca de runtime ONNX integrada no MQL5 para executar a inferência do modelo. Para o suporte do MQL5 ao ONNX, consulte o arquivo de ajuda “MQL5 Reference / ONNX models” ou a documentação oficial do MQL5 (https://www.mql5.com/en/docs/onnx ).
- Vantagens:
- Alto desempenho: o runtime ONNX geralmente é otimizado para desempenho, permitindo inferência relativamente eficiente no EA.
- Alta integração: o MQL5 possui suporte integrado ao ONNX, eliminando a necessidade de programas ou bibliotecas externas.
- Independência: o modelo ONNX convertido pode ser executado independentemente do ambiente Python.
- Desvantagens:
- Complexidade da conversão: converter modelos de linguagem complexos para o formato ONNX pode ser desafiador, exigindo o tratamento de problemas de compatibilidade de operadores.
- Dificuldade de depuração: depurar modelos ONNX é menos conveniente do que depurar modelos Python.
2. Executar diretamente scripts de inferência em Python usando Winapi
O MQL5 fornece acesso ao Winapi, permitindo chamar a função WinExec() da “kernel32.dll” para executar programas externos. Dessa forma, podemos usar scripts Python existentes para carregar o modelo GPT-2 e realizar a inferência e, em seguida, chamar o script no EA usando WinExec() e analisar seus resultados de saída (alternativamente, a função ShellExecuteW() da shell32.dll também pode realizar essa funcionalidade). Esse método exige alguma experiência em desenvolvimento e familiaridade com desenvolvimento em Windows para ser implementado.
- Vantagens:
- Simples e direto: não é necessário converter o modelo, utilizando diretamente o código Python existente.
- Flexibilidade: pode-se usar facilmente as bibliotecas e ferramentas ricas do ecossistema Python.
- Desvantagens:
- Sobrecarga de desempenho: cada inferência exige iniciar um novo processo Python, resultando em sobrecarga significativa de desempenho e ineficiência.
- Dependência: o EA depende do ambiente Python externo e de scripts.
- Troca de dados: é necessário lidar com a troca de dados entre MQL5 e Python, aumentando a complexidade.
- Segurança: várias situações inesperadas podem ocorrer, potencialmente causando falhas incontroláveis.
Nota: Este método é extremamente não recomendado! Forneço essa solução apenas para indicar que ela é viável e pode ser usada em testes ou sob condições controladas. Não a utilize sem confiança suficiente.
3. Obter resultados de inferência em Python por meio de comunicação Socket
Semelhante ao segundo método, mas usando comunicação Socket em vez de Winapi (na verdade, o protocolo HTTP também pode ser usado, de forma semelhante aos serviços HTTP fornecidos por frameworks de inferência convencionais, que essencialmente são os mesmos que Socket, e este artigo não discutirá isso em mais detalhes). O método de implementação específico consiste em executar um servidor Socket em Python para carregar o modelo e realizar a inferência, com o EA atuando como cliente que se conecta ao servidor, envia dados de entrada e recebe os resultados da inferência.
- Vantagens:
- Melhor desempenho: a comunicação Socket pode reduzir a sobrecarga de inicialização de processos e é muito mais segura.
- Flexibilidade: ainda é possível aproveitar as vantagens do Python.
- Desvantagens:
- Complexidade: é necessário implementar a lógica de comunicação entre o servidor Socket e o cliente.
- Dependência: o EA depende do ambiente Python externo e do servidor Socket, exigindo algum conhecimento para configurar o serviço.
- Estabilidade: a estabilidade das conexões Socket pode afetar a operação do EA.
Nota: Este método possui uma implementação específica em meu artigo anterior. Se você estiver interessado, pode consultar o artigo: Data label for time series mining (Part 5): Apply and Test in EA Using Socket.
Discutimos vários métodos diferentes de conversão. Atualmente, ainda tendo a escolher converter o modelo GPT-2 para o formato ONNX e integrá-lo ao EA, pois isso também pode resolver problemas de multiplataforma e o EA apresenta maior integração e estabilidade. No entanto, se os parâmetros do modelo ONNX forem muito grandes, eles não poderão ser executados no MQL5 (por exemplo, nosso modelo GPT-2 atual excede o limite de carregamento de arquivos do MQL5).
Outro problema desafiador é resolver a questão do tokenizer no modelo transformers, pois modelos como o GPT-2 vêm com um tokenizer para lidar com informações de entrada e, para executar o modelo GPT-2 no MQL5, precisamos construir o tokenizer do GPT-2 no MQL5, o que é um projeto significativo. Isso é difícil, mas não impossível. No entanto, o limite de tamanho de carregamento de arquivos do MQL5 é um problema difícil de resolver.
Embora eu tenha tentado quantizá-lo para o formato INT8, ele ainda excedeu o limite e não pôde ser carregado. Se quantizado para o formato INT4, embora o tamanho do modelo atenda aos requisitos, o MQL5 não oferece suporte a modelos quantizados no formato INT4! Portanto, só podemos lamentavelmente abandonar esse método. No entanto, ainda fornecerei um exemplo de como converter nosso modelo GPT-2 ajustado com Adapter para o formato ONNX neste artigo, esperando resolver esse problema em breve!
Neste artigo, decidi finalmente discutir o uso de comunicação Socket com o serviço de inferência em Python. A vantagem desse método é que ele pode garantir a segurança dos dados e simplificar nossa implementação do EA. No EA, precisamos apenas nos concentrar em nossa estratégia e lógica de trading, e não precisamos considerar questões adicionais de integração de módulos. Outra vantagem desse método é que, se não houver um ambiente de desenvolvimento de modelo relevante localmente, como o modelo sendo desenvolvido e treinado em um dispositivo remoto, mesmo que o ambiente de desenvolvimento seja incompatível com o ambiente local, esse método ainda pode ser usado para desenvolver o EA.
De modo geral, embora esse método possa parecer tecnicamente complexo de implementar e possa exigir mais conhecimento, ele pode alcançar alta eficiência operacional e garantir a independência do EA, o que é crucial para um ambiente de trading em tempo real eficiente. Considerando que já discutimos isso em detalhes em um artigo anterior, este artigo não descreverá os detalhes novamente. Se você tiver alguma dúvida sobre os exemplos de código, pode consultar a introdução detalhada no artigo anterior.
Converter o modelo GPT-2 para o modelo ONNX
Na seção anterior, descrevi os vários desafios encontrados ao converter o modelo GPT-2 ajustado para o formato ONNX e usá-lo no MQL5. No entanto, ainda acredito que essa seja uma direção que vale a pena tentar, portanto, neste artigo, usarei uma seção adicional para apresentar como converter esse modelo personalizado ajustado para o formato ONNX, esperando que todos possam encontrar uma solução para a situação atual. Se você não estiver interessado nessa parte, pode pular esta seção.
1. Métodos de conversão do modelo
Ⅰ. Conversão direta (https://github.com/rayhern/convert-gpt2-xl-to-onnx)
Este repositório do GitHub fornece um script para converter diretamente modelos GPT-2, com base na biblioteca transformers da Hugging Face e no exportador torch.onnx. No entanto, devido à falta de manutenção do autor a longo prazo, ele pode ter algumas limitações e pode não ser compatível com as versões mais recentes da biblioteca transformers.
- Vantagens: Fornece um script relativamente simples que pode ser usado diretamente; otimizado especificamente para conversão de modelos GPT-2.
- Desvantagens: O estado de manutenção deste repositório pode não ser claro e ele pode não ser compatível com as versões mais recentes do transformers, sendo aplicável apenas a versões específicas de modelos GPT-2.
Ⅱ. API ONNX da Microsoft (https://github.com/microsoft/onnxruntime-genai)
A biblioteca onnxruntime-genai da Microsoft fornece um conjunto de APIs de conversão e otimização ONNX para modelos de IA generativa.
- Vantagens: Otimizada para o runtime ONNX, melhorando o desempenho de inferência, e suportada e mantida pela Microsoft.
- Desvantagens: É necessário aprender a API da biblioteca onnxruntime-genai, que pode ser mais complexa em comparação com outros métodos.
Ⅲ. Usar torch.onnx para exportar o modelo
O PyTorch fornece funcionalidade integrada de exportação para ONNX (torch.onnx), que pode exportar modelos PyTorch para o formato ONNX.
- Vantagens: Fortemente integrado ao framework PyTorch, fácil de usar, torch.onnx é uma ferramenta de exportação ONNX amplamente utilizada.
- Desvantagens: Pode ser necessário lidar com alguns problemas de compatibilidade de operadores, especialmente para operadores mais novos ou personalizados, e pode ser necessário ajustar manualmente alguns parâmetros de exportação para garantir a correção e o desempenho do modelo.
Ⅳ. Usar transformers.onnx para converter o modelo
A biblioteca transformers da Hugging Face fornece sua própria ferramenta de conversão para ONNX (transformers.onnx), que pode converter facilmente modelos da biblioteca transformers para o formato ONNX.
- Vantagens: Simples e fácil de usar, fornece uma interface de linha de comando simples para converter modelos facilmente, fortemente integrada à biblioteca transformers, oferece suporte a vários modelos pré-treinados e é ativamente mantida e atualizada pela equipe da Hugging Face.
- Desvantagens: Em comparação com torch.onnx, transformers.onnx é uma ferramenta relativamente nova e pode ter problemas de compatibilidade.
Ⅴ. Usar Optimum
Optimum é uma biblioteca de ferramentas lançada pela Hugging Face para otimização e aceleração de modelos, que também fornece funcionalidade de conversão para ONNX.
- Vantagens: Integração otimizada, pode combinar conversão ONNX com outras técnicas de otimização (como quantização, poda), e é suportada e mantida pela equipe da Hugging Face.
- Desvantagens: É necessário aprender o uso da biblioteca Optimum, exigindo alguma base técnica.
Esses métodos de conversão têm suas próprias vantagens e desvantagens. Você não precisa se limitar ao método usado neste artigo e pode escolher um método adequado com base em suas necessidades. Nosso exemplo usará a biblioteca transformers.onnx para converter o modelo GPT-2.
2. Converter o modelo GPT-2 para o modelo ONNX
Após decidir usar transformers.onnx para a conversão do modelo, forneceremos agora um processo detalhado de conversão.
Ⅰ. Instalar dependências
Primeiro, certifique-se de que as bibliotecas transformers e onnx estejam instaladas. Se não estiverem instaladas, você pode usar o seguinte comando para instalá-las:
pip install transformers onnx
Se você precisar otimizar para hardware específico, como usar aceleração por GPU, também precisará instalar onnxruntime-gpu:
pip install onnxruntime-gpu
Ⅱ. Comando de conversão
O transformers.onnx fornece uma ferramenta simples de linha de comando. Sem requisitos especiais, usar essa ferramenta para conversão de modelo é simples, basta executar o seguinte comando:
python -m transformers.onnx --model=path/to/your/tuned_model --feature=causal-lm-with-past path/to/save/onnx_model
Os parâmetros neste comando:
- python -m transformers.onnx: chama a ferramenta transformers.onnx.
- --model=path/to/your/tuned_model: especifica o caminho do modelo GPT-2 ajustado. No nosso exemplo, esse caminho é gpt2_Adapter-tuning.
- --feature=causal-lm-with-past: especifica o tipo de funcionalidade do modelo. Como estamos usando um modelo de linguagem causal e precisamos oferecer suporte a past_key_values para melhorar a eficiência de geração, escolhemos causal-lm-with-past.
- path/to/save/onnx_model: especifica o caminho para salvar o modelo ONNX. Por exemplo, podemos defini-lo como gpt2_onnx.
Comando de exemplo completo:
python -m transformers.onnx --model=gpt2_Adapter-tuning --feature=causal-lm-with-past gpt2_onnx
Execute o comando acima na linha de comando, o transformers.onnx fará o download automático dos arquivos de configuração necessários e converterá o modelo para o formato ONNX. Após a conclusão da conversão, você verá um arquivo chamado model.onnx no diretório de saída especificado (neste caso, gpt2_onnx), juntamente com alguns possíveis arquivos JSON, como config.json.
No entanto, se você precisar ajustar algumas configurações durante o processo de conversão do modelo para melhor atender ao caso de uso atual, essa ferramenta claramente não consegue atender às nossas necessidades. Portanto, para cenários de aplicação complexos, ainda é necessário escrever scripts apropriados para a conversão, a fim de ter um controle mais preciso sobre a forma do modelo exportado.
Ⅲ. Script de conversão
Para converter o modelo GPT-2 ajustado com Adapter-Tuning, o processo de conversão precisa carregar o módulo Adapter e as configurações, além de definir a versão do OP do ONNX para evitar problemas de compatibilidade. Em seguida, implementaremos as funções relevantes passo a passo de acordo com nossas necessidades.
Primeiro, importamos as bibliotecas Python necessárias e as classes Adapter() e GPT2LMHeadModelWithAdapters(). Essas classes foram apresentadas em detalhes no artigo anterior (Integrate Your Own LLM into EA (Part 5): Develop and Test Trading Strategy with LLMs (III) – Adapter-Tuning). Você pode optar por importar diretamente do script existente e, aqui, copiamos essas classes para o script de conversão para melhor compreensão:
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, )
Em seguida, precisamos carregar o modelo GPT-2 ajustado e controlar o processo de conversão do modelo. Usamos a função load_model_and_tokenizer() para carregar o modelo GPT-2 ajustado, a função export_model_to_onnx() para converter o modelo para o formato ONNX e a função main() para controlar todo o processo e os caminhos de entrada/saída. Por fim, definimos uma função check_onnx() para verificar os resultados da exportação e uma função quantization() para quantização. Aqui está um exemplo:
# 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}")
A implementação desta parte do código não apresenta dificuldades, e há comentários detalhados no código, portanto não entraremos em detalhes. Discutiremos apenas as partes principais do código:
- É obrigatório usar a classe de modelo com o módulo Adapter para carregar o modelo ajustado:
model = GPT2LMHeadModelWithAdapters.from_pretrained(model_id)
- Os caminhos de arquivo devem ser convertidos para o formato de caminho suportado por transformers.onnx.export() e não podem ser usados diretamente como caminhos em string. Usamos a classe Path da biblioteca pathlib para converter:
out_path = Path(os.path.join(onnx_path, "gpt2_adapter_tuning.onnx")) - Os parâmetros tokenizer e preprocessor da função export() permitem definir apenas um deles. Caso contrário, será gerado um erro. Recomenda-se usar preprocessor:
export(model=model, config=onnx_config, opset=opset, output=output_path, preprocessor=tokenizer) - Determinar a versão do opset, que deve corresponder à versão do opset suportada pelo MQL5 para ser carregada corretamente. Escolhemos opset=14:
opset = 14 - O caminho de entrada do modelo (ou seja, a pasta que contém o modelo GPT-2 ajustado com Adapter-Tuning) é definido como a pasta gpt2_Adapter-tuning sob o caminho do projeto atual, e o caminho de saída é definido como a pasta gpt2_onnx sob o caminho do projeto atual:
model_id = "gpt2_Adapter-tuning" onnx_path = "./gpt2_onnx"
- As funções check_onnx() e quantization() não são obrigatórias e são fornecidas apenas para referência.
É claro que este é apenas um exemplo básico de script de conversão. Não definimos mais detalhes, como suporte a entrada dinâmica para sequências. Se você precisar da funcionalidade correspondente, adicione os recursos relevantes com base no script de exemplo.
O script completo de conversão também é fornecido no anexo, com o nome torch2onnx.py.
Formulação da estratégia do EA e funcionalidade do servidor
Determinamos o modo de operação do EA. Em seguida, precisamos especificar um plano para determinar quais serviços o servidor fornece e quais funcionalidades o cliente integra: o cliente EA é o principal responsável pela coleta de dados e execução de transações; o servidor Python recebe os dados enviados pelo cliente, calcula os resultados de inferência e envia os resultados de volta ao cliente; o cliente EA e o servidor Python se comunicam por meio de Socket.
1. Estratégia do EA
Em seguida, projetaremos uma estratégia de trading com base nos resultados de previsão do GPT-2. Como o foco deste artigo é demonstrar como integrar o modelo GPT-2 ao EA em MQL5, criaremos uma estratégia de trading simples como exemplo. Deve-se enfatizar que esta é apenas uma estratégia de exemplo simples para fins de demonstração e não constitui qualquer aconselhamento real de trading. Em aplicações práticas, estratégias de trading mais completas e robustas precisam ser desenvolvidas, e backtesting completo e avaliação de risco devem ser realizados.
Lógica da estratégia do EA:
- Obter os dados de preço de fechamento dos últimos 20 pontos de tempo a cada 1 minuto.
- Transmitir os dados para o servidor e aguardar que o servidor envie de volta os resultados do cálculo.
- Enviar ordens de trading com base nos sinais de trading retornados pelo servidor, sem definir stop loss ou take profit, e mantendo sempre apenas uma ordem aberta.
2. Design da função do servidor
No lado do servidor, precisamos implementar as principais funções de receber dados do cliente EA, executar a inferência do modelo para obter resultados e calcular os sinais de trading a serem enviados de volta ao cliente com base nos resultados da inferência.
Funções do lado do servidor:
- Receber dados do cliente.
- Carregar o modelo GPT-2 e o tokenizer e manter o modelo sempre pronto.
- Executar a inferência e calcular a diferença entre o preço real atual e a média do preço previsto com base nos resultados da inferência. Se a diferença for maior que 0, enviar um sinal de "buy"; se for menor que 0, enviar um sinal de "sell"; se for igual a 0, não enviar nenhum sinal.
- Verificar e decidir se deve usar CPU ou GPU para a inferência do modelo (dependendo do modo suportado pelo dispositivo atual).
Em seguida, concluiremos a implementação das funcionalidades correspondentes.
Criação do serviço de inferência
Quanto à criação do serviço de inferência, forneci uma descrição detalhada em um artigo anterior (Data label for time series mining (Part 5): Apply and Test in EA Using Socket), no qual o script server.py usado aqui é fornecido). A parte do código continuará seguindo a lógica principal do script server.py do artigo anterior, apenas adaptando-o ao nosso modelo GPT-2 ajustado e realizando algumas outras otimizações e melhorias.
O código modificado apresenta principalmente as seguintes alterações:
- Adaptar a inferência do modelo para o modelo GPT-2, com mudanças significativas na função eva().
- Otimizar a lógica de handshake do Socket, adicionando a capacidade de reconectar o cliente sem reiniciar o servidor após a desconexão, o que é mais conveniente para backtesting e não exige reiniciar o servidor após o backtesting.
- Adicionar detecção do status de conexão do cliente para evitar desperdício desnecessário de recursos.
- Evitar impressão redundante de resultados, imprimindo apenas quando os resultados de previsão mudarem.
- Adicionar lógica de tratamento de erros para evitar falhas do servidor.
- Otimizar a lógica geral do código.
Quanto à parte do código, este artigo não discutirá mais detalhes e apenas abordará as partes que precisam ser modificadas.
1. Importar bibliotecas necessárias
Além de importar as bibliotecas normais necessárias, também precisamos importar as classes Adapter e GPT2LMHeadModelWithAdapters que construímos no script. Você pode obter essas classes no meu artigo anterior sobre ajuste fino do GPT-2 ou importá-las diretamente do torch2onnx.py fornecido neste artigo. O código de exemplo opta por importar as duas classes diretamente do 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. Adicionar lógica de carregamento do modelo GPT-2 na função load_model()
No script original (server.py), a função load_model() é usada para carregar o modelo. Observe que precisamos adicionar aqui a lógica de carregamento do modelo GPT-2, bem como a lógica de carregamento do tokenizer do 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. Adicionar lógica de inferência do modelo GPT-2 na função 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"
Observe que o comprimento da entrada deve corresponder ao formato de dados usado ao treinar o modelo GPT-2 com Adapter-Tuning:
- input_data = msg[-encoder_length:]: usar os últimos 20 pontos de dados enviados pelo cliente como entrada do modelo
- prompt = ' '.join(map(str, input_data)): converter os dados para o formato de string e transformá-los em um prompt
- token = tokenizer.encode(prompt, return_tensors='pt').to(dvc): usar o tokenizer do modelo GPT-2 pré-treinado para codificar o prompt e transferi-lo para o dispositivo atualmente suportado (correspondendo ao dispositivo usado para inferência do modelo)
- attention_mask = torch.ones_like(token).to(dvc): definir a máscara de atenção para a inferência do modelo
- model.generate(token, attention_mask=attention_mask, pad_token_id=tokenizer.eos_token_id, do_sample=True, max_length=200)[0]: executar a inferência do modelo
- generated = tokenizer.decode(model.generate(...), skip_special_tokens=True): decodificar os resultados da previsão e definir para ignorar tokens especiais
- generated_prices = generated.split('\n')[0]: dividir os resultados de inferência decodificados
- try_float(s): esta função é usada para detectar se existem elementos nos resultados de inferência que não podem ser convertidos para o formato float
- generated_prices = generated_prices.split(): separar os resultados de previsão por espaços e remover separadores que não podem ser convertidos em números
- generated_prices = list(map(try_float, generated_prices)): converter todos os elementos em generated_prices para números em formato float; se houver elementos que não possam ser convertidos em números, usar a função try_float(s) para defini-los como None
- generated_prices = [f for f in generated_prices if f is not None]: percorrer todos os elementos em generated_prices e remover os elementos que são None
- generated_prices = generated_prices[0:prediction_length]: obter apenas os primeiros 10 valores previstos como referência
- if (last_price - prediction_mean) >= 0: calcular a diferença entre o último dado enviado pelo cliente e a média dos valores previstos. Se for maior ou igual a 0, enviar um sinal de "sell"; se for menor que 0, enviar um sinal de "buy"
Optamos por usar a biblioteca transformers para a inferência. Você também pode usar o script torch2onnx.py mencionado anteriormente para converter o modelo para o formato ONNX e usar a biblioteca onnxruntime para a inferência. Esse método não será discutido neste artigo.
4. Servidor
Toda a funcionalidade do servidor está integrada na classe server_(), e as alterações gerais no código não são significativas. Aqui, não faremos uma interpretação detalhada e discutiremos apenas as partes que foram modificadas.
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
- Adicionar a função de classe is_connected(self) para detectar se o cliente está online.
- Adicionar a função de classe handshake(self, data) para integrar a lógica de handshake e evitar poluir a lógica principal de parsing.
- Adicionar o membro de classe self.last_action para detectar se o sinal de trading mudou. Imprimir resultados apenas quando o sinal de trading mudar para evitar impressões frequentes. Quando o cliente se desconectar, redefinir para None para evitar o envio de sinais incorretos quando o cliente se reconectar.
Nota: Nosso endereço de host é definido como "0.0.0.0" porque, se for definido como "127.0.0.1", clientes remotos executando em um host diferente não poderão se conectar. Isso significa que, ao defini-lo como "0.0.0.0", mesmo que o servidor e o cliente não estejam no mesmo host, eles ainda podem se conectar (o cliente EA precisa definir o endereço IP correto do host).
O código completo está no arquivo server.py em anexo. Quando o servidor estiver em execução, o terminal fornecerá as informações de execução correspondentes.

Cliente EA
O cliente segue principalmente a lógica de um artigo anterior (mencionado especificamente em um artigo anterior), com as modificações correspondentes na lógica. Ele ainda mantém dois métodos de compatibilidade de socket (um usando Winapi para implementar WebSocket e outro usando o módulo Socket integrado do MQL5) para evitar interrupções de sinal causadas pela impossibilidade de conexão do Socket integrado do MQL5 em circunstâncias especiais. A lógica operacional principal é inicializar o Socket na função OnInit(), tratar a lógica de trading na função OnTick() e tratar o envio de dados ao servidor e o recebimento dos resultados de inferência em intervalos fixos na função OnTimer().
1. Definir constantes
#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`: identificador do Socket.
- `host` e `port`: endereço e porta do servidor para conexão.
- `data_len`: número de pontos de dados de preço a serem enviados.
- `pre`: string para armazenar os resultados da previsão.
- `ses_h`, `cnt_h`, `re_h`, `ws_h`: identificador de sessão, identificador de conexão, identificador de requisição e identificador de WebSocket do WinHttp, respectivamente.
2. Inicializar Socket
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); }
Na parte de inicialização, implementamos principalmente a inicialização do WebSocket via Winapi e do Socket integrado no MQL5. Essa parte não sofreu muitas alterações em comparação com o conteúdo do artigo anterior, portanto não será discutida neste artigo.
3. Estratégia de trading
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; }
Integramos toda a estratégia de trading na função OnTick() para tornar a lógica mais clara. Quando a função OnTick() é executada, verificamos se a variável global pre está vazia. Se não estiver vazia, isso indica que há resultados de previsão enviados pelo cliente.
Em seguida, enviamos requisições de trading com base nos resultados de previsão ("buy" ou "sell"):
- Se for "buy", abrir uma posição se não houver posição existente ou fechar uma ordem de venda existente.
- Se for "sell", abrir uma posição se não houver posição existente ou fechar uma ordem de compra existente.
Manter apenas uma ordem durante todo o tempo, sem definir take profit ou stop loss, e controlar a posição apenas por meio dos sinais de trading.
4. Interação com o servidor
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); } } } } }
A principal função do servidor é coletar 100 pontos de dados do gráfico atual, enviá-los ao servidor e receber os resultados de inferência do servidor, e então modificar a variável global com base nos resultados para garantir que a estratégia de trading seja executada de acordo com os resultados fornecidos pelo servidor. Aqui, utilizamos dois métodos de conexão de socket para implementar a lógica de interação de dados e selecionamos automaticamente o método apropriado com base no tipo de socket atualmente conectado.
5. Liberação de recursos
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); } }
Na função OnDeinit(), liberamos os recursos de sistema relacionados e realizamos a recuperação de recursos.
Como o processo de inferência do modelo GPT-2 não é implementado no EA, isso torna a lógica do EA muito mais simples e concisa. Observe que não adicionamos lógica de controle de risco no EA, e confiar exclusivamente nos resultados de inferência do GPT-2 para decidir se deve manter ou abrir uma posição é uma abordagem muito arriscada. Observe novamente que este exemplo de EA não deve ser usado para trading real!
O código completo é fornecido no anexo do artigo, com o nome gpt2_EA.mql5.
Backtesting
Para avaliar o desempenho do EA, podemos realizar backtesting no testador de estratégias do cliente MetaTrader 5. Selecionamos o intervalo apropriado de dados históricos, definimos os parâmetros de backtest e, em seguida, executamos o backtest (como nosso modelo gpt2 é treinado no par de moedas NZDUSD, só podemos selecionar o par NZDUSD para teste no backtest).

O backtesting está em execução:

Após a conclusão do backtesting, os resultados são os seguintes:

Você pode analisar a lucratividade do EA, o drawdown máximo, a taxa de acerto e outras métricas revisando o relatório de backtest. Lembre-se de que nossa estratégia de trading é simples, portanto os resultados do backtest não são ideais. Isso ocorre principalmente porque nossa estratégia não passou por nenhuma otimização de parâmetros ou controle de risco, e o processo de treinamento e a preparação dos dados para o modelo possuem grande potencial de otimização. De modo geral, fazer isso exige muita paciência. É importante observar que, devido a mudanças nas condições de mercado e às limitações do modelo, os resultados do backtest não podem garantir o desempenho do EA em trading real futuro, e as limitações do modelo também podem levar a resultados de previsão instáveis.
Conclusão
Neste artigo, demonstramos como integrar um modelo GPT-2 ajustado com dados financeiros específicos (do par de moedas NZDUSD) em um programa EA, explicando sistematicamente todo o processo, desde o ajuste fino do modelo e a implementação da lógica de inferência até a configuração do servidor e do cliente e, por fim, a integração das estratégias de trading.
É importante enfatizar que o design da nossa estratégia de trading é relativamente simples e serve apenas para fins de demonstração. Em aplicações práticas, estratégias mais completas e robustas precisam ser desenvolvidas, como a combinação de múltiplos indicadores técnicos, a consideração do sentimento de mercado, a definição de stop loss e take profit, entre outros.
Além disso, o processo de treinamento e a preparação dos dados para o modelo têm grande potencial de otimização, e mudanças nas condições de mercado e limitações do modelo podem levar a resultados de previsão instáveis. Apesar disso, a importância deste trabalho está em demonstrar o potencial dos grandes modelos de linguagem no trading quantitativo. Modelos como o GPT-2 podem analisar dados de mercado tradicionais e lidar com dados de notícias, dados de redes sociais e outros dados ricos em texto, fornecendo uma análise de sentimento de mercado mais abrangente para ajudar os traders a tomar decisões mais sábias. Essa capacidade multimodal é algo que os modelos financeiros tradicionais não possuem e é uma área que precisamos explorar mais a fundo.
No próximo artigo, usaremos um exemplo para demonstrar como otimizar a aplicação de grandes modelos de linguagem no trading quantitativo.
Apêndice:
| Arquivo | Descrição |
|---|---|
| torch2onnx.py | O script Python para converter o modelo GPT-2 para o formato ONNX |
| server.py | O script Python para fornecer serviços de inferência do modelo GPT2 e resultados |
| gpt2_EA.mq5 | Programa EA para testar os resultados de inferência dos modelos GPT2 |
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/13506
Aviso: Todos os direitos sobre esses materiais pertencem à MetaQuotes Ltd. É proibida a reimpressão total ou parcial.
Esse artigo foi escrito por um usuário do site e reflete seu ponto de vista pessoal. A MetaQuotes Ltd. não se responsabiliza pela precisão das informações apresentadas nem pelas possíveis consequências decorrentes do uso das soluções, estratégias ou recomendações descritas.
Automatizando Estratégias de Trading em MQL5 (Parte 4): Construindo um Sistema de Recuperação por Zonas em Múltiplos Níveis
Mecanismos de gating em aprendizado por ensemble
Componente View para tabelas no paradigma MVC em MQL5: elemento gráfico básico
A Estratégia de Negociação do Inverse Fair Value Gap
- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso
Confira o novo artigo: Integrar seu próprio LLM ao EA (Parte 5): Desenvolver e testar a estratégia de negociação com LLMs(IV) - Testar a estratégia de negociação.
Autor: Yuqiang Pan