English Русский 中文 Español Deutsch 日本語 한국어 Français Italiano Türkçe
preview
Desenvolvendo um EA de negociação do zero (Parte 22): Um novo sistema de ordens (V)

Desenvolvendo um EA de negociação do zero (Parte 22): Um novo sistema de ordens (V)

MetaTrader 5Negociação | 4 julho 2022, 17:31
865 0
Daniel Jose
Daniel Jose

1.0 - Introdução

Não é nada fácil implementar um sistema novo, muitas vezes nos deparamos com questões que dificultam muito os próximos passos, nestes casos temos que parar, e reanalisar a direção que esta sendo tomada, e se ainda é válido manter as coisas como estão, ou é melhor dar uma nova cara para o sistema.

Este tipo de decisão acontece muitas vezes e quase o tempo todo, ainda mais quando não temos uma data ou orçamento para produzir um dado sistema, quando não temos esta pressão, e podemos testar e ajustar as coisas de forma a evitar ao máximo que a coisa se torne insustentável no ponto de vista de desenvolvimento e melhorias.

Grandes programas, mas principalmente os comerciais, que são desenvolvidos com um dado orçamento ou que precisam sair dentro de um prazo, costumam ter muitas falhas que depois precisam ser corrigidas, e muitas vezes, os envolvidos no desenvolvimento do sistema, não tem tempo hábil para poder implementar ou estudar certas soluções que pode trazer muitos benefício ao sistema que esta sendo desenvolvido, com isto temos programas que muitas vezes não estão a altura do que os produtores de fato poderiam fazer, e em outros casos, temos lançamentos de versões após versões com pequenas melhorias ou correções de falhas, não por que as falhas foram descobertas tempos depois do lançamento, mas por conta que antes existia a pressão para o lançamento.

Isto é fato e acontece em toda a cadeia produtiva, mas no caso de algo que estamos criando vamos procurando o melhor caminho e de preferencia, o mais fácil, podemos nos dar a este luxo, estudar cada solução possível e viável. Parar e voltar um pouco atras, modificar e melhorar a forma como o sistema esta sendo desenvolvido, e muitas das vezes esta pequena parada com uma mudança de direção irá nos ajudar em muito no desenvolvimento do sistema desejado.

No artigo Desenvolvendo um EA de negociação do zero ( Parte 21 ) o sistema ficou quase pronto, ficando ausente apenas a parte responsável por mover as ordens diretamente dentro do gráfico, mas durante os testes para fazer isto, notei algumas coisas estranhas no código, havia muitas partes repetidas dentro do mesmo, mesmo com todo o cuidado para evitar que isto ocorresse, notei que estava acontecendo, e o que piora muito era o fato de que certas coisas não estavam funcionando da forma correta, quando usadas em ativos muito diferentes, basicamente quando o EA começou a ser projetado, e principalmente quando iniciei a documentação dele em artigos que estão sendo postados aqui, eu pensava basicamente em usa-lo somente na negociação de futuros na B3, e no caso, algo bem especifico, ele estava sendo projetado para auxiliar nas operações de Dólar ou Índice futuros, os conhecidos WDO e WIN, mas conforme o sistema foi se tornando cada vez mas próximo do sistema que eu inicialmente pretendia usar, percebi que poderia estender o sistema para outros mercados, ou outros ativos, neste ponto surgiu um problema.


2.0 - Voltando a Prancheta

Para entender o problema é preciso analisar uma coisa que muitos ignoram durante o desenvolvimento de um EA. Como os contratos são definidos no sistema de negociação ?!?! Bem, o MetaTrader 5 nos fornece estas informações, e o MQL5 nos permite ter acesso a estas mesmas informações, e é preciso que você entenda os dados para assim criar a matemática de forma a generalizar os cálculos e conseguir um sistema que seja o mais amplo possível.

O sistema de ordens que estou mostrando como desenvolver tem como finalidade, permitir que você opere diretamente pelo gráfico, não necessitando de nenhum outro recurso externo, ou alguma outra coisa que possa vim a ser criada no futuro, é uma tentativa de se criar um sistema definitivo de negociação pelo gráfico, muito parecida com a encontrada em outras plataformas, mas com o código totalmente aberto de forma que você possa adaptar e adicionar as informações que assim desejar.

A ideia é que você consiga saber o que esta acontecendo em uma posição apenas olhando para ela, mas apesar da ideia parecer muito boa, o sistema de negociação não facilita muito a vida de quem esta tentando criar um sistema que funcione bem para FOREX e para o mercado de bolsa, como por exemplo a B3, o nível de informações disponíveis é o suficiente para permitir configurar as ordens para um ou outro tipo de mercado, mas criar algo genérico se tornou um desafio, quase uma afronta pessoal, mas decidi encarrar a questão de frente e assim tentar criar um sistema que fosse genérico.

