English Русский 中文 Español Deutsch 日本語
preview
Aprendendo a construindo um Expert Advisor que opera de forma automática (Parte 09): Automação (I)

Aprendendo a construindo um Expert Advisor que opera de forma automática (Parte 09): Automação (I)

MetaTrader 5Negociação | 8 dezembro 2022, 12:48
1 197 7
Daniel Jose
Daniel Jose

Introdução

No artigo anterior,  Aprendendo a construindo um EA que opera de forma automática (Parte08): OnTradeTransaction, expliquei como você pode tirar proveito da plataforma MetaTrader 5, fazendo uso uma função de tratamento de evento, bastante curiosa. Mas aqui, iremos fazer algo diferente, iremos adicionar o primeiro nível de automação para o EA.

Mas diferente de muitos dos mecanismos, que podem ser encontrados por ai. Aqui irei mostrar um mecanismo que não irá sobrecarregar o EA, ou mesmo a plataforma. Mas o mecanismo aqui, irá poder ser utilizado inclusive em contas do tipo HEDGING, apesar de ele ser focado primeiramente, para contas do tipo NETTING.

Neste primeiro momento, iremos começar com um sistema bem simples. O que usa ordens do tipo OCO. Mas iremos expandir a coisa no futuro, de forma a usar um sistema ainda mais robusto e interessante, para quem gosta de operar mercados muito voláteis, onde o risco de ter a ordem pulada é bastante elevado.


Criando o mecanismo de Breakeven e Trailing Stop para ordens OCO

Um sistema de ordens oco, para quem não sabe do que se trata, é um sistema na qual o take profit e stop loss, estão definidos na própria ordem, ou posição. Caso a ordem seja removida, ou a posição fechada, estas ordens de take profit ou stop loss, irão ser finalizadas junto.

Estas ordens, tanto a de take profit, quanto a de stop loss, podem ser removidas, ou adicionadas a qualquer momento. Mas para fins práticos, e não complicar desnecessariamente o código, e também o artigo, iremos assumir, que elas serão sempre criadas no momento que o EA, enviar a ordem para o servidor de negociação. E serão finalizadas, quando um dos limites for atingido, fechando assim a posição.

Para criar o mecanismo de gatilho, iremos voltar nossa atenção primeiramente para a classe C_Manager. Nela já temos praticamente quase tudo pronto, e preparado para receber o sistema de gatilho, a fim de promover o breakeven e o trailing stop.  Então vamos adicionar, primeiramente, a rotina que irá gerar o breakeven de uma posição, esta rotina é vista na integra no código a seguir:

inline void TriggerBreakeven(void)
                        {
                                if (PositionSelectByTicket(m_Position.Ticket))
                                        if (PositionGetDouble(POSITION_PROFIT) >= m_Trigger)
                                                m_Position.EnableBreakEven = (ModifyPricePoints(m_Position.Ticket, m_Position.PriceOpen, m_Position.PriceOpen, m_Position.TP) ? false : true);
                        }

Muito provavelmente, você estaria esperando uma rotina consideravelmente mais complexa que a mostrada. Mas acredite, esta simples rotina, é de fato capaz de promover o breakeven de uma posição. Então se você não consegue entender como isto é possível. Vamos entender como de fato a coisa acontece, a ponto de não precisamos nada além, do que esta simples rotina.

A primeira coisa que fazemos, é executar uma chamada a PositionSelectByTicket. Esta função irá carregar todas a informações atualizadas, a respeito da posição aberta. Desta forma, podemos fazer a próxima coisa, que é usar a função PositionGetDouble, com o argumento POSITION_PROFIT, a fim conseguir obter o valor mais atual, em termos de financeiro, que foi carregada pela chamada PositionSelectByTicket. Comparamos este valor, com um que é informado durante a inicialização da classe, na chamada do constructor da mesma.

Caso este valor, seja maior ou igual ( este é o tal gatilho ), isto indica que podemos fazer o breakeven. Então enviamos o valor do preço, onde a posição foi aberta, para dentro da rotina presente na classe C_Orders. Se foi bem sucedida esta interação, a classe irá indicar que o breakeven ocorreu.

Bem simples esta função, não é mesmo ?! No entanto, esta função estará definida na clausula privativa, o que de fato será acessado pelo EA, é a função de trailing stop. Esta pode ser vista na integra logo abaixo:

inline void TriggerTrailingStop(void)
                        {
                                double price;
                                
                                if ((m_Position.Ticket == 0) || (m_Position.SL == 0)) return;
                                if (m_Position.EnableBreakEven) TriggerBreakeven(); else
                                {
                                        price = SymbolInfoDouble(_Symbol, (GetTerminalInfos().ChartMode == SYMBOL_CHART_MODE_LAST ? SYMBOL_LAST : (m_Position.IsBuy ? SYMBOL_ASK : SYMBOL_BID)));
                                        if (MathAbs(price - m_Position.SL) >= (m_Position.Gap * 2))
                                                ModifyPricePoints(m_Position.Ticket, m_Position.PriceOpen, (m_Position.SL + (m_Position.Gap * (m_Position.IsBuy ? 1 : -1))), m_Position.TP);
                                }
                        }

Uma vez, que o breakeven foi disparado e executado, na próxima vez que o EA chamar a função TriggerTrailingStop, o que iremos testar, é a possibilidade, ou não de um movimento do stop loss.

Mas, observem antes disto, onde a função de breakeven, é de fato chamada. O movimento do trailing stop, tem um gatilho um pouco mais complicado, que o movimento do breakeven. Aqui iremos fazer algo um pouco diferente. Já que diferente do breakeven, que independe do ativo, do modo de plotagem e tipo de mercado, onde a única coisa que importa, é o nível de lucro da posição. Aqui no trailing stop, precisamos saber duas coisas: O tipo de plotagem, e o tipo de posição.

Alguns programadores de EA, que desenvolvem o gatilho para trailing stop, as vezes não se preocupam, com o tipo de plotagem. De certa forma, em alguns casos, isto é o mais correto a ser feito. Já que se o ativo ter no seu histórico, incidência de um spread ( diferença entre o melhor vendedor e o melhor comprador ) relativamente alto, mesmo em um sistema de plotagem LAST, devemos ignorar o modo de plotagem. Pois se o movimento, for dentro do spread, é bastante provável, que iremos ter problemas, pois a ordem de stop loss, irá ficar em um ponto errado.

Por conta disto, o correto estudo, e entendimento do ativo, irá lhe ajudar a projetar melhor este tipo de gatilho. Mas, a ideia aqui, é capturar o preço do ativo, não importa a forma como você faz para capturar ele. O que é preciso de fato, é ter este valor em mãos. Uma vez feito, isto iremos subtrair este preço, do ponto onde o stop loss está. Neste caso não importa, se estamos vendendo ou comprando, o valor será automaticamente corrigido, a fim de termos um valor, em termos de pontos. Não um valor financeiro, o valor aqui é em pontos. Este valor precisará ser, pelo menos, duas vezes maior do que a quantidade de pontos, que iremos sempre calcular, a cada atualização feita no servidor de negociação. Se isto for alcançado, iremos mover a posição, onde o stop loss está, na quantidade de pontos do gap. Assim a distancia, neste exato momento, irá se manter sempre a mesma, e o ciclo irá recomeçar.

Este mecanismo de gatilho, funciona perfeitamente bem em qualquer tipo de situação. Com um detalhe importante: Ele é super leve, e é bem rápido de ser executado. Isto é importante. Pense nestes gatilhos, como se fossem uma ratoeira. Se o mecanismo for muito complicado, ou tiver um tempo de execução longo. O rato acabará pegando o queijo, e fugindo antes que a ratoeira, seja acionada de fato.

Entendendo isto, você precisa entender, uma outra coisa: Qual deverá ser a rotina, ou tratador de evento, que precisaremos usar, a fim de chamar estas rotinas acima ?! Talvez muitos pensem: O tratador de evento, deverá ser a rotina OnTick. Certo ?! ERRADO. E para explicar isto, vamos para o próximo tópico.


Por que não devemos usar OnTick como rotina de chamada para gatilhos ?!

Sei que é tentador, é muito tentador de fato, usar a rotina OnTick, como uma forma de chamar qualquer rotina. Mas isto, é sem duvida, o maior dos erros, que você pode cometer. O correto, é usar o evento OnTime, como mostrado 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();
        EventSetMillisecondTimer(100);

        return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
        delete manager;
        delete mouse;
        EventKillTimer();
}
//+------------------------------------------------------------------+
void OnTick() { }
//+------------------------------------------------------------------+
void OnTimer()
{
        (*manager).TriggerTrailingStop();
}
//+------------------------------------------------------------------+

Note que, no evento OnInit, definimos um valor curto, para que o evento OnTime seja gerado. Fazemos isto, usando a função EventSetMillisecondTimer. Você pode definir qualquer valor, a partir de 50 milissegundos, isto para a maioria dos casos. Mas você, deve também, não se esquecer, de chamar a rotina EventKillTimer. Isto já dentro do evento OnDeInit. Assim o EA irá liberar o evento OnTime, não fazendo a plataforma MetaTrader 5, fique gerando um evento. Mesmo que a plataforma, consiga perceber, e pare de gerar o evento, é de boa prática, liberar o sistema. Então no caso, a cada 100 milissegundos, ou 10 vezes em 1 segundo, mais ou menos. Teremos a verificação, do nosso gatilho, mostrado no tópico acima.

Mas isto não responde a pergunta: Por que, não devemos, usar a rotina, de tratamento de eventos, OnTick, como chamadora, de nossos gatilhos ?! De fato a explicação acima, não responde a esta questão. Mas vamos nos basear nela, para entender, por que não devemos fazer isto.

O evento OnTick, é disparado a cada tick, que o servidor negociar. Ao olhar o gráfico de barras, mesmo no tempo gráfico de 1 minuto, você não terá a real noção, do que de fato esta acontecendo. Para isto será preciso descer ao nível, do que é feito pelos HFT ( high frequency Trade ), ou mais conhecidos como: Robôs de institucionais.

