Desarrollando un EA comercial desde cero (Parte 13): Times And Trade (II)
Introducción
En el artículo anterior Times & Trade ( I ) presenté un sistema alternativo para organizar un gráfico con el fin de tener un indicador que nos permitas interpretar las operaciones que se han ejecutado en el mercado lo antes posible, pero ese sistema no es totalmente completo, le faltó mostrar cómo se puede acceder a alguna información y así tener una mejor comprensión de lo que está sucediendo. Esta información no tiene forma de ser presentada directamente en un gráfico, de hecho se podría hacer eso, pero la interpretación sería muy confusa, por lo que lo mejor es tener los datos presentados de forma clásica, es decir, los valores en formato de texto, sólo que nuestro EA no tiene ningún sistema capaz de hacer esta tarea, siendo necesario implementar esto.
Para no complicar el artículo anterior con información que tal vez no sea en absoluto necesaria para algunos, ya que con la forma en que el sistema fue montado será posible interpretar con gran precisión lo que está sucediendo, decidí hacer la ampliación del sistema a algo más completo. En este artículo faltan algunas cosas, o mejor decir, no son parte del sistema que se propuso en el artículo anterior, pero es necesario en algunos momentos el debido conocimiento de dicha información, que es acerca de lo que en realidad se está haciendo en el mercado.
Planificación
Tenemos que ver algunos detalles, como dice el refrán anglosajón el diablo está en los detalles, por eso véase la imagen de abajo:
¿Notas algo extraño en esta imagen? Algo que puede no tener mucho sentido, pero que está ahí... observa con mucho cuidado...
Si aún no has notado nada extraño, observa con atención la región indicada en la misma imagen.
Ahora tal vez puedas ver lo que está sucediendo, ten en cuenta que en este punto hubo cambios en los valores BID y ASK, pero sólo hubo una sola operación en este punto, incluso si de hecho hubo cambios en el valor BID o ASK no tiene mucho sentido tener sólo una sola operación, si bien esto es de hecho más común de lo que parece, este tipo de cosas no son visibles cuando se utiliza el modo de lectura que se ve a continuación:
Con esta forma de analizar el mercado nos volvemos ciegos a los movimientos de BID y ASK, da la impresión de que el mercado siempre está operando y que todos están ansiosos por cerrar una transacción, lo que en realidad no es cierto, lo que sucede en realidad es que los players establecen sus posiciones en determinados puntos y esperan a que el mercado se mueva. Cuando se capta la posición ellos intentan aprovecharse y ganar dinero con el movimiento, debido a esto es que muchas veces se mueve el BID o ASK sin que realmente se produzca ninguna operación, esto es un hecho real y se puede ver en la plataforma, pero es algo ignorado por la mayoría porque piensan que esta información no es realmente importante.
Por ello, nuestro sistema Times & Trade se muestra así en la siguiente imagen:
Pero si observan con atención verán que hay 4 configuraciones de velas en el gráfico, en realidad serían 5 pero las órdenes directas son excluidas del sistema, porque realmente no mueven el mercado, así que tenemos en realidad 4 configuraciones que se pueden ver con más detalle a continuación:
En este momento, piensas: «¿por qué en algunos casos la mecha no toca el cuerpo de la vela? ¿Por qué ocurre esto?» Pues bien, ocurre que la mecha se consigue utilizando el valor del SPREAD que, a su vez, se obtiene por la diferencia entre el BID y el ASK, pero en el caso de que se produzca una operación dentro de este SPREAD, ¿cómo quedaría de hecho la vela? Bueno, este sería el quinto tipo, visto a continuación:
O sea, es una vela DOJI, por esta razón las órdenes directas no se ven en el sistema, pero esto no explica por qué en algunos casos el cuerpo no toca la mecha. La explicación está en que algo ocurrió que hizo que el precio se moviera demasiado rápido, y por esa razón el cuerpo no toca la mecha, pero se puede pensar que esto es un fallo del sistema, que no tiene sentido que el precio haga esto, pero tiene todo el sentido, y esto ocurre exactamente cuando se disparan las órdenes de stop, para ver esto observemos la imagen de abajo:
Mira que sucede una serie de momentos en los que tenemos órdenes en las que no se está tocando ni el BID ni el ASK, todos estos puntos eran órdenes de stop que se alcanzaron, y cuando esto sucede el precio normalmente da un salto, y esto se puede ver en el gráfico, pero en el Times & Trade esto sólo se notará de hecho en caso de que estés usando un modo de gráfico para evaluar los movimientos, de lo contrario te ciegas a los stops y piensas que ahora el movimiento ha tomado fuerza, cuando en realidad puede volver rápidamente y puedes ser víctima del stop.
Pues bien, sabiendo esto cuando veas que se traza una gran serie de velas sin que la mecha toque el cuerpo, sabrás que son órdenes de stop que se dispararon, no es posible de hecho captar este movimiento durante el periodo que ocurre, ya que es algo muy rápido, pero puedes utilizar una interpretación de los valores BID y ASK para saber por qué ocurrió esto, aquí va la experiencia de mercado de cada uno, no entraré en detalles sobre ello, pero es algo en lo que debes centrarte si quieres utilizar realmente el Tape Reading como indicador.
Ahora viene el detalle: ¡¡¡Si esta información se puede ver sólo con el uso de las velas y ya son suficientes para saber varias cosas, ¿por qué es necesario tener más información???
El gran detalle es que hay momentos en los que el mercado está más lento, a la espera de alguna información que pueda salir en un momento dado, y sólo mirar el Times & Trade con velas no nos da este tipo de noción, necesitamos algo más, y esta información ya está en el propio sistema pero es difícil interpretarla de la forma en que viene, deberíamos modelar los datos de forma que sean más sencillos de analizar.
Este modelado es la razón de este artículo, después de que este modelado se ha hecho, Times & Trade cambiará y se verá como se muestra en la imagen de abajo:
En otras palabras, tendremos un conocimiento total de lo que está ocurriendo, y esto de una manera extremadamente rápida, lo que es importante para aquellos que quieren utilizar la lectura de flujo como una forma de operar.
Implementación
Para implementar el sistema tenemos que añadir algunas variables nuevas en la clase C_TimesAndTrade, y esto se puede ver en el fragmento siguiente:
#include <NanoEA-SIMD\Auxiliar\C_FnSubWin.mqh> #include <NanoEA-SIMD\Auxiliar\C_Canvas.mqh> //+------------------------------------------------------------------+ class C_TimesAndTrade : private C_FnSubWin { //+------------------------------------------------------------------+ #define def_SizeBuff 2048 #define macro_Limits(A) (A & 0xFF) #define def_MaxInfos 257 //+------------------------------------------------------------------+ private : string m_szCustomSymbol, m_szObjName; char m_ConnectionStatus; datetime m_LastTime; ulong m_MemTickTime; int m_CountStrings; struct st0 { string szTime; int flag; }m_InfoTrades[def_MaxInfos]; struct st1 { C_Canvas Canvas; int WidthRegion, PosXRegion, MaxY; string szNameCanvas; }m_InfoCanvas;
Todos los puntos resaltados son partes que se agregaron al código original, puedes ver que necesitamos usar la clase C_Canvas, pero no tiene todos los elementos que necesitamos, de hecho tenemos que agregar 4 rutinas a esta clase C_Canvas, y estas rutinas se ven en el fragmento de abajo:
// ... Código da classe C_Canvas inline void FontSet(const string name, const int size, const uint flags = 0, const uint angle = 0) { if(!TextSetFont(name, size, flags, angle)) return; TextGetSize("M", m_TextInfos.width, m_TextInfos.height); } //+------------------------------------------------------------------+ inline void TextOutFast(int x, int y, string text, const uint clr, uint alignment = 0) { TextOut(text, x, y, alignment, m_Pixel, m_width, m_height, clr, COLOR_FORMAT_ARGB_NORMALIZE); } //+------------------------------------------------------------------+ inline int TextWidth(void) const { return m_TextInfos.width; } //+------------------------------------------------------------------+ inline int TextHeight(void) const { return m_TextInfos.height; } //+------------------------------------------------------------------+ // ... Restante do código ...
Lo que hacen estas líneas es crear un texto para nosotros, algo muy sencillo, nada demasiado elegante.
La siguiente rutina que vale la pena mencionar en la clase C_TimesAndTrade se ve justo debajo:
void PrintTimeTrade(void) { int ui1; m_InfoCanvas.Canvas.Erase(clrBlack, 220); for (int c0 = 0, c1 = m_CountStrings - 1, y = 2; (c0 <= 255) && (y < m_InfoCanvas.MaxY); c0++, c1--, y += m_InfoCanvas.Canvas.TextHeight()) if (m_InfoTrades[macro_Limits(c1)].szTime == NULL) break; else { ui1 = m_InfoTrades[macro_Limits(c1)].flag; m_InfoCanvas.Canvas.TextOutFast(2, y, m_InfoTrades[macro_Limits(c1)].szTime, macroColorRGBA((ui1 == 0 ? clrLightSkyBlue : (ui1 > 0 ? clrForestGreen : clrFireBrick)), 220)); } m_InfoCanvas.Canvas.Update(); }
Esta rutina nos imprimirá los valores en un área reservada para ello, además la rutina de inicialización también sufrió pequeños cambios que se pueden ver a continuación en el resaltado:
void Init(const int iScale = 2) { if (!ExistSubWin()) { m_InfoCanvas.Canvas.FontSet("Lucida Console", 13); m_InfoCanvas.WidthRegion = (18 * m_InfoCanvas.Canvas.TextWidth()) + 4; CreateCustomSymbol(); CreateChart(); m_InfoCanvas.Canvas.Create(m_InfoCanvas.szNameCanvas, m_InfoCanvas.PosXRegion, 0, m_InfoCanvas.WidthRegion, TerminalInfoInteger(TERMINAL_SCREEN_HEIGHT), GetIdSubWinEA()); Resize(); m_ConnectionStatus = 0; } ObjectSetInteger(Terminal.Get_ID(), m_szObjName, OBJPROP_CHART_SCALE, (iScale > 5 ? 5 : (iScale < 0 ? 0 : iScale))); }
Se notó que tenemos que modificar la rutina de cambios en las dimensiones de Times & Trade, y los cambios también son dignos de mención y se pueden ver en el fragmento de abajo:
void Resize(void) { static int MaxX = 0; int x = (int) ChartGetInteger(Terminal.Get_ID(), CHART_WIDTH_IN_PIXELS, GetIdSubWinEA()); m_InfoCanvas.MaxY = (int) ChartGetInteger(Terminal.Get_ID(), CHART_HEIGHT_IN_PIXELS, GetIdSubWinEA()); ObjectSetInteger(Terminal.Get_ID(), m_szObjName, OBJPROP_YSIZE, m_InfoCanvas.MaxY); if (MaxX != x) { MaxX = x; x -= m_InfoCanvas.WidthRegion; ObjectSetInteger(Terminal.Get_ID(), m_szObjName, OBJPROP_XSIZE, x); ObjectSetInteger(Terminal.Get_ID(), m_InfoCanvas.szNameCanvas, OBJPROP_XDISTANCE, x); } PrintTimeTrade(); }
Con todo esto, el sistema está prácticamente listo, pero aún falta una rutina que es el corazón del sistema y que también sufrió cambios.
inline void Update(void) { MqlTick Tick[]; MqlRates Rates[def_SizeBuff]; int i0, p1, p2 = 0; int iflag; long lg1; static int nSwap = 0; static long lTime = 0; if (m_ConnectionStatus < 3) return; if ((i0 = CopyTicks(Terminal.GetFullSymbol(), Tick, COPY_TICKS_ALL, m_MemTickTime, def_SizeBuff)) > 0) { for (p1 = 0, p2 = 0; (p1 < i0) && (Tick[p1].time_msc == m_MemTickTime); p1++); for (int c0 = p1, c1 = 0; c0 < i0; c0++) { lg1 = Tick[c0].time_msc - lTime; nSwap++; if (Tick[c0].volume == 0) continue; iflag = 0; iflag += ((Tick[c0].flags & TICK_FLAG_BUY) == TICK_FLAG_BUY ? 1 : 0); iflag -= ((Tick[c0].flags & TICK_FLAG_SELL) == TICK_FLAG_SELL ? 1 : 0); if (iflag == 0) continue; Rates[c1].high = Tick[c0].ask; Rates[c1].low = Tick[c0].bid; Rates[c1].open = Tick[c0].last; Rates[c1].close = Tick[c0].last + ((Tick[c0].volume > 200 ? 200 : Tick[c0].volume) * (Terminal.GetTypeSymbol() == C_Terminal::WDO ? 0.02 : 1.0) * iflag); Rates[c1].time = m_LastTime; m_InfoTrades[macro_Limits(m_CountStrings)].szTime = StringFormat("%02.d.%03d ~ %02.d <>%04.d", ((lg1 - (lg1 % 1000)) / 1000) % 60 , lg1 % 1000, nSwap, Tick[c0].volume); m_InfoTrades[macro_Limits(m_CountStrings)].flag = iflag; m_CountStrings++; nSwap = 0; lTime = Tick[c0].time_msc; p2++; c1++; m_LastTime += 60; } CustomRatesUpdate(m_szCustomSymbol, Rates, p2); m_MemTickTime = Tick[i0 - 1].time_msc; } PrintTimeTrade(); }
Todas las líneas resaltadas son código añadido a la rutina para modelar los datos que queremos, el fragmento
lg1 = Tick[c0].time_msc - lTime; nSwap++;
comprobará cuánto tiempo ha pasado entre las operaciones, esto en milisegundos, y cuántas operaciones que no suscitaron cambios de precio se produjeron, si estos números son grandes se dará cuenta de que el volumen de negocios está disminuyendo, o sea que, antes de que otros lo noten, usted ya lo estará notando gracias a esta información.
Ahora el fragmento
m_InfoTrades[macro_Limits(m_CountStrings)].szTime = StringFormat("%02.d.%03d ~ %02.d <>%04.d", ((lg1 - (lg1 % 1000)) / 1000) % 60 , lg1 % 1000, nSwap, Tick[c0].volume); m_InfoTrades[macro_Limits(m_CountStrings)].flag = iflag; m_CountStrings++; nSwap = 0; lTime = Tick[c0].time_msc;
modelará los valores que se nos presentarán, fíjate que no me preocupo de probar el contador m_CountStrings, porque se encuentra limitado, así que no necesitamos probarlo, simplemente vamos a incrementarlo con cada nueva información. Este es un truco que a veces se puede hacer, yo mismo lo uso siempre que es posible, ya que ahorra en términos de procesamiento, y siendo el sistema de comercio algo que se va a utilizar en tiempo real, tenemos que tratar siempre que sea posible de optimizar el sistema, aunque sea un poco cada vez, hace una gran diferencia.
Con todo esto implementado, ejecutamos la compilación del EA y obtenemos algo como lo que se muestra a continuación:
Observe los movimientos que se describieron anteriormente en el gráfico de Times & Trade, se puede notar que comienzan a aparecer micro estructuras en el mismo Times & Trade pero no pude ni siquiera después de estudiar dichas micro estructuras sacar alguna ventaja en el hecho de que existan, pero no soy un trader experimentado así que quién sabe, tal vez alguien con más experiencia pueda hacerlo.
Este indicador es tan potente y tan informativo que he decidido hacer un vídeo mostrando una pequeña comparación entre él y los datos REALES que estaba haciendo el activo en el momento de la grabación... Quiero que entiendas que filtra mucha de la información de manera que la lectura es mucho más rápida y la comprensión del momento es mucho más sencillo... Espero que disfrutes y aproveches este FANTÁSTICO y POTENTE indicador.
Conclusión
Traducción del portugués realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/pt/articles/10412
- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso