English Русский 中文 Español Deutsch 日本語
preview
Aprendendo a construindo um EA que opera de forma automática (Parte 08): OnTradeTransaction

Aprendendo a construindo um EA que opera de forma automática (Parte 08): OnTradeTransaction

MetaTrader 5Negociação | 5 dezembro 2022, 12:09
978 0
Daniel Jose
Daniel Jose

Introdução

No artigos anteriores,  Aprendendo a construindo um EA que opera de forma automática (Parte 06): Tipos de contas (I) e  Aprendendo a construindo um EA que opera de forma automática (Parte 07): Tipos de Contas ( II ), foquei toda a explicação, de forma a mostrar, que devemos tomar alguns cuidados, ao desenvolver um EA, que irá operar de forma automática.

Antes de começarmos a realmente ver como o código do EA, deve funcionar para que ele seja automatizado. Você precisa entender como ele está se comunicando com o servidor de negociação. Para isto veja a figura 01:

Figura 01

Figura 01 - Fluxo de mensagens ...


Esta figura 01, mostra como é o fluxo de mensagens, de maneira que o EA possa enviar ordens, ou requerimentos para o servidor de negociação. observe o sentido das setas.

O único momento em que as setas são bidirecionais, é no momento que a classe C_Orders, envia um pedido para o servidor, usando a função OrderSend. Pois ela irá receber uma resposta do servidor via uma estrutura. Fora este momento, todos os demais pontos são direcionais. Mas aqui estou mostrando, apenas o fluxo para enviar pedidos a mercado, ou para pendurar ordens no book. Sendo assim, o sistema é extremamente simples.

No caso de um EA 100% automatizado, ainda precisaremos de mais algumas coisas aqui. E para um EA, com uma automatização mínima, ainda iremos precisar adicionar alguns detalhes, mas tudo irá se passar apenas entre o EA e a classe C_Manager. Em nenhum outro ponto, precisaremos adicionar código. Se bem que em um EA 100% automatizado, iremos precisar retirar a classe C_Mouse. Pois ela não terá nenhuma serventia para um EA 100% automático. É bastante importante, você entender este fluxo de mensagens, pois sem entender isto, você não conseguirá acompanhar o restante do artigo.


Adicionando as rotinas de controle e acessibilidade.

O maior dos problemas, é que muitos que utilizam a linguagem MQL5 para criar EA, não fazem uso de alguns recursos que a linguagem promove. Talvez por desconhecimento, ou por qualquer outro motivo, isto não importa. Mas se você for utilizar o MQL5 de uma maneira mais completa, a fim de melhorar a robustez e confiabilidade de seu código. Precisa sinceramente, pensar em utilizar alguns dos recursos que ela disponibiliza.

A primeira coisa que faremos, será adicionar 3 novos procedimentos, na classe C_Manager. Estes servirão para que a classe libere o EA, ou consiga saber o que o EA está planejando fazer. A primeira destas rotinas é vista logo abaixo:

inline void EraseTicketPendig(const ulong ticket)
                        {
                                m_TicketPending = (ticket == m_TicketPending ? 0 : m_TicketPending);
                        }

Esta rotina, remove o valor do ticket pendente, quando o ticket informado for igual ao ticket pendente. Normalmente isto não irá de fato acontecer. Uma ordem pendente, não será removida pelo EA, esta remoção normalmente acontece por interferência do operador, ou usuário do EA, o que não é aconselhável. Mas se o EA notar que uma ordem pendente, que ele havia colocado no book, foi removida pelo usuário, ele deverá informar isto a classe C_Manager, para que ela permita que o EA coloque, se necessário uma nova ordem pendente no book.

A próxima função a ser adicionada, é vista no código a seguir:

                void PedingToPosition(void)
                        {
                                ResetLastError();
                                if ((m_bAccountHedging) && (m_Position.Ticket > 0)) SetUserError(ERR_Unknown);
                                        else m_Position.Ticket = (m_Position.Ticket == 0 ? m_TicketPending : m_Position.Ticket);
                                m_TicketPending = 0;
                                if (_LastError != ERR_SUCCESS) UpdatePosition(m_Position.Ticket);
                                CheckToleranceLevel();
                        }

