English Русский 中文 Español Deutsch 日本語 한국어 Français Italiano Türkçe
Desenvolvendo um EA de negociação do zero

Desenvolvendo um EA de negociação do zero

MetaTrader 5Negociação | 17 dezembro 2021, 13:48
3 645 8
Daniel Jose
Daniel Jose

Introdução

Com o aumento do numero de novos usuários no mercado financeiro, é de se esperar que muitos não tem o devido conhecimento de como o sistema de ordens funciona de fato, mas existe sim aqueles que querem de fato saber o que esta acontecendo e tentam ter o maior controle possível sobre o que esta acontecendo, ou o que estão fazendo.

É bem verdade que o MetaTrader 5 nos permite ter um grande controle sobre as posições que queremos montar, mas usar o sistema que se encontra no MetaTrader 5 para pendurar ordens é algo bastante custoso e muito sujeito a erros por parte de usuários menos experientes, e se a intenção for operar contratos futuros no conhecido onde podemos ter pouco tempo para montar a ordem, a coisa se torna um pesadelo, pois preencher todos os campos em tempo hábil e de forma correta nos faz perder oportunidades de boas entradas, ou perder dinheiro se algo for preenchido de forma incorreta. 

Pensando nisto que tal usar um EA para facilitar as coisas, de forma que você simplesmente precise indica algumas coisas, como nível de alavancagem, quanto aceita perder e quanto deseja ganhar, isto financeiramente, já que muitos não entendem a relação de pontos com financeiro, e usando o mouse, posicionar a ordem diretamente no gráfico, indicando onde deseja entrar, e se será na mão da compra ou venda ....


Planejamento

A parte mais complexa quando se vai criar algo, é bolar como a coisa deve funcionar, de forma que iremos precisar criar o mínimo de código possível, pois quanto mais complexo for o código a ser criado, maior a possibilidade de erros e falhas durante o tempo de execução ( RUN TIME ), pensando nisto, procurei fazer um código que fosse o mais simples possível e ao mesmo tempo procurando usar o máximo possível o que o MetaTrader 5 já nos fornece, e o motivo para isto é que ele esta sempre sendo testado e com isto não teremos possibilidades de erros por parte da plataforma.

O código foi pensado de forma a usar uma programação OOP ( programação orientada a objetos ), com isto podemos isolar o código facilitando a sua manutenção e crescimento futuro com novas funcionalidades e melhorias.

Apesar do EA em questão ser voltado para operar na B3 ( Bolsa Brasileira ), e mais especificamente para os futuros ( Mini índice e Mini Dólar ), podermos estende-lo para todos os mercados e isto de forma muito pratica, e simples, com o mínimo de edições. Para facilitar as coisas e não ficar repetindo, a todo momento, um teste de qual ativo estamos negociando usamos a seguinte enumeração:

enum eTypeSymbolFast {WIN, WDO, OTHER};


Se você desejar operar outro ativo, que usa alguma característica especial, adicione ele aqui, também será necessário fazer pequenas modificações no código, mas usar esta enumeração facilita muita a coisa, pois reduz a possibilidade de erros. Uma parte bastante curiosa no código é a função AdjustPrice ...

   double AdjustPrice(const double arg)
     {
      double v0, v1;
      if(m_Infos.TypeSymbol == OTHER)
         return arg;
      v0 = (m_Infos.TypeSymbol == WDO ? round(arg * 10.0) : round(arg));
      v1 = fmod(round(v0), 5.0);
      v0 -= ((v1 != 0) || (v1 != 5) ? v1 : 0);
      return (m_Infos.TypeSymbol == WDO ? v0 / 10.0 : v0);
     };

