Desarrollo de un kit de herramientas para el análisis de la acción del precio (Parte 38): VWAP con búfer de ticks y motor de desequilibrio de ventana corta
Índice
- Introducción
- Descripción detallada de las principales funciones de la herramienta
- Implementación en MQL5
- Resultados
- Conclusión
Introducción
La mayoría de los operadores se dan cuenta rápidamente de que los gráficos de precios no lo dicen todo. Lo que realmente mueve el mercado se esconde justo bajo la superficie: en el libro de órdenes, donde las ofertas de compra y venta revelan quién está esperando para comprar, quién está dispuesto a vender y dónde se concentra la liquidez. Los operadores profesionales utilizan esta información a diario para identificar las zonas de oferta y demanda, detectar desequilibrios y anticipar las variaciones de precios a corto plazo con una precisión notable.
Sin embargo, los operadores minoristas rara vez ven este panorama. Muchas plataformas no ofrecen ningún acceso directo al libro de órdenes, mientras que otras lo limitan a datos retrasados o incompletos, a menudo previo pago adicional. En las plataformas de trading minoristas habituales, como MetaTrader 5, la transparencia depende por completo del bróker, y la mayoría de los operadores se ven obligados a operar en los mercados sin disponer de la información microestructural que los profesionales dan por sentada.
La herramienta de slippage se creó para subsanar esta carencia. Aunque no pretende reproducir un libro de órdenes completo ni el flujo bruto de la cinta de transacciones, reconstruye la información más útil que los operadores suelen extraer de la profundidad del mercado, utilizando únicamente los datos de ticks que proporciona cada bróker. Calcula el VWAP (precio medio ponderado por volumen) para destacar dónde se concentra la actividad, mide los desequilibrios de órdenes a corto plazo para captar la presión direccional y agrega los volúmenes por tick para ofrecer una visión más clara de la participación reciente. A continuación, estos indicadores se combinan con el contexto del spread y del ATR para ayudar a los operadores a identificar cuándo las condiciones favorecen su sesgo direccional.
Esta herramienta, que se muestra directamente en el gráfico con alertas y marcadores de operaciones, ofrece a los operadores minoristas una aproximación operativa al flujo de órdenes, lo que les permite observar cambios en la liquidez, identificar desequilibrios y afinar sus entradas de forma más eficaz, incluso sin acceso a un libro de órdenes profesional.
El siguiente diagrama ilustra esto en la práctica. Observe el movimiento bajista desde el punto E hasta F. El descenso no es una caída en línea recta; el mercado oscila, creando máximos y mínimos temporales mientras barre liquidez. Un operador que abra una posición de venta en el punto C puede acertar en cuanto a la dirección, pero, con una gestión del riesgo deficiente o un tamaño de lote excesivo, el retroceso hacia D podría hacerle saltar el stop. La herramienta «Slippage Tool» replantea esta situación sugiriendo un movimiento contrario: abrir una posición de compra en C y cerrarla en D, convirtiendo así una posible pérdida en una oportunidad con riesgo controlado. Del mismo modo, cuando el precio sube desde A, la herramienta destaca B como una zona favorable para vender, lo que ayuda a los operadores a negociar acompañando las oscilaciones del mercado en lugar de ser sacados de la posición por ellas.

El trading siempre conllevará volatilidad, cambios de tendencia y trampas de liquidez. La diferencia fundamental radica en si estos movimientos expulsan a los operadores del mercado o si, por el contrario, se convierten en oportunidades para gestionar el riesgo y la ejecución de forma más eficaz. La Slippage Tool no elimina la incertidumbre, pero aporta una capa de claridad estructural al gráfico del operador minorista, reduciendo la brecha entre las plataformas retail y la infraestructura de trading profesional.
En los apartados siguientes se detallarán los mecanismos operativos de la herramienta, se explicará la importancia de cada métrica clave y se mostrará cómo pueden utilizarse estas funciones para mejorar las decisiones de trading. Tanto si es usted un operador discrecional que busca entradas más precisas como si es un desarrollador algorítmico que explora nuevas fuentes de señales, la Slippage Tool ofrece una solución optimizada y ligera para una de las limitaciones más persistentes del trading minorista: el acceso limitado a datos fiables sobre la profundidad del mercado.
Descripción detallada de las funciones clave de la herramienta
La Slippage Tool es un sistema integrado en el gráfico de MetaTrader 5 que reconstruye señales de flujo de órdenes a partir del flujo de ticks en tiempo real (VWAP, desequilibrio entre ticks y volumen, spread y contexto de ATR), pone de relieve ventajas operativas aprovechables mediante alertas y marcadores y, opcionalmente, tiene en cuenta un margen de deslizamiento previsto al calcular el riesgo y el tamaño de lote, sirviendo como una aproximación práctica a la información del libro de órdenes cuando no se dispone de profundidad de mercado (DOM).
A continuación se presentan los cálculos matemáticos y las explicaciones detalladas de las funciones principales de este sistema.
1. VWAP (precio medio ponderado por volumen)
En un artículo anterior, ofrecí un análisis en profundidad del VWAP (precio medio ponderado por volumen). El VWAP es un indicador sofisticado que combina datos de precio y volumen para calcular un precio medio ponderado a lo largo de un periodo de tiempo determinado. A diferencia de una simple media aritmética —que trata todos los precios por igual—, el VWAP otorga mayor importancia a los niveles de precio en los que se ha registrado un mayor volumen de negociación. Este enfoque garantiza que el VWAP refleje con precisión los niveles de precio en los que se produjo la mayor parte de la actividad de negociación, captando así de forma eficaz el verdadero consenso del mercado durante ese periodo.
Al integrar el volumen en su cálculo, el VWAP ofrece una medida más significativa del «valor razonable» del mercado, ya que tiene en cuenta la intensidad de la negociación en los distintos niveles de precio. Los operadores y los participantes institucionales suelen utilizar el VWAP para evaluar las condiciones del mercado, identificar posibles puntos de entrada y salida, y valorar la dirección general del mercado en relación con este índice de referencia. Su carácter dinámico le permite servir como punto de referencia fiable para evaluar los movimientos de precios intradía y las condiciones de liquidez, lo que lo convierte en una herramienta esencial tanto para las estrategias de ejecución como para el análisis general del mercado.