O que as pessoas não sabem, ou desconhecem, é que não dá, para um EA, rodando em uma plataforma, em um computador, e muitas vezes, a centenas de quilômetros do servidor de negociação. Ter a mínima, menor, ou mais remota chance, de se equiparar ao HFT, que estará rodando em um servidor dedicado, a poucos metros do servidor. Isto por conta de uma coisa chamada latência. Quem é fã de jogos on-line, vai saber do que estou falando, mas aqueles que não são, saiba que a latência, será muito maior, do que a frequência de negócios, que estará sendo executado pelo servidor de negociação. Ou seja, esqueça o fato de desejar ter o mesmo desempenho que um HFT, você não vai conseguir isto.

Então voltamos a questão do evento OnTick. Em uma hipótese mediada, em apenas 1 milissegundo, pode acontecer de o servidor disparar, mais de 10 eventos desta natureza. Isto de forma mediana, se esta quantidade de eventos, chegar a plataforma, a fim de disparar, todos os eventos que o servidor disparou. Assim que seu EA entrar em funcionamento, a plataforma irá travar. Isto por que ela, irá ficar totalmente ocupada em tratar, muito mais eventos, do que o seu processador, ou seja, lá como você esteja fatorando as coisas, irá conseguir executar, devida a grande quantidade de chamadas, a uma mesma função.E no caso será, o gatilho de disparo do trailing Stop.

Mas pode ser que, durante um tempo, isto não aconteça de fato. E a plataforma continue rodando lisinha. Mas assim que o sistema detectar que estamos posicionados, e começar a verificar o gatilho de disparo. Poderemos ter sérios problemas, já que a probabilidade, de a plataforma travar será muito grande.

E esta será cada vez maior, se a volatilidade do ativo subir rapidamente, por conta de alguma coisa que aconteceu no mercado. Isto é especialmente comum, em ativos como índices futuros, sejam eles quais forem. Então, não tente usar o evento OnTick, como uma forma de disparar gatilhos. Esqueça este tratador de eventos para o EA. Este tratador está presente, não para que nos, meros mortais o usemos. Ele está ali, para que os tais HFT, consiga uma forma de acompanhar o servidor de negociação, pois eles sim, conseguem fazer isto. Mas nos não fazemos nem cocegas, nestes monstros devoradores de números.

Então a maneira mais adequada, de realmente fazer a verificação de um sistema de gatilhos, é sempre usando o evento OnTime. Isto de maneira que este seja configurado, em um tempo baixo o suficiente, para que não sofra perda de qualidade. Mas ao mesmo tempo, que de oportunidade de todos os gatilhos serem testados, analisados e executados. Isto de maneira correta, sem sobressaltos. Assim, você terá de fato um EA seguro, robusto, tranquilo e confiável.

Existe uma outra questão sobre gatilhos, ainda dentro deste assunto do Trailing stop, que vale a pena você também vim a saber. Alguns sistema de EA, de fato não efetuam o breakeven antes de iniciar o trailing stop. Estes já usam o trailing stop, a partir do momento que a posição é aberta. Isto pode parecer meio maluquice. Mas na verdade, o detalhe é que o sistema operacional, ou setup, já tem no seu modo de agir, este tipo de conceito. Neste caso, o sistema irá se parecer muito com o que mostrei. Mas no tentando, a diferença será justamente a distância do gap a ser utilizado. No entanto, o conceito irá permanecer igual.

Mas além deste modelo, existe um outro, onde não temos de fato um trailing stop, ou breakeven. Temos um outro tipo de sistema. Onde iremos garantir uma saída honrosa, em caso a operação comece a ir contra nossa posição. Trata-se de um outro tipo de gatilho, mas isto será visto em outra oportunidade.


Trailing Stop e Breakeven usando ordem pendente.

O sistema que foi mostrado anteriormente, funciona muito bem quando a ideia é ter uma posição, cujo sistema de ordens é do tipo OCO. Mas existe um problema neste sistema de ordens OCO. O problema é a volatilidade. Quando ela esta muito alta, tais ordens simplesmente irão, ou poderão ser puladas. Não importa o que se diga. Elas irão, ou poderão ser puladas. Caso isto aconteça, você pode ficar em maus lenções.

No entanto, existe uma "solução" ( atenção as aspas ), para este tipo de caso. Usar uma ordem pendente, de maneira a garantir uma saída de qualquer maneira. O problema nesta "solução", é que ela não pode ser implementada, em um sistema do tipo HEDGING. Ou melhor dizendo, até pode ser implementada, mas não com este EA, que estou apresentando. Se você tentar fazer isto, em uma conta HEDGING, o EA irá ser expulso do gráfico. Isto por que, para a classe C_Manager, ele estará cometendo um erro grave. Mas se você fizer algumas adaptações na classe C_Manager, a ponto de que o EA possa ter 2 posições abertas, em mãos contrárias, em uma conta HEDGING, é possível fazer a mesma coisa, que irei mostrar como fazer, no caso de você estiver usando uma conta NETTING.

Mas se você parar para pensar, não faz sentido abrir um posição, na mão contrária em uma conta HEDGING, caso o servidor de ordens, capture a ordem pendente neste caso, o melhor será mandar o servidor, fechar ambas posições. Isto faria, com que o EA, em uma conta HEDGING, tivesse o mesmo comportamento do EA, em um conta NETTING. Encerrar a posição aberta, usando assim uma ordem pendente.

