English Русский 中文 Español Deutsch 日本語 한국어 Français Italiano Türkçe
Simulink: um guia para os desenvolvedores de Expert Advisors

Simulink: um guia para os desenvolvedores de Expert Advisors

MetaTrader 5Sistemas de negociação | 5 fevereiro 2014, 12:47
3 591 0
Denis Kirichenko
Denis Kirichenko

Introdução

Há diversos artigos que descrevem as vastas possibilidades do Matlab. Para ser mais preciso, a maneira que este software é capaz de expandir as ferramentas do programador, que ele usa para desenvolver um Expert Advisor. Neste artigo, tentarei ilustrar o trabalho de um poderoso pacote de matlab como o Simulink.

Gostaria de oferecer uma maneira alternativa para desenvolver sistemas de comércio automatizados para comerciantes. Fui inspirado a atentar a este tipo de método devido a complexidade do problema que o negociante enfrenta - a criação, verificação e teste do sistema de negócio automatizado. Não sou um programador profissional. E assim, o princípio de "ir do simples para o complexo" é de suma importância para mim no desenvolvimento de um sistema de comércio automatizado. O que exatamente é simples para mim? Primeiramente, esta é a visualização do processo de criação do sistema e a lógica de seu funcionamento. Também, é um mínimo de código escrito à mão. Estas expectativas são bastante consistentes com as capacidades do pacote Simulink®, um produto bem conhecido da MATLAB, que é um líder mundial entre os instrumentos para visualização de cálculos matemáticos.

Neste artigo, tentarei criar e testar o sistema de negócio automatizado, com base no pacote Matlab e, depois, escrever um Expert Advisor para o MetaTrader 5. Além disso, todos os dados históricos para backtesting serão usados a partir do MetaTrader 5.

Para evitar confusões terminológicas, chamarei o sistema de comércio, que funciona no Simulink, com uma palavra MTS, e aquele que funciona no MQL5, simplesmente como Expert Advisor.


1. Os fundamentos do Simulink e Stateflow

Antes de prosseguirmos com ações específicas, é necessário introduzir alguma forma de mínimo teórico.

Com a ajuda do pacote Simulink®, que é uma parte do MATLAB, o usuário pode modelar, simular e analisar sistemas dinâmicos. Além disso, é possível levantar a questão sobre a natureza do sistema, para simulá-la e depois, observar o que ocorre.

Com Simulink, o usuário pode construir um modelo a partir do nada ou modificar um modelo já existente. O pacote apoia o desenvolvimento de sistemas lineares e não-lineares, que são criados com base em comportamentos discretos, contínuos e híbridos.

As propriedades principais do pacote são apresentadas no site do desenvolvedor:

  • Bibliotecas extensas e expansíveis de blocos predefinidos;
  • Editor gráfico interativo para montagem e gerenciamento de diagramas de bloco intuitivos.
  • Habilidade para gerenciar projetos complexos, segmentando modelos em hierarquias de componentes do projeto;
  • Model Explorer para navegar, criar, configurar e procurar todos os sinais, parâmetros, propriedades e código gerado associado com seu modelo;
  • Interfaces de programação de aplicação (APIs) que permitam que você conecte-se a outros programas de simulação e incorpore código próprio.
  • Blocos de função Embedded MATLAB™ para trazer algoritmos MATLAB ao Simulink e implementações de sistemas embutidos.
  • Modos de simulação (Normal, Acelerador e Acelerador rápido) para executar simulações interpretativamente ou em velocidades de código C compilado usando solucionadores de passo fixo ou variável.
  • Gerenciador de perfil e depurador gráficos para examinar resultados de simulação e então diagnosticar o desempenho e comportamentos não esperados em seu projeto.
  • Acesso completo ao MATLAB para analisar e visualizar resultados, personalizando o ambiente de modelagem e definindo dados de teste, sinal e parâmetros;
  • Ferramentas de diagnóstico e análise de modelos para garantir a consistência dos modelos e identificar erros de modelagem.

Então vamos começar imediatamente a análise do ambiente Simulink. Ele é inicializado a partir de uma janela do Matlab já aberta de duas maneiras:

  1. usando o comando Simulink na janela de comando;
  2. usando o ícone Simulink na barra de ferramentas.

Figura 1. Inicialização do Simulink

Figura 1. Inicialização do Simulink

Quando o comando é executado, a janela de navegação de bibliotecas (Simulink Library Browser) aparece.

Figura 2. Navegador de bibliotecas

Figura 2. Navegador de bibliotecas


A janela do navegador contém uma árvore de componentes de bibliotecas Simulink. Para visualizar uma seção particular da biblioteca, você simplesmente precisa selecioná-la com o mouse. Após isso, um conjunto de componentes em ícones da seção ativa da biblioteca aparecerá na seção direita da janela Simulink Library Browser. A Fig. 2 mostra a seção principal da biblioteca Simulink.

Usando o menu do navegador ou os botões de sua barra de ferramentas, você pode abrir uma janela para criar um novo modelo ou para realizar upload de um existente. Devo observar que todo o trabalho com Simulink ocorre juntamente com um sistema MATLAB aberto, no qual é possível monitorar a execução das operações, enquanto sua saída é fornecida pelo programa de modelagem.


Figura 3. A janela Simulink em branco

Figura 3. A janela Simulink em branco


