Tudo sobre Programação, com código fonte exemplo - página 12

 
Leandro Borges:

Estou criando um filtro adicional para um EA, porem a logica nao boolean.

 case PA_MODE_PATTERN_51:

        if (
        ((buffer[1].high * (1.0 - extFilPARange)) < buffer[0].close < (buffer[1].high * (1.0 + extFilPARange))) |
        ((buffer[1].low * (1.0 - extFilPARange)) < buffer[0].close < (buffer[1].low * (1.0 + extFilPARange))) |
        ((buffer[2].high * (1.0 - extFilPARange)) < buffer[0].close < (buffer[2].high * (1.0 + extFilPARange))) |
        ((buffer[2].low * (1.0 - extFilPARange)) < buffer[0].close < (buffer[2].low * (1.0 + extFilPARange))) |
        )
         return(true);
         break;

case PA_MODE_NONE:

         return(true);

         break;

default:

         return(false);

         break;


Minha ideia 'e operar em algum range nas min/max dos dias enteriores.

Se eu faco apenas uma logica o filtro funciona normal, ex:

 case PA_MODE_PATTERN_51:

        if ((buffer[1].high * (1.0 - extFilPARange)) < buffer[0].close < (buffer[1].high * (1.0 + extFilPARange)))
           return(true);

        break;


Estou na duvida o que pode estar errado, se 'e o uso de |, || ou ^. Testei os 3 e nao funciona. Qual logica que devo usar?


buffer[1].high = max dia anterior

extFilPARange = distanciamento max permitido.

O seu código não está funcionando por causa da forma como vc está usando o operador "<".

Se vc quer testar se "x" está entre "a" e "b", usar "if ( a < x < b )" não vai funcionar do jeito que vc quer, pois desse jeito ele primeiro vai comparar "a" com "x", obtendo um resultado booleano (valor 0 para verdadeiro ou valor 1 para falso) e em seguida vai comparar este último valor com "b", o que vai dar um resultado diferente do que vc quer.

Pra funcionar como vc quer, tem que usar "if ( a < x && x < b)". Assim vai funcionar pois o "<" tem precedência sobre o "&&", então ele primeiro vai fazer as duas comparações e em seguida vai fazer o "and" lógico entre os dois resultados booleanos das comparações.

Uma outra coisa que vc deve corrigir é usar o operador "||" em vez de "|" para implementar o "ou" lógico. O "I" executa a operação "ou" bit a bit. Não é o seu caso. Nesse caso específico seu até vai funcionar igual ao "||", mas em outras situações pode dar resultado diferente.

 
Rogerio Giannetti Torres:

Boa tarde Leandro:

Não confunda Operação Booleana  (  && and  ,  || or ) com operação binárias  ( | or , ^ xor  , & and, >> desl. direita, << desl. esquerda) . 

No caso você quer saber se alguma  das quatro expressões é verdadeira, então tem que usar || ( or )...   if ( expressao1 || expressao2 || expressao3 || expressao4)  {  }

O que você escreveu foi o resultado de tres operações binarias   ret = ( expressao1 | expressao2 | expressao3 | expressao4)   ==> if( ret ) { }

Obrigado pela explicacao, consegui solucionar.

Descobri que nao posso comparar x < y < Z, deve se usar x < y && Y < Z.

 
Trader_Patinhas:

O seu código não está funcionando por causa da forma como vc está usando o operador "<".

Se vc quer testar se "x" está entre "a" e "b", usar "if ( a < x < b )" não vai funcionar do jeito que vc quer, pois desse jeito ele primeiro vai comparar "a" com "x", obtendo um resultado booleano (valor 0 para verdadeiro ou valor 1 para falso) e em seguida vai comparar este último valor com "b", o que vai dar um resultado diferente do que vc quer.

Pra funcionar como vc quer, tem que usar "if ( a < x && x < b)". Assim vai funcionar pois o "<" tem precedência sobre o "&&", então ele primeiro vai fazer as duas comparações e em seguida vai fazer o "and" lógico entre os dois resultados booleanos das comparações.

Uma outra coisa que vc deve corrigir é usar o operador "||" em vez de "|" para implementar o "ou" lógico. O "I" executa a operação "ou" bit a bit. Não é o seu caso. Nesse caso específico seu até vai funcionar igual ao "||", mas em outras situações pode dar resultado diferente.

Obrigado pela explicacao, consegui solucionar exatamente dessa maneira "if ( a < x && x < b)" .
 
Leandro Borges:
Obrigado pela explicacao, consegui solucionar exatamente dessa maneira "if ( a < x && x < b)" .
Agora que eu vi que o @Rogerio Giannetti Torres já tinha respondido 2 minutos antes de mim. Acho que a resposta dele chegou enquanto eu escrevia a minha.
 