A função acima, irá fazer um ajuste no valor a ser usado no preço, de forma a posicionar as linhas no ponto correto do gráfico. Mas por que simplesmente não colocar a linha no gráfico ?!?! O motivo é que alguns ativos tem um valor de passo entre os preços, no caso do WDO ( Mini Dólar ) este passo é de 0.5 pontos, no caso do WIN ( Mini índice ) este passo é de 5 pontos, e no caso do acionário o passo é de 0.01 ponto, ou seja, cada tick tem um valor diferente para ativos distintos, e esta função faz justamente isto, ela corrige, ou melhor dizendo, ajusta o preço para o valor correto encaixando ele a uma correspondência em ticks, e isto é importante para se criar a ordem no ponto correto, caso contrário o servidor de negociação poderá negar a ordem.

Sem esta função seria complicado saber quais os valores corretos a serem usados no preenchimento da ordem oco, e o servidor iria indicar que a ordem esta preenchida da forma incorreta, impedindo ela ser executada, ou ficar posicionada. Agora vamos ver a função que é o coração do EA, a função CreateOrderPendent, ela pode ser vista abaixo.

   ulong CreateOrderPendent(const bool IsBuy, const double Volume, const double Price, const double Take, const double Stop, const bool DayTrade = true)
     {
      double last = SymbolInfoDouble(m_szSymbol, SYMBOL_LAST);
      ZeroMemory(TradeRequest);
      ZeroMemory(TradeResult);
      TradeRequest.action        = TRADE_ACTION_PENDING;
      TradeRequest.symbol        = m_szSymbol;
      TradeRequest.volume        = Volume;
      TradeRequest.type          = (IsBuy ? (last >= Price ? ORDER_TYPE_BUY_LIMIT : ORDER_TYPE_BUY_STOP) : (last < Price ? ORDER_TYPE_SELL_LIMIT : ORDER_TYPE_SELL_STOP));
      TradeRequest.price         = NormalizeDouble(Price, m_Infos.nDigits);
      TradeRequest.sl            = NormalizeDouble(Stop, m_Infos.nDigits);
      TradeRequest.tp            = NormalizeDouble(Take, m_Infos.nDigits);
      TradeRequest.type_time     = (DayTrade ? ORDER_TIME_DAY : ORDER_TIME_GTC);
      TradeRequest.stoplimit     = 0;
      TradeRequest.expiration    = 0;
      TradeRequest.type_filling  = ORDER_FILLING_RETURN;
      TradeRequest.deviation     = 1000;
      TradeRequest.comment       = "Order Generated by Experts Advisor.";
      if(!OrderSend(TradeRequest, TradeResult))
        {
         MessageBox(StringFormat("Error Number: %d", TradeResult.retcode), "Nano EA");
         return 0;
        };
      return TradeResult.order;
     };

Esta função é extremamente simples, e focada para ser o mais segura possível, aqui iremos criar uma ordem OCO que será enviada para o servidor de negociação, observem que estamos usando ordens do tipo LIMIT ou STOP, isto por conta que este tipo de ordem ser mais simples e terá sua execução garantida, mesmo em caso de movimentos bruscos nos preços.

Observem que o tipo de ordem a ser usada irá depender do preço de execução e do preço atual do ativo, assim como se você estará entrando na mão de venda ou compra, isto tudo é feito por esta linha:

TradeRequest.type = (IsBuy ? (last >= Price ? ORDER_TYPE_BUY_LIMIT : ORDER_TYPE_BUY_STOP) : (last < Price ? ORDER_TYPE_SELL_LIMIT : ORDER_TYPE_SELL_STOP));

Você também pode fazer uma coisa que muitos desejam, executar CROSS ORDER, isto é conseguido ao se indicar o ativo a ser negociado na seguinte linha:

TradeRequest.symbol = m_szSymbol;

só que ao fazer isto você terá que adicionar algumas coisas ao código para poder manipular as ordens abertas ou pendentes via sistema CROSS ORDER, já que você irá estar com o gráfico "errado". Vamos entender isto com um exemplo. Você pode esta no gráfico do índice cheio ( IND ) e operando o Mini índice ( WIN ), mas o MetaTrader 5 não irá mostrar a posição aberta ou pendente no WIN, quando você estiver usando no gráfico do IND, assim sendo será necessário você adicionar um código de forma a se fazer esta apresentação, isto é conseguido, lendo os valores da posição e usando apresentando uma linha no gráfico atual. Isto é bem interessante quando você esta operando e quer observar o histórico passado do ativo, no caso dos contratos futuros, eles tem uma data de vencimento, mas usando o CROSS ORDER, você pode por exemplo, operar o WIN ( mini índice ) usando o gráfico WIN$ ( que é o gráfico do histórico do mini índice ), isto é perfeitamente possível.

A próxima coisa a ser observada, são as seguintes linhas:

      TradeRequest.price         = NormalizeDouble(Price, m_Infos.nDigits);
      TradeRequest.sl            = NormalizeDouble(Stop, m_Infos.nDigits);
      TradeRequest.tp            = NormalizeDouble(Take, m_Infos.nDigits);

estas 3 linhas irão criar os limites da ordem oco, junto com o preço de abertura da posição, em caso de operações de curto prazo, que pode durar apenas alguns segundos, não é aconselhável entrar na operação sem usar ordens oco, visto que a volatilidade pode fazer o preço ir de um ponto a outro sem muita direção, usando esta estrutura, o próprio servidor de negociação irá cuidar da nossa posição, mas nem tudo é perfeito. Uma ordem oco irá aparecer da forma como mostra a imagem abaixo

a mesma ordem irá aparecer da seguinte forma se você abrir o editor para manipular os dados:

Com este dados preenchidos o servidor de negociação irá cuidar da ordem, e assim que ela bater em um dos pontos indicados como Perda Máxima ou Lucro Máximo a ordem será finalizada pelo sistema de negociação, mas se você retirar o valor de Perda Máxima ou Lucro Máximo, a ordem irá ficar aberta até algum outro evento acontecer, se ela estiver marcada como Day Trade, o sistema irá finalizar a ordem no final do período de negociação do dia, caso contrário ela irá ficar aberta até você encerrar ou não ter mais fundos para manter a posição.

Alguns sistemas, entenda EA, usam ordens para encerrar ordens, ou seja, uma vez que a posição esta aberta, é enviada uma contra ordem de mesmo volume para encerra a posição em um dado ponto, mas isto não é muito adequado em alguns cenários, já que se por algum motivo o ativo entra em leilão durante o pregão, a ordem pendurada poderá ser descartada, devendo ser recolocada, e isto complica o EA, já que irá ser necessário testar quais ordens estão ou não ativas, e se isto não for feito da forma correta irá implicar em dor de cabeça, já que o EA irá ficar enviando ordens uma após a outra sem nenhum critério.

   void Initilize(int nContracts, int FinanceTake, int FinanceStop, color cp, color ct, color cs, bool b1)
     {
      string sz0 = StringSubstr(m_szSymbol = _Symbol, 0, 3);
      double v1 = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE) / SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
      m_Infos.Id = ChartID();
      m_Infos.TypeSymbol = ((sz0 == "WDO") || (sz0 == "DOL") ? WDO : ((sz0 == "WIN") || (sz0 == "IND") ? WIN : OTHER));
      m_Infos.nDigits = (int) SymbolInfoInteger(m_szSymbol, SYMBOL_DIGITS);
      m_Infos.Volume = nContracts * (m_VolMinimal = SymbolInfoDouble(m_szSymbol, SYMBOL_VOLUME_MIN));
      m_Infos.TakeProfit = AdjustPrice(FinanceTake * v1 / m_Infos.Volume);
      m_Infos.StopLoss = AdjustPrice(FinanceStop * v1 / m_Infos.Volume);
      m_Infos.IsDayTrade = b1;
      CreateHLine(m_Infos.szHLinePrice, m_Infos.cPrice = cp);
      CreateHLine(m_Infos.szHLineTake, m_Infos.cTake = ct);
      CreateHLine(m_Infos.szHLineStop, m_Infos.cStop = cs);
      ChartSetInteger(m_Infos.Id, CHART_COLOR_VOLUME, m_Infos.cPrice);
      ChartSetInteger(m_Infos.Id, CHART_COLOR_STOP_LEVEL, m_Infos.cStop);
     };

