English Русский 中文 Español Deutsch 日本語
preview
Analisando o spread para preços de Bid e Ask no MetaTrader 5

Analisando o spread para preços de Bid e Ask no MetaTrader 5

MetaTrader 5Negociação | 27 outubro 2021, 10:06
2 068 0
Paul Kelly
Paul Kelly

Introdução

Se você não usar ordens limite e stop para abrir e fechar negócios, estes últimos serão executados de acordo com ordens a mercado. O preço que você receberá com esse tipo de ordem dependerá do tamanho do spread.

Ao clicar no botão comprar, você está de fato comprando ao preço de procura (Ask) que é o tamanho do spread acima do preço de oferta (Bid) usado por você para tomar sua decisão de compra.

Ao clicar no botão vender, você está de fato vendendo ao preço de oferta (Bid) que é o tamanho do spread abaixo do preço de procura (Ask).

Por conseguinte, ao clicar em "Fechar" para encerrar uma posição de compra que estava aberta, você está de fato vendendo ao preço de oferta (Bid) atual.

Por outro lado, ao encerrar uma posição de venda que estava aberta, você compra ao preço de procura (Ask) atual.

Os dados de ticks presentes no MetaTrader 5 possibilitam analisar quais valores históricos de spreads existiam de fato entre os valores Bid e Ask.

Contudo, não há razão para procurar o valor atual do spread, pois ele pode ser obtido por meio da visualização das linhas Bid e Ask.


Vamos esclarecer isso

Segundo estes gráficos, a corretora afirma que durante a sessão os spreads máximos são de 5 pips.

Se isso fosse verdade, o ciclo completo de abertura e fechamento de um negócio custaria apenas 1 pip.

Assim, para um negócio com uma relação risco/retorno de 1/1, com stop-loss de 10 pips e take-profit de 10 pips, o custo seria de 10% do seu risco/aposta.

Por isso, esse é um spread bastante justo. Por exemplo, as casas de apostas costumam arriscar 15%, enquanto a margem de lucro nos cassinos é de cerca de 4%.


BAS-EURUSD-M30

Há uma segunda linha no gráfico - a vermelha. Trata-se do spread médio real, e é quase o dobro do spread declarado pela corretora (linha tracejada preta), o que pode ser confirmado na janela de dados abaixo. Assim, no exemplo com stop-loss e take-profit que discutimos anteriormente, o custo para você será de pelo menos dois pips, isto é, de 20%. 


BAS-EURUSD-M30-DW


Além disso, os custos ainda serão os mesmos 2 pips embora você use scalping ou estratégias semelhantes com stop-loss e take profit de 5 pips, ou mesmo que decida sair antes dos stops definidos (com SL e TP de 10 pips) e com uma perda de 5 pips. Mas como você optou por sair discretamente quando negócio começou a ir contra você, os custos agora serão de 40%. 

Quando comecei a operar, costumava colocar um stop-loss a 5 pips e um take-profit de 10 para que a relação risco/lucro fosse de 2:1, (acredito que muitos iniciantes fazem isso). Claramente, nada de bom veio disso.

Por isso, realizei uma análise profunda do gráfico EURUSD M1 usando o confiável indicador Zig Zag. Defini um tamanho mínimo de etapa de 5 pips, o que era um recuo de preço aceitável para mim.

Os resultados mostraram que a maioria das pequenas oscilações ocorriam ao redor de 7 pips, enquanto as etapas de 10 pips eram muito raras. Como é claro, considerei todas as informações financeiras e a volatilidade do mercado, por isso os resultados foram baseados principalmente em médias dentro das sessões de negociação.

Mais tarde, comecei a definir um stop-loss de 10 pips e deixei o take-profit em aberto. Eu queria ficar de olho no negócio e sair quando houvesse uma perda ou lucro de 7 pips. Desse modo, os resultados já estavam melhorando, mas não havia lucros ainda. Foi nesse momento que notei grandes spreads junto à corretora com a qual eu negociava. Como é óbvio, parti em busca de uma corretora melhor.


BAS-EURUSD-M1

Se você negociar com base na divulgação de notícias ou no aumento da volatilidade do mercado, você poderá notar que o spread real da corretora subirá para 15 pips, o que é três vezes o padrão de 5 pips. Assim você terá que pagar 3 pips, ou seja, 60% de sua aposta. 


BAS-EURUSD-M1-DW

Depois das 20h30, horário do Reino Unido (21h30 segundo o horário do servidor), já não vale a pena operar, porque o spread pode ser 4, 5 ou até 6 vezes maior. O spread será ainda mais desagradável se você decidir manter alguma posição durante o fim de semana. Você pode ver no gráfico que este spread é quase 10 vezes maior do que os 5 pips padrão. Tamanho spread só pode ser coberto por um stop-loss ou take-profit extremamente altos.

BAS-EURUSD-M30-WeekEnd


OnInit() Code example

#property indicator_separate_window

#property indicator_buffers 2
#property indicator_plots   2

//--- plots
#property indicator_label1  "ActSpread"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  2

#property indicator_label2  "DeclaredSpread"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrBlack
#property indicator_style2  STYLE_DASH
#property indicator_width2  2

//--- indicator parameters
input int      numRecentBarsBack=100; //#RecentBarsBack M30+~100, M5~200, M1~500
input bool     doPrint=true;          //true=prints to the toolbox\experts log

//--- indicator buffers
double         ActSpreadBuf[], DeclaredSpreadBuf[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()  
{
   int numBars=iBars(_Symbol,PERIOD_CURRENT)-2; 
   
   // Check we have enough data for the request before we begin
   if(numRecentBarsBack>numBars) 
   { 
      Alert("Can't Do ", numRecentBarsBack, "! Only ",  
               numBars, " Bars are Available", 
               " try 100 or so for 30+ minute charts,",
               " 200 for 5 minute, or 500 for 1 minute charts.",
               " Otherwise the indicator may be too slow"
           ); 
           
      return(INIT_PARAMETERS_INCORRECT);
   }

   double sumPrice=0; 
   double avgPrice=0; 

   // Get the standard 5 point spread for the standard EURUSD currency
   double stdSpread=0.00005/iClose("EURUSD",PERIOD_M1,1); // 1.2 ~=  EURUSD std price
   
   //Find out the current average price of the instrument we are using, so we can standardise the spread and _Point
   int CheckAvgPriceBars=MathMin(numRecentBarsBack, 200);
   
   int i=0;
   for(; i<CheckAvgPriceBars; i++)
   {
      sumPrice+=iClose(_Symbol,PERIOD_CURRENT,i);
   }
   avgPrice=sumPrice/(i? i: 1.0);
   
   //convert the stdSpread to stdPoint by dividing by 5, so we compare  apples with apples, not oranges
   double stdPoint=StringToDouble(DoubleToString(avgPrice*stdSpread/5.0,6));

   Print(i, "=bars done, avgPrice=", DoubleToString(avgPrice,6), 
            " std=", DoubleToString(1.2*stdSpread, 6), 
            " stdPoint=", DoubleToString(stdPoint, 6)
         );
   
   SetIndexBuffer(0,ActSpreadBuf,INDICATOR_DATA);         
   SetIndexBuffer(1,DeclaredSpreadBuf,INDICATOR_DATA);    
   
   string indName ="BAS("+_Symbol;
          indName+=" TF="+string(_Period);
          indName+=" stdPoint="+DoubleToString(stdPoint, 6);
          indName+=") Last("+string(numRecentBarsBack)+") Bars";
          
   IndicatorSetString(INDICATOR_SHORTNAME, indName); 
   
   IndicatorSetInteger(INDICATOR_DIGITS,6); 
   
   IndicatorSetDouble(INDICATOR_MINIMUM, 0.0); 

   IndicatorSetInteger(INDICATOR_LEVELS, 20);     
   
   //mark out each standard EURUSD 5 point spread, to compare this currencies spread with EURUSD
   IndicatorSetDouble(INDICATOR_LEVELVALUE,0,  0.000000); 
   IndicatorSetDouble(INDICATOR_LEVELVALUE,1,  5*stdPoint); 
   IndicatorSetDouble(INDICATOR_LEVELVALUE,2, 10*stdPoint); 
   IndicatorSetDouble(INDICATOR_LEVELVALUE,3, 15*stdPoint); 
   IndicatorSetDouble(INDICATOR_LEVELVALUE,4, 20*stdPoint); 
   IndicatorSetDouble(INDICATOR_LEVELVALUE,5, 25*stdPoint); 
   IndicatorSetDouble(INDICATOR_LEVELVALUE,6, 30*stdPoint); 
   IndicatorSetDouble(INDICATOR_LEVELVALUE,7, 35*stdPoint); 
   IndicatorSetDouble(INDICATOR_LEVELVALUE,8, 40*stdPoint); 
   IndicatorSetDouble(INDICATOR_LEVELVALUE,9, 45*stdPoint); 
   IndicatorSetDouble(INDICATOR_LEVELVALUE,10,50*stdPoint); 
   IndicatorSetDouble(INDICATOR_LEVELVALUE,11,55*stdPoint); 
   IndicatorSetDouble(INDICATOR_LEVELVALUE,12,60*stdPoint); 
   IndicatorSetDouble(INDICATOR_LEVELVALUE,13,65*stdPoint); 
   IndicatorSetDouble(INDICATOR_LEVELVALUE,14,70*stdPoint); 
   IndicatorSetDouble(INDICATOR_LEVELVALUE,15,75*stdPoint); 
   IndicatorSetDouble(INDICATOR_LEVELVALUE,16,80*stdPoint); 
   IndicatorSetDouble(INDICATOR_LEVELVALUE,17,85*stdPoint); 
   IndicatorSetDouble(INDICATOR_LEVELVALUE,18,90*stdPoint); 
   IndicatorSetDouble(INDICATOR_LEVELVALUE,19,95*stdPoint); 
    
return(INIT_SUCCEEDED);
}

Este é um indicador simples com duas construções. Tem apenas dois parâmetros. Um deles é o 'numRecentBarsBack' - o número de barras a serem analisadas.

Antes de mais nada, no OnInit() verificamos se temos dados suficientes para o pedido. Se não houver dados suficientes, informamos o usuário sobre isso e especificamos valores mais realistas. Encerramos o indicador com um erro.

Tudo o resto em OnInit() deve estar claro. A única coisa que podemos observar adicionalmente são os níveis usados na janela adicional do indicador - seus valores correspondem a múltiplos do spread padrão para EURUSD de 5 pontos.  

Este é um passo bastante importante, pois não só gostaríamos de comparar os spreads anunciados e suas médias reais, mas também confrontar o das diversas moedas com o do EURUSD padrão, que tradicionalmente tem o spread mais baixo de todas as moedas.

Afinal, é uma abordagem bastante confusa porque é preciso obter o preço atual do EURUSD (e substituir 1,2 se não estiver) e depois dividir 5 pontos de EURUSD por esse preço para traçar o spread padrão. Em seguida, examinamos os preços numRecentBarsBack do instrumento selecionado (não testei o desempenho do indicador dos símbolos para além do Forex) e obtemos seu preço médio.

Uma vez obtido o preço médio do instrumento, podemos traçar a tabela de pontos padrão arredondados multiplicando o preço médio do instrumento pelo spread padrão obtido anteriormente e dividindo por 5 (spread padrão EURUSD em pontos).

Em seguida, no valor de cada nível utilizamos os pontos padrão arredondados que obtivemos. Também incluímos no nome curto do indicador, como mostrado no nome do indicador no gráfico do exótico USDMXN abaixo.

No exemplo do USDMXN, o spread diário é alegadamente de cerca de 0,0025, o que equivale a cerca de 3 níveis de spread acima de zero, o que corresponde a cerca de 15 pontos no gráfico EURUSD. Observe também que o spread médio real é significativamente maior do que este nível para esta corretora.

BAS-USDMXN-M30

No gráfico GBPAUD, o spread informado durante o dia é mostrado em torno de 0,00019, cerca de 2,5 níveis de spread acima de zero, o que agora equivale a cerca de 12 pips no gráfico do símbolo EURUSD. Observe também que neste gráfico os valores de spread médios reais estão bem próximos dos spreads informados pela corretora.

 BAS-GBPAUD-M30

No gráfico do GBPJPY, o spread anunciado pela corretora é de cerca de 0,020, cerca de 3 níveis de spread acima de zero, o que corresponde a cerca de 15 pips no gráfico do símbolo EURUSD. Observe também que neste gráfico os valores de spread médios reais estão bem próximos dos spreads informados pela corretora.

BAS-GBPJPY-M30

Além disso, no gráfico USDJPY o spread diário anunciado é de cerca de 0,0050, o que corresponde a cerca de 1 spread acima de zero, o que corresponde a cerca de 5 pips padrão no gráfico EURUSD. Observe também que neste gráfico os valores de spread médios reais são cerca do dobro dos valores de spread apresentados pela corretora, de modo que os comentários acima sobre a relação risco/lucro no EURUSD podem ser referentes aqui.

BAS-USDJPY-M30


Apresentamos mais alguns exemplos abaixo, você pode tirar suas próprias conclusões sobre a proporção dos níveis de spread.

BAS-GBPUSD-M30

BAS-EURGBP-M30

O segundo parâmetro no indicador é o valor bool 'doPrint' verificado no código. Se ele for true, exibimos as estatísticas para barras individuais no log do EA, conforme mostrado no exemplo abaixo. O indicador pode ser considerado mais lento se o parâmetro 'numRecentBarsBack' for definido muito alto. Por isso, 100 barras são selecionadas por padrão.

Se o parâmetro 'doPrint' for ajustado para true e o parâmetro 'numRecentBarsBack' for ajustado para um valor razoável, por exemplo, cerca de 100 no gráfico de 30 minutos ou 300 no gráfico de um minuto, então você pode copiar o log resultante do EA e enviá-lo para a corretora como prova dos valores de spread reais.

Log do spread Bid/Ask M20

Log do spread Bid/Ask M1


OnCalculate() Code Example

//--- Global variables
//--- Set the date formatting for printing to the log
const uint dtFormat=uint(TIME_DATE|TIME_MINUTES); 

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
   //--- Check for no data or Stop flag before we begin               
   if(_StopFlag || rates_total<2)  
   { 
         Alert("Error, StopFlag=", _StopFlag, " #Bars=", rates_total);    
         return(rates_total);    
   }
   
   //only do the report at indicator start up or refresh 
   if(prev_calculated>2) 
   {         
      // if we have already nulled the ActSpreadBuf just do the DeclaredSpreadBuf[] and return.
      if(prev_calculated==rates_total)
      {
         int currBar=rates_total-1;
         DeclaredSpreadBuf[currBar]=spread[currBar]*_Point;
         return(rates_total);
      }
      // else its the start of a new bar so null the ActSpreadBuf 
      else
      {
         int currBar=rates_total-1;
         ActSpreadBuf[currBar]=EMPTY_VALUE;
         return(rates_total);
      }
   }
         
         
   static int start=rates_total-numRecentBarsBack;
   
   MqlTick tickBuf[]; 
   
   double sumSpread=0;
   double thisSpread=0;
   
   int ticks=0; 
   int bid_tick=0; 
   int ask_tick=0; 
   int k=0;
   
   ArrayInitialize(ActSpreadBuf, EMPTY_VALUE);      
   ArrayInitialize(DeclaredSpreadBuf, EMPTY_VALUE); 
   
   for(int i=start; i<rates_total; i++) 
   { 
      sumSpread=0;
      thisSpread=0;
      bid_tick=0;
      ask_tick=0;
      k=0;
      
      ticks=CopyTicksRange(_Symbol, tickBuf, 
                           COPY_TICKS_INFO, // Only bid and ask changes are required
                           time[i-1]*1000,  // Start time of previous bar
                           time[i  ]*1000   // End time of previous bar
                           );
      
      while(k<ticks) 
      {
         if((tickBuf[k].flags&TICK_FLAG_ASK)==TICK_FLAG_ASK)  
            ask_tick++; 
            
         if((tickBuf[k].flags&TICK_FLAG_BID)==TICK_FLAG_BID)  
            bid_tick++; 
         
         sumSpread+=tickBuf[k].ask-tickBuf[k].bid;
         
         k++;
      }
      
      // Ensure no divide by zero errors for any missing tick data
      if(ticks>0) {                    
         thisSpread=sumSpread/ticks;
         ActSpreadBuf[i-1]=thisSpread;  
      }
      else  { 
         thisSpread=0.0; 
         ActSpreadBuf[i-1]=EMPTY_VALUE;  
      }

      DeclaredSpreadBuf[i-1]=spread[i-1]*_Point;
      
      if(doPrint) 
      {            
                  Print(TimeToString(time[i-1], dtFormat), 
                  "  NumTicks="+string(ticks),
                  "  b="+string(bid_tick),
                  "  a="+string(ask_tick),
                  "  AvgSpread=",  DoubleToString(thisSpread/_Point, 1),
                  "  DeclaredSpread=", string(spread[i-1]) 
                  );
      }
   
   }
   
   //don't do stats for incomplete current bar, but can do DeclaredSpread if it has a value
   DeclaredSpreadBuf[rates_total-1]=(spread[rates_total-1]*_Point);

//--- return value of prev_calculated for next call
return(rates_total);
}