Antes de mais nada, vamos alterar alguns parâmetros de nosso modelo. Vamos abrir Simulação --> Parâmetros de configuração. Esta janela possui diversas abas com muitos parâmetros. Estamos interessados na aba padrão Solucionador, onde você pode definir os parâmetros do solucionador do sistema de modelagem Simulink.

No tempo de Simulação, o tempo de modelagem é definido pelo tempo de início - Start time (geralmente 0), e o tempo de fim - Stop time.

Para nossa tarefa, vamos atribuir ao Start time um valor de 1. Vamos deixar o Stop time como está.

Nas opções do solucionador, também alterei o tipo para Passo Fixo, o solucionador para discreto e o passo (tamanho do passo fixo) para 1.

Figura 4. Janela de parâmetros de configuração


O ambiente Simulink é completado com sucesso pelo subsistema Stateflow, que é um pacote de modelagem orientado a eventos, baseado na teoria dos autômatos de estados finitos. Ele nos permite representar o trabalho do sistema, com base em uma cadeia de regras que especificam os eventos e ações como respostas a estes eventos.

A interface gráfica de usuário do pacote Stateflow possui os seguintes componentes:

  • Um editor de gráficos de gráficos SF;
  • Stateflow Explorer;
  • Stateflow Finder para pesquisar objetos necessários em gráficos SF;
  • Um depurador de modelos SF;
  • Real Time Workshop, um gerador de código em tempo real.

O diagrama de bloco mais comumente usado (gráfico), que está localizado na seção do Stateflow. Vamos examiná-lo.

Vamos mover o bloco da biblioteca e clicar duas vezes nele para abrir o diagrama. Uma janela em branco do editor de gráfico SF aparecerá. Ela pode ser usada para criar gráficos e seus depuradores, para obter as funções necessárias.

A barra de ferramentas está localizada no canto superior esquerdo. Há 9 botões:

  1. State (estado);
  2. History Junction (junção de histórico);
  3. Default Transition (transição padrão);
  4. Connective Junction (junção conectiva);
  5. Truth Table (tabela-verdade);
  6. Function (função);
  7. Embedded MATLAB Function (função MATLAB embutida);
  8. Box (caixa);
  9. Simulink Function Call (chamada de função Simulink).

Infelizmente é impossível considerar cada elemento em detalhes dentro do contexto deste artigo. Portanto, me limitarei a uma breve descrição destes elementos, que necessitaremos para nosso modelo. Informações mais detalhadas podem ser encontradas na seção de ajuda do Matlab, no website do desenvolvedor.

Figura 5. A visão do gráfico SF no editor

Figura 5. A visão do gráfico SF no editor

O objeto chave dos gráficos SF é o State. Ele é representado por um retângulo com cantos arredondados.

Ele pode ser exclusivo ou paralelo. Cada estado pode ser pai e possuir herdeiros. Os estados podem ser ativos ou inativos, os estados podem executar alguns procedimentos.

A transição é representada como uma linha curvada com seta, ela conecta os estados e outros objetos. Uma transição pode ser feita clicando com o botão esquerdo do mouse no objeto fonte e direcionando o cursor para o objeto alvo. A transição pode possuir suas próprias condições, que são registradas em colchetes. O procedimento de transição é indicado dentro de colchetes, e será executado se a condição for satisfeita. O procedimento, executado durante a confirmação do objeto alvo, é denotado por uma barra.

O nó alternativo (junção conectiva) possui a forma de um círculo, e permite a transição para percorrer os diferentes caminhos, cada um dos quais é definido por uma condição específica. Neste caso, a transição, que corresponde à condição especificada, é selecionada.

A função é representada como um gráfico de fluxo com as declarações da linguagem procedural Stateflow. Um gráfico de fluxo reflete a estrutura lógica de uso de transições e nós alternativos.

Um Evento é outro importante objeto do Stateflow, pertencendo ao grupo de objetos não-gráficos. Este objeto pode disparar os procedimentos do gráfico SF.

O procedimento (ação) também é um objeto não-gráfico. Ele pode chamar a função, atribuir um evento específico, transição, etc.

Os dados no modelo SF são representados por valores numéricos. Os dados não são representados como objetos gráficos. Eles podem ser criados por qualquer nível de hierarquia do modelo e possuem propriedades.

2. Descrição da estratégia de comércio

Agora, vamos explicar brevemente o comércio. Para nossos propósitos de treinamento, o Expert Advisor será bem simples, para não dizer primitivo.

O sistema de comércio automático abrirá posições na base do sinal, basicamente, após o cruzamento das movimentações exponenciais, com um período de 21 e 55 (números Fibonacci), rateador em preços fechados. Então se o EMA 21 cruza o EMA 55 a partir da parte inferior, uma posição longa é aberta, se não, uma curta.

Para a filtragem de ruído, a posição será aberta na barra K-th pelo preço de abertura da barra após o aparecimento do cruzamento 21/55. Vamos negociar em EURUSD H1. Apenas uma posição será aberta. Ela será fechada apenas se atingir o nível Take Profir ou Stop Loss.

Gostaria de mencionar que durante o desenvolvimento de sistemas de comércio automáticos e backtest de histórico, algumas simplificações da figura de comércio geral são admitidas.

Por exemplo, o sistema não verificará a execução do corretor de um sinal. Posteriormente, adicionaremos as restrições de comércio ao núcleo do sistema no MQL5.