Gostou da ideia ?! Pois bem, antes que você se empolgue, vamos a alguns detalhes, e problemas com esta ideia.

O primeiro ponto, é que a ordem pendente, não necessariamente será executada no ponto que você estará indicando. Lembre-se uma ordem pendente, irá em busca do preço, esteja onde ele estiver. Um outro problema, é que se ocorrer alguma falha séria no EA, e a posição, ou ordem, sejam canceladas ou fechadas, a outra ponta, pode ficar no vazio.

Mas existe uma vantagem, se tudo estiver ocorrendo bem, e você vim a ficar sem conexão com o servidor. O fato de você ter um ordem pendente, na mão contrária, e no mesmo volume, irá garantir que a posição, ou seja fechada ( contas NETTING ), ou o preço seja travado ( contas HEDGING ).

Como você pode ver, existem vantagens e desvantagens em usar este método.

Para fazer uso deste método, precisamos fazer algumas pequenas modificações, na classe C_Manager. Tais mudanças serão simples de serem entendidas, e poderão se desfeitas, caso você não as queira. Mas aqui, devo ressaltar um detalhe: Se você for usar este método, cuidado para não remover as ordens pendentes, que foram colocadas pelo EA. Se você fizer isto, irá ficar sem a perna responsável, por fechar a operação.

Para este sistema não é aconselhável  permitir que ele seja modificado, pelo usuário do sistema, ou seja, uma vez que o código tenha sido compilado, não é adequado, você poder desligar ele do EA. Ele deverá permanecer ligado o tempo todo, ou desligado o tempo todo. Para fazer isto, iremos criar uma nova definição no código da classe C_Manager, esta pode ser vista logo abaixo:

//+------------------------------------------------------------------+
#define def_MAX_LEVERAGE                10
#define def_ORDER_FINISH                false
//+------------------------------------------------------------------+

Quando esta definição, estiver como sendo verdadeiro ( true ), o sistema irá utilizar o método de stop via ordem pendente, ou seja, você não terá mais um ponto de take profit, pois isto irá complicar muito as coisas, podendo gerar uma perna manca. Se esta mesma definição, estiver como falso ( false ), você irá utilizar o método de de breakeven e trailing stop, visto no tópico inicial do artigo. Assim estará usando um sistema de ordem OCO. Por padrão, irei deixar ela como falso. Se desejar usar o método explicado neste tópico, mude este valor de false para true, e compile o EA.

Precisamos agora de modificar os procedimentos, que lançam as ordens no mercado, ou criam as ordens pendentes. Estas ficaram conforme mostrado logo a seguir:

//+------------------------------------------------------------------+
                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, (def_ORDER_FINISH ? 0 : m_InfosManager.FinanceStop), (def_ORDER_FINISH ? 0 : 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, (def_ORDER_FINISH ? 0 : m_InfosManager.FinanceStop), (def_ORDER_FINISH ? 0 : m_InfosManager.FinanceTake), m_InfosManager.Leverage, m_InfosManager.IsDayTrade);
                                m_Position.Ticket = (m_bAccountHedging ? tmp : (m_Position.Ticket > 0 ? m_Position.Ticket : tmp));
                        }
//+------------------------------------------------------------------+

É preciso modificar estes pontos, para que os preços de take profit e stop loss, não sejam de fato criados. Fazendo assim, o servidor entenderá que estes preços não serão criados, e você terá uma ordem, sem limites de ganho ou perda. Você pode até ficar, apavorado com o fato de enviar uma ordem a mercado, e esta não conter de fato um stop loss, ou adicionar uma ordem pendente, que também não tem um ponto de stop loss. Mas não tenha tanto receio, você precisa de fato experimentar o sistema, para entender o que estará acontecendo. Feito isto, a próxima mudança a ser feita, é vista logo abaixo:

                void PendingToPosition(void)
                        {
                                ResetLastError();
                                if ((m_bAccountHedging) && (m_Position.Ticket > 0))
                                {
                                        if (def_ORDER_FINISH)
                                        {
                                                if (ClosePosition(m_Position.Ticket)) ZeroMemory(m_Position.Ticket);
                                                ClosePosition(m_TicketPending);                                         
                                        }else 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();
                        }

Aqui, quando o EA informar que uma ordem pendente, se transformou em uma posição, teremos um problema, caso estejamos em uma conta do tipo HEDGING, e com uma posição já aberta. Neste caso, se a definição estiver como falsa, teremos o lançamento de uma mensagem de erro grave. Caso a definição esteja como verdadeira, iremos enviar o pedido de fechamento da posição original, e zeramos a região da memória dela. Fechamos também a posição recém aberta. Notem que se a conexão, com o servidor estiver em bom estado, teremos sucesso no fechamento de ambas posições, zerando assim a nossa exposição no mercado.

Agora precisamos fazer com que o sistema, crie uma ordem pendente, que será usada como sendo uma ordem de encerramento da posição, ou seja, um stop loss, que ficará no book de ofertas. Este ponto, talvez é de fato, o mais critico de todo o sistema, já que se ele não for bem planejado, você terá sérios problemas por conta, que ficará sem um ponto de stop. Por conta disto, você tem que ficar atento, ao que o EA estará fazendo observando, a janela abaixo:

Figura 01

Figura 01 : Ponto onde vemos as ordens pendentes e posições abertas

Esta janela, mostrada na figura 01, deverá sempre estar aberta, a fim de que você possa analisar o que o EA esta de fato fazendo no servidor. Não confie, cegamente no EA, por mais que ele pareça confiável, desconfie sempre, das intenções macabras do EA.

Então, para que o EA consiga ter um ponto de stop loss, a classe C_Manager irá ter que criar a ordem pendente, esta é criada da seguinte maneira:

                void UpdatePosition(const ulong ticket)
                        {
                                int ret;
                                double price;
                                
                                if ((ticket == 0) || (ticket != m_Position.Ticket)) return;
                                if (PositionSelectByTicket(m_Position.Ticket))
                                {
                                        ret = SetInfoPositions();
                                        if (def_ORDER_FINISH)
                                        {
                                                price = m_Position.PriceOpen + (FinanceToPoints(m_InfosManager.FinanceStop, m_Position.Leverage) * (m_Position.IsBuy ? -1 : 1));
                                                if (m_TicketPending > 0) if (OrderSelect(m_TicketPending))
                                                {
                                                        price = OrderGetDouble(ORDER_PRICE_OPEN);
                                                        C_Orders::RemoveOrderPendent(m_TicketPending);
                                                }
                                                m_TicketPending = C_Orders::CreateOrder(m_Position.IsBuy ? ORDER_TYPE_SELL : ORDER_TYPE_BUY, price, 0, 0, m_Position.Leverage, m_InfosManager.IsDayTrade);
                                        }
                                        m_StaticLeverage += (ret > 0 ? ret : 0);
                                }else
				{
					ZeroMemory(m_Position);
                                	if (def_ORDER_FINISH)
					{
						RemoveOrderPendent(m_TicketPending);
						m_TicketPending = 0;
					}
				}
                                ResetLastError();
                        }

Primeiramente, verificamos se o sistema de ordem esta sendo indicado como verdadeiro. No caso de ser esta a condição, calculamos um ponto de preço, para começar a montagem, e o uso da ordem pendente como uma forma de estopar a posição. Verificamos, se estamos com uma ordem já posicionada, se isto for verdadeiro, iremos capturar o preço onde ela está, e depois remover a mesma do book. Mas de uma forma ou de outra, iremos tentar criar uma nova ordem pendente, ou seja, agora se tudo estiver correto, teremos uma ordem pendente no book, que servirá como sendo uma ordem de stop loss.

Atenção:Caso a posição seja fechada, a ordem pendente deverá ser finalizada junto, isto é conseguido com estas linhas de código.

Agora precisamos mudar a função SetInfoPosition, de forma a ter uma correta indicação, de que se precisaremos, ou não fazer o breakeven, ou se já poderemos partir para o trailing stop logo de cara. A nova função ficará conforme mostrado abaixo:

inline int SetInfoPositions(void)
                        {
                                double v1, v2;
                                int tmp = m_Position.Leverage;
                                
                                m_Position.Leverage = (int)(PositionGetDouble(POSITION_VOLUME) / GetTerminalInfos().VolMinimal);
                                m_Position.IsBuy = ((ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE)) == POSITION_TYPE_BUY;
                                m_Position.TP = PositionGetDouble(POSITION_TP);
                                v1 = m_Position.SL = PositionGetDouble(POSITION_SL);
                                v2 = m_Position.PriceOpen = PositionGetDouble(POSITION_PRICE_OPEN);
                                if (def_ORDER_FINISH) if (m_TicketPending > 0) if (OrderSelect(m_TicketPending)) v1 = OrderGetDouble(ORDER_PRICE_OPEN);
                                m_Position.EnableBreakEven = (def_ORDER_FINISH ? m_TicketPending == 0 : m_Position.EnableBreakEven) || (m_Position.IsBuy ? (v1 < v2) : (v1 > v2));
                                m_Position.Gap = FinanceToPoints(m_Trigger, m_Position.Leverage);

                                return m_Position.Leverage - tmp;
                        }

Aqui fazemos uma sequencia de testes, a fim de capturar o preço onde está a ordem pendente. Mas caso o ticket da ordem pendente, ainda não tenha por algum motivo sido criado, este irá fazer com que o indicador de breakeven, seja adequadamente iniciado para o nosso proposito.

Até o momento, nem o breakeven, tão pouco o trailing stop, de fato podem ser usados no sistema, onde uma ordem pendente será utilizada, como ponto de stop. Para promover este sistema, não precisamos de fato do gatilho, pois ele já esta montado. O que precisamos, é do sistema de movimentação da ordem pendente, seja implantado no código. Então para que o breakeven, faça a movimentação, iremos fazer a seguinte adição no procedimento do sistema:

inline void TriggerBreakeven(void)
                        {
                                double price;
                                
                                if (PositionSelectByTicket(m_Position.Ticket))
                                        if (PositionGetDouble(POSITION_PROFIT) >= m_Trigger)
                                        {
                                                price = m_Position.PriceOpen + (GetTerminalInfos().PointPerTick * (m_Position.IsBuy ? 1 : -1));
                                                if (def_ORDER_FINISH)
                                                {
                                                        if (m_TicketPending > 0) m_Position.EnableBreakEven = !ModifyPricePoints(m_TicketPending, price, 0, 0);
                                                }else m_Position.EnableBreakEven = !ModifyPricePoints(m_Position.Ticket, m_Position.PriceOpen, price, m_Position.TP);
                                        }
                        }

Na versão anterior desta função, responsável por executar o breakeven. O preço onde a ordem de stop seria colocada, era exatamente o preço de abertura da posição. Como sei que muitos operadores, gostam de sempre sair com algum lucro, mesmo que pequeno. Decidi modificar a função, de maneira que ao executar o gatilho do breakeven, o EA irá posicionar a ordem de saída, 1 tick deslocado no preço de abertura. Assim você irá sair com no mínimo 1 tick de lucro.

Este sistema funciona, para qualquer ativo ou tipo de mercado, já que estamos usando dados do próprio ativo, a fim de saber onde deverá ficar a linha de stop.

Uma vez isto feito, verificamos se estamos usando o modelo de stop baseado em uma ordem pendente. Caso isto seja verdadeiro, verificamos se temos algum valor na variável de ticket pendente. Se novamente isto for verdadeiro, enviamos um requerimento, para que o ponto onde a ordem esteja, seja modificado para a nova posição. Caso estejamos usando um sistema baseado em ordens OCO, usaremos o método visto anteriormente. Esta questão, dos testes, pode parecer bobagem, mas isto evita que façamos pedidos, ou enviemos requerimentos com alguma informação inválida para o servidor.

Agora vamos ver como fica o procedimento de trailing stop, para este caso:

inline void TriggerTrailingStop(void)
                        {
                                double price, v1;
                                
                                if ((m_Position.Ticket == 0) || (def_ORDER_FINISH ? m_TicketPending == 0 : m_Position.SL == 0)) return;
                                if (m_Position.EnableBreakEven) TriggerBreakeven(); else
                                {
                                        price = SymbolInfoDouble(_Symbol, (GetTerminalInfos().ChartMode == SYMBOL_CHART_MODE_LAST ? SYMBOL_LAST : (m_Position.IsBuy ? SYMBOL_ASK : SYMBOL_BID)));
                                        v1 = m_Position.SL;
                                        if (def_ORDER_FINISH) if (OrderSelect(m_TicketPending)) v1 = OrderGetDouble(ORDER_PRICE_OPEN);
                                        if (v1 > 0) if (MathAbs(price - v1) >= (m_Position.Gap * 2)) 
                                        {
                                                price = v1 + (m_Position.Gap * (m_Position.IsBuy ? 1 : -1));
                                                if (def_ORDER_FINISH) ModifyPricePoints(m_TicketPending, price, 0, 0);
                                                else ModifyPricePoints(m_Position.Ticket, m_Position.PriceOpen, price, m_Position.TP);
                                        }
                                }
                        }

Este procedimento, a primeira vista parece bem estranho, já que fiz uso de coisas pouco comuns, para grande parte das pessoas, vamos entender o que está acontecendo aqui. Primeiramente, testamos se temos alguma posição aberta, esta é a parte fácil, mas a coisa estranha aqui, é este operador terciário, é bem incomum vê-lo sendo usado desta forma. Mas aqui, iremos separar se o teste será feito pelo ticket pendente, ou pelo valor do preço de stop loss. Esta comparação será usada em conjunto com a comparação da posição. Se os testes indicarem que não há nada a fazer, iremos simplesmente retornar ao chamador.

Tendo algo a ser feito, testamos o breakeven, se ele já foi executado, passamos a fazer a captura do preço atual do ativo, a fim de efetuar o teste se podemos ou não fazer o trailing stop. Por conta que poderemos esta necessitando, do preço onde a ordem pendente está, e a fatoração de qualquer forma será a mesma. Iniciamos a variável temporária, com o possível valor que poderá estar sendo a linha de stop loss. mas pode ser que estejamos usando a ordem pendente, como ponto de stop. Neste caso, ela deverá se mover, assim fazemos a captura do preço onde ela está. Efetuamos a fatoração, para verificar se devemos ou não fazer o movimento do stop. Se isto for possível, iremos ajustar o preço para onde a ordem será movimentada e moveremos as coisas de forma adequada, seja a ordem pendente, seja a linha de stop loss, mas quem será de fato movimentado irá depender do sistema que estaremos usando.

No vídeo 01, você pode ver uma demonstração deste sistema em funcionamento, para quem imagina ser algo bem diferente, ou mesmo não funcional. Veja o vídeo, e tire suas próprias conclusões, se bem que o melhor, é você entender o que está acontecendo, compilar o EA e fazer os seus próprios testes, faça isto em conta DEMO. Assim a compreensão de todo o sistema ficará bem mais solida e clara.

Vídeo 01 - Demonstração do sistema de Stop via ordem pendente.


Conclusão

Neste artigo, abordei o sistema de gatilho mais simples, que existe para ser colocado em um EA, e que muitos gostam ou desejam ter no seu EA. Mas este sistema não é adequado, para ser usado, caso você deseje usar o EA em uma montagem de carteira. Neste caso aconselho você a usar um sistema manual. Mas isto, é apenas um conselho que estou dando, mesmo por que, não sei exatamente como você de fato pretende usar este conhecimento.

No anexo, você terá o código na integra para poder estudar, e aprender mais sobre este tipo de mecanismo demonstrado aqui. Lembrando que no código, você terá inicialmente um EA que usará linha de stop, para usar uma ordem pendente, como sendo o ponto de stop, você deverá modificar o EA, conforme explicado neste artigo.

Já que agora temos a automação mínima requerida, para os demais passos e demonstrações, no próximo artigo, veremos como criar um EA 100% automático. Então bons estudos.

Arquivos anexados |
Últimos Comentários | Ir para discussão (7)
robertamega
robertamega | 28 dez 2022 em 21:21

O Dani, eu nao sei compilar, nao conheco muito de programacao, entrei agora nesse sistema de metatrader, voce pode me ajudar?





Daniel Jose #:

Você precisa compilar ele e depois ele irá aparecer em meio aos outros Experts Advisors que a plataforma tem por padrão, dai você o joga no gráfico da mesma forma que faria com qualquer outro programa.

Um detalhe: para ele funcionar o Algo Trading deverá esta habilitado na plataforma:

 << Algo Trading desabilitado ;

 << Algo Trading habilitado;

Daniel Jose
Daniel Jose | 29 dez 2022 em 10:32
robertamega #:

O Dani, eu nao sei compilar, nao conheco muito de programacao, entrei agora nesse sistema de metatrader, voce pode me ajudar?





Neste caso posso lhe indicar uma playlist que estou montando no YOUTUBE, é algo bem básico, mas voltado justamente para pessoas que estão começando. Os vídeos serão curtos e direcionados a um assunto especifico, mas sempre voltado ao iniciante no MetaTrader. Dê uma olhada depois, talvez lhe ajude a dar os primeiros passos. Mas tome cuidado com o que você vai de fato colocar rodando na plataforma, já que nela você estará trabalhando com a sua conta na corretora e usando dinheiro de verdade ... só digo isto CUIDADO ...

O link da playlist é este : https://www.youtube.com/watch?v=Q5rgggKuUY4&amp;list=PLpkiMqQzUzgA3fgPE1D-ZcjnEKVwgEg8z

Mackilem
Mackilem | 21 jun 2023 em 17:19

Boa tarde Daniel,

Primeiro, obrigado por compartilhar teu conhecimento! está me ajudando muito!

Eu tenho uma dúvida de como o servidor de negociação entende as ordens de stop e take profit, se são consideradas ordens separadas ou fazem parte de uma única "posição estruturada"? Ou seja, se quando fechada a posição o servidor de negociação sempre removerá o SL e TP ou se devo me preocupar com ordens orfãs?

Essa dúvida surgiu quando no seu artigo você comenta sobre o risco da "perna manca" e também quando comenta que o para ativar o trailingstop em conta hedging precisamos permitir 2 posições em aberto.

Abraço

Daniel Jose
Daniel Jose | 22 jun 2023 em 21:07
Mackilem #:

Boa tarde Daniel,

Primeiro, obrigado por compartilhar teu conhecimento! está me ajudando muito!

Eu tenho uma dúvida de como o servidor de negociação entende as ordens de stop e take profit, se são consideradas ordens separadas ou fazem parte de uma única "posição estruturada"? Ou seja, se quando fechada a posição o servidor de negociação sempre removerá o SL e TP ou se devo me preocupar com ordens orfãs?

Essa dúvida surgiu quando no seu artigo você comenta sobre o risco da "perna manca" e também quando comenta que o para ativar o trailingstop em conta hedging precisamos permitir 2 posições em aberto.

Abraço

Dúvidas fazem parte. Não é vergonha pergunta. Vergonha é manter a dúvida e divulgar informação sem conhecimento.😁

Mas vamos por partes. Vamos primeiro entender uma situação para depois entender a outra.

->Quando você coloca uma ordem no servidor, ou abre uma posição, você pode fazer isto de duas formas: Quando você ao enviar o pedido já com o stop e o take ajustado na ordem ou posição a ser aberta. Neste caso você envia apenas e somente um requerimento para servidor. Caso você não tenha colocado o stop ou take no pedido, poderá fazer isto depois, ajustando as coisas. De qualquer forma você terá apenas e somente uma ordem ou posição no servidor. Isto é o que muitos chamam de ordem OCO. Ou seja, quando o stop ou take forem executados, a posição será encerrada e tudo ficará como você já deve saber, quando se trata de ordens OCO. Acredito que sobre isto você não deve ter dúvidas.

->Agora temos um problema, que eu abordei nesta mesma serie de artigos. Uma ordem ou posição OCO não indica que o seu Take ou Stop não serão pulados. Eles somente serão executados se ocorrer algum negocio naquele preço especifico. Para evitar que a ordem seja pulada, algum programadores não usam ordens OCO, eles fazem algo um pouco diferente. Este algo diferente é que costuma gerar as tais pernas mancas, ou seja, você fica com uma ordem apregoada no book, porem esta não estará coberta por nenhuma outra ordem. Neste caso estaremos usando no mínimo de duas ordens para controlar a posição. Ao fazer isto, evitamos o tal stop pulado, isto por que, mesmo que o preço pule a ordem OCO, ele não irá pular a ordem no book, que está lá justamente para fechar a posição aberta na MARRA ... Porém isto não funciona no tipo de conta HEDGING, isto por que tais contas permitem você manter uma posição de compra e uma de venda ao mesmo tempo, no mesmo ativo. Seria quase como uma OPÇÃO BINARIA ... mas quando esta tecnica de usar duas ordens é feita em uma conta NETTING, a posição é fechada. Mas você tem que tomar o cuidado de evitar manter uma ordens no book solta.

Para entender isto, você precisa de fato ler todos os 15 artigos da serie e experimentar o sistema automático, que demonstro. Mas faça isto em contas demo, tanto no FOREX quanto na BOLSA. Ai você de fato irá entender esta questão de que falei. Não tente entende-la apenas imaginando como deveria ou poderia funcionar. Teste o sistema em contas demo, tanto no FOREX que usa contas HEDGING, quanto na BOLSA que usa contas do tipo NETTING ... 😁👍

Mackilem
Mackilem | 22 jun 2023 em 22:36
Daniel Jose #:

Dúvidas fazem parte. Não é vergonha pergunta. Vergonha é manter a dúvida e divulgar informação sem conhecimento.😁

Mas vamos por partes. Vamos primeiro entender uma situação para depois entender a outra.

->Quando você coloca uma ordem no servidor, ou abre uma posição, você pode fazer isto de duas formas: Quando você ao enviar o pedido já com o stop e o take ajustado na ordem ou posição a ser aberta. Neste caso você envia apenas e somente um requerimento para servidor. Caso você não tenha colocado o stop ou take no pedido, poderá fazer isto depois, ajustando as coisas. De qualquer forma você terá apenas e somente uma ordem ou posição no servidor. Isto é o que muitos chamam de ordem OCO. Ou seja, quando o stop ou take forem executados, a posição será encerrada e tudo ficará como você já deve saber, quando se trata de ordens OCO. Acredito que sobre isto você não deve ter dúvidas.

->Agora temos um problema, que eu abordei nesta mesma serie de artigos. Uma ordem ou posição OCO não indica que o seu Take ou Stop não serão pulados. Eles somente serão executados se ocorrer algum negocio naquele preço especifico. Para evitar que a ordem seja pulada, algum programadores não usam ordens OCO, eles fazem algo um pouco diferente. Este algo diferente é que costuma gerar as tais pernas mancas, ou seja, você fica com uma ordem apregoada no book, porem esta não estará coberta por nenhuma outra ordem. Neste caso estaremos usando no mínimo de duas ordens para controlar a posição. Ao fazer isto, evitamos o tal stop pulado, isto por que, mesmo que o preço pule a ordem OCO, ele não irá pular a ordem no book, que está lá justamente para fechar a posição aberta na MARRA ... Porém isto não funciona no tipo de conta HEDGING, isto por que tais contas permitem você manter uma posição de compra e uma de venda ao mesmo tempo, no mesmo ativo. Seria quase como uma OPÇÃO BINARIA ... mas quando esta tecnica de usar duas ordens é feita em uma conta NETTING, a posição é fechada. Mas você tem que tomar o cuidado de evitar manter uma ordens no book solta.

Para entender isto, você precisa de fato ler todos os 15 artigos da serie e experimentar o sistema automático, que demonstro. Mas faça isto em contas demo, tanto no FOREX quanto na BOLSA. Ai você de fato irá entender esta questão de que falei. Não tente entende-la apenas imaginando como deveria ou poderia funcionar. Teste o sistema em contas demo, tanto no FOREX que usa contas HEDGING, quanto na BOLSA que usa contas do tipo NETTING ... 😁👍


Muito obrigado pela explicação. Consegui entender bem agora.

Sim estou terminando de ler todos os artigos e logo iniciarei os testes.


abraço

Redes neurais de maneira fácil (Parte 29): Algoritmo ator-crítico de vantagem (Advantage actor-critic) Redes neurais de maneira fácil (Parte 29): Algoritmo ator-crítico de vantagem (Advantage actor-critic)
Nos artigos anteriores desta série, conhecemos 2 algoritmos de aprendizado por reforço. Cada um deles tem suas próprias vantagens e desvantagens. Como costuma acontecer quando nos deparamos com esses casos, surge a ideia de combinar os dois métodos em um algoritmo que incorpore o melhor dos dois. E assim compensar as deficiências de cada um deles. Falaremos sobre tal combinação de métodos neste artigo.
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.
Aprendendo a construindo um Expert Advisor que opera de forma automática (Parte 10): Automação (II) Aprendendo a construindo um Expert Advisor que opera de forma automática (Parte 10): Automação (II)
Automação não é nada sem que você consiga controlar o horário. Nenhum trabalhador consegue ser eficiente trabalhando 24 horas. No entanto, muitos acreditam que um sistema automático deva trabalhar 24 horas. Mas é sempre bom que você tenha meios de configurar um range de horário para o Expert Advisor. Neste artigo iremos tratar disto. Como adicionar adequadamente uma faixa de horário.
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.