Este código server para o EA informar a classe C_Manager, que uma ordem pendente acabou se se transformar em uma posição, ou fez alguma mudança na posição. Notem que quando esta função executa, o ticket de ordem pendente, será liberado pela classe C_Manager, permitindo desta forma, que o EA consiga pendurar uma nova ordem pendente. Mas as coisas somente, irão de fato continuar, se não foi gerado nenhum erro critico, que será analisado por esta função, vista no artigo anterior. Mas esta função, de fato não trabalha sozinha, ela precisa de uma outra função, que é vista abaixo:

                void UpdatePosition(const ulong ticket)
                        {
                                int ret;
                                
                                if ((ticket == 0) || (ticket != m_Position.Ticket)) return;
                                if (PositionSelectByTicket(m_Position.Ticket))
                                {
                                        ret = SetInfoPositions();
                                        m_StaticLeverage += (ret > 0 ? ret : 0);
                                }else ZeroMemory(m_Position);
                                ResetLastError();
                        }

Ainda faltam 2 outras funções aqui, na classe C_Manager. Mas já que elas são funções de automatização, não irei abordar este tema ainda.

Mas agora, de uma forma bem mais completa, temos finalmente a classe C_Manager e o EA, sendo amistosos um com o outro. A ponto que ambos consigam trabalhar, e garantir que não sejam agressivos, ou pouco cordiais. Desta forma, o fluxo de mensagens entre o EA e a classe C_Manager, passa a ser da seguinte maneira, vista na figura 02:

Figura 02

Figura 02: Fluxo de mensagens com as novas rotinas implementadas.


Você pode achar que este fluxo de mensagens, é muito complicado, ou não é nada funcional. Mas no entanto, ele é exatamente o que esta sendo implementado.

Mas então com base na figura 02, você deve estar pensando que o código do EA deve ser muito complicado. Mas no entanto, ele é bem mais simples do que muitos consideram ser um código necessário, para de fato ser usado em um EA. Ainda mais um que estará sendo automatizado. Lembre-se do seguinte: O EA, não gera de fato nenhuma operação. Ele apenas é um meio, ou ferramenta para se comunicar com o servidor de negociação. Então ele na verdade, apenas reage aos gatilhos que são aplicados a ele.

Com base neste entendimento, vamos dar uma passada pelo código do EA, na atual situação, antes de que ele venha a ser automatizado. Mas para quem não viu, o código do EA, não sofreu grandes mudanças deste o último artigo no qual ele havia aparecido, que foi  Aprendendo a construindo um EA que opera de forma automática ( Parte 05 ) - Gatilhos manuais ( II ). As únicas mudanças que de fato aconteceram, são vista logo abaixo:

int OnInit()
{
        manager = new C_Manager(def_MAGIC_NUMBER, user03, user02, user01, user04, user08);
        mouse = new C_Mouse(user05, user06, user07, user03, user02, user01);
        (*manager).CheckToleranceLevel();

        return INIT_SUCCEEDED;
}

Basicamente foi preciso adicionar apenas, e somente esta nova linha. Isto para que fosse testado, se haveria ocorrido algum erro mais grave, ou critico, mas agora vem uma questão: Como fazer o EA, dizer a classe C_Manager, oque estará acontecendo, com relação ao sistema de ordens ?!?! Muita gente, iria de fato ficar sem ter uma noção de como agir nesta situação. Tentando saber, como descobrir o que estará sendo feito no servidor de negociação. É neste ponto que mora o perigo.

A primeira coisa que você de fato tem que entender, é que a plataforma MetaTrader 5, assim como a linguagem MQL5. Não são ferramentas do tipo convencionais, ou seja, você não vai de fato criar um programa, que precise ficar procurando as informações. Isto por conta que o sistema é baseado em eventos e não em processos. Em uma programação baseada em eventos, você não deve pensar em passos, você deve pensar de uma forma diferente.

Para você ter uma ideia do como o pensamento precisa ser diferente. Pense no seguinte: Se você esta dirigindo, basicamente a sua intenção será chegar em um determinado destino. Mas ao longo do caminho, você deverá resolver algumas coisas, que irão acontecer, de forma aparentemente sem nenhuma conexão entre elas. Mas todas irão influenciar a sua direção, como por exemplo: Frear, acelerar, ter que mudar o caminho, por conta de alguma coisa imprevista que aconteceu. Tudo isto são eventos, dos quais você sabia que poderiam ocorrer. Mas não tinha a devida noção de quando aconteceriam.

