English Русский 中文 Deutsch 日本語 Português
preview
Análisis de spread Bid/Ask en MetaTrader 5

Análisis de spread Bid/Ask en MetaTrader 5

MetaTrader 5Trading | 6 octubre 2021, 15:57
1 664 0
Paul Kelly
Paul Kelly

Introducción

Si usted no usa órdenes Limit o Stop tanto para la entrada como para la salida, entonces usará las órdenes de mercado y, por supuesto, estas dependen del tamaño del spread Bid/Ask para determinar los precios que obtenemos.

Cuando presionamos el botón de compra, en realidad compramos al precio ASK, que supone un tamaño de margen superior al precio bid que probablemente utilizamos para decidirnos a comprar.

Al presionar el botón de venta, en realidad vendemos al precio BID, que supone un tamaño de margen inferior al precio ask.

Por supuesto, cuando presionamos el botón de cierre para cerrar una posición que habíamos comprado anteriormente, en realidad estamos vendiendo al precio BID actual.

Y lo contrario es cierto, cuando presionamos el botón de cierre para cerrar una posición que previamente habíamos acortado, en realidad estamos comprando o cubriendo al precio ASK actual.

Ahora podremos usar los datos de ticks de MetaTrader 5 para analizar cuál ha sido realmente el promedio histórico real del spread Bid/Ask reciente.

No deberíamos necesitar mirar el spread actual, porque está disponible si mostramos las líneas de precio Bid/Ask.


Veamos por qué y cómo

Al mirar estos gráficos, podemos ver que este bróker dice que la mayoría de los spreads son de 5 puntos.

Si ese fuera el caso, el proceso completo de apertura y cierre de una transacción debería costarle a usted 1 pip.

Por consiguiente, para una transacción con una ratio de riesgo-recompensa de 1/1 con un Stop Loss de 10 pips y un Take Profit de 10 pips, debería costarle el 10% de su riesgo/apuesta.

Este tipo de margen es bastante justo; por ejemplo, el total de un libro de apuestas es típicamente del 15%, el margen de beneficio de los casinos es de alrededor del 4%.


BAS-EURUSD-M30

Pero, los spreads promedio reales (la línea roja), en comparación con el margen documentado de los brókeres (línea discontinua negra), son en su mayoría dos veces más grandes que el margen declarado, como lo confirma la ventana de datos a continuación. Usando el ejemplo anterior con el mismo SL y TP, vemos que el coste para usted es normalmente de al menos 2 pips o un 20%. 


BAS-EURUSD-M30-DW


Si es usted un scalper a menor escala, y usa, por ejemplo, un SL de 5 pips y un TP de 5 pips, o si decide salir antes de que se alcancen los ejemplos anteriores, de 10 pips de SL o TP, digamos, con una pérdida de 5 pips, entonces el coste supondrá los mismos 2 pips, pero como ha jugado seguro después de que la transacción comenzara a ir en su contra, el coste porcentual será ahora del 40% de su apuesta/riesgo. 

Cuando era un tráder novato, comencé usando 5 pips de S/l y 10 pips de T/P para una relación riesgo/recompensa de 2:1, (como sospecho que hacen muchos tráders nuevos). No tenía mucho éxito, por cierto.

Así que hice un análisis profundo del gráfico EURUSD M1 con un indicador Zig Zag fiable. Lo puse en 5 pips como tamaño mínimo del lado, lo cual significaba para mí un tipo de retroceso con el que podría lidiar.

Los resultados parecen sugerir que la mayoría de los cambios pequeños fueron de alrededor de 7 pips y los lados de 10 pips fueron relativamente raros en comparación. Por supuesto, permití el uso de noticias y los mercados volátiles, por lo que los resultados fueron principalmente de periodos promedio únicamente de las sesiones comerciales.

Entonces, en consecuencia, comencé a usar un stop loss de 10 pips y dejé abierto el take profit, para poder monitorear la transacción de cerca y decidir cuándo salir si esta ya había alcanzado unas pérdidas o ganancias de 7 pips. Esto redundó en una mejora, pero, aún así, me quedé sin beneficios. Solo entonces me di cuenta de los altos spreads Bid/Ask contra los que estaba comerciando con ese bróker, así que, obviamente, busqué un bróker mejor.


BAS-EURUSD-M1

Si comerciamos cuando surgen noticias o el mercado se vuelve volátil, podremos ver que el spread promedio real sube a alrededor de 15 puntos o 3 veces los 5 puntos estándar, por lo que deberemos pagar 3 pips o el 60% de nuestra apuesta. 


BAS-EURUSD-M1-DW

