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

Aprendendo a construindo um EA que opera de forma automática (Parte 07): Tipos de Contas (II)

MetaTrader 5Negociação | 22 novembro 2022, 16:45
555 0
Daniel Jose
Daniel Jose

Introdução

No artigo anterior, Aprendendo a construindo um EA que opera de forma automática (Parte 06): Tipos de Contas (I), começamos a desenvolver, uma forma de garantir que um EA automático, funcione de forma adequada e dentro da linha. Ali foi criada uma classe, C_Manager, para servir como se fosse um gestor, ou sindico, que caso o EA venha a se comportar de maneira estranha, ou ficar mal comportado, este irá ser removido do gráfico. Sendo impedido de continuar a sua crise de loucura, e insanidade.

Naquele artigo, iniciei a explicação de como você faz para evitar que o EA, comece a disparar ordens pendentes, ou a mercado. Mas apesar do mecanismo, mostrado lá, ser suficientemente capaz de segurar o EA. Ainda assim temos alguns outros problemas envolvidos, na questão da interação entre o EA, e a classe C_Orders. E o problema esta principalmente, na conta do tipo NETTING, que será um dos temas que exploraremos neste artigo.

Mas de uma forma, ou de outra, você NUNCA, mas NUNCA mesmo, deve permitir que um EA automático, opere sem nenhum tipo de supervisão.

Não espere, que apenas o fato da programação, ser bem feita, e de forma bastante criteriosa, será o suficiente, pois não é. É preciso sempre ficar atento, ao que um EA automatizado, esta fazendo, e se ele sair da linha, removê-lo o mais rápido possível do gráfico, encerrando o que ele estava fazendo, a fim de evitar que as coisas fugam do controle.


As novas rotinas de interação entre o EA e a classe C_Orders

Tudo que foi visto nos artigos anteriores, nada irão valer, se o EA continuar podendo acessar a classe C_Orders, da forma como é visto abaixo:

//+------------------------------------------------------------------+
                void CreateOrder(const ENUM_ORDER_TYPE type, const double Price)
                        {
                                C_Orders::CreateOrder(type, Price, m_InfosManager.FinanceStop, m_InfosManager.FinanceTake, m_InfosManager.Leverage, m_InfosManager.IsDayTrade);
                        }
//+------------------------------------------------------------------+  
                void ToMarket(const ENUM_ORDER_TYPE type)
                        {
                                C_Orders::ToMarket(type, m_InfosManager.FinanceStop, m_InfosManager.FinanceTake, m_InfosManager.Leverage, m_InfosManager.IsDayTrade);
                        }
//+------------------------------------------------------------------+

Notem que mesmo tentando limitar, e controlar as coisas, o EA ainda assim, consegue enviar pedidos a mercado, e lançar novas ordens no book. Isto é uma quebra de segurança, pois se a classe C_Manager, durante a inicialização do EA, conseguiu impor que ele, seguisse certas regras, por que depois disto feito, permitimos que o EA, tenha total liberdade, para ficar lançando ordens no book, e efetuando operações a mercado ?!?! Temos que impor algum tipo de limite aqui, mesmo que este seja bastante simples. Muitas vezes, um simples teste, evita muitos tipos de problemas em potencial. Então vamos adicionar, algum controle nesta zona toda, que existe aqui, na forma de interação entre, o EA e o sistema de ordens, presente na classe C_Orders.

//+------------------------------------------------------------------+
                void CreateOrder(const ENUM_ORDER_TYPE type, const double Price)
                        {
                                if ((m_TicketPending > 0) || (m_bAccountHedging && (m_Position.Ticket > 0))) return;
                                m_TicketPending = C_Orders::CreateOrder(type, Price, m_InfosManager.FinanceStop, m_InfosManager.FinanceTake, m_InfosManager.Leverage, m_InfosManager.IsDayTrade);
                        }
//+------------------------------------------------------------------+  
                void ToMarket(const ENUM_ORDER_TYPE type)
                        {
                                ulong tmp;
                                
                                if (m_bAccountHedging && (m_Position.Ticket > 0)) return;
                                tmp = C_Orders::ToMarket(type, m_InfosManager.FinanceStop, m_InfosManager.FinanceTake, m_InfosManager.Leverage, m_InfosManager.IsDayTrade);
                                m_Position.Ticket = (m_bAccountHedging ? tmp : (m_Position.Ticket > 0 ? m_Position.Ticket : tmp));
                                if (PositionSelectByTicket(m_Position.Ticket)) SetInfoPositions(); else m_Position.Ticket = 0;
                        }