Programação baseada em eventos é isto. você tem acesso a alguns eventos, que são fornecidos pela linguagem especifica, para um trabalho especifico. Tudo que você tem que fazer, é criar alguma lógica, que consiga resolver as questões, que um dado evento gera, a fim de ter algum tipo de resultado útil.

No MQL5, temos alguns eventos que podemos, e outros que devemos tratar, isto para cada tipo de situação. Muita gente, se perde ao tentar entender a lógica por traz disto, mas ela não é complicada, muito pelo contrário. Quando você a entende, a programação passa a ser bem mais simples. Isto por que, a própria linguagem, lhe fornece os meios necessários para tratar eventuais problemas.

Este é o primeiro ponto: Use inicialmente a linguagem MQL5 para resolver os problemas. Se ela de alguma forma não for o suficiente, adicione a funcionalidade especifica. Usando uma outra linguagem como o C / C++, ou mesmo o Python, para lhe ajudar, mas primeiro tente usar o MQL5.

Segundo ponto: Você não deve tentar capturar as informações. Seja de onde quer que elas venham. Você deve simplesmente, e sempre que possível, usar, e responder aos eventos que a plataforma MetaTrader 5 estará gerando.

Terceiro ponto: Não use funções, ou tente usar eventos que de fato não são necessários nos códigos. Use exatamente o que você precisa, nem mais, nem menos. E sempre procure usar o evento correto para o trabalho correto.

Com base nestes 3 pontos, nos podemos fazer 3 tipos de escolha, a fim de fazer o EA se comunicar com a classe C_Manager, ou qualquer outra, que precisará receber os dados fornecidos pela plataforma MetaTrader 5. A primeira forma, é usar o evento disparado a cada novo ticket recebido. Este evento irá chamar a função OnTick, sinceramente, desaconselho a você usar esta função. O motivo será visto em outro momento.

A outra forma é usando um evento do relógio, que dispara a função OnTime. Mas este não é muito adequado para o que queremos no momento. Isto por conta que teríamos que ficar verificando, a cada disparo do evento do relógio, a lista de ordens, ou posições. O que de fato não é nada eficaz, tornando o EA um peso morto para a plataforma MetaTrader 5.

A ultima alternativa, é usar o evento Trade, que dispara a função OnTrade. Este evento é disparado a cada mudança, que aconteceu no sistema de ordens. Seja por lançamento de novas ordens, seja por mudanças nas posições. Mas a função OnTrade não é muito adequada em alguns casos. Mas em outros, ela irá nos poupar de fazer certas tarefas, tornando a coisa bem mais simples. Mas ao invés de usar a função OnTrade, vamos usar uma outra : a função OnTradeTransaction.


OnTradeTransaction - Que mas oque é isto ... e pra que isto serve ?!?!

Talvez esta seja a função de tratamento de eventos, mais complicada que existe dentro da linguagem MQL5.  Então use este artigo, como uma boa fonte de pesquisa, sobre esta função. Irei tentar explicar, e passar o máximo possível do que consegui entender, e aprendi sobre como usar esta função.

Para facilitar a explicação. Pelo menos neste começo. Vamos ver o código esta função, que esta presente neste EA, este código pode ser visto logo abaixo:

void OnTradeTransaction(const MqlTradeTransaction &trans, const MqlTradeRequest &request, const MqlTradeResult &result)
{
        switch (trans.type)
        {
                case TRADE_TRANSACTION_POSITION:
                        manager.UpdatePosition(trans.position);
                        break;
                case TRADE_TRANSACTION_ORDER_DELETE:
                        if (trans.order == trans.position) (*manager).PendingToPosition();
                        else (*manager).UpdatePosition(trans.position);
                        break;
                case TRADE_TRANSACTION_REQUEST: if ((request.symbol == _Symbol) && (result.retcode == TRADE_RETCODE_DONE) && (request.magic == def_MAGIC_NUMBER)) switch (request.action)
                        {
                                case TRADE_ACTION_DEAL:
                                        (*manager).UpdatePosition(request.order);
                                        break;
                                case TRADE_ACTION_SLTP:
                                        (*manager).UpdatePosition(trans.position);
                                        break;
                                case TRADE_ACTION_REMOVE:
                                        (*manager).EraseTicketPending(request.order);
                                        break;
                        }
                        break;
        }
}

Sei que este código parece bastante estranho para muitos, principalmente aqueles acostumados, a usar outros métodos, para saber o que esta acontecendo, com as suas ordens e posições. Mas garanto, que se você compreender de fato, como esta função OnTradeTransaction funciona, irá adota-la em todos os seus EA, pois ela, de fato é mão na roda.

Mas para explicar como ela funciona, irei evitar ao máximo, ficar falando em termos de dados oriundos de arquivos de log. Pois se você tentar ver uma lógica seguindo arquivos, ou padrões encontrados em arquivos de log, você pode vim a ficar maluco. Isto por que, em alguns momentos, os dados não irão ter nenhum tipo de padrão. O motivo é que esta função, é uma tratadora de eventos. Estes eventos são originados do servidor de negociação. Sendo assim, esqueça os arquivos de log. E vamos focar em tratar os eventos, que são enviados do servidor de negociação, independentemente da ordem com que eles aparecem.

Aqui basicamente, iremos sempre estar olhando para dentro de 3 estruturas, e o conteúdo das mesmas. Estas estruturas são preenchidas pelo servidor de negociação. Você deve entender que qualquer coisa feita aqui, estará sendo um tratamento do que o servidor nos informou. As constantes de negociação, que estão sendo testadas aqui, são as que de fato precisamos no EA. Pode ser que você precise de mais constantes, dependendo do que você esteja projetando. Para saber quais são elas, bastará olhar na documentação, o seguinte ponto: Tipos de Transação de negociação. Lá você poderá ver que temos 11 enumerações diferentes, novamente, cada uma delas serve para algo especifico.

Note que em diversos pontos, estou utilizando uma variável, que estará referenciando a estrutura MqlTradeTransaction. Esta estrutura, é bastante complexa e completa, no que diz respeito ao que foi visto, e entendido pelo servidor. Mas para nos, isto depende de cada tipo de coisa que você de fato queira testar, analisar e saber. O que nos interessa, é o campo type desta estrutura, por conta disto, temos este sistema de chaveamento daqui. Neste código, estamos tratando apenas, e somente, de 3 tipos de transações feitas pelo servidor: TRADE_TRANSACTION_REQUEST, TRADE_TRANSACTION_ORDER_DELETE e TRADE_TRANSACTION_POSITION. Isto por que, eles estão sendo usados aqui.

Já que é bem difícil explicar qualquer um dos tipos de transação, sem ter um exemplo para isto. Então vamos começar pelo TRADE_TRANSACTION_POSITION. Já que ele conta apenas com uma única linha, conforme pode ser visto no fragmento abaixo:

                case TRADE_TRANSACTION_POSITION:
                        manager.UpdatePosition(trans.position);
                        break;

Este evento irá sempre acontecer, quando alguma coisa ocorreu em uma posição aberta. Mas não qualquer posição, a posição que sofreu alguma modificação, é informada pelo servidor, e passamos ela para a classe C_Manager, a fim que caso seja a posição que o EA esta observando, esta possa ser atualizada. Caso não seja, ela será ignorada. Veja que isto nos economiza muito tempo, tentando buscar qual foi a posição que de fato foi modificada.

A próxima na lista, é TRADE_TRANSACTION_ORDER_DELETE. Está tem um código que para muitos, pode ser bastante confuso, e sem nenhuma lógica. Este pode se visto no fragmento abaixo:

                case TRADE_TRANSACTION_ORDER_DELETE:
                        if (trans.order == trans.position) (*manager).PendingToPosition();
                        else (*manager).UpdatePosition(trans.position);
                        break;

Quando uma ordem se torna posição, esta ordem dispara um evento. Onde o servidor informa que ela foi removida. A mesma coisa acontece, e o mesmo evento é disparado, quando uma posição é fechada. A diferença entre um evento, que informa quando uma ordens se tornar posição, e uma posição foi fechada, está no valor informado pelo servidor.

Quando a ordem se torna posição, ela irá ter o mesmo valor informado no ticket da posição, sendo assim dissemos a classe C_Manager, que uma ordem se transformou em uma posição. Já quando a posição é fechada, estes valores serão diferentes, mas também pode acontecer, de você estar com uma posição em aberto, e uma ordem foi agregada, ou reduziu o volume aberto, em ambos os casos o valor informado em trans.order e trans.position será diferente. Neste caso, fazemos um pedido de atualização para a classe C_Manager.

Em alguns casos, este evento poderá estar acompanhado de um evento TRADE_TRANSACTION_POSITION. Mas não é sempre que isto acontece. Para reforçar a explicação, vamos separar ainda mais as coisas, pois entender este código é muito importante.

Vamos primeiro entender o caso de trans.order ser igual a trans.postion. E sim eles podem ser iguais. Então não fique imaginando, que eles sempre serão diferentes. Quando eles são iguais, o servidor dispara uma enumeração TRADE_TRANSACTION_ORDER_DELETE. Esta não vem sozinha, ela vem acompanhada de outras enumerações. Não precisamos tratar de todas, apenas esta em especifico. Pois o que o servidor estará nos dizendo, é que um ordem acabou de se tornar posição. Neste momento a ordem será fechada, e uma posição será aberta, com o mesmo valor de bilhete da ordem que foi fechada.

Mas pode acontecer, de o servidor não nos enviar uma enumeração TRADE_TRANSACTION_POSITION. Apesar de no primeiro momento, você pode ficar ali esperando esta enumeração, o servidor simplesmente não a disparou. Mas com toda a certeza, ele irá disparar a de remoção. Os valores indicados serão iguais, rigorosamente iguais. Neste caso você sabe, é uma ordem que estava no book, se transformou em posição. Mas no caso de uma ordem a mercado, a coisa funciona um pouco diferente, depois iremos ver este caso.

Agora caso de trans.order ser diferente de trans.position. O servidor irá também disparar outras enumerações. Mas da mesma forma, não fique contando que aquela especifica irá vim. Pode acontecer de o servidor não disparar ela. Mas irá disparar a que estou usando. Neste caso, isto indica que a posição acaba de ser fechada, por qualquer motivo, que não estou analisando aqui. Mas que estará sendo informado nas estruturas recebidas, pelo evento TradeTransaction. Por isto, é que este tratador de eventos é tão interessante. Pois você não precisa sair procurando as informações. Elas estão ali, basta você ir a estrutura correta, e ler o que está sendo informado. Entenderão o por que dos testes serem feitos da forma como estão sendo feitos ?!?!

Normalmente em programas que não usam este tratador de eventos. O programador criar uma laço que irá percorrer todas as posições abertas, ou ordens pendentes. Procurando saber qual foi executada, ou fechada. Isto é pura perda de tempo, fazendo com que o EA, fique ocupado com coisas completamente inúteis, que podem ser capturadas mais facilmente. Isto por que o servidor de negociação, já fez todo o trabalho pesado pra nos, nos informando qual ordem pendente foi fechada, qual posição foi aberta, ou qual posição foi fechada. E você ali, criando laços para saber destas informações.

Agora vamos a parte, que por sinal será mais longa de ser explicada, e mesmo assim, não irei abordar todos os casos. O motivo, é o mesmo do caso anterior. Não é simples explicar todos os casos, sem ter um exemplo para isto. Mas mesmo assim, o que será explicado aqui, já ajudará muita gente. Para facilitar, vamos capturar apenas e somente o fragmento que iremos estudar agora. Este pode ser visto logo abaixo:

                case TRADE_TRANSACTION_REQUEST: if ((request.symbol == _Symbol) && (result.retcode == TRADE_RETCODE_DONE) && (request.magic == def_MAGIC_NUMBER)) switch (request.action)
                        {
                                case TRADE_ACTION_DEAL:
                                        (*manager).UpdatePosition(request.order);
                                        break;
                                case TRADE_ACTION_SLTP:
                                        (*manager).UpdatePosition(trans.position);
                                        break;
                                case TRADE_ACTION_REMOVE:
                                        (*manager).EraseTicketPending(request.order);
                                        break;
                        }
                        break;

Esta enumeração, TRADE_TRANSACTION_REQUEST, é disparada em quase todos os casos. É bem raro ela não ser disparada. Então muitas das coisas que podemos fazer em termos de testes, pode ser feito dentro dela. Mas já que esta é uma enumeração, que o servidor dispara bastante, é preciso que filtremos ainda mais as coisas nela.

Mas se server de consolo, normalmente o servidor dispara esta enumeração, depois de algum requerimento feito pelo EA, ou pela plataforma. Isto quando o usuário, faz algo relacionado ao sistema de ordens. Mas não conte com isto sempre, pois as vezes, o servidor simplesmente dispara esta enumeração. As vezes sem um motivo aparente, por conta disto que temos que filtrar, o que esta sendo informado.

Primeiramente, filtramos o ativo, você pode usar qualquer uma das estruturas para saber isto, mas prefiro usar esta daqui. Depois, verificamos se o pedido foi aceito pelo servidor, para isto, usamos este teste daqui. E para terminar, testamos o numero mágico, a fim de filtrar ainda mais as coisas. Agora vem a parte onde muita gente acaba se embananando. Isto por que, não sabe como preencher o restante do código.

Quando usando um switch, para fazer a checagem do tipo de ação, não estamos, e não iremos analisar a ação feita no servidor. Não é isto que iremos de fato fazer. Na verdade, estaremos fazendo exatamente uma contra checagem, do que foi enviado para o servidor, seja pelo EA, seja pela plataforma. Os tipos são 6, e são bem clássicos. Vamos então a eles, que são uma enumeração chamada  ENUM_TRADE_REQUEST_ACTIONS. Para facilitar, veja a tabela abaixo, que é a mesma que pode ser vista na documentação. Mas a peguei emprestada, para ajudar na explicação, e irei colocar a descrição de uma forma um pouco diferente da encontrada na documentação.

Tipo de ação Descrição da ação
TRADE_ACTION_DEAL Coloca uma ordem de negociação para ser executada a mercado
TRADE_ACTION_PENDING Coloca uma ordem no book para ser executada nos parâmetros indicados
TRADE_ACTION_SLTP Modifica o valor de stop loss e take profit de uma posição
TRADE_ACTION_MODIFY Modifica os parâmetro de uma ordem pendente que esteja no book
TRADE_ACTION_REMOVE Remove uma ordem pendente que ainda esta no book
TRADE_ACTION_CLOSE_BY Fecha um posição.

Tabela 01

Se você de fato esta prestando atenção, ao que esta sendo programado deste o inicio desta serie de artigos. Mas no entanto, não prestou a devida atenção, a programação feita, precisará rever onde o campo, Tipo de ação presente na tabela 01, foi usado no nosso código. E não estou falando do tratador de eventos OnTradeTransaction, pois isto não vale. Existe um outro ponto, que estes enumeradores já foram utilizados. Onde ?!?! Na classe C_Orders.

Abra o código fonte e na classe C_Orders, olhe os seguintes procedimentos: CreateOrder, ToMarket, ModifyPricePoints ClosePosition. Desta forma, você verá em cada um deles, com exceção do procedimento ClosePosition, onde não estou usando a enumeração TRADE_ACTION_CLOSE_BY, todos os outros estão lá.

E por que isto é importante para nos aqui, no tratador de eventos OnTradeTransaction ?!?! O motivo é que estas enumerações, serão as mesmas que estarão, e poderão ser vista no momento em que formos analisar, que tipo de ação que a  enumeração TRADE_TRANSACTION_REQUEST, esta se referindo, por isto que no código do tratador de eventos OnTradeTransaction, você esta vendo as enumerações TRADE_ACTION_DEAL e a TRADE_ACTION_SLTP, além da TRADE_ACTION_REMOVE, por conta que são elas, que o EA deverá prestar atenção.

Mas e enquanto as outras ?!?! Para nosso proposito aqui, que será criar um EA automático, as outras não tem nenhuma importância, elas servem para outro tipo de coisa. Se você quer ver uma aplicação destes outro tipos, pode olhar este artigo: Desenvolvendo um EA de negociação do zero ( Parte 25 ) - Dado robustez ao sistema ( II ), onde mostro possibilidades de uso das demais enumerações. 

Então tudo bem, já que expliquei de onde veio aqueles cases, vamos entender o que cada uma delas esta fazendo, começando pelo que é visto abaixo:

        case TRADE_ACTION_DEAL:
                (*manager).UpdatePosition(request.order);
                break;

Quando uma ordem a mercado, é executada este enumerador é chamado, mas não somente neste caso, existe um segundo caso que ele também é chamado. Quando falei da enumeração TRADE_TRANSACTION_ORDER_DELETE, falei que existia um caso, em que os valores de trans.order e trans.postion, poderiam ser iguais, é este é o segundo caso, que esta enumeração TRADE_ACTION_DEAL, é disparada pelo servidor de negociação. Então podemos assim, adicionar o valor do ticket informado, como sendo agora uma posição em aberto. Mas repare que se acontecer qualquer coisa, como por exemplo, uma posição diferente ainda estiver aberta, acontecerá um disparo de erro, e este irá fazer com que o EA, finalize a sua execução, isto não é visto aqui, e sim no código UpdatePosition

O próximo código na sequencia, é visto no fragmento abaixo:

        case TRADE_ACTION_SLTP:
                (*manager).UpdatePosition(trans.position);
                break;

Este enumerador irá ser disparado, quando acontecer a mudança dos valores de limite, os conhecidos take profit e stop loss, ele simplesmente irá atualizar os valores de stop e take. Mas esta versão é muito básica, existem formas de deixar isto um pouco mais interessante, mas por hora está de bom tamanho. E a última enumeração que temos no código, é vista logo no fragmento abaixo:

        case TRADE_ACTION_REMOVE:
                (*manager).EraseTicketPending(request.order);
                break;

Este fragmento irá ser disparado, quando uma ordem é removida, precisando fazer como que a classe C_Manager, seja alertada a fim de permitir que o EA, possa conseguir enviar uma ordem pendente. Normalmente, uma ordem pendente não será removida do book. Mas pode ser que o usuário, ou operador tenha feito isto. Ao remover a ordem, seja acidentalmente, ou propositalmente do book, e caso o EA não comunique isto a classe C_Manager, ele ficará impedido de enviar uma outra ordem pendente.


Conclusão

Neste artigo, mostrei como você pode usar o sistema de tratamento de eventos, a fim de conseguir lidar com mais agilidade, e de uma forma melhor com questões envolvendo o sistema de ordens, a fim de deixar o EA mais rápido. Assim ele não precisará, ficar procurando informações a todo o momento. É verdade, que aqui ainda estamos lidando com um EA, que não conta com nenhum nível de automação. Mas em breve, iremos adicionar uma automação, mesmo que básica no sistema, a fim de ter um sistema de breakeven e trailing stop gerenciados pelo EA.

No anexo, você terá o código do EA que foi visto e explicado nestes 3 últimos artigos. Então estude com calma este código. Entenda como ele de fato funciona, pois isto irá lhe ajudar bastante nas próximas etapas.


Arquivos anexados |
DoEasy. Controles (Parte 17): Recorte de seções invisíveis de objetos, objetos-botões WinForms auxiliares com setas DoEasy. Controles (Parte 17): Recorte de seções invisíveis de objetos, objetos-botões WinForms auxiliares com setas
Neste artigo vamos criar funcionalidade para esconder seções de objetos que ultrapassam as margens de seu contêiner e vamos elaborar objetos-botões auxiliares com setas para usá-los como parte de outros objetos WinForms.
Como desenvolver um sistema de negociação baseado no indicador Awesome Oscilador Como desenvolver um sistema de negociação baseado no indicador Awesome Oscilador
Neste novo artigo da nossa série, nós aprenderemos sobre uma nova ferramenta técnica que pode ser útil em nossas negociações e ele é o indicador Awesome Oscillator (AO). Nós aprenderemos como desenvolver um sistema de negociação por este indicador.
DoEasy. Controles (Parte 18): Preparando a funcionalidade para rolagem de guias no TabControl DoEasy. Controles (Parte 18): Preparando a funcionalidade para rolagem de guias no TabControl
Neste artigo colocaremos os botões de controle de rolagem de cabeçalhos no objeto WinForms TabControl caso a fileira de cabeçalhos não se ajuste ao tamanho do controle, e faremos o deslocamento da linha de cabeçalho quando clicamos no cabeçalho de uma guia cortada.
Como desenvolver um sistema de negociação baseado no indicador Índice de Vigor Relativo Como desenvolver um sistema de negociação baseado no indicador Índice de Vigor Relativo
Um novo artigo em nossa série sobre como desenvolver um sistema de negociação pelo indicador técnico mais popular. Neste artigo, nós aprenderemos como fazer isso pelo indicador Índice de Vigor Relativo.