Apesar de não ter certeza se de fato irei conseguir fazer tal coisa, irei mostrar como você pode encontrar as informações que são necessárias, e se for preciso adaptar o EA para que ele se adeque ao sistema local você terá as bases e o conhecimento necessário para conseguir fazer isto, mesmo que o sistema não lide inicialmente com a modelagem, você irá conseguir adaptar as coisas.

Uma observação é que estes dados podem ser conseguidos via código utilizando o MQL5, mas para facilitar irei utilizar o MetaTrader 5 para mostrar onde os dados estão.


2.0.1 - Ativo de uma empresa ( AÇÃO ) negociada na B3

Bem observe as 2 imagens abaixo:

     

Os pontos em destaque são os dados que precisamos ter para poder calcular como a posição será montada.

É importante saber disto, pois se você está gerando uma posição com base em um valor financeiro, você precisará destes dados para calcular os valores de Stop Loss e Take Profit, caso não faça uso de ordens OCO, a coisa é um pouco mais tranquila, mas aqui irei considerar que todas as ordens serão ordens ou posições do tipo OCO.

Um detalhe importante: No caso do ativo ser negociado no mercado fracionário, sim na B3 existe diferença entre os mercados, o volume mínimo irá ser de 1% do valor indicado, então ao invés de você negociar de 100 em 100, irá fazer isto de 1 em 1, isto faz um pouco de diferença no cálculo, lembre-se deste detalhe.


2.0.2 - Contratos futuros na B3

Bem as regras para os contratos futuros são diferentes das ações, o volume muda conforme você troca entre um contrato cheio e um mini contrato, e mesmo de ativo para ativo, por exemplo se você for negociar BOI terá que olhar como os dados são de fato preenchidos com relação a alavancagem, já que ela é diferente dos que irei focar aqui. Bem aqui irei focar nos mini contratos, já que em alguns casos um contrato cheio irá corresponder a 25 mini contratos, mas isto vária, então tem que olhar as regras de volume que estão presentes na própria B3 ( Bolsa Brasileira ).

Desta forma observem as imagens abaixo do mini dólar

     

Estes contratos tem prazo de validade, mas isto não vem a ser importante para o artigo, já que no artigo Desenvolvendo um EA de negociação do zero ( Parte 11 ), eu expliquei como fazer um sistema de ordens cruzadas, de forma a negociar os contratos futuros diretamente pelo histórico deles, e se você estiver utilizando aquele método não irá precisar se preocupar qual o contrato atualmente negociado, o próprio EA fará isto por você. Mas observe os pontos marcados, vejam que são diferentes do sistema acionário, isto muitas vezes pode gerar alguns problemas, mas o EA até então dava conta de lidar com isto, é verdade que era pouco intuitivo, mas com o tempo você acabava por acostumar qual deveria ser os valores a serem usados na alavancagem de forma a negociar um dado volume financeiro.

Mas eu decidi subir a régua, e neste ponto começa as dificuldades.


2.0.3 - FOREX

O sistema forex era o meu problema, o EA não conseguia lidar com ele, e quando eu conseguia resolver o problema de ajustar a alavancagem no forex, não conseguia utilizar o mesmo código do EA na B3, e isto estava me irritando, pois para mim não faz sentido ter dois EAs com praticamente todo o código idêntico, e apenas uma única diferença, para entender veja as imagens abaixo:

     

Bem, este é o problema, na B3 temos 4 valores, mas no Forex temos 2 valores, faltava 2 valores e isto estava fazendo os cálculos não casarem entre os mercados.

Este fato fazia o EA gerar um cálculo que dificultava muito o entendimento do que estava sendo de fato feito, pois hora se alavancava muito, hora o volume fazia o sistema de negociação negar a ordem por que o volume estava sendo muito baixo do volume mínimo que era esperado, outra hora os pontos de limites da ordem OCO não eram aceitos pois as posições estavam erradas, ou seja uma bagunça sem fim.

Percebendo isto, decide fazer uma mudança no EA, agora não irei calcular o valor como ele estava sendo feito, passei a calcular ele de uma outra forma, na verdade ele começou a ser ajustado conforme o ativo que estamos negociando, independente de estar negociando em Bolsa ou em Forex, então o EA irá se adaptar aos dados e assim fazer os cálculos da forma correta, mas é preciso que você saiba o que esta sendo negociado, e conheça os dados da negociação, caso contrário, irá se alavancar mais do que o desejado, ou pode alavancar menos que o necessário, mas apesar de agora por motivos computacionais eu permitir o uso de valores em ponto flutuante no volume, você deve evitar fazer isto, deve de fato usar valores inteiros, que indicam o nível de alavancagem que esta sendo feito.

Então entenda bem, você não estará informando ao EA qual o volume que você deseja negociar, mas sim quanto de alavancagem esta sendo feita em cima do volume mínimo exigido, desta forma eu resolvi o problema, você poderá testar isto pessoalmente e comprovar o que eu disse, bastará complicar o código fonte anexado no fim deste artigo.

Mas para facilitar o entendimento e diminuir o seu trabalho, vou fazer uma rápida apresentação dos resultados n próximo topico.


3.0 - Visualizando os dados

