Como desenvolver um Expert Advisor usando ferramentas de UML
Os cientistas investigam o que já é; Engenheiros criam o que nunca foi.
Albert Einstein
Introdução
Em meu artigo Simulink: um guia para os desenvolvedores de Expert Advisors eu sugiro uma modelagem de um Expert Advisor usando sistemas dinâmicos. No entanto, esta abordagem representa apenas um aspecto do criador dos sistemas de negociação - o comportamento dinâmico do sistema. Os profissionais têm a ferramenta específica que expande a metodologia de um desenvolvedor de sistema de negociação. Neste artigo iremos discutir como desenvolver um Expert Advisor usando a ferramenta universal - linguagem gráfica UML.
Em geral, sendo uma linguagem gráfica, a UML é usada para modelagem visual de sistemas de software orientados por objetos. Mas, como eu vejo, podemos usar suas ferramentas para desenvolver um sistema de negociação. Além disso, MQL5 pertence à família das linguagens orientadas por objeto, e isso torna a nossa tarefa mais fácil.
Para os propósitos de modelagem, escolhi um programa gratuito para o modelador de ideias de software de software não comercial.
1. Fundamentos de UML
Como a UML pode ajudar a criar um Expert Advisor? Primeiro, os gráficos - o problema de modelagem multi-aspecto pode ser resolvido usando as imagens gráficas que estão disponíveis na linguagem. Segundo, a legibilidade. Mesmo que um Expert Advisor seja grande e complexo, a universalidade da UML permite apresentar seu modelo usando diagramas.
Como os desenvolvedores da UML dizem, a característica específica da percepção humana reside no fato de que um texto com imagens é mais facilmente percebido do que um texto bruto.
Vamos discutir brevemente os conceitos básicos da UML. Se você está interessado no assunto, você pode tomar conhecimento das ferramentas da UML a partir das inúmeras publicações que estão disponíveis gratuitamente na web.
A estrutura da UML pode ser exibida em um diagrama (Fig. 1).
Fig. 1. A estrutura da UML
Blocos de construção incluem o seguinte: entidades (os elementos do modelo), relacionamentos (que ligam as coisas) e diagramas (representando modelos de UML).
Diagramas de UML permitem visualizar a representação do sistema projetado a partir de diferentes pontos de vista.
Mecanismos comuns incluem: especificações (descrição da semântica), adornos (marcação das características importantes do modelo), divisões comuns (abstração e suas instâncias, interfaces e implementação), os mecanismos de extensibilidade (restrições, estereótipos e valores marcados).
A arquitetura é responsável pela apresentação de alto nível do sistema em seu ambiente. A arquitetura de UML pode ser melhor descrita pela "visão da arquitetura 4+1" (Fig. 2):
- Visão lógica
- Visão do processo
- Visão do desenvolvimento
- Visão física
- Cenários
Fig. 2. Visão da arquitetura 4+1
Também deve ser notado que a UML tem a sua própria hierarquia de diagramas canônicos (Fig. 3). A versão da linguagem 2.2 utiliza 14 tipos de diagramas de UML.
Fig. 3. Diagramas de UML canônicos
Além disso, proponho considerar alguns casos especiais da utilização dos diagramas de UML. Assim, podemos passar de uma abstração para uma variante específica de uso de qualquer um dos diagramas para fins de desenvolvimento da EA. Novamente, o princípio do desenho multi-aspectos dos sistemas de negociação, o qual é fornecido pela hierarquia de diagramas UML, contribui para a solução sistemática e compreensiva da tarefa de criação de TS.
2. Diagramas de UML
2.1 Uso dos diagramas de caso
Como diz o ditado, um bom começo é metade da batalha. Normalmente, embora não necessariamente, o trabalho analítico começa com o uso dos diagramas de casos. Ele descreve o sistema do ponto de vista dos utilizadores.
Ao criá-lo, podemos:
- Especificar as variantes do uso TS
- Especificar os limites da TS
- Determinar atores TS
- Definir a relação entre os atores e as versões TS.
O caso de uso é uma lista de passos, normalmente definindo as interações entre um papel (conhecido em UML como um "ator") e de um sistema, para alcançar um objetivo.
Um ator "especifica um papel desempenhado por um utilizador ou qualquer outro sistema que interage com a pessoa. Atores podem representar papéis desempenhados por usuários humanos, hardware externo, ou outros assuntos.
Relacionamento é uma conexão semântica entre os elementos individuais de um modelo.
Você pode notar que este tipo de diagrama é bastante geral, e reflete a natureza conceitual da TS, ao invés de sua implementação. Mas esse é o ponto - movimento do geral para o específico, do abstrato ao concreto. Quem disse que não somos artistas? Nós desenhamos uma visão, começando com idéias gerais e esboços. Primeiro desenhamos traços em uma tela. E depois adicionamos cores. Detalhes de desenhos...
Então, vamos tentar criar um diagrama de caso de uso para um sistema de negociação.
Como atores de entrada, eu escolhi as seguintes funções: Desenvolvedor, analista de sistemas, gerente de risco e administrador. Deve notar-se que estas funções podem ser desempenhadas por uma ou mais pessoas. Quais as ações que o nosso sistema de negociação toma e quais ações são tomadas em relação a ele?
Assim, o desenvolvedor pode criar e implementar um TS. Além disso, ele ou ela podem participar na otimização do TS. O analista de sistemas otimiza o TS. O gerente de risco é responsável pela gestão de risco. O administrador monitora todo o trabalho da TS. Do lado da produção, vemos que o usuário faz um proveito como um resultado do funcionamento do TS. Este papel é uma soma dos papéis tal como o Trader e o Investor. E o gerente, bem como o administrador, supervisiona o trabalho do TS.
O diagrama contém o bloco "Sistema de Negociação". Ele expressa o limite TS e o separa do mundo exterior.
Agora, algumas palavras sobre a relação entre os atores e os casos de uso, bem como entre os atores e outros atores e os casos de uso e outros casos de uso. A maioria dos relacionamentos são representados por associações, marcados por uma linha sólida. Isto significa que um certo ator inicia um caso de uso. Assim, o gerente de risco inicia o processo de gestão de riscos, etc. Os atores que iniciam os casos de uso são os principais, e aqueles que usam os resultados das ações cometidas - são secundários. Por exemplo, um ator secundário é o gestor do lado da saída.
Associação pode indicar que o ator inicia o caso de uso adequado.
Generalização simula a generalidade apropriada de funções.
Extensão é um tipo de relação de dependência entre o caso de uso base e seu caso especial.
Incluir define a relação do caso de uso base para outro caso de uso, o comportamento funcional de que nem sempre é utilizado pelo caso base, mas apenas sob condições adicionais.
No entanto, note que um papel secundário, no que diz respeito ao caso de uso, não significa que esse papel é de importância secundária. Além disso, no diagrama, vemos que o papel do usuário TS é composto de funções do Trader e do Investor através das relações de generalização mostradas como uma linha com a ponta da flecha triangular "não pintada".
Fig. 4. Diagrama do uso de caso do TS
Os casos de uso de "posição aberta" e "posição fechada", por sua vez, estão relacionados por uma generalização com o "Trading". O último caso é a única base para os outros dois. Assim, ele inclui o caso de uso "gerenciar risco". E seu comportamento é complementar ao caso dependente de "lucro".
Visto que o lucro TS é formado na condição de que o preço de venda de um ativo é maior do que seu preço de compra, eu usei o relacionamento de extensão para estes casos. O diagrama também mostra o ponto de extensão, ou seja, uma condição específica, em que o caso "lucrar" é usado. Relações de dependência são exibidas pela linha tracejada com uma seta com os estereótipos correspondentes "incluir" e "estender".
Para cada caso de uso, você precisa criar um cenário, que é para descrever uma sequência de passos que leva ao alvo pretendido. O caso de uso pode ser descrito em diversas formas. As formas comumente aceitas incluem as seguinte: descrições de texto, pseudocódigo, diagrama de atividade, diagrama de interação.
Deve notar-se que um negociador está interessado num TS no seu sentido estrito em vez daquele que é mostrado na fig. 4. Portanto, além disso, eu sugiro focar na "negociação" do caso de uso com a extensão "lucrar".
2.2 Diagrama de classe
Usando o diagrama de classe, vamos descrever a estrutura TS. Ou seja, iremos apresentar um modelo de uma estrutura estática do sistema de negociação em termos de classes de programação orientada a objetos. Assim, vamos refletir a lógica da programação TS.
Em UML um diagrama de classe é um tipo de diagramas de estrutura estática. Ele descreve a estrutura do sistema mostrando suas classes, seus atributos e operadores, bem como o relacionamento das classes.
Quais são as vantagens deste tipo de diagrama? Aqueles que são um pouco familiarizados com as linguagens de programação orientadas a objeto, irão notar imediatamente a noção familiar da "classe". A classe atua no diagrama de classes UML como o bloco de construção básico. Por exemplo, quando a geração de um código C++, o bloco de classe UML é criado automaticamente sob a forma de um modelo de classe. Você só vai precisar terminar a execução de cada método e propriedade.
Agora, vamos tentar projetar algo como um exemplo. Mas primeiro eu gostaria de chamar a atenção para o artigo "Prototype of a Trading Robot", no qual o autor descreve as vantagens de usar uma lógica em linha reta. Na minha opinião, muito eficaz e produtivo é o princípio de aninhamento - "módulos de macros funções de comércio".
Por exemplo, precisamos de um Expert Advisor que usa a possibilidade de aulas de negociação da biblioteca padrão.
Usando o bloco de classe, crie um modelo de classe no diagrama de classes. Eu o chamei de CTradeExpert. Nós adicionamos alguns atributos (em MQL5 eles são membros de dados da classe) para a nova classe. Eles são: Magic_No, e_trade, e_account, e_deal, e_symbol, e_pnt. Também inserimos um método construtor da classe CTradeExpert. Graficamente, o funcionamento será como mostrado na fig. 5.
Fig. 5. Modelo UML da classe CTradeExpert
O caractere "-" na frente de um atributo indica que o atributo tem o direito de acesso no modo «privado», «#» - «protegido», «+» - «público». Assim, para o atributo Magic_No o especificador de acesso é definido como privado, para e_pnt - como público, e para os outros - como protegidos. Os dois pontos que segue o nome do atributo, indica um tipo de dado para atributos e tipo de dados retornados por métodos. Por exemplo, o atributo Magic_No é do tipo int, e_trade - CTrade, etc.
Nós não estamos adicionando os métodos e atributos agora, estamos simplesmente mostrando como nossa classe CTradeExpert está conectada com as classes da biblioteca padrão. Para fazer isso, adicione 6 blocos de classes ao diagrama e os chame da seguinte forma: CTrade, CAccountInfo, CDealInfo, CSymbolInfo, CObject. Agora associamos o modelo da classe CTradeExpert com 4 blocos de classes de comércio por meio de relações de dependência com o estereótipo "use" (a linha traçada pontilhada com uma seta).
Dependência é uma relação semântica entre duas entidades, em que uma alteração na independente das mesmas pode afetar a semântica da outra dependente.
Estereotipo em UML é uma descrição do comportamento do objeto.
Então, nós ligamos esses blocos com o CObject do bloco pela relação de generalização utilizando uma linha com a ponta da flecha triangular "não pintada". Adicione comentários às classes da biblioteca padrão. Agora, o nosso diagrama UML aparece como mostrado na figura 6.
Fig. 6. Diagrama de classe de UML
Agora só precisamos gerar o código utilizando a função "gerar" da guia "gerar" na barra lateral (Fig. 7).
Fig. 7. Código gerado
O mais apropriado é a linguagem С++. Nós vamos usar C++ para gerar o código da classe Expert Advisor, e então facilmente traduziremos em MQL5.
Para este diagrama o código gerado é como se segue:
// class CTradeExpert { private: int Magic_No; protected: CTrade e_trade; protected: CAccountInfo e_account; protected: CDealInfo e_deal; protected: CSymbolInfo e_symbol; public: double e_pnt; public: void CTradeExpert () { } }; // class CObject { }; // class CTrade : public CObject { }; // class CDealInfo : public CObject { }; // class CSymbolInfo : public CObject { }; // class CAccountInfo : public CObject { };
Uma sintaxe muito familiar, não é? Nós só precisamos ajustar o corpo da classe. Para este efeito, em MetaEditor criamos um arquivo para a nova classe TradeExpert.mqh. Copie o código gerado anteriormente para ele. Para facilitar a leitura nós excluímos o especificador de acesso repetido protegido para os membros da classe CTradeExpert.
Exclua as linhas conectadas com a declaração das classes da biblioteca padrão. Depois disso, adicione o arquivo incluindo a instrução #include para cada classe utilizada da biblioteca padrão, porque essas classes já estão definidas pelo desenvolvedor. E adicione nossos comentários. Como resultado, obtemos o código como este:
//includes #include <Trade\Trade.mqh> #include <Trade\AccountInfo.mqh> #include <Trade\DealInfo.mqh> #include <Trade\SymbolInfo.mqh> //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CTradeExpert { private: int Magic_No; // Expert Advisor magic protected: CTrade e_trade; // An object for executing trade orders CAccountInfo e_account; // An object for receiving account properties CDealInfo e_deal; // An object for receiving deal properties CSymbolInfo e_symbol; // An object for receiving symbol properties public: double e_pnt; // Value in points public: CTradeExpert() { } }; //+------------------------------------------------------------------+
agora vamos adicionar mais alguns módulos de funções comerciais a nossa classe Expert Advisor.
Estes podem ser: CheckSignal, OpenPosition, CheckPosition, ClosePosition etc. Espero que você já saiba o princípio de "serviço de condição". Neste caso, nossa classe de teste CTradeExpert não pareceria difícil para você. Eu foquei especificamente em algum exemplo já conhecido de um Expert Advisor para tornar mais fácil para você entender os mecanismos da UML.
Assim, agora o modelo da classe parece como o mostrado na Fig. 8.
Fig. 8. Modelo UML da classe CTradeExpert
Para o modelo atualizado da classe, também podemos gerar um código usando o método já descrito.
2.3 Diagrama de Atividades
Usando este tipo de diagrama UML, podemos estudar o comportamento do sistema usando os modelos de fluxo de dados e controle. Os diagramas de atividades são representações gráficas dos fluxos de trabalho de atividades e ações escalonadas.
O diagrama de atividade difere do fluxograma, que descreve apenas os passos do algoritmo. A notação do diagrama de atividades é maior. Por exemplo, é possível especificar o estado dos objetos no mesmo.
Os diagramas de atividades são usadospelos desenvolvedores para descrever:
- Regras de negócio;
- Casos de uso único;
- Série complexa de casos de uso múltiplo;
- Processos com soluções e fluxos alternativos;
- Operações paralelas;
- Estruturas de fluxos de programas e controle de lógica.
Supondo que a classe especialista criada CTradeExpert, será utilizada no arquivo Test_TradeExpert.mq5 do Expert Advisor. Como nos lembramos, o modelo padrão ao criar um EA no MetaEditor 5 fornece três funções manipuladoras de eventos padrão: OnInit, OnDeinit e OnTick. Vamos no juntar a eles.
Vamos tentar mostrar um diagrama com a nossa contagem de operação EA para o arquivo Test_TradeExpert.mq5. Aqui deve-se notar que o Expert Advisor, ou melhor, a sua estrutura, é bastante primitiva. Nós só estamos treinando agora. A estrutura EA simples é ok para esta finalidade.
Deixe-nos desenhar um diagrama para uma utilização de nosso Expert Advisor, o algoritmo o qual é representado no arquivo Test_TradeExpert.mq5.
Assim, tudo começa com o nó inicial (Fig. 9). A partir deste nó, um controle simbólico move-se para o nó chamando a ação "Criar uma instância de Expert Advisor". Esta ação inicia o fluxo do objeto (seta azul), que altera o estado do nó do objeto (myTE=created), e o fluxo de controle para um nó que se chama "Inicializar o Expert Advisor".
Um fluxo de controle é representado sob a forma de uma margem de atividade, que liga os dois nós da atividade e sobre o qual apenas tokens de controle são transmitidos.
Um fluxo de objeto é representado como uma borda da atividade, para a qual só objetos ou dados do tipo token são transmitidos.
Um nó de atividade é uma classe abstrata para os pontos individuais no fluxo de atividades ligadas por arestas.
Um nó de decisão é um nó de controle, que escolhe entre os fluxos de saída.
Um nó de objeto representa objetos utilizados na atividade.
Uma aresta de atividade é uma classe abstrata para ligações dirigidas entre dois nós de atividades.
O nó inicial mostra onde começa a atividade.
O nó final de uma atividade completa todos os fluxos de atividade.Isto, por sua vez, altera o estado do objeto myTE (myTE=initialized) e passa o token de controle para o nó de decisão. Se o Expert Advisor é inicializado com sucesso, o fluxo de controle vai para o nó "processo do evento comercial NewTick». Se a inicialização falhar, então o token de controle entra pela primeira vez no nó de generalização e, em seguida, no nó de ação "deinicializar o Expert Advisor".
Os tokens são construções abstratas que são introduzidas para conveniência em descrever o processo dinâmico de execução de um gráfico de atividade estatisticamente definido. O token não pode conter qualquer informação adicional (um símbolo vazio), neste caso é chamado um token de controle de fluxo, ou pode conter uma referência a uma estrutura de objeto ou dados, e, neste caso, é chamado um token de fluxo de dados.
Vejamos o primeiro controle de fluxo que vem do nó de decisão. Ele é dirigido para uma área com uma ação interrompida, como indicado por um retângulo com cantos arredondados desenhados pela linha pontilhada vermelha e o estereotipo de "interrupção". Quando o fluxo de controle está nesta área, ele pode parar inesperadamente. Se você ativar o nó de ação (sinalizador laranja), que recebe o evento "descarregar Expert Advisor", ele irá interromper todos os fluxos. O token de controle se move para a aresta interrompida (seta de zigue-zague laranja), e depois para o nó de conexão. Depois que a EA é deinicializada. Em seguida, o token de controle vai para o nó "excluir variáveis globais", então o fluxo será concluído no nó de atividade final.
O nó de ação "deinicializar Expert Advisor" também altera o estado do objeto myTE (Myte = deinicializado) por um fluxo de objeto. O nó "excluir variáveisglobais", por sua vez, remove o myTE do objeto (Myte=excluído).
Fig. 9. Diagrama de atividade para Test_TradeExpert.mq5
Suponha que o fluxo de controle é estável: EA não é descarregado. A partir do nó "processar o evento de comércio NewTick» o fluxo move-se para outro bloco - área de expansão, o estereotipo deste é definido como "repetitivo" (retângulo verde com linhas pontilhadas).
Eu chamo esta área de "bloco comercial", para refletir as características básicas e melhorar a percepção do diagrama. Um rasgo característico do bloco é a execução cíclica de operações para os objetos recebidos. Precisamos de apenas 2 ciclos - lidar com as direções longas e curtas. Na entrada ao bloco e na saída do bloco há nós de expansão que incluem objetos de direção comerciais (longos ou curtos).
Um nó de expansão é uma coleção de objetos que entra ou sai da área de expansão, que é executada uma vez para cada objeto.
O nó de ação que envia um sinal (ação de sinal enviada) representa o sinal enviado.
O nó de ação que aceita um evento (aceitar ação de evento), espera para o recebimento de um evento do tipo apropriado.
Assim, cada sentido é tratado por estes nós como: "Verificar sinal" (sinal de envio do nó), "receber sinal" (sinal de recepção do nó), "posição aberta" (sinal de envio do nó), "verificar posição" (sinal de envio do nó), "fechar posição" (sinal de envio do nó). Deve notar-se que o objeto de direção (dir) pode ser transmitido no fluxo do objeto entre os nós de ação, tal como indicado pelas setas de cor violeta. As operações em um bloco continuará enquanto o Expert Adviser é descarregado.
2.4 O diagrama de sequência
Nós usamos o diagrama de sequência para descrever a sequência de interação do objeto. Um aspecto muito importante deste tipo de diagrama é o tempo.
Assim, o diagrama tem duas escalas em uma forma implícita. A horizontal é responsável pela sequência de interações dos objetos. A vertical é um eixo de tempo. O início do intervalo de tempo é a parte superior do diagrama.
A parte superior do diagrama contém objetos do diagrama, que interagem. Um objeto tem a sua própria linha de vida como uma linha pontilhada vertical. Os objetos de troca de mensagens. Eles são representados por setas. Quando um objeto está ativo, ele recebe o foco de controle. Graficamente, este foco é expresso como um retângulo estreito na linha de vida.
Um objeto é um retângulo que contém um nome de objeto sublinhado e o nome da classe (opcional), separados por dois pontos.
Uma linha de vida de um objeto é uma linha que mostra a existência de um objeto durante um certo período de tempo, quanto maior for a linha, maior será a existência do objeto.
O foco de controle é desenhado como um retângulo estreito, o lado superior dos quais indicam o início da recepção do foco de controle pelo objeto (início de atividade), e a sua desvantagem - o fim do foco de controle (final de atividade).
Em UML, cada interação está descrita por um conjunto de mensagens, as quais os objetos participam na sua troca.
Vamos praticar um pouco.
O terminal é um ator. Ele inicia a operação do Expert Advisor. Outros objetos marcados com o estereótipo "evento" são os eventos do terminal do cliente: Init, Deinit e NewTick. Claro, se você quiser, pode ampliar o leque de eventos. Ao iniciar um Expert Advisor, o objeto myTE é criado no nível global. Ele é uma instância da classe CTradeExpert. O objeto de classe é um pouco menor do que os outros objetos no diagrama, o que indica que ele é criado após a função do construtor.
Um comando de criação é marcado com uma linha de traço pontilhado com uma seta aberta e uma mensagem 1.1 CTradeExpert(). A linha de traço pontilhado com uma seta indica o tipo de "criação" do construtor padrão CTradeExpert(). Depois de criar uma instância CTradeExpert o passo 1.2 é ativado - o foco de controle é devolvido ao terminal. Para facilitar a leitura, indico mensagens síncronas no formato de #.#, como 1.1, e assíncronas - #. Em seguida, o terminal processa o evento de inicialização usando a função OnInit() no passo 2.1, o foco é retornado no passo 2.2. Mensagens do tipo "chamada" são mostradas como linhas com uma seta triangular "pintada" no final.
Se o evento de inicialização retorna um valor diferente de zero ao terminal, significa que a inicialização falhou: passo 3.1 é utilizado, o que leva à geração e manuseamento do evento de deinicialização. No passo 3.2, o foco de controle é devolvido para o terminal. Em seguida, o objeto da classe CTradeExpert é excluído (passo 4.1). A propósito, na criação de um diagrama de classe, eu não inclui a função destrutora CTradeExpert na classe. Isto pode ser feito depois. Esta é uma das vantagens da construção do diagrama - o processo de construção de vários diagramas é iterativo. O que foi feito pela primeira vez para um diagrama, pode ser feito em seguida para outro, e mais tarde você pode modificar o primeiro.
Deve notar-se que o código MQL5 de um modelo EA padrão não contém um bloco que trata a inicialização que falhou. Eu especifiquei para salvar a lógica da sequência. O diagrama de sequência UML usa o bloco opcional com uma condição de guarda OnInit()!=0, que é equivalente à construção MQL5 se (OnInit()!= 0) {}.
No passo 4.2, o controle é transferido para o terminal.
Agora, o terminal está pronto para manipular o evento NewTick.
O processamento deste evento se dá no ciclo do bloco significando um ciclo infinito. Ou seja, a EA irá lidar com este evento até que nos o desativarmos. O terminal processa o evento NewTick utilizando a função OnTick (passo 5). No passo 6, o foco do controle é transferido para o myTE do Expert Advisor. Usando 4 mensagens reflexivas, implementa as seguintes funções: CheckSignal, OpenPosition, CheckPosition, ClosePosition. A reflexividade é devido ao fato de o objeto Expert Advisor enviar mensagens para si.
Além disso, estas funções da classe CTradeExpert estão delimitadas no bloco (2) do ciclo. Dois meios em qual o ciclo consiste por dois passos. Por quê dois? Porque ele lida com duas direções de negociação - longas e curtas (a partir do passo 7 a 10). No passo 11, o foco é passado para o terminal.
Os passos 12 e 13 são responsáveispela deinicialização e exclusão do objeto Expert Advisor, respectivamente.
Fig. 10. Diagrama SD para Test_TradeExpert.mq5
Assim, temos as habilidades de desenhos primários. Com a ajuda de diagramas da criação, o trabalho do desenvolvedor é otimizado. Podemos agora começar a escrever um código para o arquivo Test_TradeExpert.mq5. Claro, você pode fazer sem diagramas. Mas quando você tem um complexo Expert Advisor, o uso de diagramas reduz a probabilidade de erros e permite-lhe gerir de forma eficiente o desenvolvimento do seu TS.
Usando o modelo Expert Advisor, agora criamos o Test_TradeExpert.mq5.
Nós criamos uma instância da classe myTE CTradeExpert a nível global.
Agora vamos encher o corpo da função OnTick().
Nós escrevemos as funções da classe, como segue:
for(long dir=0;dir<2;dir++) { myTE.CheckSignal(dir); myTE.OpenPosition(dir); myTE.CheckPosition (dir); myTE.ClosePosition(dir); }
Algo como isso será o tratamento do evento NewTick. é claro, ainda precisamos especificar cada uma das funções que serão usadaspelos membros de dados da classe, entre outros. Mas vamos deixar esse trabalho para o futuro. Agora, nosso objetivo é transferir a lógica de diagramas UML no código MQL5.
3. Desenvolvimento e apresentação de um Expert Advisor baseado nos diagramas de UML
Como exemplo, vamos criar diagramas para um complexo Expert Advisor. Vamos definir as suas características no contexto de uma dada estratégia implementada no MQL5. Em geral, nosso Expert Advisor irá realizar operações de comércio, em especial irá gerar sinais de negociação, manter posições abertas e gerir o dinheiro. Ele é particularmente uma estratégia de negociação modelo. No entanto, para fins de treinamento, vamos tentar trabalhar com este.
Primeiro, vamos criar um diagrama de caso de uso para o nosso EA. Apenas em certas medidas ele irá ser diferente do que foi discutido anteriormente. Prestei atenção ao ambiente interno do TS, ignorando o exterior (Fig. 11), como no código, vamos implementar apenas as tarefas de negociação.
Fig. 11. Diagrama do uso de caso do TS
Agora vamos definir a estrutura do Expert Advisor. Suponha que vamos usar os desenvolvimentos da biblioteca padrão, porque é consistente com os objetivos declarados da TS. Recentemente, tem sido substancialmente alargado. E acima de tudo, diz respeito às classes de estratégias de negociação. Assim, nosso objetivo é criar um diagrama de classes. Não será simples, então você precisa de paciência.
Aqui eu gostaria de salientar que consideramos a biblioteca padrão para algumas razões. Em primeiro lugar, em sua base, tentamos criar um robô de negociação. E, segundo, o que também é importante, nós temos um pouco de prática trabalhando com diagramas UML. Em terceiro lugar, talvez, a próprio biblioteca é muito valiosa. Assim, podemos aprender muitas coisas úteis a partir da biblioteca, e, ao mesmo tempo, tentar entender sua estrutura não muito simples.
A conversão de um código na estrutura de um diagrama UML é chamado de engenharia reversa. Na verdade, estamos fazendo isso manualmente. Existe um software profissional que permite que você faça isso automaticamente (IBM Rational Rose, Visual Paradigm para UML, etc.). Mas, para fins práticos, eu acho que nós precisamos trabalhar "manualmente".
Vamos criar um modelo da classe de base para implementar estratégias de negociação CExpert usando o bloco "Classe". Vamos ver quais outras classes e construções são utilizadas no corpo da classe CExpert. Primeiro, deve-se notar que a classe CExpert deriva da classe de base CExpertBase, a qual, por sua vez, deriva da classe de base CObject.
No diagrama nós criamos blocos para estas classes, e definimos a relação entre entre as classes usando uma linha com uma ponta da flecha triangular "não pintada" (generalização). Adicione um comentário ao modelo da classe CExpert (um retângulo amarelo com um vértice inclinado). A estrutura de classe intermediária agora se parece como o seguinte - Fig. 12. Vamos chamar o diagrama Expert.
Fig. 12. O diagrama Expert, a visão inicial
Vamos ver o código no arquivo Expert.mqh. A classe CExpert, entre outras coisas, envolve enumerações ENUM_TRADE_EVENTS e ENUM_TIMEFRAMES, umas das 8 estruturas pré definidas MqlDateTime. A classe também usa outras instâncias de classe, tais como: CExpertTrade, CExpertSignal, CExpertMoney, CExpertTrailing, CIndicators, CPositiontInfo e COrderInfo.
Agora, precisamos fazer algumas alterações para o diagrama. Primeiro, nós especificamos que as classes CExpertSignal, CExpertMoney, CExpertTrailing são derivadas a partir da classe de base CExpertBase, e as classes CPositiontInfo, COrderInfo são derivadas a partir do CObject (Eu configurei o estereótipo "metaclasse" para ele)
Vamos marcar as relações de dependência com o "uso" de estereótipo entre o bloco da classe CExpert e outras classes, não esqueça da estrutura e enumerações do MqlDateTime. Nós mudamos o estilo de cor dos blocos e obtivemos a seguinte estrutura - Fig. 13.
Fig. 13. O diagrama Expert, a visão inicial
No entanto, esta estrutura não reflete a imagem completa, porque há um número de classes que são utilizadas indiretamente pelas classes já mencionadas. De qual tipo de classe elas são? Primeiro, a classe CExpertTrade é derivada a partir do CTrade. O último é uma subclasse de CObject.
A classe CExpertTrade usa a enumeração ENUM_ORDER_TYPE_TIME, classes CSymbolInfo e CAccountInfo também são filhas do CObject. A classe CTrade também usa instâncias das classes de CSymbolInfo. Vamos fazer alterações no diagrama. Agora, nosso diagrama tem a seguinte forma - Fig. 14.
Fig. 14. O diagrama Expert, a visão inicial
Novamente, o diagrama não está completo. Por exemplo, se você olhar no arquivo Trade.mqhda biblioteca padrão, você verá que CTrade usa diversas estruturas diferentes, enumerações e a classe CSymbolInfo. Se eles são todos apresentados em um diagrama, será muito carregado. E isso fará com que seja difícil de entender.
Para lidar com essa dificuldade, eu usei um pacote para o diagrama. Ele encapsula classes relacionadas, enumerações, outros pacotes, etc. Eu liguei o pacote com os elementos do diagrama através da interface. Por exemplo, o diagrama para o pacote CTrade pode ser representado como segue - Fig. 15.
Fig. 15. O diagrama de classe para o pacote CTrade
O diagrama do pacote CTrade mostra relações de dependência da classe CTradecom enumerações e estrutura.
Relações com a classe de base do CObject e a classe utilizada CSymbolInfo são implementadas através de uma interface.
Perto das interfaces há um ícone de relação com o diagrama de classe que contém o pacote CTrade como elemento único. Clicando sobre qualquer uma das interfaces o traz automaticamente ao diagrama original (Fig. 16).
Fig. 16. O diagrama Expert com interfaces
As relações de interface são laranjas. O ícone do diagrama de classe próximo ao pacote CTrade indica a possibilidade de movimento a este diagrama. Assim, utilizando-se a encapsulação, podemos melhorar significativamente a legibilidade do diagrama de classe.
Então, vamos seguir em frente. A classe CObject usa ponteiros para instâncias da mesma classe em seu corpo. Portanto, podemos definir a relação de dependência para o bloco CObject com o estereótipo "use" em relação a si mesmo.
Vamos olhar para o bloco do modelo de classe CExpertBase. Com base nas primeiras linhas do arquivo de cabeçalho ExpertBase.mqh podemos dizer que essa classe usa várias instâncias de várias classes e enumerações. Portanto, para o modelo de classe e suas relações, é razoável criar o pacote CExpertBase.
Então primeiro vamos definir o modelo de classe CExpertBase no diagrama do pacote. Através da interface mostramos relacionamento com a classe da base do CObject, e a relação de utilização com as classes CSymbolInfo e CAccountInfo. Em seguida, usando blocos de classes e relações de dependência, vamos especificar que a classe CExpertBase usa as seguintes classes: CiOpen, CiHigh, CiLow, CiSpread, CiTime, CiTickVolume e CiRealVolume.
As primeiras quatro classes são derivadas a partir do CPriceSeries, e as ultimas quatro – do CSeries. Além disso, a classe CSeries tem um filho CPriceSeries e é, por sua vez, um filho do CArrayObj. As relações de atributos tem sido usadas anteriormente, como lembramos. Denote-os como um relacionamento de generalização no diagrama.
Não se esqueça que a classe CExpertBase usa em seu corpo tais como enumerações: ENUM_TYPE_TREND, ENUM_USED_SERIES, ENUM_INIT_PHASE, ENUM_TIMEFRAMES. A última enumeração também é utilizado pelos filhos de classe CPriceSeries e CSeries. A não perder as relações, e para tornar o diagrama claro, vamos ajustar o modelo para cada um dos elementos do esquema. Como resultado, obtivemos o seguinte esquema (Fig. 17).
Fig. 17. O diagrama de classe para o pacote CExpertBase
Ele ainda não está completo, e nós vamos ter que trabalhar um pouco mais nele. Acontece que as quatro classes que herdam a classe CPriceSeries também usam a classe CDoubleBuffer. Além disso, cada uma das quatro classes usa sua classe de buffer que deriva a partir do CDoubleBuffer. Dessa forma, COpen usa COpenBuffer etc. CDoubleBuffer tem uma classe de base (CArrayDouble) e usa ENUM_TIMEFRAMES.
CArrayDouble herda CArray, usa ponteiros para as instâncias de sua mesma classe e a enumeração ENUM_DATATYPE. A classe COpenBuffer e outras classes de buffer da série de preços (CHighBuffer, CLowBuffer, CCloseBuffer) usam a enumeração ENUM_TIMEFRAMES.
As quatro classes que herdam a classe CSeries usam apenas suas próprias classes de buffer (CSpreadBuffer, CTimeBuffer, CTickVolumeBuffer, CRealVolumeBuffer). O primeiro da classe de buffers CSpreadBuffer herda CArrayInt, outros – CArrayLong. As duas últimas classes usam os ponteiros para as instâncias de sua própria classe, a enumeração ENUM_DATATYPE, e são derivadas da CArray, a qual, por sua vez, é um filho da classe CObject.
A classe CPriceSeries e seus filhos usam a classe CDoubleBuffer e a enumeração ENUM_TIMEFRAMES.
CSeries usa enumerações ENUM_SERIES_INFO_INTEGER, ENUM_TIMEFRAMES. Ela herda CArrayObj. Este último herda a CArray, usa ENUM_POINTER_TYPE, os ponteiros para as instâncias de sua própria classe e da classe CObject. Como resultado, obtivemos o diagrama mostrado na figura 18.
Fig. 18. Diagrama de classe estendido ao pacote CExpertBase
E o diagrama original Expert para classes e pacotes CExpert, CExpertBase, CSymbolInfo, CAccountInfo e CObject no qual as interfaces parecem com o seguinte (Fig.19).
Fig. 19. O diagrama Expert com interfaces
Também adicionei a enumeração ENUM_ORDER_TYPE usada pelo CExpertTrade. Para facilitar a leitura, eu marquei o grupo de relações com cores diferentes.
Continuamos o nosso trabalho. Espero que você entenda a lógica. O modelo de uma classe no diagrama pode ter muitos relacionamentos com outras classes e outras entidades. Então, eu só substitui alguns conjuntos com um pacote no diagrama de base.
Então, vamos estudar o CSymbolInfo. Se você olhar para o código do SymbolInfo.mqh, você verá que a classe de base CSymbolInfo usa algumas enumerações e estruturas de MQL5. é bom usar um pacote para ele e suas relações (Fig. 20).
Fig. 20. Diagrama do pacote CSymbolInfo
Qualquer espaço livre no diagrama pode ser usado para comentários. Além disso, eu marquei a interface de relação com a classe matriz do CObject. O diagrama Expert original do pacote e das classes será ligeiramente modificado. Darei sua versão atualizada mais tarde, quando todas as classes e pacotes estiverem refletidos no diagrama.
Então, vamos seguir em frente. Vamos olhar para o código de MQL5 em AccountInfo.mqh. Como se vê, CAccountInfo também usa algumas enumerações. Nós as refletimos no diagrama do pacote que irá criar para esta classe e suas relações com outras entidades (Fig. 21).
Fig. 21. Diagrama do pacote CAccountlInfo
Agora vamos lidar com a classe CExpert. Para esta classe, também criamos um pacote CExpert, que aparecerá como mostrado na Fig. 22. Nós continuamos a melhorar a legibilidade do nosso diagrama principal. A classe CExpert está ligada com várias outras classes, como indicado pelas linhas de interface laranjas com uma seta.
Fig. 22. Diagrama do pacote CExpert
Vamos explorar outras classes restantes. Vamos criar mais pacotes para elas.
CExpertSignal deriva da CExpertBase. Esta relação foi já mostrada no diagrama original Expert. Além disso, a classe CExpertSignal usa CArrayObj, COrderInfo, CIndicators e instâncias de sua própria classe (Fig .23). Em particular, a interface de relacionamento com a classe CArrayObj nos trará o diagrama do pacote CExpertBase, que mostra a relação da classe CArrayObj com outras entidades.
Fig. 23. Diagrama do pacote CExpert
Eu não estou mostrando todos os diagramas agora - eles estão todos disponíveis no arquivo anexado Expert.simp. Agora vamos dar uma olhada no nosso diagrama atualizado de pacotes e classes Expert (Fig. 24).
Como você pode ver, quase todas as classes chaves no diagrama foram encapsuladas em pacotes para tornar o diagrama mais fácil de entender. Eu mudei a cor da linha de generalização para marrom, a fim de distingui-la da linha da relação de dependência.
Fig. 24. O diagrama de pacotes e classes de Expert
Assim, temos refletido tudo o que pode ser feito a partir do código disponível na biblioteca padrão para criação de diagramas. Nós só precisamos adicionar mais alguns blocos, que especificam as operações comerciais do Expert Advisor.
O primeiro bloco é o bloco do CmyExpert que herda as "habilidades" de negociação a partir da classe CExpert. Este é o bloco, no qual tivemos por muito tempo ocupados em engenharia reversa. Ele irá implementar uma estratégia comercial específica. Também precisamos especificar as funções virtuais das classes de base do EA.
para este fim, criamos um bloco de classe CmyExpertSignal, CmyExpertMoney, CmyExpertTrailing e indicamos que eles são derivados do apropriado (Fig. 25).
Fig. 25. Diagrama expandido de pacotes e classes de Expert
Quais funções e dados cada uma dessas classes devem incluir ao desenvolvedor. Aqui, eu estou tentando mostrar o esquema mais geral, e não uma implementação específica de uma classe derivada. Assim, para cada uma das classes de derivados podemos criar um diagrama separado com uma lista detalhada de métodos e propriedades incluídas, como tem sido feito, por exemplo, na Fig. 8.
Agora vamos ver como podemos usar o diagrama de sequência em nosso trabalho. Deixe-me lembrá-lo que ele mostra como nossa EA opera com relação ao cronograma.
Então, escrevemos detalhes do trabalho EA em ordem cronológica (Fig. 26).
Fig. 26. O diagrama de sequência do Expert Advisor
O terminal serve como um ator. A nível global, ele cria o objeto myTrader - uma instância de CmyExpert (Passo 1.1). Verde denota eventos predefinidos do terminal do cliente (Init, Deinit, NewTick, Trade). A lógica do diagrama de sequência foi descrita anteriormente. Aqui eu gostaria de apontar algumas questões específicas. Quando o corpo do Expert Advisor cresce, e há cada vez mais códigos, ele se torna mais difícil de se apresentar no diagrama.
Para resolver esse problema, use a abordagem de bloco. Um conjunto de algumas funções comuns é visualizo sob a forma de um bloco. Como regra geral, é outro diagrama de sequência. Diz-se ser uma interação de utilização.
Assim, neste caso, eu criei um diagrama de sequência denominado OnInit a fim de refletir a lógica de manipulação do evento terminal Init em um diagrama separado. Sintaticamente, é definido como uma fronteira com a palavra chave ref (referência) e é usado quando o token de controle passa de OnInit (passo 2.1) para a linha de vida do objeto Init.
Além disso, eu configurei um movimento de interface para este diagrama de sequência para OnInit. Ou seja, se você clicar duas vezes sobre a borda, você pode realmente abrir um diagrama de sequência detalhada de OnInit (Fig. 27).
Fig. 27. O diagrama da sequência de OnInit
Mover para outros diagramas de sequência é muito conveniente para repetições de algumas ações.
Por exemplo, o diagrama OnInit contém ações conectadas com a deinicialização EA, o processamento do qual é feito no myTrader_Deinit (Fig. 28).
Fig. 28. O diagrama da sequência de myTrader_Deinit
Em geral, nesta fase de projeto EA tenho quatro diagramas de sequência. Naturalmente, durante um desenvolvimento mais sério você pode precisar de diagramas adicionais. Por exemplo, eu não tenho tratado outros eventos do terminal do cliente (NewTick, Trade).
Conclusões
Neste artigo, eu sugeri levar em conta a natureza multidimensional do processo de desenvolvimento Expert Advisor usando a linguagem UML gráfica, que é usada para modelagem visual de sistemas de software orientados a objetos. A principal vantagem dessa abordagem é a visualização do criador.
Como qualquer fenômeno complexo, a UML tem suas desvantagens, as quais o desenvolvedor deve estar ciente (redundância, imprecisão semântica, etc.).
Espero que a metodologia descrita do desenvolvimento EA seja interessante para você. Ficaria agradecido por todos os comentários e críticas construtivas.
Localização de arquivos:
# | Arquivo | Via |
Descrição |
---|---|---|---|
1 | TradeExpert.mqh | %MetaTrader%\MQL5\Include | Classe Expert Advisor |
2 | Test_TradeExpert.mq5 | %MetaTrader%\MQL5\Experts | Expert Advisor |
3 | Expert.simp | Projetos %Documents%\UML | Projetos de diagramas UML |
4 | SoftwareIdeasModeler.4.103.zip | %Program Files%\SoftwareIdeasModeler | Arquivo de distribuição modelador de ideias de sofware |
Referência:
- Free UML courses. The Internet University of Information Technology
- Jim Arlow, Ila Neutstadt. UML2 and the Unified Process Practical: Object-Oriented Analysis and Design
- Leonenkov A. Object-Oriented Analysis and Design Using UML and IBM Rational Rose.
- Martin Fowler UML Distilled: A Brief Guide to the Standard Object Modeling Language. - 192 стр.
- Paul Kimmel. UML Demystified. - 272 стр.
- F. A. Novikov, D. Y. Ivanov. Modeling in UML
- Mark Priestly. Practical Object-Oriented Design With Uml, Mcgraw Hill Higher Education; 2nd edition, 2007.
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/304
- 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