A rotina acima, é responsável por iniciar os dados do EA da forma indicada pelo usuário e assim criar a ordem OCO, a única real mudança que irá precisar se fazer nesta rotina, será na seguinte linha

m_Infos.TypeSymbol = ((sz0 == "WDO") || (sz0 == "DOL") ? WDO : ((sz0 == "WIN") || (sz0 == "IND") ? WIN : OTHER));

isto quando você adicionar um tipo de ativo, além dos atuais, e precisar suprir alguma coisa especifica não coberta pelo atual código.

      m_Infos.Volume = nContracts * (m_VolMinimal = SymbolInfoDouble(m_szSymbol, SYMBOL_VOLUME_MIN));
      m_Infos.TakeProfit = AdjustPrice(FinanceTake * v1 / m_Infos.Volume);
      m_Infos.StopLoss = AdjustPrice(FinanceStop * v1 / m_Infos.Volume);

as 3 linhas acima irão fazer os ajustes necessários para a correta criação da ordem, nContracts é um fator de alavancagem, ou seja, você deverá usar valores como 1, 2, 3 ....  ou seja você não precisa saber qual o volume mínimo que o ativo precisa para ser negociado, tudo que você precisa de fato, é indicar o fator de alavancagem deste volume mínimo, por exemplo: Se um ativo necessita de um volume mínimo de 5 contratos, então indicado uma alavancagem de 3, o sistema irá automaticamente saber que deverá abrir uma posição com 15 contratos, isto facilita muito quando trabalhamos com ativos diversos e que tem diferentes níveis de alavancagem. Já as 2 outras linhas irão ajustar de forma adequada qual deverá ser o Take Profit e Stop Loss baseados no financeiro que o usuário estiver indicando, e isto será feito sobre o volume a ser negociado, ou seja, se o volume aumentar, mantendo o financeiro, estes pontos irão diminuir, se o financeiro aumentar mantendo o volume, este pontos irão aumentar, algo bem simples e direto, assim você pode facilmente ajustar as coisas de forma a não precisar ficar fazendo cálculos para montar a posição, o próprio EA fará os cálculos, ou seja você diz qual o ativo, qual vai ser a alavancagem, quanto de financeiro você estará arriscando e buscando, e o EA monta a ordem para você da forma correta.

   inline void MoveTo(int X, int Y, uint Key)
     {
      int w = 0;
      datetime dt;
      bool bEClick, bKeyBuy, bKeySell;
      double take = 0, stop = 0, price;
      bEClick  = (Key & 0x01) == 0x01;    //Clique esquerdo
      bKeyBuy  = (Key & 0x04) == 0x04;    //SHIFT Pressionada
      bKeySell = (Key & 0x08) == 0x08;    //CTRL Pressionada
      ChartXYToTimePrice(m_Infos.Id, X, Y, w, dt, price);
      ObjectMove(m_Infos.Id, m_Infos.szHLinePrice, 0, 0, price = (bKeyBuy != bKeySell ? AdjustPrice(price) : 0));
      ObjectMove(m_Infos.Id, m_Infos.szHLineTake, 0, 0, take = price + (m_Infos.TakeProfit * (bKeyBuy ? 1 : -1)));
      ObjectMove(m_Infos.Id, m_Infos.szHLineStop, 0, 0, stop = price + (m_Infos.StopLoss * (bKeyBuy ? -1 : 1)));
      if((bEClick) && (bKeyBuy != bKeySell))
         CreateOrderPendent(bKeyBuy, m_Infos.Volume, price, take, stop, m_Infos.IsDayTrade);
      ObjectSetInteger(m_Infos.Id, m_Infos.szHLinePrice, OBJPROP_COLOR, (bKeyBuy != bKeySell ? m_Infos.cPrice : clrNONE));
      ObjectSetInteger(m_Infos.Id, m_Infos.szHLineTake, OBJPROP_COLOR, (take > 0 ? m_Infos.cTake : clrNONE));
      ObjectSetInteger(m_Infos.Id, m_Infos.szHLineStop, OBJPROP_COLOR, (stop > 0 ? m_Infos.cStop : clrNONE));
     };