No exemplo acima com OnCalculate(), observe o uso de CopyTicksRange() só para obter os dados de ticks entre o início da barra/vela do índice anterior e o início da barra/vela com o índice atual. Observe também que precisamos converter a matriz de time[] em milisegundos multiplicando-a por 1000, porque os dados datetime têm precisão de segundos e CopyTicksRange() requer milisegundos.

ticks=CopyTicksRange(_Symbol, tickBuf, 
                           COPY_TICKS_INFO, // Only bid and ask changes are required
                           time[i-1]*1000,  // Start time of previous bar
                           time[i  ]*1000   // End time of previous bar
                           );
      

Repare também que o indicador coleta os ticks de Bid e Ask, embora eles não sejam exibidos nos gráficos. O valor dos ticks de Bid deve corresponder ao valor na matriz tick_volume[] - e ele corresponde, como se pode ver na janela de dados.


Comentário sobre o upload de ticks

Se quiser verificar um instrumento com o qual normalmente não trabalha, você precisa adicioná-la à Observação do Mercado por meio do menu Exibir\Símbolos clicando duas vezes no símbolo desejado. Nesta janela, vá para a guia ticks e solicite "Cada tick" uma data um mês ou mais antes de hoje no primeiro menu de datas; já na segunda janela de data defina a data como amanhã para propagar seu banco de dados local de ticks.