Galera, estou com um problema e não consigo resolver.. Quero que o preço atual do ativo quando for menor que a Banda de Bollinger inferior, abra uma compra e vice versa.. Alguém pode me ajudar por favor? O E.A não abre de acordo o comando.. Segue o Código!!

#include  <Trade/Trade.mqh>
CTrade trade;

void OnTick()
  {
  
double ask,bid,last;
double mediaBBArray[];
double upperBBArray[];
double lowerBBArray[];
int bbDefinicao;

      ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
      bid = SymbolInfoDouble(_Symbol,SYMBOL_BID);
      last = SymbolInfoDouble(_Symbol,SYMBOL_LAST);

      bbDefinicao = iBands (_Symbol,_Period,20,0,2,PRICE_CLOSE);
      ArraySetAsSeries (mediaBBArray,true);
      ArraySetAsSeries (upperBBArray,true);
      ArraySetAsSeries (lowerBBArray,true);
      CopyBuffer (bbDefinicao,0,0,3,mediaBBArray);
      CopyBuffer (bbDefinicao,1,0,3,upperBBArray);
      CopyBuffer (bbDefinicao,2,0,3,lowerBBArray);
      double MediaBBValor = NormalizeDouble (mediaBBArray[0],2);
      double UpperBBValor = NormalizeDouble (upperBBArray[0],2);
      double LowerBBValor = NormalizeDouble (lowerBBArray[0],2);
      
            if(last < LowerBBValor)
               {
                  trade.Buy (1, _Symbol, ask, ask - 50, ask + 100);
               } 
            else if (last > UpperBBValor)
               {
                  trade.Sell (1, _Symbol, bid, bid + 50, bid - 100);
               }   
  }
 

Olá pessoal.

Criei um indicador, conforme parte do código abaixo, que se baseou no evento do preço (price) que é o meu buffer, porém necessito também das informações de abertura e fechamento. Não sei como fazer esta inclusão no código abaixo. Preciso de uma direção para acessar os dados open e close.

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[])
   {CopyBuffer(iBands(_Symbol,_Period,20,0,2,PRICE_CLOSE),1,0,rates_total,BBSupBuffer);
   CopyBuffer(iBands(_Symbol,_Period,20,0,2,PRICE_CLOSE),0,0,rates_total,BBMediaBuffer);
   CopyBuffer(iBands(_Symbol,_Period,20,0,2,PRICE_CLOSE),2,0,rates_total,BBInfBuffer);
//---
  for(int i=1; i<rates_total;i++)
     {
      if(price[i-1]>BBMediaBuffer[i] && price[i]<BBMediaBuffer[i])
        {
         VendaBuffer[i]=price[i];
        }
      else
        {
         VendaBuffer[i]=0;
        }

      if(price[i-1]<BBMediaBuffer[i] && price[i]>BBMediaBuffer[i])
        {
         CompraBuffer[i]=price[i];
        }
      else
        {
         CompraBuffer[i]=0;
        }
     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+


Obrigado a todos.

 

Fórum de negociação, sistemas de negociação automatizados e testes de estratégias de negociação

CalendarValueHistory problema de fuso horário

Rogerio Giannetti Torres, 2019.08.14 04:56

Gilberto, 

não é bem assim. O  mqlCalendarValue.time  está em hora GMT,  então se  mqlCalendarValue.time  = 05:30:00  aqui é 02:30:00, mas no horário de verão aqui é 03:30:00.  Então deixar fixo 3 hora no programa é uma furada, Assim sendo, use o TimeGMTOffset() que já fica ajustado para 02:00:00 horas durante o horário de verão.

Se você quer calcular a hora da notícia em  relação ao servidor Forex o cálculo é: 

1) Ajuste a hora do evento para hora local ==>  horaEvento =  mqlCalendarValue.time - TimeGTMOffSet();

2) Em seguida ajuste para o horário do evento em função da hora do servidor ==>  horaEvento = horaEvento + (TimeTradeServer() - TimeLocal());

Mas tem um problema, como o TimeLocal() é a hora do PC  vai ter que confiar que a hora do PC está correta.


 

Fórum de negociação, sistemas de negociação automatizados e testes de estratégias de negociação

Forcas Vendedoras e compradoras

Joscelino Celso de Oliveira, 2019.03.15 01:58

//-- PRE-CALCULO VOLUMES DE TICKS NAS PONTAS COMPRADORA E VENDEDORA

   MqlTick tick_array[]; 
   CopyTicks(_Symbol,tick_array,COPY_TICKS_TRADE,0,10);
   MqlTick tick = tick_array[0];