A rotina acima irá apresentar a ordem a ser criada, ela usa o movimento do mouse para apresentar onde a ordem será pendurada, mas para que isto de fato aconteça, você deverá indicar se deseja comprar ( SHIFT Pressionada ) ou vender ( CTRL Pressionada ) e uma vez que ocorrer um clique, uma ordem pendente será criada naquele ponto.

No caso de você desejar apresentar mais dados como por exemplo, ponto de cobertura, bastará adicionar o objeto nesta rotina.

Até este ponto temos todo o EA funcionando e sendo capaz de criar ordens OCO, mas como nem tudo é perfeito ....


O problema das ordens OCO

As ordens oco tem um problema, que não é culpa do sistema MetaTrader 5 ou do servidor de negociação, mas sim da própria volatilidade muito presente em alguns momentos no mercado. Teoricamente o preço deveria se mover de forma linear, sem ressaltos, mas, as vezes temos uma alta volatilidade que produz Gaps dentro do CandleStick, e quando estes gaps ocorrem no ponto onde o preço da ordem Stop Loss ou Take Profit estão, estes pontos não serão acionados e por consequência a ordem não é encerrada, pode também acontecer de durante a movimentação destes pontos pelo usuário, o preço ficar fora deste túnel, cujo limites são representados pelo Stop e Take, e se isto acontecer a ordem também não será encerrada. Isto é muito perigoso e difícil de prever quando vai acontecer, mas como programador, você tem que prever isto e criar mecanismos para minimizar os danos.

Para atualizar e tentar manter o preço dentro do túnel, ou limites, usamos 2 rotinas. A primeira é mostrada abaixo:

   void UpdatePosition(void)
     {
      for(int i0 = PositionsTotal() - 1; i0 >= 0; i0--)
         if(PositionGetSymbol(i0) == m_szSymbol)
           {
            m_Take      = PositionGetDouble(POSITION_TP);
            m_Stop      = PositionGetDouble(POSITION_SL);
            m_IsBuy     = PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY;
            m_Volume    = PositionGetDouble(POSITION_VOLUME);
            m_Ticket    = PositionGetInteger(POSITION_TICKET);
           }
     };

ela irá ser chamada pela OnTrade que é a rotina que o MetaTrader 5 chama a cada mudança executada nas posições. A próxima rotina a ser usada é chamada por OnTick para verificar e garantir que o preço fique no túnel ou dentro dos limites da ordem oco, veja ela abaixo:

   inline bool CheckPosition(const double price = 0, const int factor = 0)
     {
      double last;
      if(m_Ticket == 0)
         return false;
      last = SymbolInfoDouble(m_szSymbol, SYMBOL_LAST);
      if(m_IsBuy)
        {
         if((last > m_Take) || (last < m_Stop))
            return ClosePosition();
         if((price > 0) && (price >= last))
            return ClosePosition(factor);
        }
      else
        {
         if((last < m_Take) || (last > m_Stop))
            return ClosePosition();
         if((price > 0) && (price <= last))
            return ClosePosition(factor);
        }
      return false;
     };