Conclusão

Antes de começar a negociar qualquer moeda, você precisa não apenas entender o nível real de risco quando estiver usando o algoritmo adotado (sobretudo, para scalping, swing trading, etc.), mas também comparar os riscos de diferentes moedas com base no tamanho padrão geral do spread.

Partindo do que descobri, eu recomendaria aos traders que escolhessem as principais moedas que estão diretamente ligadas ao dólar: USDCAD, USDCHF, USDJPY, EURUSD e GBPUSD. Estas são as divisas que apresentaram os spreads mais baixos.

Também é possível fazer com que as corretoras saibam que podemos ver spreads reais e que podemos detectar quando os mesmos aumentam. Boa sorte com isso! E, de qualquer forma, não esqueça que se você não conseguir encontrar uma corretora com níveis de spread aceitáveis para negociar durante certas horas, não negocie, porque você não terá lucro!

Passo a antecipar suas perguntas - o algoritmo só funciona na plataforma MetaTrader 5, porque o MetaTrader 4 não tem dados de ticks. Esta é outra razão para migrar para a quinta versão da plataforma.

Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/9804

Arquivos anexados |
Explorando as possibilidades de criar gráficos de velas multicoloridas Explorando as possibilidades de criar gráficos de velas multicoloridas
Neste artigo, veremos as possibilidades de criação de indicadores de velas personalizados, e falaremos sobre suas vantagens e desvantagens.
Gráficos na biblioteca DoEasy (Parte 83): classe abstrata de objetos gráficos padrão Gráficos na biblioteca DoEasy (Parte 83): classe abstrata de objetos gráficos padrão
Neste artigo, criaremos uma classe para um objeto gráfico abstrato. Este objeto será a base para a criação de classes de objetos gráficos padrão. Os objetos gráficos têm muitas propriedades, e hoje, antes de criarmos uma classe de objetos gráficos abstratos, precisamos realizar um intenso trabalho preliminar, especificando ditas propriedades nas enumerações da biblioteca.
Gráficos na biblioteca DoEasy (Parte 84): classes herdeiras do objeto gráfico abstrato padrão Gráficos na biblioteca DoEasy (Parte 84): classes herdeiras do objeto gráfico abstrato padrão
Neste artigo, veremos como se criam classes herdeiras do objeto gráfico abstrato padrão do terminal. O objeto deste tipo de classe descreve propriedades comuns a todos os objetos gráficos, isto é, ele é apenas um tipo de objeto gráfico. Para entender se pertence a um objeto gráfico real, precisamos gerar herança a partir dele, já na classe do objeto herdeiro precisamos escrever as propriedades que são específicas do objeto gráfico em particular.
Como se tornar um bom programador (Parte 4): agilizando a velocidade de programação Como se tornar um bom programador (Parte 4): agilizando a velocidade de programação
Suponho que todo desenvolvedor quer escrever código mais rapidamente. Porém, a habilidade de escrever código de forma rápida e produtiva não é uma característica inata que apenas uns poucos trazem consigo. Trata-se de uma habilidade que qualquer programador pode desenvolver, independentemente da experiência prévia ou da quantidade de texto digitado com o teclado.