3. A modelagem de uma estratégia de negócio no Simulink

Para começar, precisaremos realizar o upload dos dados de preço históricos para o ambiente Marlab. Realizaremos isso usando um script MetaTrader 5, que salvaremos (testClose.mq5).

No Matlab, estes dados (Open, High, Low, Close, Spread) também serão carregados usando um script m simples (priceTxt.m).

Usando movavg (função Matlab padrão), criaremos arrays de Médias Móveis Exponenciais:

[ema21, ema55] = movavg(close, 21, 55, 'e');

Bem como um array auxiliar de índices de barra:

num=1:length(close);

Vamos criar as seguintes variáveis:

K=3; sl=0.0065; tp=0.0295;

Vamos começar o processo de modelagem.

Crie uma janela em branco do Simulink e chame-a de mts ao salvá-la. Todas as seguintes ações foram duplicadas em um formato de vídeo. Se algo não estiver bem claro, ou mesmo não estiver claro de modo algum, você pode observar minhas ações assistindo ao vídeo.

Quando estiver salvando o modelo, o sistema pode imprimir o seguinte erro:

??? O arquivo "C:\\Simulink\\mts.mdl" contém caracteres que são incompatíveis com a codificação de caracteres atual, windows-1251. Para evitar este erro, faça uma das ações seguintes:
1) Utilize a função slCharacterEncoding para alterar a codificação de caracteres atual para uma destas: Shift_JIS, windows-1252, ISO-8859-1.
2) Remova os caracteres não suportados. O primeiro caractere não suportado é na linha 23, byte offset 15.

Para eliminar isso, você apenas precisa fechar todas as janelas de modelos e alterar a codificação usando os seguintes comandos:

bdclose all
set_param(0, 'CharacterEncoding', 'windows-1252');

Vamos especificar a fonte de informação de nosso modelo.

O papel de tal fonte de informação serão os dados históricos do MetaTrader 5, que contém os preços de abertura, máximo, mínimo e de fechamento. Além disso, levaremos em conta o Spread, mesmo que ele tenha se tornado flutuante relativamente recentemente. Por fim, gravaremos a hora de abertura da barra. Para propósitos de modelagem, alguns arrays de dados iniciais serão interpretados como um sinal, ou seja, como um vetor de valores de uma função de tempo em pontos discretos no tempo.

Vamos criar um subsistema "FromWorkspace" para obter os dados da área de trabalho do Matlab. Selecione a seção de Portas e Subsistemas no navegador de bibliotecas Simulink. Arraste o bloco de "Subsistema" para a janela de modelo Simulink, usando o mouse. Renomeie-o para "FromWorkspace", clicando no subsistema. Então entre no bloco clicando duas vezes com o botão esquerdo do mouse no bloco para criar as variáveis de entrada e saída e as constantes para o sistema.

Para criar as fontes de sinal no Library Browser, escolha o Signal Processing Blockset, e fontes (Signal Processing Sources). Usando seu mouse, arraste o bloco "Signal from workspace" para a janela de subsistema do modelo FromWorkspace. Uma vez que o modelo terá 4 sinais de entrada, simplesmente duplicamos o bloco, e criaremos mais 3 cópias. Vamos especificar agora quais variáveis serão processadas por bloco. Para fazer isso, clique duas vezes no bloco, e insira o nome da variável nas propriedades. Estas variáveis serão: open, ema21, ema55, num. Nomearemos os blocos da seguinte maneira: open signal, ema21 signal, ema55 signal, num signal.

Agora, da seção "Commonly used blocks" do Simulink, adicionaremos um bloco para criar um canal (Bus Creator). Abra o bloco e altere o número de entradas para 4. Conecte o sinal open, o sinal ema21, sinal ema55, blocos de sinal num com as entradas do bloco Bus Creator.

Além disso, teremos mais 5 constantes de entrada. A bloco "Constant" é adicionado a partir da seção "Commonly used blocks". Assim como o valor (Constant value), especificaremos os nomes das variáveis: spread, high, low, tp, sl:

  • spread - este é um array de valores spread;
  • high - este é um array de valores de preços máximos;
  • low - este é um array de valores de preços mínimos;
  • tp - valor Take Profit em termos absolutos;
  • sl - valor Stop Loss em termos absolutos.

Chamaremos os blocos da seguinte maneira: spread array, high array, low array, Take Profit, Stop Loss.

Selecione o bloco de porta de saída (Out1) na seção "Portas e subsistemas" do Simulink e mova-o para a janela de subsistema. Crie 5 cópias da porta de saída. A primeira, conectaremos com o vloco do Bus Creator, e as outras - alternativamente, com os arrays de spread, alto, baixo e blocos Take Profit e Stop Loss.

Renomearemos a primeira porta para price e as outras - pelo nome da variável de saída.

Para criar um sinal de comércio, vamos inserir o bloco de adição (Add) a partir da seção "Operações matemáticas" do Simulink. Chamaremos diferencial emas. Dentro do bloco, mudaremos a lista de sonais, c + + para + -. Usamos a combinação de teclas Ctrl+K, gire o bloco 90° em sentido horário. Conecte o bloco do sinal ema21 com a entrada "+" e o sinal ema55 com a "-".

Então insira o bloco Delay, a partir da seção Signal Processing Blockset, de Signal Operations. Chamaremos de Delay K. No campo Delay (amostras) deste bloco, inseriremos o nome da variável K. Conecte-o com o bloco anterior.