Donde:
𝑃(i) = precio del i-ésimo tick𝑉(i) = volumen de tick del i-ésimo tick
Cuando el precio cotiza por encima del VWAP, esto indica que el mercado cotiza con una prima respecto a su media, lo que denota un sentimiento alcista. Por el contrario, si el precio cotiza por debajo del VWAP, esto indica un descuento, lo que refleja tendencias bajistas. Los operadores suelen utilizar el VWAP como nivel dinámico de soporte o resistencia, basando sus decisiones en este valor de referencia.

Dado que no todos los brókeres ofrecen datos completos del libro de órdenes del mercado, esta herramienta reconstruye una línea VWAP derivada exclusivamente de los datos de ticks recibidos. Este enfoque permite a los operadores acceder a información comparable a la que se obtiene de las «zonas de valor razonable» del libro de órdenes, lo que ofrece una aproximación valiosa al equilibrio del mercado y contribuye a una toma de decisiones fundamentada.
2. Desequilibrio
El desequilibrio indica si en la actividad de negociación predominan los compradores agresivos o los vendedores agresivos. En un libro de órdenes tradicional, esto suele evaluarse comparando el volumen de las órdenes pasivas en el lado bid frente al lado ask. Sin embargo, cuando no se dispone de datos directos del libro de órdenes, la herramienta infiere el desequilibrio del mercado de forma indirecta mediante el análisis del comportamiento de los ticks, lo que ofrece una forma alternativa de evaluar la presión direccional y el sentimiento del mercado.

Donde:
BuyVolume = suma de los volúmenes de tick cuando el precio se movió al alza
SellVolume = suma de los volúmenes de tick cuando el precio se movió a la baja
Un desequilibrio positivo indica presión compradora, lo que refleja el predominio de compradores más agresivos, mientras que un desequilibrio negativo denota presión vendedora, con predominio de vendedores más agresivos.

La herramienta supervisa los movimientos del precio tick a tick. Cada movimiento al alza (uptick) se cuenta como actividad de compra, mientras que cada movimiento a la baja (downtick) se asocia con la venta. Este cálculo continuo y en tiempo real proporciona una medida constante de qué lado ejerce actualmente una mayor influencia en el mercado, lo que ofrece una valiosa perspectiva sobre la dinámica direccional a corto plazo.
3. Spread
El spread es una de las medidas más fundamentales y esenciales de la microestructura del mercado. Representa el coste de la inmediatez, es decir, lo que los operadores deben «pagar» para ejecutar una orden de mercado inmediata. Este indicador ofrece información fundamental sobre las condiciones de liquidez y la eficiencia general del mercado, y refleja los costes de transacción asociados a una ejecución rápida.
![]()
Un spread estrecho suele indicar condiciones de mercado líquidas y eficientes, lo que facilita una operativa más fluida y eficiente en costes. Por el contrario, un spread amplio sugiere una menor liquidez, mayores costes de transacción y, en ocasiones, puede señalar tensión o incertidumbre en el mercado.

La herramienta supervisa continuamente el spread en tiempo real. Sus señales pueden filtrarse en función de umbrales de spread predefinidos, lo que ayuda a los operadores a evitar entradas durante los periodos en los que los costes de transacción son inusualmente elevados. Este enfoque simula el comportamiento de los observadores del libro de órdenes que se abstienen de operar cuando la profundidad de mercado es escasa, lo que favorece unas condiciones de ejecución más favorables.
4. Flujo
El flujo actúa como un indicador de sentimiento a corto plazo, que refleja si los ticks recientes son predominantemente alcistas o bajistas dentro de una ventana móvil determinada. Sirve para tomar el pulso en tiempo real a la presión del flujo de órdenes, lo que proporciona a los operadores una visión inmediata del impulso predominante en el mercado.

- Donde:

Al agregar volúmenes con signo en tiempo real, la herramienta construye una imagen dinámica de la presión del flujo de órdenes a corto plazo. Este enfoque refleja fielmente la forma en que un operador interpreta los desequilibrios cambiantes en la escalera del libro de órdenes (DOM), lo que ofrece una valiosa perspectiva sobre el sentimiento inmediato del mercado y el sesgo direccional.

En conjunto, estas cuatro características (VWAP, desequilibrio, spread y flujo) capturan la información esencial del libro de órdenes del mercado. Lo consiguen extrayendo las dinámicas clave del mercado únicamente a partir de datos de ticks en bruto, lo que les permite ofrecer información valiosa sobre la microestructura incluso en brókeres que no ofrecen compatibilidad total con el libro de órdenes.
Implementación en MQL5
En esta sección, ofreceré una guía paso a paso sobre cómo crear la herramienta «Slippage» utilizando el lenguaje de programación MQL5.
Encabezado del archivo, inclusiones y declaraciones anticipadas.
Al principio del archivo, el script establece los metadatos (#property) e incluye Trade.mqh; a continuación, declara las firmas de VWAP y Flow para que puedan utilizarse antes de sus definiciones. El encabezado tiene tres funciones prácticas: documenta la autoría y la versión para su mantenimiento posterior, activa el modo estricto del compilador —que garantiza una semántica MQL5 moderna y más segura— y declara las dependencias para que el EA pueda llamar a las rutinas de negociación en caso de que se añadan entradas automatizadas. Las declaraciones anticipadas son una pequeña comodidad estilística: le permiten colocar las funciones de alto nivel más legibles en cualquier parte del archivo sin tener que preocuparse por el orden textual. Desde el punto de vista del mantenimiento, este bloque superior es la hoja de ruta que esperan los usuarios: indica qué capacidades externas (identificadores de indicadores, herramientas de negociación) están disponibles y prepara al usuario para encontrar las principales métricas que se implementarán más adelante.
// File metadata and includes #property copyright "Copyright 2025, MetaQuotes Ltd." #property link "https://www.mql5.com/en/users/lynnchris" #property version "1.0" #property strict #include <Trade\Trade.mqh> // CTrade utility for possible auto-trade usage
Enumeraciones y parámetros de entrada (interfaz de configuración).
Las definiciones de enum y la extensa lista de variables de entrada conforman la API pública de la herramienta: son los controles que utiliza un operador para ajustar el comportamiento sin modificar el código. Las enumeraciones proporcionan nombres fáciles de entender para las opciones de la interfaz de usuario (esquinas del panel, modos de alerta). Los parámetros de entrada exponen los parámetros críticos de la señal: ventana de VWAP en minutos, ventana de desequilibrio en segundos, fracción del spread respecto al ATR para la detección de un spread bajo, umbral de flujo e histéresis para las alertas, porcentaje de riesgo y multiplicador del ATR para los stops, así como numerosas opciones de interfaz de usuario/diseño. Exponer estos valores como parámetros de entrada es una decisión de diseño importante: hace que el EA sea versátil en distintos instrumentos y estilos de operativa.
En un artículo para producción, explique el rango recomendado y las ventajas e inconvenientes de cada parámetro de entrada: por ejemplo, unas ventanas de VWAP más largas aportan estabilidad, pero pierden capacidad de respuesta a corto plazo; un valor mayor de InpImbWindowSec suaviza el flujo, pero atenúa las señales de microestructura. Destaque también que se proporcionan valores por defecto razonables, pero que se debe orientar a los usuarios para que los ajusten en función de la frecuencia de ticks y la microestructura del mercado de cada instrumento.
// Enums (UI choices) and user-exposed inputs (tuning knobs) enum eCorner { COR_LT=0, COR_LB=1, COR_RT=2, COR_RB=3 }; enum eAlertMode { AM_SINGLE=0, AM_ROLLING_CLEAR=1, AM_POOL_REUSE=2 }; input int InpVWAPminutes = 1440; // VWAP window in minutes (rolling) input int InpImbWindowSec = 30; // Imbalance/flow window in seconds input double InpCheapSpreadFrac = 0.50; // Spread < ATR * this fraction => "cheap" input double InpFlowTh = 0.30; // flow threshold for alerts input double InpFlowHystFactor = 0.80; // hysteresis factor for flow reset input double InpRiskPct = 1.0; // risk per trade as % of balance input double InpStopATRmult = 1.2; // stop = ATR * this multiplier input uint InpRingSize = 20000; // tick ring buffer size input uint InpTimerSec = 2; // UI refresh / aggregation cadence
Estado global y convenciones de nomenclatura.
Las variables globales inicializan el estado operativo: la configuración del símbolo, los parámetros de mercado (g_point, g_tickVal), el identificador del indicador ATR, un objeto CTrade y un conjunto de matrices que implementan un búfer circular de ticks. El código utiliza el prefijo g_ para los nombres de objetos del gráfico; este uso de espacio de nombres es crucial para una limpieza segura de los objetos, ya que garantiza que el EA solo manipule sus propias etiquetas y no elimine accidentalmente los dibujos de otros indicadores.
Las matrices del búfer circular (g_time, g_bid, g_ask, g_last, g_vol), junto con los índices g_head, g_used, g_size, constituyen la columna vertebral de todos los cálculos agregados; almacenar los ticks localmente evita llamadas repetidas a las API de la plataforma, mejora el determinismo y permite la agregación por ventanas temporales. Las variables globales también almacenan valores anteriores para detectar cambios y reducir el redibujado innecesario de la interfaz. En los artículos, destaque que el estado global debe gestionarse con cuidado en MQL5, ya que el terminal se ejecuta en un único hilo y las fugas de memoria procedentes de identificadores de indicadores u objetos huérfanos son escollos habituales.
// Globals: symbol settings, ring-buffer arrays and indices string g_sym=""; double g_point=0.0, g_tickVal=0.0, g_tickSize=0.0; double g_volMin=0, g_volMax=0, g_volStep=0; int g_atrHandle = INVALID_HANDLE; MqlTick g_latestTick; datetime g_time[]; // ring buffer timestamps double g_bid[], g_ask[], g_last[], g_vol[]; // ring buffer data int g_head = -1; // index of most recent slot int g_used = 0; // number of filled slots int g_size = 0; // capacity (InpRingSize)
Pequeñas funciones auxiliares (SafeDiv, ARGB, RR).
Unas pocas funciones auxiliares muy sencillas mejoran la corrección y la legibilidad. SafeDiv es un envoltorio defensivo que evita errores de división por cero, un patrón importante cuando se trabaja con datos en tiempo real que pueden contener ceros o valores no inicializados. ARGB compone un entero de color con mezcla alfa para los fondos de los paneles; elegir una rutina de alfa centraliza los cálculos de color y mantiene conciso el código de la interfaz de usuario. RR calcula la relación riesgo/beneficio en una sola expresión, al tiempo que protege frente a un denominador cero. Estas funciones auxiliares son breves pero esenciales: mantienen la lógica principal centrada en la semántica de trading, en lugar de en tareas repetitivas de infraestructura, y protegen frente a excepciones en tiempo de ejecución que son difíciles de depurar en la operativa real.// Defensive helpers used across the codebase double SafeDiv(double a, double b) { return (b == 0.0 ? 0.0 : a/b); } uint ARGB(color c, int a) // produce ARGB color integer { if(a<0) a=0; if(a>255) a=255; return ((uint)a<<24) | (c & 0x00FFFFFF); } double RR(double entry,double stop,double tp) // simple R/R guard { return (entry - stop != 0.0 ? (tp - entry) / (entry - stop) : 0.0); }
Inicialización y adición al búfer circular (BufInit / BufAdd).
El diseño del búfer circular es deliberado: BufInit impone una capacidad mínima y redimensiona las matrices, mientras que BufAdd escribe el último tick en la siguiente posición y vuelve al principio mediante aritmética modular. Esto proporciona un tiempo de inserción O(1) y una huella de memoria fija y compacta. En la práctica, se elige este patrón en lugar de inserciones ilimitadas (como ArrayResize en cada tick) para evitar reasignaciones frecuentes de memoria en instrumentos de alta frecuencia. BufAdd también normaliza el volumen utilizando volume_real cuando está presente y, en su defecto, recurre a volume o a 1,0, ya que muchas fuentes de datos minoristas omiten los volúmenes realistas o los representan de forma diferente. Un valor mayor de InpRingSize conserva más historial para ventanas de VWAP largas, pero consume más memoria. Este compromiso afecta a la capacidad de respuesta y al uso de la memoria RAM.// Initialize ring buffer with minimum capacity void BufInit(int n) { if(n < 128) n = 128; g_size = n; ArrayResize(g_time, n); ArrayResize(g_bid, n); ArrayResize(g_ask, n); ArrayResize(g_last, n); ArrayResize(g_vol, n); g_head = -1; g_used = 0; } // Append a tick into the circular buffer (O(1) insertion) void BufAdd(const MqlTick &q) { if(g_size <= 0) return; g_head = (g_head + 1) % g_size; g_time[g_head] = q.time; g_bid[g_head] = q.bid; g_ask[g_head] = q.ask; g_last[g_head] = q.last; double vol = (q.volume_real > 0 ? q.volume_real : q.volume); g_vol[g_head] = (vol > 0 ? vol : 1.0); // safe fallback if(g_used < g_size) g_used++; }
Función de acceso al precio (función Mid).
La función Mid devuelve el mejor precio disponible para un tick almacenado: prefiere el último precio (última operación) si está presente y, de lo contrario, usa el punto medio entre bid y ask. Este enfoque por capas es pragmático: las operaciones ejecutadas son la prueba más directa del precio ejecutado, pero algunas actualizaciones de ticks solo contienen cotizaciones, por lo que el punto medio aproxima el valor razonable. Devolver 0 para las ranuras no utilizables indica a las funciones llamadoras que deben omitir esas entradas. Tenga en cuenta que la preferencia por el último precio frente al punto medio influye en la sensibilidad: un VWAP o un flujo centrado en el último precio reaccionará únicamente cuando se produzcan operaciones, mientras que el uso de puntos medios aumenta la densidad, pero puede introducir ruido de cotizaciones.// Prefer last trade price; fallback to midpoint if last absent double Mid(int idx) { if(idx < 0 || idx >= g_size) return 0.0; if(g_last[idx] > 0.0) return g_last[idx]; if(g_bid[idx] > 0.0 && g_ask[idx] > 0.0) return 0.5 * (g_bid[idx] + g_ask[idx]); return 0.0; }
Funciones de acceso al spread y al ATR.
SpreadPips y ATR encapsulan dos medidas ortogonales: el coste inmediato de transacción y la volatilidad del mercado. SpreadPips llama a SymbolInfoTick y divide ask - bid entre g_point para expresar el spread en pips (o puntos), lo que facilita las comparaciones con el ATR. ATR() lee el valor más reciente del ATR utilizando CopyBuffer sobre un identificador de iATR, mientras que ATR_Avg calcula una media móvil corta. Esta separación es importante: el ATR se trata como una referencia de volatilidad utilizada para dimensionar los stops y para la prueba de «spread estrecho» (spread < ATR * fracción). Es importante tener en cuenta el coste computacional: CopyBuffer realiza operaciones de E/S y debe utilizarse con moderación; además, hay que aclarar que el ATR se calcula en un marco temporal determinado por InpTF, por lo que elegir InpTF afecta al ATR y, por tanto, tanto a los stops como a las decisiones sobre si el spread es bajo.// Spread in pips (points normalized by g_point) double SpreadPips() { MqlTick t; if(!SymbolInfoTick(g_sym, t) || g_point == 0.0) return 0.0; return (t.ask - t.bid) / g_point; } // Latest ATR (indicator handle must be created beforehand) double ATR() { if(g_atrHandle == INVALID_HANDLE) return 0.0; double buf[]; if(CopyBuffer(g_atrHandle, 0, 0, 1, buf) == 1) return buf[0]; return 0.0; } // Average ATR across 'bars' (caps at 200 to limit work) double ATR_Avg(int bars) { if(g_atrHandle == INVALID_HANDLE || bars <= 0) return 0.0; int cap = MathMin(bars, 200); double buf[]; int copied = CopyBuffer(g_atrHandle, 0, 0, cap, buf); if(copied <= 0) return 0.0; double s = 0.0; for(int i=0; i<copied; i++) s += buf[i]; return s / copied; }
El agregador (Acc): el recopilador de datos central.
Acc es la rutina central única de agregación a la que llaman las funciones VWAP y de flujo. Dada una marca de tiempo since, recorre el búfer circular hacia atrás desde el tick más reciente y acumula precio*volumen (para el numerador del VWAP), el volumen total (denominador del VWAP) y, opcionalmente, cuando flowNeeded es true, recuentos de ticks alcistas y bajistas. El bucle se detiene cuando encuentra un tick anterior a since, lo que hace que la función respete la ventana temporal. Los detalles de implementación importan: prev se inicializa en DBL_MAX para omitir la primera comparación; se omiten los ticks con precios no válidos; el índice da la vuelta cuando llega al inicio.
La función cuenta deliberadamente up y dn como ocurrencias (recuento de ticks) en lugar de sumar volúmenes con signo; se trata de una decisión de diseño motivada por la simplicidad y la robustez en fuentes de datos que carecen de volumen fiable. Es importante dejar claro que Acc permite tanto el VWAP ponderado por volumen como el flujo basado en ticks, pero la métrica de flujo elegida aquí cuenta eventos, no volúmenes; esa diferencia tiene consecuencias prácticas para el comportamiento de las señales.
// Accumulate price*volume and volume; optionally compute up/dn tick counts void Acc(datetime since, double &pxVol, double &vol, int &up, int &dn, bool flowNeeded) { pxVol = 0.0; vol = 0.0; up = 0; dn = 0; if(g_used == 0) return; int idx = g_head; double prev = DBL_MAX; for(int i = 0; i < g_used; ++i) { if(g_time[idx] < since) break; double p = Mid(idx); if(p <= 0.0) { idx--; if(idx < 0) idx = g_size - 1; continue; } double w = (g_vol[idx] > 0.0 ? g_vol[idx] : 1.0); pxVol += p * w; // VWAP numerator vol += w; // VWAP denominator if(flowNeeded && prev != DBL_MAX) { if(p > prev) up++; else if(p < prev) dn++; } prev = p; idx--; if(idx < 0) idx = g_size - 1; } }
Implementación de VWAP (función VWAP).
La función VWAP convierte Acc, de propósito general, en la fórmula habitual. Calcula since a partir de TimeCurrent() menos los minutos configurados, pasa ese valor a Acc para obtener px y v, y devuelve px / v. La función devuelve cero cuando no hay volumen, lo que evita que se produzcan NaNs. Desde un punto de vista conceptual, el VWAP de esta herramienta es un VWAP móvil con ventana temporal (no un VWAP de sesión por defecto), lo que le permite controlar su capacidad de respuesta mediante InpVWAPminutes. El VWAP se suele utilizar de dos formas: un VWAP de ventana larga como referencia del valor razonable y VWAP de ventana corta para la microestructura intradía; además, se muestra cómo modificar el cálculo para obtener un VWAP basado en la sesión, si se desea.// Rolling VWAP over last 'minutes' minutes double VWAP(int minutes) { if(minutes <= 0) return 0.0; datetime since = TimeCurrent() - (datetime)minutes * 60; double px = 0.0, v = 0.0; int u, d; Acc(since, px, v, u, d, false); return (v > 0.0 ? px / v : 0.0); }
Implementación del flujo (función Flow).
Flow utiliza Acc con flowNeeded=true para obtener los recuentos de ticks alcistas y ticks bajistas, y devuelve (up - dn) / (up + dn), un desequilibrio normalizado del recuento de ticks en el intervalo [-1, 1]. Este sencillo ratio ofrece una idea inmediata de la actividad direccional: los valores cercanos a +1 indican que casi todos los ticks de la ventana fueron ticks alcistas, lo que sugiere compras agresivas por ticks, mientras que -1 indica un sesgo vendedor.
Conviene destacar especialmente la elección explícita del recuento de ticks en lugar de los volúmenes con signo ponderados por volumen: el recuento de ticks otorga el mismo peso a todos los movimientos de precio y es robusto frente a operaciones grandes aisladas y anómalas; en cambio, el flujo ponderado por volumen mide la masa que hay detrás de los movimientos y puede resultar más informativo cuando los tamaños reales de las operaciones son fiables. Ambos enfoques son válidos; el ejemplo que figura a continuación muestra la implementación que se utiliza actualmente.
// Tick-count based flow (implemented in base tool) double Flow(int sec) { if(sec <= 0) return 0.0; datetime since = TimeCurrent() - sec; double px = 0.0, v = 0.0; int up = 0, dn = 0; Acc(since, px, v, up, dn, true); int tot = up + dn; return (tot ? double(up - dn) / tot : 0.0); // normalized [-1,1] } // Alternative: volume-weighted flow (replace Acc's tick-count mode) // *Requires modifying Acc to accumulate signedVol and totalVol* double VolumeWeightedFlow(int sec) { if(sec <= 0) return 0.0; datetime since = TimeCurrent() - sec; int idx = g_head; double signedVol = 0.0, totalVol = 0.0; double prev = DBL_MAX; for(int i = 0; i < g_used; ++i) { if(g_time[idx] < since) break; double p = Mid(idx); if(p <= 0.0) { idx--; if(idx < 0) idx = g_size - 1; continue; } double w = (g_vol[idx] > 0.0 ? g_vol[idx] : 1.0); if(prev != DBL_MAX) { if(p > prev) signedVol += w; else if(p < prev) signedVol -= w; } totalVol += w; prev = p; idx--; if(idx < 0) idx = g_size - 1; } return (totalVol ? signedVol / totalVol : 0.0); // normalized to [-1,1] }
Funciones auxiliares para objetos, paneles y etiquetas (EnsureObj, SetLabelIfChanged, SetRectIfChanged).
Las funciones auxiliares de la interfaz de usuario abstraen la creación repetitiva de objetos y las actualizaciones de propiedades, y evitan de forma inteligente llamadas ObjectSet* innecesarias comparando primero los valores actuales y actualizándolos solo cuando cambia alguna propiedad. Esto reduce el parpadeo y el uso de CPU, ya que las llamadas a la API del terminal para crear objetos o establecer sus propiedades tienen un coste. EnsureObj centraliza la semántica de creación de objetos, mientras que SetLabelIfChanged y SetRectIfChanged estandarizan las actualizaciones de propiedades para las etiquetas y los fondos de rectángulo. Desde el punto de vista de la ingeniería de software, se trata de una buena práctica: aislar las peculiaridades de la plataforma y mantener clara la lógica principal. En la documentación, se debe señalar que estas funciones auxiliares también configuran sistemáticamente los objetos como no seleccionables, lo que evita la manipulación accidental del gráfico y hace que el panel se comporte como un panel de control, en lugar de como elementos interactivos del gráfico.// Create object if missing void EnsureObj(string name, ENUM_OBJECT type) { if(ObjectFind(0, name) == -1) ObjectCreate(0, name, type, 0, 0, 0); } // Update label text & position only if changed (reduces redraws) void SetLabelIfChanged(string name, int corner, int xdist, int ydist, string text, int fontsize, color col, string font) { EnsureObj(name, OBJ_LABEL); if(ObjectGetInteger(0,name,OBJPROP_CORNER) != corner) ObjectSetInteger(0,name,OBJPROP_CORNER,corner); if(ObjectGetInteger(0,name,OBJPROP_XDISTANCE) != xdist) ObjectSetInteger(0,name,OBJPROP_XDISTANCE,xdist); if(ObjectGetInteger(0,name,OBJPROP_YDISTANCE) != ydist) ObjectSetInteger(0,name,OBJPROP_YDISTANCE,ydist); if(ObjectGetString(0,name,OBJPROP_TEXT) != text) ObjectSetString(0,name,OBJPROP_TEXT,text); if(ObjectGetInteger(0,name,OBJPROP_FONTSIZE) != fontsize) ObjectSetInteger(0,name,OBJPROP_FONTSIZE,fontsize); if(ObjectGetInteger(0,name,OBJPROP_COLOR) != (int)col) ObjectSetInteger(0,name,OBJPROP_COLOR,col); if(ObjectGetString(0,name,OBJPROP_FONT) != font) ObjectSetString(0,name,OBJPROP_FONT,font); ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false); } // Update rectangle only when a property changed void SetRectIfChanged(string name,int corner,int xdist,int ydist,int xsize,int ysize,uint bgARGB) { EnsureObj(name, OBJ_RECTANGLE_LABEL); if(ObjectGetInteger(0,name,OBJPROP_CORNER) != corner) ObjectSetInteger(0,name,OBJPROP_CORNER,corner); if(ObjectGetInteger(0,name,OBJPROP_XDISTANCE) != xdist) ObjectSetInteger(0,name,OBJPROP_XDISTANCE,xdist); if(ObjectGetInteger(0,name,OBJPROP_YDISTANCE) != ydist) ObjectSetInteger(0,name,OBJPROP_YDISTANCE,ydist); if(ObjectGetInteger(0,name,OBJPROP_XSIZE) != xsize) ObjectSetInteger(0,name,OBJPROP_XSIZE,xsize); if(ObjectGetInteger(0,name,OBJPROP_YSIZE) != ysize) ObjectSetInteger(0,name,OBJPROP_YSIZE,ysize); if((uint)ObjectGetInteger(0,name,OBJPROP_BGCOLOR) != bgARGB) ObjectSetInteger(0,name,OBJPROP_BGCOLOR,bgARGB); if((uint)ObjectGetInteger(0,name,OBJPROP_COLOR) != bgARGB) ObjectSetInteger(0,name,OBJPROP_COLOR,bgARGB); ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false); }
Creación y disposición del panel (CreatePanelObjects y UpdatePanelObjects).
CreatePanelObjects instancia el conjunto de etiquetas y rectángulos que forman el panel de información; UpdatePanelObjects es un motor de maquetación que calcula los anchos de texto, los tamaños de las barras y las posiciones, y luego actualiza las propiedades para reflejar visualmente las métricas más recientes. Utiliza una constante de ancho de carácter para estimar el ancho de las etiquetas, calcula el espacio disponible para las barras y dibuja barras proporcionales en primer plano para el spread, el ATR y el flujo.
El código utiliza un vocabulario visual compacto —un encabezado, líneas de resumen, tres barras horizontales y una marca de tiempo en el pie de página— para que los operadores puedan captar las señales esenciales de un solo vistazo. La disposición del panel corresponde a las siguientes métricas: vincule cada elemento de la interfaz de usuario con su variable subyacente (spPips: barra de spread; flow: barra de flujo) y explique los compromisos de diseño: los anchos de texto aproximados precalculados evitan llamadas complejas a las métricas de fuentes, pero pueden producir una ligera desalineación con fuentes poco comunes; la mezcla alfa elegida ayuda a que la interfaz de usuario sea legible sin ocultar el gráfico.
// Minimal set of dashboard objects used by UpdatePanelObjects void CreatePanelObjects() { EnsureObj("ESGP_bg", OBJ_RECTANGLE_LABEL); EnsureObj("ESGP_hdr", OBJ_LABEL); EnsureObj("ESGP_lbl", OBJ_LABEL); EnsureObj("ESGP_vwap", OBJ_LABEL); EnsureObj("ESGP_spbar", OBJ_RECTANGLE_LABEL); EnsureObj("ESGP_spbar_fg", OBJ_RECTANGLE_LABEL); EnsureObj("ESGP_flow_lbl", OBJ_LABEL); // Make them non-selectable by default string objs[] = {"ESGP_bg","ESGP_hdr","ESGP_lbl","ESGP_vwap","ESGP_spbar","ESGP_spbar_fg","ESGP_flow_lbl"}; for(int i=0;i<ArraySize(objs);i++) ObjectSetInteger(0,objs[i],OBJPROP_SELECTABLE,false); }
Gestión de alertas y marcadores visuales.
El subsistema de alertas admite tres modos: reemplazo único, limpieza continua (nombres únicos basados en marcas de tiempo) y un conjunto circular de marcadores en pool. Las alertas se dibujan, de forma opcional, únicamente cuando se cumple la prueba de spread bajo y el flujo cruza los umbrales configurados, incorporando histéresis para evitar oscilaciones repetidas. El código almacena una marca de tiempo en OBJPROP_TOOLTIP para cada marcador, y AutoClearOldAlerts elimina los marcadores obsoletos con una antigüedad superior a InpAlertMaxAgeSec. Se trata de un método elegante y con pocas dependencias para llevar un registro en el propio gráfico: evita la necesidad de recurrir a un almacenamiento externo y, al mismo tiempo, ofrece a los operadores un registro de auditoría visible de los eventos de señales. Estas decisiones de diseño mejoran la facilidad de uso para los operadores: contar con marcadores persistentes simplifica la revisión y el backtesting mediante la comparación visual, mientras que la histéresis reduce el ruido y las reactivaciones falsas.// Draw a simple buy/sell alert label in the panel corner void DrawAlertMarker(bool isBuy) { string nm = (isBuy ? "ESGP_alert_buy" : "ESGP_alert_sell"); if(ObjectFind(0, nm) != -1) ObjectDelete(0, nm); ObjectCreate(0, nm, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, nm, OBJPROP_CORNER, COR_LT); ObjectSetInteger(0, nm, OBJPROP_XDISTANCE, 8); ObjectSetInteger(0, nm, OBJPROP_YDISTANCE, isBuy ? 60 : 80); ObjectSetString(0, nm, OBJPROP_TEXT, isBuy ? "▲ BUY" : "▼ SELL"); ObjectSetInteger(0, nm, OBJPROP_FONTSIZE, 12); ObjectSetInteger(0, nm, OBJPROP_COLOR, isBuy ? clrLime : clrRed); ObjectSetInteger(0, nm, OBJPROP_SELECTABLE, false); ObjectSetString(0, nm, OBJPROP_TOOLTIP, IntegerToString((int)TimeCurrent())); // store timestamp }
Gestión del ciclo de vida de OnInit y OnDeinit.
OnInit lleva a cabo todas las tareas de inicio necesarias: selección del símbolo, cambio opcional del marco temporal del gráfico, obtención de los parámetros del símbolo (SYMBOL_POINT, SYMBOL_VOLUME_STEP, etc.), creación del indicador ATR con iATR, inicialización del búfer circular, creación de los objetos del panel y configuración del temporizador con EventSetTimer. En cada paso se comprueba si hay errores (por ejemplo, un identificador ATR no válido) y se devuelve INIT_FAILED cuando falla una inicialización crítica, lo cual es una práctica de seguridad importante.int OnInit() { g_sym = (_Symbol); if(!SymbolSelect(g_sym, true)) return INIT_FAILED; g_point = SymbolInfoDouble(g_sym, SYMBOL_POINT); g_tickVal = SymbolInfoDouble(g_sym, SYMBOL_TRADE_TICK_VALUE); g_tickSize= SymbolInfoDouble(g_sym, SYMBOL_TRADE_TICK_SIZE); g_volMin = SymbolInfoDouble(g_sym, SYMBOL_VOLUME_MIN); g_volMax = SymbolInfoDouble(g_sym, SYMBOL_VOLUME_MAX); g_volStep = SymbolInfoDouble(g_sym, SYMBOL_VOLUME_STEP); // create ATR handle for InpTF and InpATRperiod (example uses default TF & period) g_atrHandle = iATR(g_sym, PERIOD_M1, 14); if(g_atrHandle == INVALID_HANDLE) return INIT_FAILED; BufInit((int)InpRingSize); CreatePanelObjects(); EventSetTimer((int)InpTimerSec); return INIT_SUCCEEDED; }
OnDeinit se encarga de la limpieza: detiene el temporizador, elimina los objetos del panel y de alerta, y libera los identificadores de indicadores. Si no se liberan los identificadores de indicadores o se dejan activos los temporizadores, pueden producirse fugas ocultas de memoria o de identificadores en el terminal, así como un comportamiento inesperado cuando se vuelve a adjuntar el EA.
void OnDeinit(const int reason) { EventKillTimer(); // remove panel objects (prefix "ESGP_") int total = ObjectsTotal(0); for(int i=total-1; i>=0; --i) { string nm = ObjectName(0, i); if(StringFind(nm, "ESGP_", 0) == 0) ObjectDelete(0, nm); } if(g_atrHandle != INVALID_HANDLE) { IndicatorRelease(g_atrHandle); g_atrHandle = INVALID_HANDLE; } }
Estrategia de ingesta en OnTick.
OnTick está diseñado intencionadamente para ser ligero: lee el último tick con SymbolInfoTick y lo añade al búfer circular mediante BufAdd. El procesamiento intensivo se aplaza a OnTimer. Se trata de una decisión arquitectónica importante: algunos instrumentos generan cientos o miles de ticks por segundo, y realizar actualizaciones costosas de la interfaz de usuario o lecturas de indicadores dentro de OnTick puede saturar el hilo principal y ralentizar el terminal. Al separar la ingesta de datos del procesamiento, el EA sigue siendo ágil y determinista. Esta arquitectura también simplifica las pruebas: OnTimer se ejecuta a un ritmo controlado, por lo que el comportamiento medido es más fácil de reproducir.void OnTick() { MqlTick q; if(SymbolInfoTick(g_sym, q)) { g_latestTick = q; // store latest tick BufAdd(q); // append into ring buffer (fast) } }
Bucle principal de OnTimer: cálculos, toma de decisiones, interfaz de usuario y alertas.
OnTimer es el coordinador: se encarga de que el búfer esté actualizado, impone una cadencia de actualización, calcula el spread y el ATR en pips, aplica la prueba del «spread bajo», llama a VWAP y a Flow, calcula el tamaño de la posición y los parámetros de riesgo, decide si actualizar el panel (mediante umbrales de cambio) y evalúa la lógica de alertas. La rutina de cálculo del tamaño de la posición en función del riesgo calcula un nivel de stop basándose en el ATR y InpStopATRmult, convierte la distancia del stop en ticks y en valor monetario por lote, y calcula un tamaño de lote que limita el riesgo de la cuenta según InpRiskPct, redondeándolo al g_volStep del bróker y acotándolo entre los volúmenes mínimo y máximo permitidos. La decisión de activar la alerta requiere tanto un spread bajo como un flujo que supere el umbral, con histéresis mediante InpFlowHystFactor para evitar cambios rápidos de estado. Presente este párrafo en su artículo como explicación del «motor de decisión»: en él se muestra cómo el filtrado por costes (spread frente a ATR), la confirmación direccional (flujo) y la gestión monetaria (cálculo del riesgo y del lote) se combinan para formar una señal de trading práctica.
Es fundamental dejar claro que, en la implementación actual, el flujo se basa en el recuento de ticks: mide la frecuencia de los ticks alcistas frente a los ticks bajistas, y no el volumen total que hay detrás de esos movimientos. Esta elección hace que la métrica sea robusta en fuentes de datos que carecen de un volumen fiable por tick, pero también implica que la métrica puede verse sesgada por muchos ticks pequeños frente a una sola operación grande. El VWAP se implementa como un VWAP móvil con ventana temporal (basado en minutos), y no como un VWAP de sesión, lo que influye en su interpretación: el VWAP móvil es reactivo, mientras que el VWAP de sesión ofrece una referencia intradía.
El spread se normaliza a pips mediante g_point, mientras que el ATR se lee en puntos y se convierte a pips para que las comparaciones sean coherentes. Se pueden tener en cuenta tanto las fórmulas implementadas como las versiones alternativas. También puede cambiar a un flujo ponderado por volumen (modifique Acc para acumular los volúmenes con signo y dividirlos entre el volumen total).
void OnTimer() { // 1) ensure buffer has latest tick (sometimes needed) MqlTick t; if(SymbolInfoTick(g_sym, t)) { if(g_used == 0 || g_time[g_head] != t.time) BufAdd(t); } // 2) compute metrics double spPips = SpreadPips(); double atrPts = ATR(); // ATR in price units (points) double atrPips = (atrPts > 0 && g_point > 0) ? atrPts / g_point : 0.0; bool cheap = (atrPts > 0 && spPips < atrPips * InpCheapSpreadFrac); double vwap = VWAP(InpVWAPminutes); double flow = Flow(InpImbWindowSec); // tick-count flow // 3) Example risk sizing (conservative) double bal = AccountInfoDouble(ACCOUNT_BALANCE); double bid = SymbolInfoDouble(g_sym, SYMBOL_BID); double stop = bid - InpStopATRmult * atrPts; double riskPx = bid - stop; double ticks = (g_tickSize > 0 ? riskPx / g_tickSize : 0.0); double cashPerLot = ticks * g_tickVal; double maxLoss = bal * InpRiskPct / 100.0; double rawLot = (cashPerLot > 0.0 ? maxLoss / cashPerLot : 0.0); double lot = (g_volStep > 0.0 ? MathFloor(rawLot / g_volStep) * g_volStep : 0.0); // 4) Alerting with hysteresis double resetThresh = InpFlowTh * InpFlowHystFactor; static bool buyF=false, sellF=false; if(cheap) { if(flow >= InpFlowTh && !buyF) { Alert("BUY edge: cheap spread + buy flow"); buyF = true; sellF = false; DrawAlertMarker(true); } else if(flow < resetThresh) buyF = false; if(flow <= -InpFlowTh && !sellF) { Alert("SELL edge: cheap spread + sell flow"); sellF = true; buyF = false; DrawAlertMarker(false); } else if(flow > -resetThresh) sellF = false; } }
Por último, algunas consideraciones sobre las pruebas de estrés: es posible que la granularidad de ticks del probador de estrategias no refleje el comportamiento del flujo de datos en vivo, por lo que se necesitan reproducción de ticks o datos históricos de ticks para validar la lógica basada en ticks. El registro debe realizarse con criterio (evite saturar con mensajes Print en instrumentos activos) y se recomienda perfilar el uso de la CPU cuando el valor de InpTimerSec sea pequeño. Preajustes recomendados de parámetros (por ejemplo, InpVWAPminutes de 60 a 240 para uso intradía, InpImbWindowSec de 10 a 60 para la detección de microestructura, InpCheapSpreadFrac de 0,3 a 0,7 en función del instrumento). Se recomienda seguir un enfoque de ajuste por etapas: empezar con umbrales conservadores, verificar primero las señales con marcadores visuales y activar el trading automático únicamente tras haber realizado rigurosas pruebas prospectivas. Se sugieren mejoras como ofrecer la opción de utilizar el VWAP basado en sesiones, hacer que el flujo esté ponderado por volumen, añadir un suavizado EMA al flujo para reducir los vaivenes y ofrecer el registro del historial de ticks para un análisis reproducible fuera de línea.
Resultados
Tras desarrollar el EA, el siguiente paso fue su despliegue para realizar pruebas, que pueden llevarse a cabo bien en una cuenta de demostración, bien mediante backtesting. Voy a compartir una serie de imágenes capturadas durante el proceso de pruebas en el terminal MetaTrader 5 para ilustrar el rendimiento y el comportamiento del sistema.
En el diagrama que aparece a continuación, el panel muestra una alerta de COMPRA emitida anteriormente (encabezado verde / marcador BUY). Sin embargo, el flujo actual de ventana corta es ligeramente negativo, con un desequilibrio de aproximadamente -10,3 % y un flujo de -0,10.
El spread de 71,0 pips es relativamente pequeño en comparación con la volatilidad actual, lo que el sistema considera «bajo» (se cumple la condición de spread bajo). Dado que el ATR es bastante elevado, de 469,4 pips, los stops de protección calculados en función del ATR dan lugar a amplias distancias de stop y de take-profit: aproximadamente 563,3 pips para el stop y 1.126,6 pips para el TP2R, lo que se traduce en una relación riesgo/beneficio de 2,00.
En general, se cumple el filtro de coste del EA (que indica un spread bajo). Sin embargo, la confirmación direccional mediante el flujo es ligeramente bajista en este momento, por lo que el sistema no genera una nueva señal de compra a pesar del marcador de compra existente procedente de la señal anterior.
Tras la señal de compra inicial, el mercado evolucionó a favor de la operación con el paso del tiempo. El diagrama correspondiente ilustra este movimiento positivo. En estos momentos, se ha detectado una nueva señal de venta, lo que refleja la evolución de las condiciones del mercado.
Posteriormente, el mercado se revirtió a la baja, lo que confirmó la validez de la señal. Consulte la ilustración que aparece a continuación para obtener una confirmación visual de este movimiento.
Todas y cada una de las señales van acompañadas de una notificación de alerta y se registran en la pestaña «Expertos» de MetaTrader 5, lo que permite un seguimiento y un registro exhaustivos.
Conclusión
La herramienta Slippage Tool se desarrolló para dar respuesta a un reto práctico y habitual al que se enfrentan los operadores minoristas: el acceso limitado a datos fiables del libro de órdenes, aunque siguen necesitando señales del flujo de órdenes para identificar puntos de entrada con mayor probabilidad de éxito. En lugar de intentar sustituir una escalera completa de profundidad del mercado, este sistema extrae de la secuencia de ticks disponible la información más útil sobre la microestructura. Utiliza un VWAP móvil como referencia del valor razonable, una métrica de desequilibrio y flujo de ventana corta para resaltar la presión direccional, y el contexto de spread y ATR para garantizar que las señales sean operables y tengan en cuenta el riesgo. Gracias a la visualización en el gráfico, las alertas y la lógica automatizada de cálculo del tamaño de posición, la herramienta transforma los datos de ticks en bruto en información lista para la toma de decisiones en tiempo real.
Lo que distingue a la herramienta Slippage Tool es su enfoque pragmático, centrado en la solidez y la facilidad de uso. Funciones como un búfer circular y la ingesta ligera en OnTick ayudan a mantener el rendimiento del terminal en instrumentos con gran actividad de ticks; las funciones auxiliares defensivas y la detección de cambios evitan redibujados innecesarios; y las alertas incluyen histéresis y modos de marcadores configurables para minimizar el ruido y las señales falsas. La lógica integrada de cálculo del tamaño de la posición vincula la generación de señales con la gestión real del capital, evaluando cada operación potencial en función de los stops basados en el ATR y el riesgo de la cuenta, lo que fomenta un cálculo disciplinado del tamaño de la posición frente a la apertura imprudente de posiciones.
Es importante tener en cuenta las limitaciones de la herramienta. Sirve como aproximación a la información del libro de órdenes, no como una fuente directa de profundidad de mercado (DOM): el flujo se calcula a partir del recuento de ticks (u, opcionalmente, ponderado por volumen), y el VWAP se reconstruye a partir de las operaciones ejecutadas y los puntos medios. Por lo tanto, las señales deben validarse en el contexto de los gráficos, los distintos marcos temporales y los datos de ticks reproducidos. Parámetros como la ventana del VWAP, la ventana de desequilibrio, la fracción del spread y los umbrales de flujo deben ajustarse en función de la frecuencia de ticks y la volatilidad de cada instrumento; no existe una configuración universal.
Para los profesionales que deseen implementar el sistema con confianza, se recomienda seguir un enfoque por etapas: (1) validar visualmente las señales utilizando el panel y los marcadores en modo de reproducción o demo; (2) ajustar los umbrales de forma conservadora y verificar el rendimiento en pruebas prospectivas; y (3) solo entonces plantearse automatizar las entradas con reglas sólidas de stop y de tiempo de espera, junto con un registro exhaustivo. Las futuras mejoras podrían incluir un modo de VWAP de sesión seleccionable, el cálculo opcional del flujo ponderado por volumen, el suavizado mediante media móvil exponencial (EMA) para reducir las oscilaciones bruscas y un registro de eventos exportable para facilitar un análisis reproducible.
Consulte mis otros artículos.
Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/19290
Advertencia: todos los derechos de estos materiales pertenecen a MetaQuotes Ltd. Queda totalmente prohibido el copiado total o parcial.
Este artículo ha sido escrito por un usuario del sitio web y refleja su punto de vista personal. MetaQuotes Ltd. no se responsabiliza de la exactitud de la información ofrecida, ni de las posibles consecuencias del uso de las soluciones, estrategias o recomendaciones descritas.
Utilizando redes neuronales en MetaTrader
Guía de aprendizaje automático para MetaTrader 5 (Parte 2): Etiquetado de datos financieros para modelos de aprendizaje automático
Particularidades del trabajo con números del tipo double en MQL4
MetaTrader se une a Google Sheets con Pythonanywhere: guía para un flujo de datos seguro
- 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
¿por qué no hay ningún panel?
Señor,
¿por qué no hay ningún panel?