Primeiro vamos ver o caso do mercado acionário, em particular na bolsa brasileira ( B3 ) vejam abaixo como as coisas será mostradas pelo EA e pelo MetaTrader 5.


3.0.1 - Ativo da B3

No caso de um ativo, ou ação de alguma empresa negociada na bolsa brasileira, o volume mínimo negociado é de 100, então ao informar um grau de alavancagem de 1 estaremos de fato operando o valor mínimo requerido pelo ativo, desta forma fica mais simples saber o quanto estamos alavancados, se desejar comprar ou vender mais, não precisará saber que estará negociando de 100 em 100, bastará indicar o grau de alavancagem e o EA fará os cálculos para que a ordem seja criada da forma correta.

Caso você esteja usando o fracionário, bastará indicar a quantidade de frações a serem usadas na alavancagem, ou seja 50 significa que você estará usando 50 frações, se indicar 15 você estará se alavancando em 15 frações e assim por diante.

e o resultado disto é visto logo abaixo na caixa de ferramentas do MetaTrader 5, vejam que uma ordem com o lote mínimo foi criada, e se você analisar os valores de take e stop irá ver que são os mesmos informados no gráfico, ou seja o EA funcionou aqui.


3.0.2 - Mini Dólar

Aqui o volume é de 1 em 1, mas no caso dos contratos cheios o valor é diferente, mas quero que reparem no Chart Trade, os valores indicados como Take e Stop são os mesmo dos encontrados acima, mas o EA ajusta os valores de forma correta, então os valores que devem ser levados em consideração são os valores encontrados no indicador do gráfico, devendo os valores do Chart Trade serem ignorados, mas eles estarão próximos do valores indicados no gráfico.


na caixa de ferramentas iriamos ver os seguintes dados:

da mesma forma como no ativo anterior se for executado o cálculo para verificar os níveis de stop e take você irá ver que eles batem com o indicado pelo EA, nos indicadores no gráfico, ou seja o EA passou nesta etapa também e sem precisar recompilar o código, apenas trocando de ativo.


3.0.3 - Forex

Aqui a coisa é um pouco mais complicado, para quem não tem familiaridade com o forex, os pontos parecem ser bem estranhos, mas mesmo assim o EA consegue lidar com eles.


e o MetaTrader 5 irá nos informar esta operação pendente da seguinte forma:


lembrando que no forex, os níveis de alavancagem são bem diferentes dos demais mostrados acima, mas se você efetuar os cálculos e souber operar no forex, irá ver que o EA consegui fornecer os pontos corretos, e a ordem foi criada perfeitamente.

Isto tudo é feito sem nenhuma outra modificação além do que irei mostrar na parte da implementação, apesar terem sido feitas muitas outras mudanças além das que irei mostrar, para de fato conseguir fazer com que o EA se adaptasse tanto ao mercado de bolsa quanto ao mercado de forex, sem precisar ser recompilado, mas o foco aqui é finalizar os artigos anteriores mostrando como fazer a movimentação dos níveis de stop ou take diretamente no gráfico.


4.0 - Implementação

Bem vamos começar vendo alguns pontos que foram mudados no código.

Primeiramente foi retirado o sistema de limites que foi implementado a 3 ou 4 versões atras, isto foi uma decisão baseada no fato de que em alguns momentos o EA não estava se ajustando corretamente ao sistema de alavancagem, ainda mais quando ele era portado da BOLSA para o FOREX.

Foi adicionado um novo modelo de calculo, para que o EA pode-se funcionar da mesma forma no mercado de FOREX e BOLSA. É importante que você saiba que antes desta versão, isto não era possível, o EA no inicio de seu desenvolvimento estava mais voltado para trabalhar e auxiliar em operações de BOLSA, mas decidi estender a funcionalidade dele também para o mercado de FOREX, já que a forma de operar e ler o mercado é praticamente igual.

Existem detalhes quanto as questões de alavancagem, e que nas versões anteriores, o EA não conseguia lidar com elas, mas com as mudanças feitas, ele agora pode ser usado tanto em FOREX quanto em BOLSA, sem nenhuma grande mudança no seu código, mas isto fez com que o código sofresse muitas mudanças para que o EA se ajusta-se a alavancagem do FOREX e ao mesmo tempo viesse a manter a sua compatibilidade com o mercado de BOLSA.

Uma destas mudanças é vista logo no inicio do código:

int OnInit()
{
        static string   memSzUser01 = "";
        
        Terminal.Init();
        WallPaper.Init(user10, user12, user11);
        Mouse.Init(user50, user51, user52);
        if (memSzUser01 != user01)
        {
                Chart.ClearTemplateChart();
                Chart.AddThese(memSzUser01 = user01);
        }
        Chart.InitilizeChartTrade(user20 * Terminal.GetVolumeMinimal(), user21, user22, user23);
        VolumeAtPrice.Init(user32, user33, user30, user31);
        TimesAndTrade.Init(user41);
        TradeView.Initilize();
                
        OnTrade();
        EventSetTimer(1);
   
        return INIT_SUCCEEDED;
}