Os blocos diferenciais e o Delay K formatam a frente (diferença de nível) do sinal de controle para cálculos apenas no estágio de modelagem, onde foram alterados. O subsistema, que criaremos mais tarde, será ativado se pelo menos um elemento for alterado em seu nível de sinal.

Então, a partir da seção "Blocos comumente usados" do Simulink, adicionamos um multiplexador with (com) e um bloco (Mux). Similarmente, rotacione o bloco 90° no sentido horário. Dividiremos a linha de sinal do bloco de atraso em dois, e a conectaremos com os multiplexadores.

A partir da seção Stateflow, insira um bloco Gráfico. Insira o gráfico. Adicione dois eventos de entrada (Buy e Sell) e dois eventos de saída (OpenBuy e OpenSell). O valor de gatilho (Trigger) para o evento (Buy) definiremos para Falling (ativação do subsistema por uma frente negativa) e para os eventos Sell, definiremos para Rising (ativação do subsistema por uma frente positiva). O valor de gatilho (Trigger) para os eventos OpenBuy e OpenSell, definiremos para a posição da chamada Function (Calling) (ativação do subsistema será determinada pela lógica do trabalho na função S determinada).

Criaremos uma transição por padrão com três nós alternativos. O primeiro nó será conectado por uma transição ao segundo nó, definindo as condições e o procedimento a eles para Buy {OpenBuy;}, e ao terceiro, definindo o procedimento para Sell {OpenSell;}. Conecte a entrada do gráfico com o multiplexador, e as duas saídas - com outro multiplexador, que pode ser copiado do primeiro. O último bloco será conectado à porta de saída, que copiaremos de uma análoga, e chamaremos Buy/Sell.

E eu quase esqueci! Para o modelo funcionar adequadamente, precisamos criar um objeto de canal virtual, que ficará localizado no espaço de trabalho do Matlab. Para fazer isto, inseriremos o Bus Editor (Editor de Barramento) por meio do menu Tools (Ferramentas). No editor, selecione o item Add Bus (Adicionar Barramento). Chame-o InputBus.

Insira os elementos de acordo com os nomes nas variáveis de entrada: open, ema21, ema55 e num. Abra o Bus Creator (Criador de Barramento) e marque a caixa de seleção próxima a Specify properties via bus object (Definir as propriedades por meio do objeto de barramento). Em outras palavras, conectamos nosso bloco com o objeto de canal virtual que criamos. O canal virtual significa que os sinais são combinados apenas graficamente, sem afetar a distribuição de memória.

Salve as alterações na janela do subsistema. Isto conclui nosso trabalho com o subsistema FromWorkspace.


Agora é hora de criar a "Caixa preta". Será um bloco que, com base nos sinais de entrada, processará a informação e realizará as decisões de comércio. é claro, ela precisará ser criada por nós, em vez de um programa de computador. Afinal, apenas nós podemos decidir sobre as condições sob as quais o sistema deve realizar uma negociação. Além disso, o bloco terá que exibir as informações sobre as negociações concluídas na forma de sinais.

O bloco necessário é chamado de Chart (Gráfico) e está localizado na seção Stateflow (Fluxo de estado). Agora já estamos familiarizados com ele, não? Usando "arrastar e soltar", o movemos para nossa janela de modelo.

Figura 6. Os blocos do sistema de entrada e o gráfico StateFlow

Figura 6. Os blocos do sistema de entrada e o gráfico StateFlow


Abra o gráfico e insira nossos dados nele. Antes de tudo, vamos criar um objeto de canal, como fizemos no subsistema FromWorkspace. Mas, diferentemente do anterior, que nos fornecia os sinais a partir do espaço de trabalho, este retornará o resultado obtido. E assim, chamaremos o objeto OutputBus. Seus elementos se tornarão: barOpen, OpenPrice, TakeProfit, StopLoss, ClosePrice, barClose, Comment, PositionDir, posN, AccountBalance.

Agora vamos começar a construir. Na janela de gráfico, exibiremos a transição padrão (nº 1).

Para as condições e procedimentos, indicaremos:

[Input.num>=56 && Input.num>Output.barClose] {Output.barOpen=Input.num;i = Input.num-1;Output.posN++;}

Esta condição significa que os dados serão processados se o número de barras de entrada for pelo menos 56, bem como se a barra de entrada for maior que a barra de fechamento da posição anterior. Então a barra de abertura (Output.barOpen) é atribuída ao número da barra de entrada, por uma variável índice de i - o índice (começando de 0), e o número de posições abertas aumenta em 1.

A segunda transição é executada apenas se a posição aberta não for a primeira. Caso contrário, a terceira transição é executada, que atribuirá à variável de balanço de conta (Ouput.AccountBalance) o valor 100000.

A quarta transição é executada se o gráfico for iniciado pelo evento OpenBuy. Nesse caso, a posição será direcionada à compra (Output.PositionDir = 1), o preço de abertura será igual ao preço da barra de abertura, levando em conta o spread (Output.OpenPrice = Input.open + spread [i] * 1e-5). Os valores dos sinais de saída StopLoss e TakeProfit também serão especificados.

Se um evento OpenSell ocorrer, então o fluxo seguirá a quinta transição e definirá seus valores para os sinais de saída.

A sexta transição é realizada se a posição for longa, caso contrário, o fluxo seguirá para a sétima transição.