Ni siquiera debemos considerar comerciar después de las 20:30 hora del Reino Unido (21:30 hora del servidor de gráficos), porque podría ser 4, 5, 6 veces mayor o incluso mucho más, especialmente si decidimos mantener nuestra posición comercial durante el fin de semana, lo cual, como podemos ver a continuación, es casi 10 veces el margen estándar de 5 puntos; a menos, claro, que tengamos niveles de stop loss y take profit extremadamente grandes.

BAS-EURUSD-M30-WeekEnd


Ejemplo de código de OnInit()

#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);
}

Para este indicador simple con 2 gráficas, solo hay 2 parámetros, el primero, 'numRecentBarsBack', es para el número de barras que queremos analizar.

Lo primero que hacemos en OnInit() es comprobar que tenemos suficientes datos para satisfacer la solicitud; si no los tenemos, alertaremos al usuario y sugeriremos algunos valores realistas que utilizar. Luego saldremos del indicador con un error.

El resto de OnInit() es bastante estándar, salvo por los niveles usados en la subventana del indicador, que se establecen en valores que se correspondan con múltiplos del margen estándar de 5 puntos EURUSD. 

Este es un paso bastante importante porque, además de querer ver la comparación entre los valores promedios de spread declarados y reales, también queremos ver cómo de grande es el spread de diferentes divisas en comparación con el EURUSD estándar, que normalmente muestra el spread más bajo disponible de todas las divisas.

Este es un método bastante complicado porque tenemos que obtener el precio actual de EURUSD (y sustituir 1.2, si no existe) y usar 5 puntos de EURUSD divididos por ese precio para construir un spread estándar. Luego, iteramos a través de los precios numRecentBarsBack del instrumento Fórex actual (no lo he probado con instrumentos que no sean Fórex) para obtener el precio promedio de ese instrumento.

Una vez tenemos el precio promedio de los instrumentos, podemos construir un punto estándar redondeado multiplicando el precio promedio de los instrumentos por el spread estándar previamente construido y dividiendo por 5, el punto de spread estándar de EURUSD.

Este punto estándar redondeado se usa en cada valor de nivel y también se incluye en el nombre breve de los indicadores, como podemos ver en el nombre de los indicadores en el gráfico USDMXN "exótico" a continuación.

En este ejemplo de USDMXN  el spread declarado durante el día comercial es de alrededor de 0.0025, es decir, aproximadamente 3 niveles de spread desde cero, por lo que se corresponde con alrededor de 15 puntos en un gráfico de EURUSD. También debemos considerar que el spread promedio real varía ampliamente incluso por encima de ese nivel alto para este bróker.

BAS-USDMXN-M30

El gráfico de GBPAUD a continuación, muestra que el spread declarado durante el día comercial es de alrededor de 0.00019, es decir, aproximadamente 2.5 niveles de spread por encima de cero, por lo que se corresponde con alrededor de 12 puntos en el gráfico EURUSD. También debemos tener en cuenta que en este gráfico los valores de spread promedio reales están bastante cerca de los valores declarados para este bróker.

 BAS-GBPAUD-M30

El gráfico de GBPJPY a continuación, muestra que el spread declarado durante el día comercial es de alrededor de 0.020, es decir, aproximadamente 3 niveles de spread por encima de cero, por lo que se corresponde con alrededor de 15 puntos en el gráfico EURUSD. También debemos tener en cuenta que en este gráfico los valores de spread promedio reales están bastante cerca de los valores declarados para este bróker.

BAS-GBPJPY-M30

El gráfico de USDJPY a continuación, muestra que el spread declarado durante el día comercial es de alrededor de 0.0050, es decir, aproximadamente 1 nivel de spread por encima de cero, por lo que se corresponde con alrededor de 5 puntos en el gráfico EURUSD. También debemos considerar que en este gráfico los valores de spread promedio reales están de nuevo bastante cerca del doble de los valores declarados para este bróker, por lo que los mismos comentarios sobre los niveles de porcentaje de riesgo/recompensa de EURUSD también se aplican aquí. 

BAS-USDJPY-M30


Aquí tenemos algunos ejemplos más, así que podrá hacer sus propias valoraciones sobre las relaciones entre los niveles de spread.

BAS-GBPUSD-M30

BAS-EURGBP-M30

El segundo parámetro es el 'doPrint' booleano, marcado en el código y que, si es verdadero, imprimirá las estadísticas de las barras individuales en el diario de expertos, como lo muestran los ejemplos a continuación. Esto puede ralentizar el indicador si el valor de 'numRecentBarsBack' es demasiado elevado, por lo que el valor por defecto es 100.

Si establecemos el parámetro 'doPrint' en true y 'numRecentBarsBack' en un valor razonable de alrededor de 100 para un gráfico de 30 minutos, o de 300 para un gráfico de 1 minuto, podremos copiar las entradas del diario y enviarlas a nuestro bróker como prueba de sus verdaderos spreads Bid/Ask.