//+------------------------------------------------------------------+

Notem que agora, colocamos algumas regras para que o EA, não tenha tanta liberdade assim, a fim de usar a classe C_Orders. Vamos entender, o que está acontecendo aqui, começando pela função CreateOrderCaso tenhamos um valor, na variável que informa o ticket da ordem pendente, um novo pedido será negado, mas também será negado, se estivermos em uma conta HEDGING, com uma posição aberta. Simples assim. Mas, se estas condições permitirem, poderemos enviar um pedido, a fim de ter uma ordem pendente no book, e se o pedido for bem sucedido, teremos no final o ticket da ordem, que foi pendurada, sendo impedidos de enviar um novo pedido, e uma chamada posterior.

Agora vem o grande detalhe, que é na função ToMarket, neste caso, o pedido é efetivado a mercado, no melhor preço disponível, para que seja executado. Vamos então ver as condições, que permitem o envio de uma ordem a mercado. Este envio, somente será permitido, se não temos uma posição aberta, em uma conta do tipo HEDGING. Agora o detalhe: Caso seja possível fazer o envio da ordem a mercado, este será feito, mas não podemos, usar no primeiro momento, o valor retornado pela chamada. Isto por conta que o valor, pode ser diferente, do valor do ticket da posição, caso estejamos em uma conta NETTING. Se você colocar o valor diretamente no valor do ticket da posição, pode perder o valor real do ticket, pois talvez neste caso, o valor retornado será apenas temporário, por conta disto temos este novo teste. Aqui, caso estejamos em uma conta HEDGING, o valor retornado, pode ser armazenado tranquilamente no ticket de posição, mas, ele somente será armazenado, no caso de uma conta NETTING, se o ticket de posição estiver em zero, caso contrário o valor será ignorado. Quando isto estiver sido feito, podemos atualizar os dados da posição, ou zerar o valor do ticket de posição, mas tudo isto irá depender do teste, que será feito aqui neste ponto.


Problemas na conta NETTING em um EA automático

Existe um problema, potencialmente bastante danoso, que acomete um EA automático, que esteja sendo usado em uma conta NETTING. No artigo anterior, mostrei um problema, que poderia ocorrer na conta HEDGING. Mas agora vamos explorar, um problema diferente, no entanto, que somente acontece, nas contas NETTING. Se o EA, não tiver alguma trava, ele irá em algum momento, vim a explorar esta brecha, que muitos EA tem, e seus usuários não tem o devido conhecimento da brecha.

O problema é o seguinte: Em uma conta NETTING, o servidor de negociação, irá de forma automática, criando um preço médio da posição, conforme você vai mudando o preço de compra, em uma posição comprada, ou de venda. No caso de estar fazendo um SHORT, mas, de uma forma ou de outra, o preço médio, assim como o volume da posição, irá mudar.

Para um EA, que será operado de forma manual, não existe nenhum problema aqui, já que o operador, será responsável por enviar qualquer pedido ao servidor. O problema, é quando automatizamos o EA, neste caso, pode acontecer de ele disparar, ao começar a explorar, uma certa brecha, ou vulnerabilidade presente na sua programação. Detalhe: O problema, não esta no servidor de negociação, e tão pouco na plataforma MetaTrader 5, o problema esta no EA.

Irei tentar explicar, de uma forma que todos possam entender, mas o ideal, é que você tenha algum conhecimento, de como o mercado funciona, para que o entendimento seja facilitado. Mas irei tentar, deixar a questão, o mais clara possível.

Quando um EA automático, envia uma ordem de compra ou venda, a fim de abrir uma posição, ele o faz baseado em algum tipo de gatilho. Apesar de ainda não ter falado de gatilhos, logo chegaremos lá, mas o problema, não é o gatilho, em alguns casos, pode até ser, mas em grande maioria, não é o gatilho o responsável.