if(hora>=hora_abertura && hora<=close_time)
  {
   if(( tick.flags&TICK_FLAG_BUY)==TICK_FLAG_BUY)          //-- Se for um tick de compra
      {
        sumVolBuy+=(long)tick.volume;
        
      }
   else if(( tick.flags&TICK_FLAG_SELL)==TICK_FLAG_SELL)   //-- Se for um tick de venda
      {
        sumVolSell+=(long)tick.volume;
        
      }
    }

Estou tentando capturar as somatórias de ticks nas pontas vendedoras e compradoras, conforme trecho do cogido a seguir.

Ocorre que não tenho confiança nos valores que estão sendo retornados. Alguém com sucesso neste tipo de abordagem e estrategia?


 

Fórum de negociação, sistemas de negociação automatizados e testes de estratégias de negociação

Dúvida sobre OrderSelect() e OrdersTotal()

Márcio Hermes, 2019.08.22 04:52

Olá a todos.

Estou desenvolvendo uma função para agredir o preço BID com as ordens pendentes de venda, e me deparei com algumas dúvidas, pois na conta demo, é quase tudo uma maravilha.

Está descrito abaixo o funcionamento da função, porém vou dar um resumo básico:

 - a função, primeiramente, guarda o valor de BID em uma variável local para garantir o preço de agressão sempre igual.

 - coleta a ordem de venda com o maior preço; modifica o preço para o valor guardado na variável local (valor BID naquele momento) e envia a ordem; se sobrou saldo de cotas, a ordem é alterada para o preço original, que também está guardado numa variável local;

 - se a ordem de venda foi totalmente executada, será coletada uma nova ordem de venda com maior preço, repetindo os passos descritos acima; 

OBS.: Estou em posição comprada, logo a função executa operações de venda, me "retirando" do mercado. Em Fundos Imobiliários, não é possível posicionar vendido.

Acredito que estou fazendo alguma confusão com a forma como as ordens são executadas, como coletar dados para averiguação. A função descrita abaixo pode não estar semanticamente correta.