Log de spread Bid/Ask M20

Log de spread Bid/Ask M1


Ejemplo de código de OnCalculate()

//--- 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);
}

Del ejemplo anterior de OnCalculate(), el punto principal a tener en cuenta es el uso de CopyTicksRange() para obtener solo los datos de ticks entre el inicio de la barra/vela de los índices anteriores y el inicio de la barra/vela de los índices actuales. También debemos considerar que tenemos que convertir la matriz time[] a milisegundos multiplicándola por 1000, porque los datos de fecha y hora solo son precisos hasta el segundo, y CopyTicksRange() requiere 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
                           );
      

También debemos tener en cuenta que acumulamos los ticks Bid/Ask, aunque no los usamos en las gráficas. El valor de los ticks de la oferta debe coincidir con el valor de la matriz tick_volume[], y funciona como se muestra en la ventana de datos.


Nota adicional sobre la descarga de ticks...

Si desea verificar una divisa que no usa normalmente, deberá añadir dicha divisa desde el elemento de menú Ver\Símbolos, clicando dos veces en ella para Mostrar el símbolo. Mientras esté en esta ventana, también deberá ir a la pestaña de ticks y solicitar en Todos los Ticks una fecha o un mes antes de hoy en el menú de la primera fecha, y luego configurar el segundo menú de fecha en "mañana" para generar su base de datos local de ticks.


Conclusión

Antes de comerciar con una divisa, deberemos saber cuáles son nuestros porcentajes de riesgo para el tipo de transacción (scalping, swing, posición...) que estamos considerando, y también comparar nuestras divisas favoritas con otras disponibles usando un tamaño de margen estándar común.

Usando mis estudios como base, recomendaría a los tráders que se ciñan a las principales divisas directamente vinculadas al dólar americano, a saber, USDCAD, USDCHF, USDJPY, EURUSD y GBPUSD, ya que tienen los spreads generales más bajos.

Todos debemos informar a nuestros brókeres de que ahora podemos ver sus verdaderos spreads Bid/Ask, incluso si estamos comerciando solo con comisiones, si aumentan sus diferenciales a niveles muy altos. Buena suerte y recuerde que es mejor no comerciar si no puede encontrar un bróker con spreads Bid/Ask razonables durante las horas comerciales, ¡ya que usted NO PUEDE ganar!

Antes de que alguien pregunte, este proceso solo se puede ejecutar en MetaTrader 5, porque los datos de ticks no están disponibles en MetaTrader 4, así que ahí tiene una buena razón para actualizarse.

Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/9804

Archivos adjuntos |
Explorando opciones para crear velas multicolores Explorando opciones para crear velas multicolores
En este artículo, abordaremos las distintas posibilidades de crear indicadores personalizados con velas, señalando sus correspondientes ventajas y desventajas.
Combinatoria y teoría de la probabilidad en el trading (Parte III): Primer modelo matemático Combinatoria y teoría de la probabilidad en el trading (Parte III): Primer modelo matemático
Como continuación lógica del tema, hoy analizaremos la necesidad de desarrollar modelos matemáticos multifuncionales para las tareas comerciales. En este sentido, el presente artículo describirá el proceso completo de desarrollo del primer modelo matemático para describir fractales desde cero. Dicho modelo debería convertirse en un componente importante, además de ser multifuncional y universal, incluso a la hora de sentar las bases teóricas para el futuro desarrollo de la rama.
Perceptrón Multicapa y Algoritmo de Retropropagación (Parte II): Implementación en Python e integración en MQL5 Perceptrón Multicapa y Algoritmo de Retropropagación (Parte II): Implementación en Python e integración en MQL5
Se ha puesto a disposición un paquete de Python con el propósito de desarrollar la integración en MQL, lo que abre las puertas a numerosas posibilidades como la exploración de datos, la creación y el uso de modelos de aprendizaje automático. Esta integración nativa de MQL5 en Python abre las puertas a muchas posibilidades de uso que nos permiten construir desde una simple regresión lineal a un modelo de aprendizaje profundo. Entendamos cómo instalar y preparar el entorno de desarrollo y usar algunas de las bibliotecas de aprendizaje automático.
Gráficos en la biblioteca DoEasy (Parte 82): Refactorización de los objetos de la biblioteca y colección de objetos gráficos Gráficos en la biblioteca DoEasy (Parte 82): Refactorización de los objetos de la biblioteca y colección de objetos gráficos
En el presente artículo, mejoraremos todos los objetos de la biblioteca: para ello, asignaremos a cada objeto su tipo único y continuaremos desarrollando la clase de colección de objetos gráficos de la biblioteca.