A oitava transição verifica se o preço de barra máximo alcançou o nível TakeProfit, ou se o preço de barra mínimo alcançou o nível de StopLoss. Caso contrário, o valor da variável índice i é aumentado em um (nona transição).

A décima transição verifica as condições que surgem em StopLoss: o preço mínimo da barra cruzou o nível StopLoss. Se for confirmada, o fluxo seguirá para a 11ª transição e então para a 12ª, onde os valores das diferenças de preço das posições de abertura e fechamento, o balanço de conta atual e o índice da barra de fechamento são definidos.

Se a décima transição não for confirmada, a posição será fechada em TakeProfit (13ª transição). E depois, a partir do 14º, o fluxo seguirá para a 12º transição.

Os procedimentos e condições para as transições para uma posição curta são os opostos.

Por fim, criamos novas variáveis no gráfico. Para integrá-las automaticamente em nosso modelo, precisamos executar o modelo diretamente na janela de gráfico, clicando no botão "Start simulation" (iniciar simulação). Ele é similar ao botão de Play em tocadores de música. Neste ponto, o Stateflow Symbol Wizard (Assistente de símbolo de fluxo de estado) (objetos mestres SF) será executado, e sugerirá salvar os objetos criados. Pressione o botão SelectAll (selecionar todos) e clique em Create (Criar). Os objetos serão criados. Vamos agora abrir o Model Browser (navegador de modelos). à esquerda, clique em nosso gráfico na Hierarquia de Modelos. Vamos ordenar os objetos por tipo de dados (DataType).

Adicione mais dados, usando os comandos de menu "Add" (adicionar) e "Data" (dados). Vamos chamar a primeira variável de Input. Altere o valor dos Scopes (escopos) para Input, e o Type (tipo) para "Bus: . E então insira o nome do canal criado anteriormente, InputBus, diretamente neste campo. Assim nossa variável Input terá o tipo de InputBus. Vamos definir o valor de Port (porta) para um.

Complete a mesma operação com a variável Output. Ela apenas deve ter o tipo Output Scope e Output Bus.

Vamos mudar o escopo para as variáveis alta, baixa, sl, tp e spread para o valor de "entrada". Respectivamente, vamos definir os números de porta na seguinte ordem: 3, 4, 6, 5, 2.

Vamos também alterar o escopo da variável Lots (lotes) para Constant (constante). Na aba "Value Attributes" (atributos de valor) vamos inserir 1, eventos OpenBuy e OpenSell - para Input no campo "Initial" (inicial) (à direita). Nos eventos, altere o valor de gatilho para "Function call" (chamada de função).

Crie uma variável interna len, com um escopo Constant. Na aba "Value Attributes", no campo "Initial value", inseriremos um comprimento de função m (close). Assim ela será igual ao comprimento do array close, que está localizado no espaço de trabalho do Matlab.

Para as variáveis high e low, inseriremos um valor de [len 1] no campo Size (tamanho). Assim, na memória, teremos reservados os tamanhos de array de high e low como o valor de [len 1].

Também vamos indicar para a variável K, na aba "Value Attributes", no campo "Initial value" (à direita), a variável K vigente, obtida do espaço de trabalho.

Como resultado, temos um subsistema Chart, com 7 portas de entrada e uma porta de saída. Vamos posicionar o bloco de tal maneira que os eventos de entrada estejam na parte inferior. Vamos renomear o bloco "Position handling" (manipulação de posição). No gráfico em si, também exibiremos o nome do bloco. Combine os blocos do subsistema FromWorkspace e "Position handling" através das portas apropriadas. E altere a cor dos blocos.

Deve ser observado que o subsistema "Position handling" apenas funcionará ser for "acordado" pelos eventos de entrada OpenBuy ou OpenSell. Desta maneira, otimizamos a operação do subsistema para evitar cálculos desnecessários.

Figura 7. Subsistemas FromWorkspace e Position handling


Agora temos que criar um subsistema para imprimir os resultados de processamento no espaço de trabalho do Matlab e combiná-lo com o subsistema "Position handling". Será a tarefa mais fácil.

Vamos criar um subsistema "ToWorkspace" para obter os resultados no espaço de trabalho. Repita os passos que tomamos quando criamos o subsistema "FromWorkspace". No navegador de bibliotecas, selecione a seção Simulink Ports & Subsystems. Usando o mouse, arraste o bloco "Subsystem" para a janela de modelo Simulink. Renomeie-o para "ToWorkspace", clicando no subsistema. Combine o bloco com o subsistema "Position handling".

Para criar a log de variáveis nele, clique duas vezes no bloco com o botão esquerdo do mouse.

Uma vez que o subsistema receberá dados do objeto OutputBus, que é um barramento não virtual, então precisamos selecionar os sinais deste canal. Para fazer isto, selecionamos a seção "Commonly used blocks" (blocos comumente usados) do Simulink no navegador de bibliotecas, e adicionamos um "Bus Selector" (seletor de barramento). O bloco terá 1 entrada e 2 sinais de saída, enquanto precisamos ter 10 destes sinais.

Vamos conectar o bloco à porta de entrada. Pressione o botão "Start Simulation" (iniciar simulação) (este é nosso botão "Play"). O compilador começará a construir o modelo. Ele não será construído com sucesso, mas criará os sinais de entrada para o bloco de seleção de barramento. Se entrarmos no bloco, veremos que os sinais necessários aparecem no lado esquerdo da janela, que são transmitidos por meio do OutputBus. Todos eles precisam ser selecionados, usando o botão "Select" (selecionar), e movidos para o lado direito - "Selected signals" (sinais selecionados).

Figura 8. Parâmetros do bloco Bus Selector

Figura 8. Parâmetros do bloco Bus Selector


Vamos novamente consultar a seção "Commonly used blocks" do navegador de bibliotecas do Simulink, e adicionar o bloco multiplexador Mux. Ele indica o número de entradas, que é igual a 10.

Então entre na seção "Sinks" do navegador de bibliotecas do Simulink e mova o bloco ToWorkspace para a janela de subsistema. Ali indicaremos o novo nome da variável "AccountBalance" e alteraremos o formato de saída (Save format) de "Structure" (estrutura) para "Array". Combine o bloco com o multiplexador. Apague a porta de saída, uma vez que ela não será mais necessária. Personalize a cor dos blocos. Salve a janela. O subsistema está pronto.

Antes de construir o modelo devemos verificar a presença das variáveis no espaço de trabalho. As seguintes variáveis devem estar presentes: InputBus, K, OutputBus, close, ema21, ema55, high, low, num, open, sl, spread, tp.

Vamos definir o valor de Stop Time como o parâmetro para definir num (end). Ou seja, o vetor processado terá o comprimento que foi definido pelo último elemento do array num.

Antes de começar a construir um modelo, precisamos escolher um compilador, usando o seguinte comando:

mex-setup

Por favor, escolha seu compilador para criar os arquivos de interface externa (MEX):
Você gostaria que o mex localizasse os compiladores instalados [y] / n? y

Selecione um compilador:

[1] Lcc-win32 C 2.4.1 in C:\PROGRA~2\MATLAB\R2010a\sys\lcc
[2] Microsoft Visual C++ 2008 SP1 in C:\Program Files (x86)\Microsoft Visual Studio 9.0
[0] None

Compilador: 2

Como você pode ver, selecionei Microsoft Visual C ++ 2008 compiler SP1.

Vamos iniciar a construção. Pressione o botão "Start simulation". Há um erro: Stateflow Interface Error: (erro de interface do fluxo de estado) Port width mismatch. (incompatibilidade de comprimento de porta) Input "spread"(#139) expexts a scalar. (Entrada "spread" (#139) espera um escalar. O sinal é o vetor unidimensional com 59739 elementos.

A variável "spread" não deve ser de tipo double, e sim herdar seu tipo do sinal do Simulink.

No Model Browser, para esta variável, especificaremos "Inherit: Same as Simulink" (herdar: mesmo que o Simulink), e no campo "size" (tamanho), especificaremos "-1". Salve as alterações.

Vamos executar o modelo novamente. Agora o compilador funciona. Ele mostrará alguns avisos menores. E, em menos de 40 segundos, o modelo processará os dados de aproximadamente 60.000 barras. O comércio é realizado de '2001 .01.01 00:00 ' a '2010 .08.16 11:00'. A quantidade total de posições open é 461. Você pode observar como o modelo funciona no seguinte clipe.



4. Implementação da Strategy no MQL5

E assim, nosso sistema de comércio automatizado é compilado no Simulink. Agora precismos transferir esta ideia de comércio para o ambiente MQL5. Temos que lidar com blocos e objetos Simulink, através dos quais expressamos a lógica de nosso Expert Advisor de comércio. A tarefa atual é transferir o sistema de comércio logico para o Expert Advisor do MQL5.

Entretanto, deve ser observado que alguns blocos não necessariamente têm que estar definidos de alguma maneira no código MQL5, porque suas funções podem estar escondidas. Tentarei comentar com o maior número de detalhes sobre qual linha está relacionada a cada bloco, no código real. Algumas vezes este relacionamento pode ser indireto. E, às vezes, isso pode refletir uma conexão da interface dos blocos ou objetos.

Antes de começar esta seção, deixe-me chamar sua atenção para o artigo "Guia passo-a-passo para escrever Expert Advisors em MQL5 para iniciantes". Este artigo fornece uma descrição facilmente compreensível das principais ideias e regras básicas da escrita de um Expert Advisor no MQL5. Mas eu não vou me alongar nelas agora. Usarei algumas linhas do código MQL5 de lá.

4.1 Subsistema "FromWorkspace"

Por exemplo, temos um bloco "open signal" no subsistema "FromWorkspace". No Simulink, ele é necessário para obter o preço de barra de abertura durante o backtesting, e para abrir uma posição neste preço, no caso de um sinal de comércio ser recebido. Este bloco obviamente não está presente no código MQL5, porque o Expert Advisor solicita a informação de preço imediatamente após receber o sinal de comércio.

No Expert Advisor, precisaremos processar os dados recebidos das médias móveis. Portanto, criaremos para eles arrays dinâmicos e variáveis auxiliares correspondentes, como manipuladores.

int ma1Handle;  // Moving Average 1 indicator handle: block "ema21 signal"
int ma2Handle;  // indicator handle Moving Average 2: block "ema55 signal"

ma1Handle=iMA(_Symbol,_Period,MA1_Period,0,MODE_EMA,PRICE_CLOSE); // get handle of Moving Average 1 indicator 
ma2Handle=iMA(_Symbol,_Period,MA2_Period,0,MODE_EMA,PRICE_CLOSE); // get handle of Moving Average 2 indicator

double ma1Val[]; // dynamic array for storing the values of Moving Average 1 for every bar: block "ema21 signal"
double ma2Val[]; // dynamic array for storing the values of Moving Average 2 for every bar: block "ema55 signal"

ArraySetAsSeries(ma1Val,true);// array of indicator values MA 1: block "ema21 signal"
ArraySetAsSeries(ma2Val,true);// array of indicator values MA 2: block "ema55 signal"

Todas as outras linhas, que de alguma maneira afetam as móveis ema21 e ema55, podem ser consideradas como auxiliares.

"Take Profit" e "Stop Loss" são definidas como variáveis de entrada:

input int TakeProfit=135;   // Take Profit: Take Profit in the FromWorkspace subsystem
input int StopLoss=60;      // Stop Loss:  Stop Loss in the FromWorkspace subsystem
Levando em conta que existem 5 dígitos significativos para EURUSD, os valores de TakeProfit e StopLoss precisarão ser atualizados da seguinte maneira:
int sl,tp;
sl = StopLoss;
tp = TakeProfit;
if(_Digits==5)
 {
  sl = sl*10;
  tp = tp*10;
 }

Os arrays "spread", "high" e "low" são usados para servir os valores, uma vez que são responsáveis pelo fornecimento de dados históricos, na forma de uma matriz de dados de preço relevantes, para identificar as condições de comércio.

Eles não estão explicitamente representados no código. Entretanto, pode ser argumentado que o array "spread", por exemplo, é necessário para formar um stream de pergunta de preços. E os outros dois são necessários para determinar as condições para fechar uma posição, que não são especificados no código, uma vez que são automaticamente executados no MetaTrader 5, após alcançar um certo nível de preço.

O bloco "num signal" é auxiliar e não é exibido no código do Expert Advisor.

O bloco "emas differential" verifica as condições para abrir posições curtas ou longas buscando as diferenças. O "K Delay" cria um atraso para os arrays, que são médios ao valor de K.

O evento Buy ou Sell é criado, é um evento de entrada para o subsistema de abertura de posição.

No código, ele é expresso da seguinte maneira:

// event Buy (activation by the negative front)
bool Buy=((ma2Val[1+K]-ma1Val[1+K])>=0 && (ma2Val[K]-ma1Val[K])<0) ||
         ((ma2Val[1+K]-ma1Val[1+K])>0 && (ma2Val[K]-ma1Val[K])==0);

// event Sell (activation by the positive front)
bool Sell=((ma2Val[1+K]-ma1Val[1+K])<=0 && (ma2Val[K]-ma1Val[K])>0)||
         ((ma2Val[1+K]-ma1Val[1+K])<0 && (ma2Val[K]-ma1Val[K])==0);
O subsistema de abertura de posição cria os eventos "OpenBuy" e "OpenSell" por si mesmo, que são processados no subsistema "Position handling", usando as condições e procedimentos.

4.2 Subsistema "Position handling"

O subsistema começa a funcionar processando os eventos OpenBuy e OpenSell.

Para a primeira transição do subsistema, uma das condições é a presença de não menos que 56 barras, que é indicada no código por meio da verificação de tais condições:

if(Bars(_Symbol,_Period)<56) // 1st transition of the «Position handling»subsystem : condition [Input.num>=56]
      {
        Alert("Not enough bars!");
        return(-1);
      }

A segunda condição para a transição: o número da barra de abertura deve ser maior que a barra de fechamento (Input.num; Output.barClose), ou seja, a posição foi fechada.

No código, é indicado da seguinte maneira:

//--- 1st transition of the «Position handling» subsystem: condition [Input.num>Output.barClose]

bool IsBought = false;  // bought
bool IsSold = false;    // sold
if(PositionSelect(_Symbol)==true) // there is an opened position
 {
   if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY)
     {
      IsBought=true;  // long
     }
   else if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL)
     {
      IsSold=true;    // short
     }
  }
// check for opened position
if(IsTraded(IsBought,IsSold))
 {
   return;
 }

//+------------------------------------------------------------------+
//| Function of the check for opened position                        |
//+------------------------------------------------------------------+
bool IsTraded(bool IsBought,bool IsSold)
  {
   if(IsSold || IsBought)
     {
      Alert("Transaction is complete");
      return(true);
     }
   else
      return(false);
  }

A quarta transição é responsável por abrir uma posição longa.

é representada como segue:

// 4th transition procedures of the «Position handling» subsystem: open long position
 mrequest.action = TRADE_ACTION_DEAL;                                  // market buy
 mrequest.price = NormalizeDouble(latest_price.ask,_Digits);           // latest ask price
 mrequest.sl = NormalizeDouble(latest_price.bid - STP*_Point,_Digits);  // place Stop Loss
 mrequest.tp = NormalizeDouble(latest_price.bid + TKP*_Point,_Digits);  // place Take Profit
 mrequest.symbol = _Symbol;                                           // symbol
 mrequest.volume = Lot;                                              // total lots
 mrequest.magic = EA_Magic;                                          // Magic Number
 mrequest.type = ORDER_TYPE_BUY;                                       // order to buy
 mrequest.type_filling = ORDER_FILLING_FOK;                            // the specified volume and for a price, 
                                                                               // equal or better, than specified
 mrequest.deviation=100;                                             // slippage
 OrderSend(mrequest,mresult);
 if(mresult.retcode==10009 || mresult.retcode==10008) // request completed or order placed
    {
     Alert("A buy order has been placed, ticket #:",mresult.order);
    }
 else
    {
     Alert("A buy order has not been placed; error:",GetLastError());
     return;
    }

A quinta transição é responsável por abrir uma posição curta.

é representada como segue:

// 5th transition procedures of the «Position handling» subsystem: open a short position
 mrequest.action = TRADE_ACTION_DEAL;                                  // market sell
 mrequest.price = NormalizeDouble(latest_price.bid,_Digits);           // latest bid price
 mrequest.sl = NormalizeDouble(latest_price.ask + STP*_Point,_Digits);  // place a Stop Loss
 mrequest.tp = NormalizeDouble(latest_price.ask - TKP*_Point,_Digits);  // place a Take Profit
 mrequest.symbol = _Symbol;                                          // symbol
 mrequest.volume = Lot;                                             // lots
 mrequest.magic = EA_Magic;                                         // Magic Number
 mrequest.type= ORDER_TYPE_SELL;                                      // sell order
 mrequest.type_filling = ORDER_FILLING_FOK;                           // in the specified volume and for a price, 
                                                                              // equal or better, than specified in the order
 mrequest.deviation=100;                                             // slippage
 OrderSend(mrequest,mresult);
 if(mresult.retcode==10009 || mresult.retcode==10008) // request is complete or the order is placed
    {
     Alert("A sell order placed, ticket #:",mresult.order);
    }
 else
    {
     Alert("A sell order is not placed; error:",GetLastError());
     return;
    }

Outras transições nas subcategorias estão claramente não apresentadas no Expert Advisor, uma vez que os procedimentos apropriados (ativação de paradas ou obtenção de um nível Take Profit) são realizados automaticamente no MQL5.

O subsistema "ToWorkspace" não está representado no código MQL5 porque sua tarefa é apresentar a saída para os espaços de trabalho do Matlab.


Conclusões

Usando uma ideia simples de comércio como exemplo, criei o sistema de comércio automatizado no Simulink, no qual realizei um backtest sobre dados históricos. No início, estava incomodado pela questão: "Há uma razão em envolver-se com toda esta bagunça quando você pode implementar rapidamente um sistema de comércio por meio de código MQL5?"

Claro, você pode fazer isso sem a visualização do processo de criar o sistema e a lógica de seu trabalho. Mas isto é apenas para programadores experientes ou pessoas simplesmente talentosas. Quando o sistema de comércio estende-se com novas condições e funções, a presença de um diagrama de bloco e seu trabalho realizará o trabalho do comerciante.

Eu também gostaria de mencionar que eu não tentei opor as capacidades de linguagem do Simulink contra a linguagem MQL5. Eu meramente ilustrei como você pode criar um sistema de comércio automatizado usando um design de blocos. Talvez, no futuro, os desenvolvedores do MQL5 criarão um construtor visual de estratégias, que facilitará o processo de escrita de Expert Advisors.

Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/155

Arquivos anexados |
mts.mq5 (9.93 KB)
testclose.mq5 (3.49 KB)
matlab.zip (28.68 KB)
Handler de evento "nova barra" Handler de evento "nova barra"
A linguagem de programação é capaz de resolver problemas em um nível completamente novo. Mesmo as tarefas que já tenham soluções, graças à programação orientada a objeto elas podem atingir um nível ainda maior. Neste artigo, consideramos um exemplo especialmente simples de verificação de uma nova barra em um gráfico, que foi transformado em uma ferramenta bastante poderosa e versátil. Qual ferramenta? Descubra neste artigo.
Encontrando erros e registrando Encontrando erros e registrando
O MetaEditor 5 possui o recurso de depuração Mas, quando você escreve seus programas MQL5, geralmente você deseja exibir não apenas valores individuais, mas todas as mensagens que aparecem durante o trabalho online e teste. Quando o conteúdo do arquivo de registro tem um tamanho grande, é óbvio automatizar a recuperação rápida e fácil da mensagem requerida. Neste artigo consideraremos várias maneiras de encontrar erros em programas do MQL5 e métodos de registro. Além disso, simplificaremos o logging em arquivos e conheceremos um programa simples LogMon para visualizações confortáveis dos registros.
Gás neural em desenvolvimento: Implementação em MQL5 Gás neural em desenvolvimento: Implementação em MQL5
Este artigo mostra um exemplo de como desenvolver um programa MQL5 implementando o algorítimo adaptável de fazer o cluster chamado gás neural em desenvolvimento (GNG). O artigo é destinado para usuários que tenham estudado a documentação de linguagem e têm determinadas habilidades de programação e conhecimento básico na área de neuroinformática.
O uso de bibliotecas de classe de negócio padrão MQL5 ao escrever um Expert Advisor O uso de bibliotecas de classe de negócio padrão MQL5 ao escrever um Expert Advisor
Este artigo explica como usar as principais funcionalidades das Classes de negócio da biblioteca padrão do MQL5 ao escrever Expert Advisors que implementam o fechamento e modificação de posição, posicionamento de ordem pendente e exclusão e verificação de Margem antes de posicionar um negócio. Também demonstramos como as classes de negócio podem ser usadas para obter detalhes de ordens e transações.