o trecho destacando não existia originalmente, mas não foi só isto que mudou. No entanto o foco aqui não será esta implementação, e sim como usar o EA para mover os pontos de take e stop presentes no gráfico, de forma direta sem uso de nenhum outro artificio, então vamos fazer isto a partir de agora.


4.0.1 Movendo as ordens diretamente no gráfico

Fazer isto nas versões anteriores não era algo simples, muito pelo contrário, existia uma serie de pendencias e dificuldade que foram geradas no decorrer do tempo, que dificultava muito isto, um dos motivos era que o código estava muito espalhado dificultando a implementação de maneira viável do sistema de movimento de ordens diretamente no gráfico, o sistema originalmente não tinha sido pensado para se chegar neste ponto.

Bem para vocês terem ideia do grau de mudanças que foram necessárias para que o EA conseguisse fazer isto, que é tratar o evento de movimento de ordens seja elas pendentes ou posições, neste caso os limites das mesmas, diretamente no gráfico com o auxilio do mouse, veja como o EA era antes.

O problema é que quando os objetos foram criados, eles substituíram a classe C_HLineTrade, e isto no artigo Desenvolvendo um EA de negociação do zero ( Parte 20 ), o sistema começou a ter uma estrutura bastante mais complexas. então para não mostrar toda a imagem acima de novo, veja apenas o que aconteceu

a seta indica o ponto de ligação onde saiu a classe C_HLineTrade para entrada de novas classes. Bem isto permitiu fazer o que pode ser visto nos artigos anteriores, mas o fato de ter a classe C_OrderView estava atrapalhando o andamento do desenvolvimento, e não teve jeito, ela teve que sair, mas não foi somente isto, o que de fato aconteceu foi que a classe C_TradeGraphics se uniu a antiga classe C_OrderView, e estas receberam uma nova denominação, C_IndicadorTradeView, esta classe então substituiu ambas, mas ao mesmo tempo permitiu o desenvolvimento do sistema de movimentação de ordens.

E o que irei apresentar aqui é a primeira versão deste sistema, já esta sendo trabalhada um outra versão que em breve irei colocar em um outro artigo.


4.0.1.1 - Codificando o novo sistema


Com a união, o novo sistema ficou com a seguinte configuração que pode ser vista abaixo:


A região verde indica um conjunto de classes que ficam soltas, ou seja o EA não irá de fato tomar conta delas, quem é responsável por elas é o MetaTrader 5, mas como assim ?!?!  Calma você vai entender. O EA de fato irá apenas criar, posicionar e remover as classes e todos os objetos que foram criados por estas classes, se você procurar dentro do código do EA, não irá encontrar nenhuma estrutura ou variável que de fato estará referenciando os objetos que a região verde estará criando, isto permite que possamos criar um numero ilimitados de objetos, desde que o MetaTrader 5 consiga alocar memória no sistema operacional, o numero de objetos não será limitada por nenhum tipo de estrutura ou variável dentro do EA.

Você pode pensar que somente um maluco criaria tal estrutura, então podem me chamar de maluco, pois criei e ela funciona, e por incrível que pareça não sobrecarrega tanto o sistema, muita gente me chama de louco e não é de agora, então .... Bem mas continuando, você pode notar uma certa lentidão no momento que for mover as ordens pendentes ou os limites de uma posição, mas isto não é por falha do código, e nem por conta de algum problema no seu computador ou no MetaTrader 5, o problema é que o sistema irá mover as ordens pendentes ou limites movendo as mesmas no próprio servidor de negociação, e isto se você não sabe, tem uma latência, ou um retado entre o movimento e a resposta do servidor, mas esta é a melhor e mais segura forma de operar em alguns cenários, mas não nos permite fazer uma outra coisa que eu quero que o EA execute, então nos próximos artigos iremos corrigir isto adicionando uma nova funcionalidade no EA, e ao mesmo tempo deixar o sistema mais fluido, mas isto sem modificar a estrutura acima, apenas manipulando o código de forma adequada, apesar de isto deixar o sistema menos seguro, mas até lá quem sabe eu encontre um boa solução para este empecilho.

Bem mas vamos ver alguns pontos de maior destaque no código novo atual, começando com uma função pouco explorada, seu código é visto abaixo:

void OnTradeTransaction(const MqlTradeTransaction &trans, const MqlTradeRequest &request, const MqlTradeResult &result)
{
#define def_IsBuy(A) ((A == ORDER_TYPE_BUY_LIMIT) || (A == ORDER_TYPE_BUY_STOP) || (A == ORDER_TYPE_BUY_STOP_LIMIT) || (A == ORDER_TYPE_BUY))

        ulong ticket;
        
        if (trans.symbol == Terminal.GetSymbol()) switch (trans.type)
        {
                case TRADE_TRANSACTION_DEAL_ADD:
                case TRADE_TRANSACTION_ORDER_ADD:
                        ticket = trans.order;
                        ticket = (ticket == 0 ? trans.position : ticket);
                        TradeView.IndicatorInfosAdd(ticket);
                        TradeView.UpdateInfosIndicators(0, ticket, trans.price, trans.price_tp, trans.price_sl, trans.volume, (trans.position > 0 ? trans.deal_type == DEAL_TYPE_BUY : def_IsBuy(trans.order_type)));
                        break;
                case TRADE_TRANSACTION_ORDER_DELETE:
                                if (trans.order != trans.position) TradeView.RemoveIndicator(trans.order);
                                else
                                        TradeView.UpdateInfosIndicators(0, trans.position, trans.price, trans.price_tp, trans.price_sl, trans.volume, trans.deal_type == DEAL_TYPE_BUY);
                                if (!PositionSelectByTicket(trans.position))
                                        TradeView.RemoveIndicator(trans.position);
                        break;
                case TRADE_TRANSACTION_ORDER_UPDATE:
                        TradeView.UpdateInfosIndicators(0, trans.order, trans.price, trans.price_tp, trans.price_sl, trans.volume, def_IsBuy(trans.order_type));
                        break;
                case TRADE_TRANSACTION_POSITION:
                        TradeView.UpdateInfosIndicators(0, trans.position, trans.price, trans.price_tp, trans.price_sl, trans.volume, trans.deal_type == DEAL_TYPE_BUY);
                        break;
        }
        
        
#undef def_IsBuy
}

este código é bastante interessante, pois ele evita que precisemos vim a ficar testando cada nova posição que vai aparecendo, ou sendo modificada, o que de fato acontece é que o próprio servidor irá nos informar o que esta acontecendo, desta forma precisamos apenas fazer com que o EA responda aos eventos de forma correta. Estude bem este modo de codificar e usar este evento OnTradeTransaction, pois se eu fosse usar o modelo de analisar as coisas igual era feito na versão anterior do código, iriamos gastar muito tempo em certos testes e verificações, mas desta forma o próprio servidor faz o serviço pesado para nos, e temos a garantia de que os idnicadores que estão no gráfico de fato estão mostrando o que o servidor esta vendo naquele exato momento.

Antes de entrar nos pontos em destaque no código acima, vamos ver um outro fragmento

void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
        Mouse.DispatchMessage(id, lparam, dparam, sparam);
        switch (id)
        {
                case CHARTEVENT_CHART_CHANGE:
                        Terminal.Resize();
                        WallPaper.Resize();
                        TimesAndTrade.Resize();
        break;
        }
        Chart.DispatchMessage(id, lparam, dparam, sparam);
        VolumeAtPrice.DispatchMessage(id, sparam);
        TradeView.DispatchMessage(id, lparam, dparam, sparam);
        ChartRedraw();
}

vejam que será tudo tratado em um local só, desta forma podemos passar para a classe e ver um pouco mais o que acontece dentro dela.


4.1 - A classe C_IndicatorTradeView

Esta classe irá fazer todo o trabalho de apresentação dos dados e manipulação dos mesmo, basicamente ela engloba as antigas classe C_OrderView mais C_TradeGraphics, como eu já havia falado, no entanto ela irá conseguir manipular os dados de uma forma totalmente diferente, vamos ver alguns pontos que merecem destaque nesta classe.

Começaremos com a função de inicialização, que tem seu código visto abaixo:

void Initilize(void)
{
        int orders = OrdersTotal();
        ulong ticket;
        bool isBuy;
        long info;
        double tp, sl;

        ChartSetInteger(Terminal.Get_ID(), CHART_SHOW_OBJECT_DESCR, false);
        ChartSetInteger(Terminal.Get_ID(), CHART_SHOW_TRADE_LEVELS, false);
        ChartSetInteger(Terminal.Get_ID(), CHART_DRAG_TRADE_LEVELS, false);
        for (int c0 = 0; c0 <= orders; c0++) if ((ticket = OrderGetTicket(c0)) > 0) if (OrderGetString(ORDER_SYMBOL) == Terminal.GetSymbol())
        {
                info = OrderGetInteger(ORDER_TYPE);
                isBuy = ((info == ORDER_TYPE_BUY_LIMIT) || (info == ORDER_TYPE_BUY_STOP) || (info == ORDER_TYPE_BUY_STOP_LIMIT) || (info == ORDER_TYPE_BUY));
                IndicatorInfosAdd(ticket);
                UpdateInfosIndicators(-1, ticket, OrderGetDouble(ORDER_PRICE_OPEN), OrderGetDouble(ORDER_TP), OrderGetDouble(ORDER_SL), OrderGetDouble(ORDER_VOLUME_CURRENT), isBuy);
        }
        orders = PositionsTotal();
        for (int c0 = 0; c0 <= orders; c0++) if (PositionGetSymbol(c0) == Terminal.GetSymbol())
        {
                tp = PositionGetDouble(POSITION_TP);
                sl = PositionGetDouble(POSITION_SL);
                ticket = PositionGetInteger(POSITION_TICKET);
                IndicatorInfosAdd(ticket);
                UpdateInfosIndicators(1, ticket, PositionGetDouble(POSITION_PRICE_OPEN), tp, sl, PositionGetDouble(POSITION_VOLUME), PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY);
        }
        CreateIndicatorTrade(def_IndicatorTicket0, IT_PENDING);
        CreateIndicatorTrade(def_IndicatorTicket0, IT_TAKE);
        CreateIndicatorTrade(def_IndicatorTicket0, IT_STOP);
}

