Conversión de coordenadas de pantalla a tiempo/precio y viceversa

La presencia de distintos principios para medir el espacio de trabajo del gráfico conduce a la necesidad de recalcular las unidades de medida entre sí. Existen dos funciones para ello.

bool ChartTimePriceToXY(long chartId, int window, datetime time, double price, int &x, int &y)

bool ChartXYToTimePrice(long chartId, int x, int y, int &window, datetime &time, double &price)

La función ChartTimePriceToXY convierte las coordenadas del gráfico de la representación tiempo/precio (time/price) en coordenadas X e Y en píxeles (x/y). La función ChartXYToTimePrice realiza la operación inversa: convierte las coordenadas X e Y en valores de tiempo y precio.

Ambas funciones requieren que se especifique el ID del gráfico en el primer parámetro chartId. Además, el número de la subventana window se pasa en ChartTimePriceToXY (debe estar dentro del número de ventanas). Si hay varias subventanas, cada una de ellas tiene su propia serie temporal y una escala a lo largo del eje vertical (denominada condicionalmente «precio» con el parámetro price).

El parámetro window es la salida en la función ChartXYToTimePrice. La función rellena este parámetro junto con time y price. Esto se debe a que las coordenadas de los píxeles son comunes a toda la pantalla, y el origen x/y puede caer en cualquier subventana.

Coordenadas de pantalla, precio y hora

Coordenadas de pantalla, precio y hora

Las funciones devuelven true una vez completadas con éxito.

Tenga en cuenta que el área rectangular visible que corresponde a las cotizaciones o a las coordenadas de la pantalla está limitada en ambos sistemas de coordenadas. Por lo tanto, son posibles situaciones en las que, con datos iniciales específicos, la hora, los precios o los píxeles recibidos estarán fuera del área de visibilidad. En concreto, también pueden obtenerse valores negativos. Veremos un ejemplo de recálculo interactivo en el capítulo sobre eventos en gráficos.

En la sección anterior vimos cómo se puede averiguar dónde se lanzó un programa MQL. Aunque físicamente sólo hay un punto de caída final, su representación en coordenadas de pantalla y cotización, por regla general, contiene un error de cálculo. Dos nuevas funciones para convertir píxeles en precio/tiempo y viceversa nos ayudarán a asegurarnos de ello.

El script modificado se llama ChartXY.mq5. A grandes rasgos, puede dividirse en 3 etapas. En la primera etapa, obtenemos las coordenadas del punto de caída, como antes.

void OnStart()
{
   const int w1 = PRTF(ChartWindowOnDropped());
   const datetime t1 = PRTF(ChartTimeOnDropped());
   const double p1 = PRTF(ChartPriceOnDropped());
   const int x1 = PRTF(ChartXOnDropped());
   const int y1 = PRTF(ChartYOnDropped());
   ...

En la segunda etapa, intentamos transformar las coordenadas de pantalla x1 y y1 durante (t2) y el precio (p2), y las comparamos con las obtenidas a partir de las funciones OnDropped anteriores.

   int w2;
   datetime t2;
   double p2;
   PRTF(ChartXYToTimePrice(0x1y1w2t2p2));
   Print(w2" "p2" "t2);
   PRTF(w1 == w2 && t1 == t2 && p1 == p2);
   ...

A continuación, realizamos la transformación inversa: utilizamos las coordenadas de cotización t1 y p1 obtenidas para calcular las coordenadas de pantalla -x2 y y2, y también las comparamos con los valores originales x1 y y1.

   int x2y2;
   PRTF(ChartTimePriceToXY(0w1t1p1x2y2));
   Print(x2" "y2);
   PRTF(x1 == x2 && y1 == y2);
   ...

Como veremos más adelante en el registro de ejemplo, todas las comprobaciones anteriores fallarán (habrá ligeras discrepancias en los valores). Así que necesitamos un tercer paso.

Recalculemos las coordenadas de cotización y pantalla con el sufijo 2 en los nombres de las variables y guardémoslas en las variables con el nuevo sufijo 3. A continuación, comparamos entre sí todos los valores de la primera y la tercera etapa.

   int w3;
   datetime t3;
   double p3;
   PRTF(ChartXYToTimePrice(0x2y2w3t3p3));
   Print(w3" "p3" "t3);
   PRTF(w1 == w3 && t1 == t3 && p1 == p3);
   
   int x3y3;
   PRTF(ChartTimePriceToXY(0w2t2p2x3y3));
   Print(x3" "y3);
   PRTF(x1 == x3 && y1 == y3);
}

Vamos a ejecutar el script en XAUUSD, gráfico H1. Aquí están los datos del punto original.

ChartWindowOnDropped()=0 / ok
ChartTimeOnDropped()=2021.11.22 18:00:00 / ok
ChartPriceOnDropped()=1797.7 / ok
ChartXOnDropped()=234 / ok
ChartYOnDropped()=280 / ok

La conversión de píxeles en cotizaciones da los siguientes resultados:

ChartXYToTimePrice(0,x1,y1,w2,t2,p2)=true / ok
0 1797.16 2021.11.22 18:30:00
w1==w2&&t1==t2&&p1==p2=false / ok

Hay diferencias tanto de tiempo como de precio. El recuento retrospectivo tampoco es perfecto en términos de precisión.

ChartTimePriceToXY(0,w1,t1,p1,x2,y2)=true / ok
232 278
x1==x2&&y1==y2=false / ok

La pérdida de precisión se produce debido a la cuantización de los valores en los ejes según las unidades de medida, en concreto píxeles y puntos.

Para terminar, el último paso demuestra que los errores obtenidos anteriormente no son artefactos de la función, porque el recálculo round-robin conduce al resultado original.

ChartXYToTimePrice(0,x2,y2,w3,t3,p3)=true / ok
0 1797.7 2021.11.22 18:00:00
w1==w3&&t1==t3&&p1==p3=true / ok
ChartTimePriceToXY(0,w2,t2,p2,x3,y3)=true / ok
234 280
x1==x3&&y1==y3=true / ok

En pseudocódigo, esto puede expresarse mediante las siguientes igualdades:

ChartTimePriceToXY(ChartXYToTimePrice(XY)) = XY
ChartXYToTimePrice(ChartTimePriceToXY(TP)) = TP

Aplicando la función ChartTimePriceToXY a los resultados del trabajo ChartXYToTimePrice se obtendrán las coordenadas originales. Lo mismo ocurre con las transformaciones en el otro sentido: aplicando ChartXYToTimePrice a los resultados de ChartTimePriceToXY se obtendrá una coincidencia.

Por lo tanto, se debe considerar cuidadosamente la implementación de algoritmos que utilicen funciones de recálculo si están sujetos a requisitos de precisión mayores.

Otro ejemplo de uso de ChartWindowOnDropped se dará en el script ChartIndicatorMove.mq5 en la sección Gestionar indicadores en el gráfico.