Este trecho de código é executado após o envio da ordem de venda, com o preço modificado para o valor BID (agressão de venda), pois preciso saber se a ordem tem saldo de cotas. Se houver saldo, preciso modificar novamente a ordem de venda para o seu preço original, que está guardado na variável ' current_order_price'. 

         // trecho de código para alterar a ordem se houver cotas não executadas.
         ticket = result.order;          
         if(!OrderSelect(ticket)){ // <= isso está estranho

Procurando aqui na comunidade, encontrei um tópico (https://www.mql5.com/pt/forum/87308) que me ajudou a clarear um pouco as coisas. Já entendi que uma ordem executada em sua totalidade não pode ser selecionada por ' OrderSelect()', então vem a primeira dúvida:

 - na lógica da função que desenvolvi, se a ordem foi totalmente executada, será coletada uma nova ordem de venda, para agredir BID. Então ...

  if(!OrderSelect(ticket)){ // <= isso está estranho
         
     PrintFormat("OrderSelect error %d",GetLastError());     // if unable to send the request, output the error code
     ResetLastError();
     //end_of_processing = true; // to exit do-while
     continue; // pula para a próxima iteração     
  }

... se o 'OrderSelect()' retornar 'false', significa que a ordem foi totalmente executada. 

E a dúvida está justamente nessa forma de verificação, que não parece ser a mais adequada, apesar de ter lógica.

A outra questão está no loop que optei usar (do-while).

Optei por usar um do-while para garantir que, a cada iteração, sempre vou pegar o valor atual de 'OrdersTotal()' para pesquisar por uma nova ordem de venda. Pelo que entendi, através de outros questionamentos, como há o "risco" de uma execução total de uma ordem, ' OrdersTotal()'  vai ser alterado. Lógico que mesmo tendo esse cuidado, e se eu não estiver errado, um evento de trade pode acontecer durante a execução da função descrita abaixo.

A outra dúvida é se esse do-while faz sentido neste caso, ou se tem uma outra forma de abordagem. 


/**
   Função para agredir, com todas as ordens pendentes de venda, exclusivamente e somente, na melhor oferta de compra (BID).
   
   Funcionamento:
    1 - o valor da melhor oferta de compra (BID), será atribuido a uma variável local;
    2 - será coletada a ordem de venda mais distante do preço ASK (ou seja, com maior preço);
    3 - será modificado o preço, desta ordem de venda, para o preço BID, atribuido a uma 
    variável local;
    4 - caso a ordem de venda seja integralmente executada, será repetido 
    os passos 2 e 3;
    5 - caso sobre saldo de cotas, a ordem será alterada em seu preço novamente, para o valor anterior
    e a função é finalizada.
*/
void CTradeFIIDialog::BaterBID_ComTodasAsOrdensPendentesDeVenda(){
      
   // coletar o preço BID atual para uma variável local;
   double BID_atual = SymbolInfoDouble(Symbol(),SYMBOL_BID); 
   
   double current_order_price = 0.0;
   bool end_of_processing = false;
   double maior = 0.0;
   ulong ticket = 0;
   
   MqlTradeRequest request = {0};
   MqlTradeResult result = {0};
   int orders_total = 0;
   
   do{
      
      current_order_price = 0.0;
      orders_total = 0;
      ticket = 0.0;
      //--- zerar os valores de pedido e o seu resultado
      ZeroMemory(request);
      ZeroMemory(result); 
   
      orders_total = OrdersTotal();
      if(orders_total <= 0){
         Print("BaterBID_ComTodasAsOrdensPendentesDeVenda - Não há ordens pendentes na pedra.");
         end_of_processing = true; // to exit do-while
         continue; 
      }
      
      for(int i = 0; i < orders_total; i++){
         if(OrderGetTicket(i) > 0) {
            if((OrderGetString(ORDER_SYMBOL) == Symbol())
               && (OrderGetInteger(ORDER_MAGIC) == MAGIC_NUMBER)
               && (OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_SELL_LIMIT)) {
             
               if(OrderGetDouble(ORDER_PRICE_OPEN) >  maior){
                  maior  = OrderGetDouble(ORDER_PRICE_OPEN);
                  ticket = OrderGetInteger(ORDER_TICKET); 
               }
            }          
         }
      }
      
      if(maior <= 0.0){
         Print("BaterBID_ComTodasAsOrdensPendentesDeVenda - Não há ordens de venda na pedra.");
         end_of_processing = true; // to exit do-while
         continue;
      }
      
      current_order_price = maior; // apenas uma atribuição para melhor entendimento da função
      maior = 0.0;
      
      // modifica a ordem para agredir o preço BID.
      request.action = TRADE_ACTION_MODIFY;
      request.order = ticket;
      request.price = BID_atual;
      request.symbol =Symbol(); // símbolo
      
      if(!OrderSend(request, result)) {
        PrintFormat("BaterBID_ComTodasAsOrdensPendentesDeVenda - modify order buy limit - OrderSend error %d", GetLastError());
        ResetLastError();
        end_of_processing = true; // to exit do-while
        continue; // pula para a próxima iteração            
      }else{
            
         PrintFormat("Ordem Modificada! retcode=%u  deal=%I64u  order=%I64u  price=%.4f",result.retcode,result.deal,result.order,result.price); 
         
         // trecho de código para alterar a ordem se houver cotas não executadas.
         ticket = result.order;          
         if(!OrderSelect(ticket)){ // <= isso está estranho
         
            PrintFormat("OrderSelect error %d",GetLastError());     // if unable to send the request, output the error code
            ResetLastError();
            //end_of_processing = true; // to exit do-while
            continue; // pula para a próxima iteração     
         } 
             
         double vol = OrderGetDouble(ORDER_VOLUME_CURRENT);         
         if(vol > 0){
         
            //--- zerar os valores de pedido e o seu resultado
            ZeroMemory(request);
            ZeroMemory(result);  
            
            // modifica novamente a ordem de venda para o seu valor original.
            request.action = TRADE_ACTION_MODIFY;
            request.order = ticket;
            request.price = current_order_price;
            request.symbol =Symbol(); // símbolo
            if(!OrderSend(request, result)) {
               PrintFormat("BaterBID_ComTodasAsOrdensPendentesDeVenda - REMODIFY order buy limit - OrderSend error %d", GetLastError());
               ResetLastError();
               end_of_processing = true; // to exit do-while
               continue; // pula para a próxima iteração            
            }else{
               PrintFormat("BaterBID_ComTodasAsOrdensPendentesDeVenda - REMODIFY order buy limit - order=%I64u  price=%.4f", ticket, current_order_price);
               end_of_processing = true; // to exit do-while
            }
         }       
      }       
   }while(!end_of_processing);
   
   
   // coletar a ordem de venda mais distante de ASK, ou seja, com maior preço;
   // coletar o preço atual da ordem de venda para uma variável local;
   // modificar o preço desta ordem de venda para o preço BID;
   // verificar se sobrou saldo de cotas;
   // caso tenha sobrado saldo, alterar novamente o valor da ordem de venda para o valor anterior;
   // caso a ordem foi executada integralmente, coletar a ordem mais distante de ASK da lista que sobrou.
}


Abraço a todos.