Uma vez que a posição esteja aberta, e isto em uma conta do tipo NETTING, o EA, pode por um motivo, ou outro, começar a usar a seguinte estratégia, fecha uma parte do volume, e abre outra. Desta forma, o preço médio começará a se deslocar, agora o problema, pode ser que o EA começe a fazer isto, de uma forma disparada, louco e alucinado. Caso isto aconteça, ele pode em muitos dos casos, perder grandes somas de dinheiro em questão de minutos, as vezes segundos, dependendo do volume negociado.

E este é o problema, o EA lança uma ordem, e depois fica ali, sem fechar a posição, lançando novos requerimentos ao servidor, de forma a mudar o preço médio. Isto muitas vezes sem que o operador, que está, ou deveria estar supervisionado o EA, de fato consiga perceber, já que o volume mostrado não se altera, mas o preço sim, e alguns operadores, não notam esta mudança no preço. Muitas das vezes, pode acontecer, da posição já esta dando um grande prejuízo, antes que o operador, de fato note que existe algo de errado ali.

Apesar de alguns EA automáticos, serem programados para usar este tipo de estratégia, e de forma intencional, alguma pessoas, tem este tipo de brecha no seu EA automático e não percebem, ou não sabem disto. Já que em alguns casos, e aqui entra a questão do gatilho, a pessoa, pode estar usando um tipo de gatilho, que faz o EA, comprar ou vender e em alguma situação de mercado bem especifico, o EA pode vim a fazer exatamente o que foi descrito acima. Mas, se a programação já previa isto, o operador irá ficar atento. Mas se não estava previsto este comportamento, o operador que estará supervisionando o EA, pode acabar se assustando ao ver o que o EA estará fazendo.

Por conta disto, não subestime o sistema, por mais que você confie, e acredite que o seu EA automático é seguro, não o subestime. Pois pode acontecer, de ele encontrar alguma brecha, que você não havia previsto no momento da programação do mesmo. Mas felizmente, existe uma forma relativamente simples de suplantar esta falha, pelo menos minimizando um pouco os seus danos. Então vamos ver como fazer isto, pelo menos na questão que envolve a programação.


Limitando o Volume de negócios no EA

A forma mais simples de reduzir, pelo menos um pouco, o problema descrito no tópico anterior, é limitando o volume que o EA pode de fato trabalhar. Não existe uma forma 100% ideal, mas podemos tentar, na medida do possível, gerar alguma forma, que possa nos trazer algum conforto. E a maneira mais simples, será limitando o volume que o EA consegue trabalhar, durante todo o tempo que ele estiver em execução.

Preste atenção a isto, não estou dizendo para limitar o volume em uma posição aberta, estou dizendo para limitar o volume que ele irá operar, durante todo o período. Ou seja, ele pode operar x vezes o volume mínimo, mas uma vez que ele tenha alcançado aquela quantidade, de volume mínimo, que ele poderia negociar, ele não poderá abrir uma nova posição. Não interessa se ele esteja com uma posição equivalente a 1 volume mínimo, e que podesse operar 50 vezes este volume, se ele já atingiu esta cota de 50, ele não poderá abrir mais posições, ou aumentar a posição já aberta.

A trava se baseia justamente nisto. Mas temos um detalhe aqui: Não existe uma trava 100% segura. Tudo irá depender do operador que estiver supervisionando o EA. Caso o operador de maneira inadvertida, desligue a trava, reiniciando o EA, este é que será, e deverá ser responsabilizado por qualquer falha que possa vim a ocorrer. Já que pode ter acontecido do EA estourar a cota, sendo removido do gráfico, e o operador vim recolocar o EA, de volta no gráfico. Neste caso, não existe trava que consiga segurar tão atitude.

Para começar a fazer isto, precisaremos de uma variável que seja estática, global e privativa, dentro da classe C_Manager, esta pode ser vista no fragmento abaixo:

static uint m_StaticLeverage;

Mas para inicializar uma variável estática dentro da classe, não podemos utilizar o constructor da classe, a inicialização no caso, irá ficar fora do corpo da classe. Mas normalmente dentro do arquivo de origem, no caso o arquivo de cabeçalho C_Manager.mqh, então fora do corpo da classe, você verá o seguinte código:

uint C_Manager::m_StaticLeverage = 0;

Ao ver este tipo de código em um arquivo, não precisa ficar assustado, é apenas uma variável estática sendo inicializada. Para quem não sabe, esta inicialização, se dá antes mesmo do constructor da classe ser de fato referenciado. Então em alguns tipos de código, isto é bastante útil. Mas o fato da variável esta sendo inicializada, fora do corpo da classe, não indica de fato que ela irá poder ser acessada fora da classe. Lembre-se: O motivo é o encapsulamento, todas a variáveis, devem ser declaradas como sendo privativas. Isto para que a sua classe, seja a mais robusta possível, evitando assim quebra se segurança, ou perda na confiabilidade do trabalho da classe.

Mas aqui temos outra questão igualmente importante: Por que usar uma variável global privativa, e estática, dentro da classe C_Manager ?!?! Não poderiamos usar uma variável, que não fosse estática, pelo menos ?!?! A resposta é NÃO, e o motivo, é que se por qualquer circunstância, a plataforma MetaTrader 5, vier a reinicializar o EA, qualquer dado armazenado fora de uma variável estática, será perdido. Atenção a isto, estou me referindo ao fato da plataforma MetaTrader 5 reinicializar o EA, e não no fato de você remover o EA, e depois coloca-lo de volta no gráfico. Isto são situações diferentes. No caso de o EA, ser removido do gráfico, e depois recolocado, qualquer informação, mesmo em variáveis estáticas, será perdida. Nestes casos a única forma, seria armazenar os dados em arquivo, e depois recuperar eles lendo o mesmo arquivo. Já a reinicialização, não implica de fato que o EA foi removido, ela pode acontecer em várias situações, e todas irão envolver o disparo de um evento DeInit, que irá chamar a função OnDeInit dentro do código. Esta reinicialização, não acomete apenas o EA, ela também ocorre com indicadores, por isto que Scripts, colocados no gráfico podem vim a ser removidos, caso ocorra um disparo de evento DeInit. Já que os scripts, não são reinicializados, eles não tem esta propriedade, eles simplesmente saem do gráfico e não são repostos automaticamente pelo MetaTrader 5.

Agora precisamos adicionar uma definição no código da classe, isto para identificar o máximo de vezes, que o volume mínimo, poderá ser usado ou operado pelo EA, esta definição é vista logo abaixo:

#define def_MAX_LEVERAGE       10

Uma vez que já temos onde armazenar, a quantidade de volume mínimo que o EA negociou, e temos uma definição máxima de volume que pode ser utilizado, podemos promover uma forma de contabilizar este volume. Esta é a parte mais interessante de ser feita. Mas antes de fazer isto, precisamos efetuar algumas mudanças no código, que foi visto no artigo anterior, como mostrado abaixo:

//+------------------------------------------------------------------+
                void CreateOrder(const ENUM_ORDER_TYPE type, const double Price)
                        {
                                if ((m_StaticLeverage >= def_MAX_LEVERAGE) || (m_TicketPending > 0) || (m_bAccountHedging && (m_Position.Ticket > 0))) return;
                                m_TicketPending = C_Orders::CreateOrder(type, Price, m_InfosManager.FinanceStop, m_InfosManager.FinanceTake, m_InfosManager.Leverage, m_InfosManager.IsDayTrade);
                        }
//+------------------------------------------------------------------+  
                void ToMarket(const ENUM_ORDER_TYPE type)
                        {
                                ulong tmp;
                                
                                if ((m_StaticLeverage >= def_MAX_LEVERAGE) || (m_bAccountHedging && (m_Position.Ticket > 0))) return;
                                tmp = C_Orders::ToMarket(type, m_InfosManager.FinanceStop, m_InfosManager.FinanceTake, m_InfosManager.Leverage, m_InfosManager.IsDayTrade);
                                m_Position.Ticket = (m_bAccountHedging ? tmp : (m_Position.Ticket > 0 ? m_Position.Ticket : tmp));
                                if (PositionSelectByTicket(m_Position.Ticket)) SetInfoPositions(); else m_Position.Ticket = 0;
                        }
//+------------------------------------------------------------------+

Ao adicionar estes testes, estou dizendo que se o volume contabilizado for maior que o volume máximo indicado, o EA não poderá efetuar a operação, aqui ainda existem alguns detalhes a ser resolvidos futuramente, mas por hora será feito assim. Notem também, que existe uma linha que foi riscada do código, isto por conta que ela irá atrapalhar o trabalho de contabilização.

Ok, agora precisamos de algumas rotinas para nos ajudar a nos comunicar com o EA, a fim de que esta classe C_Manager, possa gerenciar o que o EA estará fazendo. Para isto, iremos começar criando uma rotina bem discreta, mas no entanto extremamente necessária, esta pode ser vista no código a seguir:

inline void UpdatePosition(const bool bSwap = false)
                        {
                                int ret;
                                
                                if ((m_bAccountHedging) && (m_Position.Ticket > 0) && (bSwap)) SetUserError(ERR_Unknown);
                                m_Position.Ticket = ((m_Position.Ticket == 0) && (bSwap) ? m_TicketPending : m_Position.Ticket);
                                m_TicketPending = (bSwap ? 0 : m_TicketPending);
                                if (PositionSelectByTicket(m_Position.Ticket))
                                {
                                        ret = SetInfoPositions();
                                        m_StaticLeverage += (ret > 0 ? ret : 0);
                                }
                        }

Não subestime este código acima, apesar de ele parecer ser um código de baixo valor em termos de complexidade, ele é extremamente necessário para que a classe C_Manager, consiga gerenciar o que esta sendo feito pelo EA. Para entender este código profundamente, é necessário entender como, e quando o EA irá chamar este código, mas isto será visto depois, já que o procedimento dentro do EA, é bem diferente do que muitos fazem e seguem fazendo.

Apenas observando este código acima, podemos notar algumas coisas. Se estivermos, em uma conta HEDGING, e com uma posição em aberto, e ainda assim temos bSwap como sendo verdadeira, isto com toda a certeza é um erro. Apenas indicamos isto, pois o erro será tratado em outro local. Se não temos, nenhum valor sendo indicado na variável que contem o ticket da posição, e ainda assim temos bSwap sendo verdadeira. Isto indica que uma ordem pendente se tornou posição, mas se tinhamos uma posição já aberta, então a ordem pendente, e isto no caso de uma conta NETTING, modificou o volume da posição, e possivelmente o preço de entrada, este tipo de coisa é analisado neste linha daqui.

Se bSwap, veio sendo configurada como verdadeiro, significa que a ordem pendente deixou de existir, isto é ajustado aqui. Agora fazemos o seguinte teste: Verificamos se a posição está aberta, em caso afirmativo, executamos o procedimento que atualiza os dados da mesma, durante este procedimento de atualização, é calculado a diferença entre o volume, antes e depois da atualização, e este volume nos é retornado. Caso esta informação, que foi retornada seja positiva, indicando que o volume, ou fator de alavancagem aumentou. Este tipo de coisa é bem comum nas contas NETTING, mas nas contas HEDGING, o valor retornado sempre será o valor da alavancagem atual, iremos somar este valor retornado, ao valor que havia antes na variável estática. Assim temos uma forma de contabilizar o volume que o EA estará, ou já terá utilizado durante o tempo que ele esta sendo executado.

Mas sem pensar muito no assunto, você logo percebe que precisamos de uma outra rotina. Esta servirá para remover, ou fechar uma posição, e de fato precisamos disto, e esta rotina pode ser vista logo abaixo:

inline void RemovePosition(void)
                        {
                                if (m_Position.Ticket == 0) return;
                                if (PositionSelectByTicket(m_Position.Ticket)) ClosePosition(m_Position.Ticket);
                                ZeroMemory(m_Position);
                        }

Aqui não tem erro, é tiro certo, o EA estará fechando a posição aberta, ou esta simplesmente informando a classe C_Manager, que o servidor fechou a posição, seja por conta de que os limites ( take profit ou stop loss ) foram atingidos, seja por que ocorreu algo que fez a posição ser fechada, isto não importa. Mas se o EA chamar de forma equivocada esta rotina, sem que uma posição esteja aberta, iremos simplesmente retornar. Caso a posição esteja aberta, ela será fechada, e no final iremos limpar todos os dados presentes na região da memória, onde estão os dados da posição.