Esta rotina é muito critica, já que ela será executada a cada variação de tick do ativo, ou seja, ela tem que ser o mais simples possível para que o calculo e testes sejam feitos da forma o mais eficiente, tanto quanto for possível. Mas reparem que ao mesmo tempo que mantemos o preço dentro do túnel, também verificamos algo curioso, que pode ser retirado caso você assim deseje, entrarei em mais detalhes sobre este teste extra na próxima seção. Dentro desta rotina temos a chamada para uma função, o código desta função é mostrado abaixo:

   bool ClosePosition(const int arg = 0)
     {
      double v1 = arg * m_VolMinimal;
      if(!PositionSelectByTicket(m_Ticket))
         return false;
      ZeroMemory(TradeRequest);
      ZeroMemory(TradeResult);
      TradeRequest.action     = TRADE_ACTION_DEAL;
      TradeRequest.type       = (m_IsBuy ? ORDER_TYPE_SELL : ORDER_TYPE_BUY);
      TradeRequest.price      = SymbolInfoDouble(m_szSymbol, (m_IsBuy ? SYMBOL_BID : SYMBOL_ASK));
      TradeRequest.position   = m_Ticket;
      TradeRequest.symbol     = m_szSymbol;
      TradeRequest.volume     = ((v1 == 0) || (v1 > m_Volume) ? m_Volume : v1);
      TradeRequest.deviation  = 1000;
      if(!OrderSend(TradeRequest, TradeResult))
        {
         MessageBox(StringFormat("Error Number: %d", TradeResult.retcode), "Nano EA");
         return false;
        }
      else
         m_Ticket = 0;
      return true;
     };

Esta função irá encerrar um dado volume, sendo ela a nossa proteção, mas lembre-se, para que ela funcione você terá que estar conectado, já que ela é executada na plataforma cliente MetaTrader 5, e se por um acaso a conexão com o servidor de negociação falhar, esta função será completamente inútil não servindo para nada.

Mas olhando estes 2 últimos códigos, vemos que podemos finalizar um dado volume em um ponto especifico, e ao fazer isto estamos fazendo uma parcial ou reduzindo a nossa exposição, vamos então entender como usar esta funcionalidade.


Trabalhando com parciais

As parciais é algo que muitos gostam e querem fazer quando estão operando, o EA apresentado permite fazer isto, apesar de tudo eu não mostro como implementar tal código, e o motivo disto é que as parciais são um problema a parte, mas se você desejar fazer isto, tudo que precisará fazer é chamar a rotina CheckPosition indicando o preço onde ela ocorrerá e volume que será realizado, o próprio EA fará o restante.

O fato de eu falar que parciais são um caso a parte, é por elas serem algo muito pessoal, é difícil criar algo genérico o suficiente para que satisfaça a todos. O próprio fato de que você pode estar fazendo swing irá fazer com que uma solução de matriz dinâmica seja inviável, para day trade seria adequado, desde que você não encerre o EA enquanto estiver posicionado, mas se for preciso por algum motivo fechar o EA, a solução de matriz não é muito adequada, será preciso fazer uso de algum meio de armazenamento, e a forma como os dados serão formatados dentro de um arquivo, vai depender do que você pretende fazer.

Uma coisa é fato, você deve evitar ao máximo fazer parciais usando ordem de abertura de posição, o risco de isto dar dor de cabeça é enorme. Explico: Vamos supor que você esta posicionado com 3x de alavancagem na mão de compra, e deseja realizar lucro com 2x ficando ainda alavancado em 1x, a forma de se fazer isto é vendendo 2x de alavancagem, no entanto se você fizer o EA enviar uma ordem de venda a mercado, pode ser que a volatilidade faça o preço ir e bater no seu Take Profit antes da ordem de venda ser de fato executada, isto fará com que você entre em uma posição vendida em uma tendência que pode ser desfavorável. No entanto você pode desejar enviar uma ordem Sell Limit ou Sell Stop para executar esta desalavancagem em 2x, por um lado isto parece a primeira vista adequado, mas pense melhor sobre isto, pois se a ordem for enviada antes do preço bater no ponto de parcial, você pode vim a ter uma surpresa muito desagradável, com a sua posição aberta vim a ser estopada para pouco depois a ordem pendurada vim a ser aberta aumentando em muito o seu prejuízo, no entanto se a volatilidade vier com muita força, pode acontecer a mesma coisa que acontece em um caso de entrar a mercado, como foi explicado acima.

Então na minha visão, como programador, a melhor opção ao se desejar fazer parciais, é emular o envio de ordens a mercado, mas tomando o devido cuidado para que o volume nunca exceda o volume ainda aberto e é isto que eu estou fornecendo com este EA, uma forma de emular tal coisa, mas a forma de se chamar a parcial, deixo a cargo de cada um.


Conclusão

Construir um EA para negociação não é algo tão trivial como alguns pensam, a coisa em si é bem simples frente a alguns outro problemas que muitas vezes enfrentamos em programação, no entanto criar algo que seja estável e suficientemente confiável a ponto de arriscarmos nosso dinheiro ao usar a solução, isto sim é algo que muitas vezes é desafiador. Mas aqui eu propus algo que irá facilitar a vida de quem esta começando a usar o MetaTrader 5 e não tem os devidos conhecimentos de como programar um EA, isto por que o EA não irá abrir ordens mais apenas irá ajudar a se fazer uma abertura de forma mais confiável, uma vez que a ordem foi pendurada, o EA não terá mais coisas a se fazer, o trabalho passa a ser feito pelo MetaTrader 5 e não mais pelo EA, salvo as partes acima declaradas durante a explicação do código.

Este EA pode ser muito aperfeiçoado em diversos aspectos de forma que você poderá colocar ele para operar algum setup, é verdade que terá que adicionar mais código para ele ficar mais independente do MetaTrader 5 , mais isto vai da criatividade e necessidade de cada um.

O grande trunfo deste EA é o fato de ele usar o próprio MetaTrader 5 para fazer as coisa que não estão no código do mesmo, e com isto ser extremamente estável e confiável.





Arquivos anexados |
EA_Nano_rvl_1.1.mq5 (23.44 KB)
Últimos Comentários | Ir para discussão (8)
Daniel Jose
Daniel Jose | 25 dez 2021 em 11:04
joecafrois #:
Pelo q entendo precisa ter conhecimento de "Algo Trading" para mexer com isso...

Não precisa ter conhecimento em AlgoTrading ... mas ele precisa estar habilitado sempre que você for usar um EA ( Expert Advisor ), caso contrário o EA fica com o seu funcionamento limitado.

Daniel Jose
Daniel Jose | 25 dez 2021 em 11:28
Feresther #:

Bom dia,

Muito bom, só não entendi uma coisa. Quando coloco a ordem no WIN e WDO o EA abre 6 ordens com o número de contratos que inseri em "alavancagem". Então mesmo se eu quiser operar com 1 contrato, não consigo, ele abre 6.

Será algum conceito que me passou despercebido? Sou iniciante, portanto, parto dessa premissa.

Muito obrigado por compartilhar.

Pode estar acontecendo do sistema estar enviando mais de uma ordem quando você clica no mouse, os motivos podem ser diversos, mas obrigado por reportar 😁👍, para resolver este infortúnio, você deverá adicionar um teste extra no clique do mouse, os pontos a modificar ou adicionar estão marcados em VERDE ... muita atenção para digitar da forma como está, caso contrário poderá não enviar a ordem, ou ela não ser aceita pelo servidor ... mas adicionando este teste extra deverá resolver o seu problema. A lógica é a seguinte : Quando se clicar no mouse, a variavel STATIC será setada, e somente será resetada permitindo enviar uma nova ordem quando o mouse já não estiver pressionado.