Basicamente o que estamos fazendo é criar os indicadores necessários para trabalhar, e apresentar qualquer coisa que esteja presente na conta, como posições, ou ordens pendentes, mas as linhas em destaque são importantes aqui, pois caso você não esteja utilizando um sistema de ordens cruzadas, você terá no gráfico os pontos das ordens, originais do MetaTrader 5, e se você clicar e arrastar estes pontos, o EA irá atualizar os novos pontos com as mudanças nos indicadores, isto até que não atrapalha muito, mas temos que de fato usar o sistema que esta sendo desenvolvido, caso contrário qual o sentido em desenvolve-lo ?!?!

Bem o próximo código que merece destaque é visto abaixo:

void UpdateInfosIndicators(char test, ulong ticket, double pr, double tp, double sl, double vol, bool isBuy)
{
        bool isPending;
                                
        isPending = (test > 0 ? false : (test < 0 ? true : (ticket == def_IndicatorTicket0 ? true : OrderSelect(ticket))));
        PositionAxlePrice(ticket, (isPending ? IT_RESULT : IT_PENDING), 0);
        PositionAxlePrice(ticket, (isPending ? IT_PENDING : IT_RESULT), pr);
        SetTextValue(ticket, (isPending ? IT_PENDING : IT_RESULT), vol);
        PositionAxlePrice(ticket, IT_TAKE, tp);
        PositionAxlePrice(ticket, IT_STOP, sl);
        SetTextValue(ticket, IT_TAKE, vol, (isBuy ? tp - pr : pr - tp));
        SetTextValue(ticket, IT_STOP, vol, (isBuy ? sl - pr : pr - sl));
}

ele recebe alguns dados e atualiza todos os demais para nos, apresentando os valores corretos só que em termos de valor financeiro, e os pontos onde as ordens estão, basicamente não precisamos nos preocupar se a ordem é pendente ou é uma posição, a própria rotina irá fazer o chaveamento de forma que iremos ver isto no gráfico de maneira adequada.

A próxima rotina é vista a seguir

inline double SecureChannelPosition(void)
{
        double Res = 0, sl, profit, bid, ask;
        ulong ticket;
                                
        bid = SymbolInfoDouble(Terminal.GetSymbol(), SYMBOL_BID);
        ask = SymbolInfoDouble(Terminal.GetSymbol(), SYMBOL_ASK);
        for (int i0 = PositionsTotal() - 1; i0 >= 0; i0--) if (PositionGetSymbol(i0) == Terminal.GetSymbol())
        {
                ticket = PositionGetInteger(POSITION_TICKET);
                SetTextValue(ticket, IT_RESULT, PositionGetDouble(POSITION_VOLUME), profit = PositionGetDouble(POSITION_PROFIT), PositionGetDouble(POSITION_PRICE_OPEN));
                sl = PositionGetDouble(POSITION_SL);
                if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
                {
                        if (ask < sl) ClosePosition(ticket);
                }else
                {
                        if ((bid > sl) && (sl > 0)) ClosePosition(ticket);
                }
                Res += profit;
        }
        return Res;
};

Esta é chamada pelo evento OnTick, sendo desta forma bastante critica em termos de velocidade e peso no sistema, desta forma a única coisa que ela faz fora os teste é atualizar o valor para nos no indicador, e isto é feito pelo código em destaque, notem que o bilhete a posição é algo muito importante para nos.

Vamos então ver a rotina que esta em destaque no fragmento acima, e ela pode ser vista logo abaixo

void SetTextValue(ulong ticket, eIndicatorTrade it, double value0, double value1 = 0.0, double priceOpen = 0.0)
{
        double finance;
                                
        switch (it)
        {
                case IT_RESULT  :
                        PositionAxlePrice(ticket, it, priceOpen);
                        PositionAxlePrice(ticket, IT_PENDING, 0);
                        m_EditInfo2.SetTextValue(MountName(ticket, it, EV_PROFIT), value1);
                case IT_PENDING:
                        m_EditInfo1.SetTextValue(MountName(ticket, it, EV_EDIT), value0 / Terminal.GetVolumeMinimal(), def_ColorVolumeEdit);
                        break;
                case IT_TAKE    :
                case IT_STOP    :
                        finance = (value1 / Terminal.GetAdjustToTrade()) * value0;
                        m_EditInfo1.SetTextValue(MountName(ticket, it, EV_EDIT), finance);
                        break;
        }
}

Desta forma os valores serão apresentados no indicador, mas agora vem a questão: Como mover eles ?!?! Bem isto é feito por outros 3 código, é bem verdade que você pode descartá-los e utilizar o próprio sistema do MetaTrader 5 que é consideravelmente mais rápido do que o sistema atual do EA, mas como eu disse, vou dar preferencia em usar o EA, já que ele irá receber outras melhorias em breve.

A primeira rotina reponsável pelas movimentação, é vista abaixo, mas apenas os fragmentos necessários para a movimentação dos pontos seja os limites ou a própria ordem em sim foram colocados ai, já que todo o código é bem mais extenso e desnecessário para o entendimento de como fazer a movimentação com base nos movimentos do mouse.

void DispatchMessage(int id, long lparam, double dparam, string sparam)
{
        ulong   ticket;

// ... Código ....

        switch (id)
        {
                case CHARTEVENT_MOUSE_MOVE:
                        Mouse.GetPositionDP(dt, price);
                        mKeys   = Mouse.GetButtonStatus();
                        bEClick  = (mKeys & 0x01) == 0x01;    //Clique esquerdo
                        bKeyBuy  = (mKeys & 0x04) == 0x04;    //SHIFT Pressionada
                        bKeySell = (mKeys & 0x08) == 0x08;    //CTRL Pressionada
                        if (bKeyBuy != bKeySell)
                        {
                                if (!bMounting)
                                {
                                        Mouse.Hide();
                                        bIsDT = Chart.GetBaseFinance(leverange, valueTp, valueSl);
                                        valueTp = Terminal.AdjustPrice(valueTp * Terminal.GetAdjustToTrade() / leverange);
                                        valueSl = Terminal.AdjustPrice(valueSl * Terminal.GetAdjustToTrade() / leverange);
                                        m_TradeLine.SpotLight(MountName(def_IndicatorTicket0, IT_PENDING, EV_LINE));
                                        bMounting = true;
                                }
                                tp = price + (bKeyBuy ? valueTp : (-valueTp));
                                sl = price + (bKeyBuy ? (-valueSl) : valueSl);
                                UpdateInfosIndicators(0, def_IndicatorTicket0, price, tp, sl, leverange, bKeyBuy);
                                if ((bEClick) && (memLocal == 0)) CreateOrderPendent(leverange, bKeyBuy, memLocal = price, tp, sl, bIsDT);
                        }else if (bMounting)
                        {
                                UpdateInfosIndicators(0, def_IndicatorTicket0, 0, 0, 0, 0, false);
                                Mouse.Show();
                                memLocal = 0;
                                bMounting = false;
                        }else if ((!bMounting) && (bKeyBuy == bKeySell))
                        {
                                if (bEClick)
                                {
                                        bIsMove = false;
                                        m_TradeLine.SpotLight();
                                }
                                MoveSelection(price, mKeys);
                        }
                        break;

// ... Código ...
                case CHARTEVENT_OBJECT_CLICK:
                        if (GetIndicatorInfos(sparam, ticket, price, it, ev)) switch (ev)
                        {

// ... Código ...

                                case EV_MOVE:
                                        if (bIsMove)
                                        {
                                                m_TradeLine.SpotLight();
                                                bIsMove = false;
                                        }else
                                        {
                                                m_TradeLine.SpotLight(MountName(ticket, it, EV_LINE));
                                                bIsMove = true;
                                        }
                                        break;
                        }
                        break;
        }
}

Vamos tentar entender o que esta acontecendo, no final tem um video mostrando como fazer, e o que estará acontecendo de fato, mas vamos tentar entender primeiro.

Cada indicador tem um objeto que permite que o indicador seja selecionado, com exceção do de resultado, que é um indicador que você não pode movimentar, ao clicar neste ponto, a linha do indicador irá mudar, ficando mais espessa, quando isto acontece, os movimentos do mouse serão capturados e convertidos em uma nova posição para este indicador, até que venhamos a dar um novo clique fora do objeto de seleção que permite o movimento do indicador, veja que não é preciso ficar segurando o botão do mouse, apenas clique uma vez, arraste, e depois clique novamente.

Mas apenas uma parte do trabalho esta sendo feito de fato aqui, temos outras 2 rotinas para nos ajudar, uma já foi vista pouco acima, que é a responsável por mostrar os valores calculados, a próxima é a responsável por ser a pedra fincada que faz o EA ficar parecendo uma lesma ao se usar o sistema de movimento das ordens ou limites, e pode ser vista logo abaixo:

void MoveSelection(double price, uint keys)
{
        static string memStr = NULL;
        static ulong ticket = 0;
        static eIndicatorTrade it;
        eEventType ev;
        double tp, sl, pr;
        bool isPending;
                                
        string sz0 = m_TradeLine.GetObjectSelected();
        
        if (sz0 != NULL)
        {
                if (memStr != sz0) GetIndicatorInfos(memStr = sz0, ticket, pr, it, ev);
                isPending = OrderSelect(ticket);
                switch (it)
                {
                        case IT_TAKE:
                                if (isPending) ModifyOrderPendent(ticket, macroGetPrice(IT_PENDING), price, macroGetPrice(IT_STOP));
                                else ModifyPosition(ticket, price, macroGetPrice(IT_STOP));
                                break;
                        case IT_STOP:
                                if (isPending) ModifyOrderPendent(ticket, macroGetPrice(IT_PENDING), macroGetPrice(IT_TAKE), price);
                                else ModifyPosition(ticket, macroGetPrice(IT_TAKE), price);
                                break;
                        case IT_PENDING:
                                pr = macroGetPrice(IT_PENDING);
                                tp = macroGetPrice(IT_TAKE);
                                sl = macroGetPrice(IT_STOP);
                                ModifyOrderPendent(ticket, price, (tp == 0 ? 0 : price + tp - pr), (sl == 0 ? 0 : price + sl - pr));
                                break;
                }
        };
}

Chamo esta rotina de pedra fincada pelo seguinte: ELA É RESPONSÁVEL PELO SISTEMA DE POSICIONAMENTO SER LENTO .... se você não entendeu, veja os pontos em destaque, cada um deles é uma função que esta dentro da classe C_Router, e irá enviar um pedido para o servidor de negociação, então se o servidor por um motivo ou outro demorar para responder, e isto sempre irá acontecer por conta da latência, o sistema de posicionamento irá ficar mais ou menos lento, mas se o servidor responder rapidamente, o sistema ficará fluido, ou melhor, a coisa irá se dar de forma mais suave, mas depois iremos modificar isto, por conta que este sistema não nos permite fazer uma outra coisa, mas é preciso que você tenha em mente que desta forma você estará operando de uma forma um pouco mais segura, ainda mais quem gosta de operar em movimentos de grande volatilidade, onde os preços podem se deslocar muito rapidamente, mas mesmo assim você corre o risco de ter os limites pulados, não tem como, algo tem que ser sacrificado, mas para quem aceita operar sabendo esta vendo é exatamente o que estará dentro do servidor, o EA fica pronto neste ponto, mas para quem deseja ganhar fluidez no funcionamento do EA, mesmo ao custo de não ter os pontos respeitados, nos próximos artigos a coisa irá mudar de forma a deixar as coisas mais interessantes.

No video abaixo eu mostro como se dá de fato o trabalho todo, então atenção aos valores no gráfico e na caixa de ferramentas, onde é mostrado o que esta acontecendo com a ordem.



5.0 - Conclusão

Apesar de agora termos um EA bastante interessante para operar, aconselho a você usa-lo durante um tempo em uma conta demo para se habituar a forma como ele trabalha, mas prometo que não haverá mais grandes mudanças, na forma de se trabalhar com ele, apenas melhorias, e em um artigo futuro iremos adicionar algumas coisas que estão faltando neste EA, em detrimento de alguma segurança que ele ainda nos fornece, mas de uma forma ou de outra ele estará sendo uma ótima fonte de aprendizado de como o sistema de negociação funciona e como manipular a plataforma de forma a se ter qualquer tipo de modelagem de dados que precisarmos.

Não se esqueça de uma coisa, caso você esteja achando o sistema de movimentação das ordens, ou dos limites muito lento, você pode remover os pontos que mostrei no artigo e usar o próprio MetaTrader 5 para mover as ordens ou limites, e usar o EA como um suporte para auxiliar na leitura e interpretação dos dados. Fica a sua escolha fazer isto, ou não ...


Arquivos anexados |
Como desenvolver um sistema de negociação baseado no indicador CCI Como desenvolver um sistema de negociação baseado no indicador CCI
Neste novo artigo da nossa série para aprender a projetar os sistemas de negociação, eu apresentarei o indicador Commodities Channel Index (CCI), eu explicarei suas especificidades e compartilharei com você como criar um sistema de negociação baseado neste indicador.
Ciência de Dados e Aprendizado de Máquina (Parte 01): Regressão Linear Ciência de Dados e Aprendizado de Máquina (Parte 01): Regressão Linear
É hora de nós, como traders, treinarmos nossos sistemas e a nós mesmos para tomar decisões com base no que o número diz. Não aos nossos olhos, e o que nossas entranhas nos fazem acreditar, é para onde o mundo está indo, então vamos nos mover perpendicularmente à direção da onda.
Desenvolvendo um EA de negociação do zero (Parte 23): Um novo sistema de ordens (VI) Desenvolvendo um EA de negociação do zero (Parte 23): Um novo sistema de ordens (VI)
Deixando o sistema de ordens mais fluido. Aqui irei mostrar como e onde mudar no código para se ter algo mais fluído, onde você pode modificar os limites da posição muito mais rapidamente.
Como desenvolver um sistema de negociação baseado no indicador RSI Como desenvolver um sistema de negociação baseado no indicador RSI
Neste artigo, eu compartilharei com você um dos indicadores mais populares e comumente usados no mundo das negociações, o RSI. Você aprenderá como desenvolver um sistema de negociação usando este indicador.