Apesar destas duas rotinas acima funcionarem bem, em varias situações diferentes, elas são muito pouco adequadas para o que de fato precisaremos fazer. Então não fique muito empolgado ao ver estas rotinas, e imaginar que elas são próprias para um EA automatizado, com um grande nível de robustez, pois como acabei de dizer, elas funcionam, isto é fato, mas não são adequadas, para o que quero mostrar como construir, precisaremos de outras rotinas melhores. No entanto, isto não será visto aqui neste artigo, e o motivo é que precisarei mostrar, o por que de usar um outro tipo de rotina, mas para que o entendimento seja adequado, é preciso mostrar o código do EA, e este será visto no próximo artigo.

Com base em todo este trabalho, já temos finalmente um sistema, em tese, robusto e bastante confiável, a ponto que podemos finalmente começar a automatizar o mesmo, de forma que ele possa operar sendo apenas supervisionado, por um operador humano. Mas notem que foi dito a palavra, EM TESE, isto por que, podem acontecer falhas ainda no sistema. Mas estas agora serão testadas utilizando a variável _LastError, de forma que podemos verificar se algo de errado aconteceu. E se a falha for grave, como as que usam a enumeração personalizada de erro, que foi vista no artigo anterior, devemos remover o EA do gráfico.

A remoção do EA do gráfico, não é uma das tarefas mais complicadas e serem executadas. Na verdade ela é bem simples de ser feita, bastando para isto efetuarmos uma chamada a função ExpertRemove. Mas esta tarefa, esta longe de ser o nosso maior, e verdadeiro problema. O problema mesmo, é o que fazer com a posição aberta e a ordem pendente ? Que provavelmente ainda existem. Este é o problema.

Na pior das hipóteses, você simplesmente fecha elas, ou as remove manualmente. Mas pensem no fato de que você pode estar com 2 ou mais EA executando de forma automática, em uma conta do tipo HEDGING, no mesmo ativo, e um destes EA simplesmente decide sair da linha, e é por conta disto, será removido do gráfico. Agora você tem que observar as ordens, e posições que poderão ser encontradas na caixa de ferramentas na aba negociação ( Figura 01 ), e procurar encerrar as operações que o EA mal criado havia aberto ou feito. No caso a frase: " mal criado", não quer dizer que o EA, não foi bem programado, mas creio que entenderam a ideia.

Figura 01

Figura 01 : Onde encontrar as ordens e posições na plataforma MetaTrader 5

Aqui a programação, pode nos ajudar um pouco, mas não espere milagres, ela apenas nos ajuda dentro das possibilidades da mesma. Então vamos ver como podemos usar a programação, de maneira a nos ajudar, neste caso especifico, onde um EA mal criado, resolveu sair por ai, cometendo as suas loucuras, e acabou sendo expulso do gráfico por suas maus hábitos e má conduta.


Usando o Destructor

O destructor, é uma função da classe, que não é de fato, assim como o constructor, chamado pelo código em qualquer ponto, na verdade um constructor, assim como seu parceiro, o destructor, é chamado apenas uma única vez durante todo o tempo de vida da classe. O constructor quando a classe nasce, e o destructor quando ela morre. Em ambas as situações, você como programador, dificilmente irá dizer quando uma classe irá nascer, e quando ela irá morrer. Normalmente quem faz isto é o compilador, mas em casos específicos, nos programadores, podemos dizer quando uma classe irá nascer, e quando ela irá morrer, isto usando algumas coisa no código. Mas a chamada para lhe dar vida, pode até acontecer por conta que parâmetros que usamos nos constructores, mas dizer via parâmetros, o que ela irá fazer quando morrer, isto não acontece.

Mas não se preocupe por enquanto com isto, quando formos ver o código do EA, você entenderá melhor isto.

Independente de quando a classe irá morrer, podemos dizer o que ela deverá fazer, quando isto acontecer. Desta forma, podemos dizer a classe C_Manager, que no momento em que ela for expulsar o EA do gráfico, que ela o faça, e elimine qualquer coisa que foi feita, e deixada como rastro pelo EA, ou seja, podemos fechar a posição aberta, e remover a ordem pendente que estiver no book. Mas lembre-se de confirmar isto observando a caixa de ferramentas, figura 01, pois pode ser que o EA foi expulso do gráfico, mas o destructor não conseguiu efetivar a sua tarefa.

Para de fato fazer isto, vamos adicionar um novo valor na enumeração de erro, este pode ser visto abaixo:

class C_Manager : private C_Orders
{
        enum eErrUser {ERR_Unknown, ERR_Excommunicate};
        private :

Este valor irá indicar ao destructor, que o EA esta sendo banido, excomungado, expulso a ponta pés, e a pedradas do gráfico, e tudo que estiver sobre a responsabilidade dele, deve ser desfeito. Para entender como o destructor poderá receber este valor, se ele não pode de fato receber nenhum valor via parâmetro, vamos ver o código do mesmo, este pode ser apreciado logo abaixo:

                ~C_Manager()
                {
                        if (_LastError == (ERR_USER_ERROR_FIRST + ERR_Excommunicate))
                        {
                                if (m_TicketPending > 0) RemoveOrderPendent(m_TicketPending);
                                if (m_Position.Ticket > 0) ClosePosition(m_Position.Ticket);
                                Print("EA was kicked off the chart for making a serious mistake.");
                        }
                }

Vejam que o código é bem simples, e estaremos testando o valor de _LastError, a fim de verificar o que pode ter acontecido. Então, caso o valor de erro seja o novo adicionado a enumeração, isto significa que o EA estará sendo expulso do gráfico por seu mal comportamento. Neste caso, se existir alguma ordem pendente, será enviado um pedido ao servidor para que a ordem seja removida, assim como também, se existir uma posição aberta, será enviado um pedido ao servidor para que a posição seja encerrada, e no final informamos no terminal o que aconteceu.

Mas lembre-se, isto não é de todo seguro, apenas estamos tentando obter algum tipo de ajuda da programação. Você como operador, deverá ficar atento e remover qualquer ordem, ou posição que o EA possa ter deixado para traz, ao ser expulso do gráfico.  Com isto concluímos este tópico que foi bem curtinho, mas imagino que tenha dado para passar o recado. Mas antes de terminar este artigo, vamos ver mais uma coisa, mas isto será visto no próximo tópico.


Criando um nível de tolerância a erros.

Se você observou todo o código deste artigo, e do anterior, e conseguiu compreender o que estou explicando, deve estar imaginando que a classe C_Manager, é muito dura com o EA, não admitindo nenhum tipo de falha, mesmo as menores. Sim, isto de fato esta acontecendo, mas podemos mudar um pouco isto, não de uma maneira a que o EA possa cometer falhas ou deslizes, mas existem alguns tipos de erros, e falhas que não são tão graves, e outros que se quer são culpa do EA.

Um deste erros, é quando o servidor reporta o erro TRADE_RETCODE_MARKET_CLOSED, isto pelo fato do mercado estar fechado. Este tipo de erro pode ser tolerado, já que não é culpa do EA. Um outro é o TRADE_RETCODE_CLIENT_DISABLES_AT, que é gerado por conta que o AlgoTrading, esteja desabilitado na plataforma.

Existem vários tipos de erros, que podem acontecer e não são gerados pelo EA, podem ser gerados por vários motivos, então simplesmente ser muito duro com o EA, o culpando por tudo que possa estar dando errado, não é uma atitude de fato justa. Desta forma precisamos criar algum meio de controlar, e tolerar alguns tipos de erros. Se o mesmo não nos parecer grave, podemos fazer com que ele seja ignorado, e o EA permaneça no gráfico, mas se ele de fato for um erro grave, podemos tomar algum tipo de decisão baseado no nível de gravidade do erro.

Desta forma dentro da classe C_Manager, criamos uma função publica, de forma que o EA possa chamá-la, quando este estiver na dúvida sobre a gravidade de um possível erro que possa ter acontecido. Então vamos ver do se que trata a tal função, seu código pode ser visto logo abaixo:

                void CheckToleranceLevel(void)
                        {
                                switch (_LastError)
                                {
                                        case ERR_SUCCESSreturn;
                                        case ERR_USER_ERROR_FIRST + ERR_Unknown:
                                                Print("A serious error has occurred in the EA system. This one cannot continue on the chart.");
                                                SetUserError(ERR_Excommunicate);
                                                ExpertRemove();
                                                break;
                                        default:
                                                Print("A low severity error has occurred in the EA system. Your code is:", _LastError);
                                                ResetLastError();
                                }
                        }

Aqui não estou dando uma solução definitiva, e tão pouco a mais 100% adequada. Estou apenas, e somente demonstrando como você deverá proceder, a fim de criar uma maneira de que exista, uma tolerância a erros no EA. No código acima, estou mostrando 2 exemplos, onde a tolerância será diferente.

Existe a possibilidade de acontecer um erro mais grave, e neste caso o EA terá ser ser expulso do gráfico. A maneira correta de fazer isto, é usando estas 2 funções, uma para seta o erro de expulsão, e a outra que manda o EA ser removido. Desta forma, o destructor da classe C_Manager, irá tentar limpar, ou desfazer, o que estava sendo feito pelo EA. E existe uma segunda maneira, onde o erro é mais leve. Neste caso, você simplesmente emite uma mensagem de alerta para o operador, e remove a indicação de erro, deixando o valor limpo, desta forma, se a chamada ocorrer sem que exista um erro, a função simplesmente irá retornar.

O ideal é que você promova o tratamento dos erros aqui, definindo um a um quais podem ser tolerados, e quais não serão. Uma outra coisa, é que apesar de não ter feito a adição desta chamada dentro da classe C_Manager, ou seja, a tolerância aos erros será bem alta, você não deve de fato fazer isto. Você poderá adicionar uma chamada a esta rotina acima, em determinados momentos, isto para evitar de esquecer de adicionar as chamadas no EA. Mas a principio, esta chamada será feita dentro do código do EA, em pontos bem específicos.


Conclusão

Este artigo complementa o artigo anterior, de modo que o conteúdo não ficasse muito cansativo de ser lido e compreendido. acredito que deu para cumprir esta tarefa.

Sei que muitos já gostariam de ver o código do EA, a fim de usar o que foi visto aqui, mas as coisas não são tão simples assim, quando o assunto é um EA automático. Então no próximo artigo, irei tentar passar um pouco da minha experiência no assunto onde abordaremos os cuidados, problemas e riscos envolvidos na codificação do EA ... o foco lá, será apenas, e somente o código do EA, já que com base nestes dois últimos artigos, terei muito o que mostrar no próximo artigo desta serie. Então estude com calma, e tente compreender como este sistema de classes funciona, pois a coisa irá ser bem densa no próximo artigo.


A matemática do mercado: lucro, prejuízo e custos A matemática do mercado: lucro, prejuízo e custos
Neste artigo, eu mostrarei como calcular o lucro ou prejuízo total de qualquer negociação, incluindo comissão e swap. Eu fornecerei o modelo matemático mais preciso e o usarei para escrever o código e compará-lo com o padrão. Além disso, eu também tentarei entrar na função principal da MQL5 para calcular o lucro e chegar ao fundo de todos os valores necessários da especificação.
DoEasy. Controles (Parte 16): Objeto WinForms TabControl - múltiplas fileiras de cabeçalhos de guias, modo esticamento de cabeçalhos consoante o tamanho do contêiner DoEasy. Controles (Parte 16): Objeto WinForms TabControl - múltiplas fileiras de cabeçalhos de guias, modo esticamento de cabeçalhos consoante o tamanho do contêiner
Neste artigo vamos continuar o desenvolvimento do controle TabControl, e trataremos da localização dos cabeçalhos das guias nos quatro lados do controle para todos os modos de tamanho de cabeçalho: "Normal", "Fixed" e "Fill To Right".
Ciência de Dados e Aprendizado de Máquina — Redes Neurais (Parte 02): Arquitetura das Redes Neurais Feed Forward Ciência de Dados e Aprendizado de Máquina — Redes Neurais (Parte 02): Arquitetura das Redes Neurais Feed Forward
Há detalhes a serem abordadas na rede neural feed-forward antes de finalizarmos este assunto, a arquitetura é uma delas. Vamos ver como nós podemos construir e desenvolver uma rede neural flexível para as nossas entradas, o número de camadas ocultas e os nós para cada rede.
Como desenvolver um sistema de negociação baseado no indicador Bull's Power Como desenvolver um sistema de negociação baseado no indicador Bull's Power
Bem-vindo a um novo artigo em nossa série sobre como desenvolver um sistema de negociação com base nos indicadores técnicos mais populares, aqui está um novo artigo sobre como aprender a desenvolver um sistema de negociação pelo indicador técnico Bull's Power.