inline void MoveTo(int X, int Y, uint Key)
{
        static double d_block = 0; 
        int w = 0;
        datetime dt;
        bool bEClick, bKeyBuy, bKeySell;
        double take = 0, stop = 0, price;
        bEClick  = (Key & 0x01) == 0x01;                //Clique esquerdo
        bKeyBuy  = (Key & 0x04) == 0x04;                //SHIFT Pressionada
        bKeySell = (Key & 0x08) == 0x08;                //CTRL Pressionada
        ChartXYToTimePrice(Infos.Id, X, Y, w, dt, price);
        ObjectMove(Infos.Id, Infos.szHLinePrice, 0, 0, price = (bKeyBuy != bKeySell ? AdjustPrice(price) : 0));
        ObjectMove(Infos.Id, Infos.szHLineTake, 0, 0, take = price + (Infos.TakeProfit * (bKeyBuy ? 1 : -1)));
        ObjectMove(Infos.Id, Infos.szHLineStop, 0, 0, stop = price + (Infos.StopLoss * (bKeyBuy ? -1 : 1)));
        if ((bEClick) && (bKeyBuy != bKeySell) && (d_block == 0)) CreateOrderPendent(bKeyBuy, Infos.Volume, (d_block = price), take, stop, Infos.IsDayTrade); else d_block = 0;
        ObjectSetInteger(Infos.Id, Infos.szHLinePrice, OBJPROP_COLOR, (bKeyBuy != bKeySell ? Infos.cPrice : clrNONE));
        ObjectSetInteger(Infos.Id, Infos.szHLineTake, OBJPROP_COLOR, (take > 0 ? Infos.cTake : clrNONE));
        ObjectSetInteger(Infos.Id, Infos.szHLineStop, OBJPROP_COLOR, (stop > 0 ? Infos.cStop : clrNONE));
};
C4rl1n
C4rl1n | 28 ago 2023 em 19:08
Boa Tarde, onde eu ajusto o número de pontos e número de lotes para o mini-índice?
Daniel Jose
Daniel Jose | 29 ago 2023 em 14:03
C4rl1n #:
Boa Tarde, onde eu ajusto o número de pontos e número de lotes para o mini-índice?

Na verdade neste código o ajuste é automático. Você diz o financeiro e o número de contratos a operar e o código faz o ajuste em termos de pontos ... Esta informação é dada no momento em que você coloca o Expert Advisor no gráfico. 😁👍

C4rl1n
C4rl1n | 29 ago 2023 em 16:53
entendi, é porque estou querendo desenvolver o meu EA, mas o número de lotes e de pontos não esta batendo
Gráficos na biblioteca DoEasy (Parte 87): coleção de objetos gráficos, controlamos a modificação de propriedades de objetos em todos os gráficos abertos Gráficos na biblioteca DoEasy (Parte 87): coleção de objetos gráficos, controlamos a modificação de propriedades de objetos em todos os gráficos abertos
No artigo, continuaremos a trabalhar no rastreamento dos eventos de objetos gráficos padrão e na criação de funcionalidades que permitem controlar as alterações nas propriedades dos objetos gráficos localizados em qualquer gráfico aberto no terminal.
Gráficos na biblioteca DoEasy (Parte 86): coleção de objetos gráficos, controlamos a modificação de propriedades Gráficos na biblioteca DoEasy (Parte 86): coleção de objetos gráficos, controlamos a modificação de propriedades
Este artigo analisa o rastreamento de modificações nos valores de propriedades, remoção e renomeação de objetos gráficos dentro da biblioteca.
Gráficos na biblioteca DoEasy (Parte 88): coleção de objetos gráficos, matriz dinâmica bidimensional para armazenar propriedades de objetos que mudam dinamicamente Gráficos na biblioteca DoEasy (Parte 88): coleção de objetos gráficos, matriz dinâmica bidimensional para armazenar propriedades de objetos que mudam dinamicamente
Neste artigo, criaremos uma classe de matriz multidimensional dinâmica com a capacidade de alterar a quantidade de dados em qualquer dimensão. Com base na classe criada, criaremos uma matriz dinâmica bidimensional para armazenar algumas propriedades alteradas dinamicamente de objetos gráficos.
Use canais e bate-papos em grupo da MQL5.community Use canais e bate-papos em grupo da MQL5.community
O site MQL5.com reúne traders de todo o mundo que publicam artigos, códigos e produtos gratuitos no Mercado, desenvolvem projetos para outros usuários no serviço Freelance e copiam sinais de negociação. Você pode se comunicar com eles no fórum, nos bate-papos para traders e nos canais MetaTrader.