Marcado de datos en el análisis de series temporales (Parte 2): Creando conjuntos de datos con marcadores de tendencias utilizando Python
Introducción
En el artículo anterior, hablamos sobre el marcado de datos, la observación de tendencias en un gráfico y el almacenamiento de datos en un archivo csv. En esta parte haremos las cosas de forma distinta: comenzaremos con los datos en sí.
Así, procesaremos los datos usando Python. ¿Por qué Python? Porque es cómodo de usar. Además, la enorme biblioteca de Python puede ayudarnos a abreviar significativamente nuestro ciclo de desarrollo.
¡Manos a la obra!
Contenido:
- Seleccionando una biblioteca de Python
- Obteniendo los datos del cliente MT5 con ayuda de la biblioteca MetaTrader 5.
- Convirtiendo el formato de datos
- Marcado de datos
- Verificación manual
- Particularidades
Seleccionando una biblioteca de Python
Todos sabemos que Python tiene muchos desarrolladores excelentes para crear una amplia variedad de bibliotecas, lo cual hace que el desarrollo resulte más rápido y fácil. A continuación podrá ver mi colección de bibliotecas de Python. Algunas se basan en distintas arquitecturas, algunas pueden usarse para operar y otras pueden utilizarse para realizar pruebas con la historia comercial. Esto incluye, entre otros, datos marcados.
- statsmodels - módulo de Python que permite a los usuarios explorar datos, estimar modelos estadísticos y realizar pruebas estadísticas:http://statsmodels.sourceforge.net
- dynts - paquete de Python para analizar y gestionar series temporales:https://github.com/quantmind/dynts
- PyFlux - biblioteca de Python para el modelado de series temporales y la inferencia (frecuentista y bayesiana) a partir de modelos:https://github.com/RJT1990/pyflux
- tsfresh - extracción automática de características relevantes de series temporales:https://github.com/blue-yonder/tsfresh
- hasura/quandl-metabase - inicio rápido de Hasura para visualizar conjuntos de datos de series temporales de Quandl usando Metabase:https://platform.hasura.io/hub/projects/anirudhm/quandl-metabase-time-series
- Facebook Prophet - herramienta para generar pronósticos de alta calidad para datos de series temporales que posean estacionalidad múltiple con crecimiento lineal o no lineal:https://github.com/facebook/prophet
- tsmoothie - biblioteca de Python para suavizar series temporales y detectar valores atípicos de forma vectorizada:https://github.com/cerlymarco/tsmoothie
- pmdarima -biblioteca estadística diseñada para llenar los vacíos en las capacidades de análisis de series temporales de Python, incluida una función equivalente:https://github.com/alkaline-ml/pmdarima
- gluon-ts - Modelado probabilístico (vProbabilistic) de series temporales en:https://github.com/awslabs/gluon-ts
- gs-quant - kit de herramientas Python para finanzas cuantitativas:https://github.com/goldmansachs/gs-quant
- willowtree - implementación de Python sólida y flexible de willow tree para fijar los precios de derivados:https://github.com/federicomariamassari/willowtree
- financial-engineering - aplicación de métodos de Monte Carlo a proyectos de ingeniería financiera en Python:https://github.com/federicomariamassari/financial-engineering
- optlib - biblioteca Python para fijar los precios de opciones financieras:https://github.com/dbrojas/optlib
- tf-quant-finance - biblioteca TensorFlow de alto rendimiento para finanzas cuantitativas:https://github.com/dbrojas/optlib
- Q-Fin - biblioteca Python para matemáticas financieras:https://github.com/RomanMichaelPaolucci/Q-Fin
- Quantsbin - herramientas para fijar precios y gráficos de precios de opciones vainilla, griegas y otros tipos de análisis:https://github.com/quantsbin/Quantsbin
- finoptions - implementación completa del paquete R fOptions en Python con una implementación parcial de fExoticOptions para fijar el precio de varias opciones:https://github.com/bbcho/finoptions-dev
- pypme - cálculo de PME (Public Market Equivalent, equivalente en el mercado público):https://github.com/ymyke/pypme
- Blankly - prueba con datos históricos totalmente integrada, negociación en papel e implementación en vivo:https://github.com/Blankly-Finance/Blankly
- TA-Lib - envoltorio Python para TA-Lib (http://ta-lib.org/):https://github.com/mrjbq7/ta-lib
- zipline - biblioteca Python de trading algorítmico:https://github.com/quantopian/zipline
- QuantSoftware Toolkit - plataforma de software de código abierto basada en Python diseñada para respaldar la creación y gestión de portafolios:https://github.com/QuantSoftware/QuantSoftwareToolkit
- finta - indicadores de análisis técnico implementados en Pandas:https://github.com/peerchemist/finta
- Tulipy - biblioteca de indicadores de análisis técnico financiero (enlaces de Python para tulipindicators):https://github.com/cirla/tulipy
- lppls - módulo de Python para configurar el modelo Log-Periodic Power Law Singularity (LPPLS, ley de potencia log-periódica de singularidad):https://github.com/Boulder-Investment-Technologies/lppls
Obteniendo los datos del cliente MT5 con ayuda de la biblioteca MetaTrader 5.
Si aún no tiene instalado Python, no le recomiendo instalar la versión oficial. Es mejor usar Anaconda, que resulta más fácil de mantener. Pero la versión normal de Anaconda es enorme e incluye una gran cantidad de contenido: controles visuales, editor y mucho más. Para mi vergüenza, casi nunca he utilizado esta versión y recomiendo encarecidamente la versión simplificada, miniconda. Lo encontrará aquí - Miniconda :: Anaconda.org
1. Inicializamos el entorno básico
Comenzaremos creando un entorno virtual y abriendo el tipo Anaconda Promote:
conda create -n Data_label python=3.10
Escribiremos "y" y esperaremos a que se cree el entorno, luego introduciremos:
conda activate Data_label
Nota:Al crear un entorno virtual conda, añadiremos python=x.xx; de lo contrario, tendremos problemas durante el uso.
2. Instalamos la biblioteca requerida
Instalaremos nuestra biblioteca MetaTrader 5 necesaria, introduciendo en conda Promote:
pip install MetaTrader5
Luego instalaremos pytrendseries, e introduciremos en conda Promote:
pip install pytrendseries
3. Creamos un archivo Python
En el MetaEditor, iremos a "Servicio" -> "Ajustes", e introduciremos nuestra ruta de Python en la columna Python de la opción "Compiladores". Nuestra propia ruta es G:miniconda3\envs\Data_label:
Luego seleccionaremos "Archivo" -> "Nuevo archivo" (o presione Ctrl + N) para crear un nuevo archivo, y en la ventana emergente seleccionaremos "Python Script":
Después clicaremos en Siguiente e introduciremos un nombre de archivo, por ejemplo:
Después de clicar en "Aceptar", aparecerá la siguiente ventana:
4. Conectamos un cliente y recibimos datos
Ahora eliminaremos el código original generado automáticamente y lo reemplazaremos con el siguiente:
# Copyright 2021, MetaQuotes Ltd. # https://www.mql5.com import MetaTrader5 as mt if not mt.initialize(): print('initialize() failed!') else: print(mt.version()) mt.shutdown()
Luego lo compilaremos y lo ejecutaremos para comprobar si hay errores. Si no hay problemas veremos lo siguiente:
Si tenemos "initialize() failed!" añadiremos una ruta de parámetro a la función inicialize(), que será la ruta al archivo ejecutable del cliente, como se muestra en el siguiente código ponderado por colores (color-weighted):
# Copyright 2021, MetaQuotes Ltd. # https://www.mql5.com import MetaTrader5 as mt if not mt.initialize("D:\\Project\\mt\\MT5\\terminal64.exe"): print('initialize() failed!') else: print(mt.version()) mt.shutdown()Todo está listo, vamos a obtener los datos:
# Copyright 2021, MetaQuotes Ltd. # https://www.mql5.com import MetaTrader5 as mt if not mt.initialize("D:\\Project\\mt\\MT5\\terminal64.exe"): print('initialize() failed!') else: sb=mt.symbols_total() rts=None if sb > 0: rts=mt.copy_rates_from_pos("GOLD_micro",mt.TIMEFRAME_M15,0,10000) mt.shutdown() print(rts[0:5])
En el código anterior, añadiremos "sb=mt.symbols_total()" para evitar un mensaje de error, dado que no se han hallado símbolos, y "copy_rates_from_pos("GOLD_micro", mt. TIMEFRAME_M15,0,10000)" indicará el copiado de 10 000 barras del periodo GOLD_micro M15. Tras realizar la compilación, obtendremos el siguiente resultado:
En este punto, habremos recibido correctamente los datos del cliente.
Convirtiendo el formato de datos
Aunque hayamos recibido los datos del cliente, no necesitaremos el formato de datos. Los datos tendrán el aspecto "numpy.ndarray":
"[(1692368100, 1893.51, 1893.97,1893.08,1893.88,548, 35, 0)
(1692369000, 1893.88, 1894.51, 1893.41, 1894.51, 665, 35, 0)
(1692369900, 1894.5, 1894.91, 1893.25, 1893.62, 755, 35, 0)
(1692370800, 1893.68, 1894.7 , 1893.16, 1893.49, 1108, 35, 0)
(1692371700, 1893.5 , 1893.63, 1889.43, 1889.81, 1979, 35, 0)
(1692372600, 1889.81, 1891.23, 1888.51, 1891.04, 2100, 35, 0)
(1692373500, 1891.04, 1891.3 , 1889.75, 1890.07, 1597, 35, 0)
(1692374400, 1890.11, 1894.03, 1889.2, 1893.57, 2083, 35, 0)
(1692375300, 1893.62, 1894.94, 1892.97, 1894.25, 1692, 35, 0)
(1692376200, 1894.25, 1894.88, 1890.72, 1894.66, 2880, 35, 0)
(1692377100, 1894.67, 1896.69, 1892.47, 1893.68, 2930, 35, 0)
...(1693822500, 1943.97, 1944.28, 1943.24, 1943.31, 883, 35, 0)
(1693823400, 1943.25, 1944.13, 1942.95, 1943.4 , 873, 35, 0)
(1693824300, 1943.4, 1944.07, 1943.31, 1943.64, 691, 35, 0)
(1693825200, 1943.73, 1943.97, 1943.73, 1943.85, 22, 35, 0)]"
Usaremos pandas para realizar la conversión. El código añadido estará marcado en verde:
# Copyright 2021, MetaQuotes Ltd. # https://www.mql5.com import MetaTrader5 as mt import pandas as pd if not mt.initialize("D:\\Project\\mt\\MT5\\terminal64.exe"): print('initialize() failed!') else: print(mt.version()) sb=mt.symbols_total() rts=None if sb > 0: rts=mt.copy_rates_from_pos("GOLD_micro",mt.TIMEFRAME_M15,0,1000) mt.shutdown() rts_fm=pd.DataFrame(rts)
Ahora veremos nuevamente el formato de datos:
print(rts_fm.head(10))
Los datos de entrada deberán ser pandas. El formato DataFrame contendrá una columna como datos observables (en formato float o int), por lo que deberemos procesar los datos en el formato solicitado por pytrendseries de la siguiente manera:
td_data=rts_fm[['time','close']].set_index('time')
Veamos cómo se ven las primeras 10 líneas de datos:
print(td_data.head(10))
Nota: "td_data" no será el último estilo de datos, sino solo un producto de transición para obtener las tendencias de los datos.
Nuestros datos ahora serán completamente utilizables, pero para operaciones posteriores será mejor convertir nuestro formato de fecha en un marco de datos, por lo que añadiremos el siguiente código antes de "td_data=rts_fm[['time','close']].set_index( 'tiempo')":
rts_fm['time']=pd.to_datetime(rts_fm['time'], unit='s')
Los datos de salida se verán así:
time | close |
---|---|
2023-08-18 20:45:00 | 1888.82000 |
2023-08-18 21:00:00 | 1887.53000 |
2023-08-18 21:15:00 | 1888.10000 |
2023-08-18 21:30:00 | 1888.98000 |
2023-08-18 21:45:00 | 1888.37000 |
2023-08-18 22:00:00 | 1887.51000 |
2023-08-18 22:15:00 | 1888.21000 |
2023-08-18 22:30:00 | 1888.73000 |
2023-08-18 22:45:00 | 1889.12000 |
2023-08-18 23:00:00 | 1889.20000 |
Código completo de la sección:
# Copyright 2021, MetaQuotes Ltd. # https://www.mql5.com import MetaTrader5 as mt import pandas as pd if not mt.initialize("D:\\Project\\mt\\MT5\\terminal64.exe"): print('initialize() failed!') else: print(mt.version()) sb=mt.symbols_total() rts=None if sb > 0: rts=mt.copy_rates_from_pos("GOLD_micro",mt.TIMEFRAME_M15,0,1000) mt.shutdown() rts_fm=pd.DataFrame(rts) rts_fm['time']=pd.to_datetime(rts_fm['time'], unit='s') td_data=rts_fm[['time','close']].set_index('time') print(td_data.head(10))
Marcado de datos
1. Obtenemos los datos de las tendencias
Primero, importaremos el paquete pytrendseries:
import pytrendseries as pts
Usaremos la función pts.detecttrend() para encontrar la tendencia y luego definiremos una variable td para esta función. Hay dos opciones para este parámetro: "downtrend" (tendencia bajista) y "uptrend" (tendencia alcista):
td='downtrend' # or "uptrend"
Necesitaremos un parámetro más "wd" como periodo máximo de tendencia:
wd=120
También tendremos un parámetro opcional, pero personalmente creo que es mejor definirlo; este parámetro definirá el periodo mínimo de tendencia:
limit=6
Ahora podemos rellenar los parámetros de la función para obtener la tendencia:
trends=pts.detecttrend(td_data,trend=td,limit=limit,window=wd)
Comprobemos el resultado:
print(trends.head(15))
desde | hasta | price0 | price1 | index_from | index_to | time_span | drawdown | |
---|---|---|---|---|---|---|---|---|
1 | 2023-08-21 01:00:00 | 2023-08-21 02:15:00 | 1890.36000 | 1889.24000 | 13 | 18 | 5 | 0.00059 |
2 | 2023-08-21 03:15:00 | 2023-08-21 04:45:00 | 1890.61000 | 1885.28000 | 22 | 28 | 6 | 0.00282 |
3 | 2023-08-21 08:00:00 | 2023-08-21 13:15:00 | 1893.30000 | 1886.86000 | 41 | 62 | 21 | 0.00340 |
4 | 2023-08-21 15:45:00 | 2023-08-21 17:30:00 | 1896.99000 | 1886.16000 | 72 | 79 | 7 | 0.00571 |
5 | 2023-08-21 20:30:00 | 2023-08-21 22:30:00 | 1894.77000 | 1894.12000 | 91 | 99 | 8 | 0.00034 |
6 | 2023-08-22 04:15:00 | 2023-08-22 05:45:00 | 1896.19000 | 1894.31000 | 118 | 124 | 6 | 0.00099 |
7 | 2023-08-22 06:15:00 | 2023-08-22 07:45:00 | 1896.59000 | 1893.80000 | 126 | 132 | 6 | 0.00147 |
8 | 2023-08-22 13:00:00 | 2023-08-22 16:45:00 | 1903.38000 | 1890.17000 | 153 | 168 | 15 | 0.00694 |
9 | 2023-08-22 19:00:00 | 2023-08-22 21:15:00 | 1898.08000 | 1896.25000 | 177 | 186 | 9 | 0.00096 |
10 | 2023-08-23 04:45:00 | 2023-08-23 06:00:00 | 1901.46000 | 1900.25000 | 212 | 217 | 5 | 0.00064 |
11 | 2023-08-23 11:30:00 | 2023-08-23 13:30:00 | 1904.84000 | 1901.42000 | 239 | 247 | 8 | 0.00180 |
12 | 2023-08-23 19:45:00 | 2023-08-23 23:30:00 | 1919.61000 | 1915.05000 | 272 | 287 | 15 | 0.00238 |
13 | 2023-08-24 09:30:00 | 2023-08-25 09:45:00 | 1921.91000 | 1912.93000 | 323 | 416 | 93 | 0.00467 |
14 | 2023-08-25 15:00:00 | 2023-08-25 16:30:00 | 1919.88000 | 1913.30000 | 437 | 443 | 6 | 0.00343 |
15 | 2023-08-28 04:15:00 | 2023-08-28 07:15:00 | 1916.92000 | 1915.07000 | 486 | 498 | 12 | 0.00097 |
También podremos visualizar el resultado usando la función "pts.vizplot.plot_trend()":
pts.vizplot.plot_trend(td_data,trends)
De forma similar, podremos observar la tendencia alcista por el código:
td="uptrend" wd=120 limit=6 trends=pts.detecttrend(td_data,trend=td,limit=limit,window=wd) print(trends.head(15)) pts.vizplot.plot_trend(td_data,trends)
El resultado será:
desde | hasta | price0 | price1 | index_from | index_to | time_span | drawup | |
---|---|---|---|---|---|---|---|---|
1 | 2023-08-18 22:00:00 | 2023-08-21 03:15:00 | 1887.51000 | 1890.61000 | 5 | 22 | 17 | 0.00164 |
2 | 2023-08-21 04:45:00 | 2023-08-22 10:45:00 | 1885.28000 | 1901.35000 | 28 | 144 | 116 | 0.00852 |
3 | 2023-08-22 11:15:00 | 2023-08-22 13:00:00 | 1898.78000 | 1903.38000 | 146 | 153 | 7 | 0.00242 |
4 | 2023-08-22 16:45:00 | 2023-08-23 19:45:00 | 1890.17000 | 1919.61000 | 168 | 272 | 104 | 0.01558 |
5 | 2023-08-23 23:30:00 | 2023-08-24 09:30:00 | 1915.05000 | 1921.91000 | 287 | 323 | 36 | 0.00358 |
6 | 2023-08-24 15:30:00 | 2023-08-24 17:45:00 | 1912.97000 | 1921.24000 | 347 | 356 | 9 | 0.00432 |
7 | 2023-08-24 23:00:00 | 2023-08-25 01:15:00 | 1916.41000 | 1917.03000 | 377 | 382 | 5 | 0.00032 |
8 | 2023-08-25 03:15:00 | 2023-08-25 04:45:00 | 1915.20000 | 1916.82000 | 390 | 396 | 6 | 0.00085 |
9 | 2023-08-25 09:45:00 | 2023-08-25 17:00:00 | 1912.93000 | 1920.03000 | 416 | 445 | 29 | 0.00371 |
10 | 2023-08-25 17:45:00 | 2023-08-28 18:30:00 | 1904.37000 | 1924.86000 | 448 | 543 | 95 | 0.01076 |
11 | 2023-08-28 20:00:00 | 2023-08-29 06:30:00 | 1917.74000 | 1925.41000 | 549 | 587 | 38 | 0.00400 |
12 | 2023-08-29 10:00:00 | 2023-08-29 12:45:00 | 1922.00000 | 1924.21000 | 601 | 612 | 11 | 0.00115 |
13 | 2023-08-29 15:30:00 | 2023-08-30 17:00:00 | 1914.98000 | 1947.79000 | 623 | 721 | 98 | 0.01713 |
14 | 2023-08-30 23:45:00 | 2023-08-31 04:45:00 | 1942.09000 | 1947.03000 | 748 | 764 | 16 | 0.00254 |
15 | 2023-08-31 09:30:00 | 2023-08-31 15:00:00 | 1943.52000 | 1947.00000 | 783 | 805 | 22 | 0.00179 |
2. Marcado de datos
1) Analizamos el formato de los datos
① indicará que los datos comienzan antes de que se inicie la primera tendencia bajista. Digamos que es una tendencia alcista;
② indicará una tendencia bajista;
③ indicará una tendencia alcista en la mitad de los datos;
④ indicará el final de la última tendencia bajista.
Por lo tanto, deberemos implementar la lógica de marcado para estas cuatro partes.
2) Lógica de marcado
Comenzaremos definiendo algunas variables básicas:
rts_fm['trend']=0 rts_fm['trend_index']=0 max_len_rts=len(rts_fm) max_len=len(trends) last_start=0 last_end=0
Recorramos la variable "trends" para obtener el inicio y el final de cada dato:
for trend in trends.iterrows():
pass
Luego obtendremos los índices inicial y final para cada segmento:
for trend in trends.iterrows(): start=trend[1]['index_from'] end=trend[1]['index_to']
Como rts_fm["tendencia"] se inicializará a 0, no necesitaremos cambiar la columna de tendencia de una tendencia alcista, pero sí necesitaremos ver si el inicio de los datos supone una tendencia bajista. Si no, entonces supondremos una tendencia alcista:
for trend in trends.iterrows(): start=trend[1]['index_from'] end=trend[1]['index_to'] if trend[0]==1 and start!=0: # Since the rts_fm["trend"] itself has been initialized to 0, there is no need to change the "trend" column rts_fm['trend_index'][0:start]=list(range(0,start))
Al igual que con el inicio de los datos, deberemos ver si termina en una tendencia bajista al final de los datos:
for trend in trends.iterrows(): start=trend[1]['index_from'] end=trend[1]['index_to'] if trend[0]==1 and start!=0: # Since the rts_fm["trend"] itself has been initialized to 0, there is no need to change the "trend" column rts_fm['trend_index'][0:start]=list(range(0,start)) elif trend[0]==max_len and end!=max_len_rts-1: #we need to see if it ends in a downtrend at the end of the data rts_fm['trend_index'][last_end+1:len(rts_fm)]=list(range(0,max_len_rts-last_end-1))
Procesamiento de segmentos de tendencia alcista distintos del inicio y el final de los datos:
for trend in trends.iterrows(): start=trend[1]['index_from'] end=trend[1]['index_to'] if trend[0]==1 and start!=0: # Since the rts_fm["trend"] itself has been initialized to 0, there is no need to change the "trend" column rts_fm['trend_index'][0:start]=list(range(0,start)) elif trend[0]==max_len and end!=max_len_rts-1: #we need to see if it ends in a downtrend at the end of the data rts_fm['trend_index'][last_end+1:len(rts_fm)]=list(range(0,max_len_rts-last_end-1)) else: #Process the uptrend segments other than the beginning and end of the data rts_fm["trend_index"][last_end+1:start]=list(range(0,start-last_end-1))
Procesaremos cada segmento de tendencia bajista:
for trend in trends.iterrows(): start=trend[1]['index_from'] end=trend[1]['index_to'] if trend[0]==1 and start!=0: # Since the rts_fm["trend"] itself has been initialized to 0, there is no need to change the "trend" column rts_fm['trend_index'][0:start]=list(range(0,start)) elif trend[0]==max_len and end!=max_len_rts-1: #we need to see if it ends in a downtrend at the end of the data rts_fm['trend_index'][last_end+1:len(rts_fm)]=list(range(0,max_len_rts-last_end-1)) else: #Process the uptrend segments other than the beginning and end of the data rts_fm["trend_index"][last_end+1:start]=list(range(0,start-last_end-1)) #Process each segments of the downtrend rts_fm["trend"][start:end+1]=1 rts_fm["trend_index"][start:end+1]=list(range(0,end-start+1)) last_start=start last_end=end
3) Opcional
Supondremos que el inicio y el final de los datos tienen una tendencia ascendente. Si creemos que no resulta lo suficientemente preciso, también podremos quitar las partes inicial y final. Para hacer esto, añadiremos el siguiente código después de que se complete el bucle for:
rts_fm['trend']=0 rts_fm['trend_index']=0 max_len_rts=len(rts_fm) max_len=len(trends) last_start=0 last_end=0 for trend in trends.iterrows(): start=trend[1]['index_from'] end=trend[1]['index_to'] if trend[0]==1 and start!=0: # Since the rts_fm["trend"] itself has been initialized to 0, there is no need to change the "trend" column rts_fm['trend_index'][0:start]=list(range(0,start)) elif trend[0]==max_len and end!=max_len_rts-1: #we need to see if it ends in a downtrend at the end of the data rts_fm['trend_index'][last_end+1:len(rts_fm)]=list(range(0,max_len_rts-last_end-1)) else: #Process the uptrend segments other than the beginning and end of the data rts_fm["trend_index"][last_end+1:start]=list(range(0,start-last_end-1)) #Process each segments of the downtrend rts_fm["trend"][start:end+1]=1 rts_fm["trend_index"][start:end+1]=list(range(0,end-start+1)) last_start=start last_end=end rts_fm=rts_fm.iloc[trends.iloc[0,:]['index_from']:end,:]
3. Comprobación
Ahora veremos si nuestros datos coinciden con nuestras expectativas (el ejemplo solo analizará los primeros 25 datos):
rts_fm.head(25)
time | open | high | low | close | tick_volume | spread | real_volume | trend | trend_index | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 2023-08-22 11:30:00 | 1898.80000 | 1899.72000 | 1898.22000 | 1899.30000 | 877 | 35 | 0 | 0 | 0 |
1 | 2023-08-22 11:45:00 | 1899.31000 | 1899.96000 | 1898.84000 | 1899.81000 | 757 | 35 | 0 | 0 | 1 |
2 | 2023-08-22 12:00:00 | 1899.86000 | 1900.50000 | 1899.24000 | 1900.01000 | 814 | 35 | 0 | 0 | 2 |
3 | 2023-08-22 12:15:00 | 1900.05000 | 1901.26000 | 1899.99000 | 1900.48000 | 952 | 35 | 0 | 0 | 3 |
4 | 2023-08-22 12:30:00 | 1900.48000 | 1902.44000 | 1900.17000 | 1902.19000 | 934 | 35 | 0 | 0 | 4 |
5 | 2023-08-22 12:45:00 | 1902.23000 | 1903.59000 | 1902.21000 | 1902.64000 | 891 | 35 | 0 | 0 | 5 |
6 | 2023-08-22 13:00:00 | 1902.69000 | 1903.94000 | 1902.24000 | 1903.38000 | 873 | 35 | 0 | 1 | 0 |
7 | 2023-08-22 13:15:00 | 1903.40000 | 1904.29000 | 1901.71000 | 1902.08000 | 949 | 35 | 0 | 1 | 1 |
8 | 2023-08-22 13:30:00 | 1902.10000 | 1903.37000 | 1902.08000 | 1902.63000 | 803 | 35 | 0 | 1 | 2 |
9 | 2023-08-22 13:45:00 | 1902.64000 | 1902.75000 | 1901.75000 | 1901.80000 | 1010 | 35 | 0 | 1 | 3 |
10 | 2023-08-22 14:00:00 | 1901.79000 | 1902.47000 | 1901.33000 | 1901.96000 | 800 | 35 | 0 | 1 | 4 |
11 | 2023-08-22 14:15:00 | 1901.94000 | 1903.04000 | 1901.72000 | 1901.73000 | 785 | 35 | 0 | 1 | 5 |
12 | 2023-08-22 14:30:00 | 1901.71000 | 1902.62000 | 1901.66000 | 1902.38000 | 902 | 35 | 0 | 1 | 6 |
13 | 2023-08-22 14:45:00 | 1902.38000 | 1903.23000 | 1901.96000 | 1901.96000 | 891 | 35 | 0 | 1 | 7 |
14 | 2023-08-22 15:00:00 | 1901.94000 | 1903.25000 | 1901.64000 | 1902.41000 | 1209 | 35 | 0 | 1 | 8 |
15 | 2023-08-22 15:15:00 | 1902.39000 | 1903.00000 | 1898.97000 | 1899.87000 | 1971 | 35 | 0 | 1 | 9 |
16 | 2023-08-22 15:30:00 | 1899.86000 | 1901.17000 | 1896.72000 | 1896.85000 | 2413 | 35 | 0 | 1 | 10 |
17 | 2023-08-22 15:45:00 | 1896.85000 | 1898.15000 | 1896.12000 | 1897.26000 | 2010 | 35 | 0 | 1 | 11 |
18 | 2023-08-22 16:00:00 | 1897.29000 | 1897.45000 | 1895.52000 | 1895.97000 | 2384 | 35 | 0 | 1 | 12 |
19 | 2023-08-22 16:15:00 | 1895.96000 | 1896.31000 | 1893.87000 | 1894.48000 | 1990 | 35 | 0 | 1 | 13 |
20 | 2023-08-22 16:30:00 | 1894.43000 | 1894.60000 | 1892.64000 | 1893.38000 | 2950 | 35 | 0 | 1 | 14 |
21 | 2023-08-22 16:45:00 | 1893.48000 | 1894.17000 | 1888.94000 | 1890.17000 | 2970 | 35 | 0 | 1 | 15 |
22 | 2023-08-22 17:00:00 | 1890.19000 | 1894.53000 | 1889.94000 | 1894.20000 | 2721 | 35 | 0 | 0 | 0 |
23 | 2023-08-22 17:15:00 | 1894.18000 | 1894.73000 | 1891.51000 | 1891.71000 | 1944 | 35 | 0 | 0 | 1 |
24 | 2023-08-22 17:30:00 | 1891.74000 | 1893.70000 | 1890.91000 | 1893.59000 | 2215 | 35 | 0 | 0 | 2 |
Podemos ver que hemos añadido con éxito tipos de tendencias y marcadores de índices de tendencias a los datos.
4. Guardamos un archivo
Podemos guardar datos en la mayoría de formatos. Por ejemplo, podemos guardarlos como un archivo JSON utilizando el método to_json(), o como un archivo HTML usando el método to_html(), etc. Como demostración, utilizaremos el almacenamiento en formato CSV. Al final del código añadiremos:
rts_fm.to_csv('GOLD_micro_M15.csv')
Verificación manual
Ya hemos realizado la mayor parte del trabajo por ahora, pero si queremos obtener datos más precisos, necesitaremos una mayor intervención manual en el código. Aquí solo señalaremos algunas áreas y no proporcionaremos una demostración detallada.
1. Verificando la integridad de los datos
La verificación puede encontrar que falta información de datos, lo cual podría significar que faltan todos los datos o que falta un campo en ellos. La integridad de los datos es uno de los criterios más esenciales al evaluar la calidad de los datos. Por ejemplo, si los datos del mercado de valores anteriores para el periodo M15 difieren en 2 horas de los datos siguientes, entonces deberemos utilizar las herramientas correspondientes para completar los datos. Obviamente, por lo general resulta difícil obtener datos sobre los tipos de cambio o los datos del mercado de valores desde nuestro terminal de cliente, pero si recibimos series temporales de otras fuentes, como datos de tráfico o meteorológicos, deberemos prestar especial atención a esta situación.
La integridad de la calidad de los datos se puede evaluar de forma relativamente fácil y, por lo general, podremos valorarla usando valores registrados y únicos en las estadísticas de datos. Por ejemplo, si los datos del precio de las acciones en el periodo anterior tienen un precio de cierre de 1 000, pero el precio de apertura se convierte en 10 en el siguiente periodo, deberemos verificar si faltan datos.
2. Comprobamos la precisión del marcado de datos
El método de marcado de datos implementado anteriormente puede tener ciertas vulnerabilidades. Para obtener datos de marcado precisos, no podemos confiar únicamente en los métodos ofrecidos en la biblioteca pytrendseries. Deberemos visualizar los datos adicionalmente, observar si la clasificación de las tendencias de los datos resulta demasiado sensible o, por el contrario, insensible. Puede que sea necesario dividir los datos en partes o fusionarlos. Este trabajo requiere mucho esfuerzo y tiempo, por lo que no tendría sentido dar ejemplos específicos todavía.
La medida de la precisión se refiere a la información registrada en los datos y puede detectar desviaciones en los mismos. A diferencia de la coherencia, los datos con problemas de precisión no suponen simplemente inconsistencias en las reglas. Los problemas de coherencia pueden deberse a reglas incoherentes de registro de datos, pero no necesariamente a errores.
3. Realice pruebas estadísticas básicas para garantizar que el margen de beneficio sea razonable.
- Distribución de integridad: compruebe de forma rápida e intuitiva que el conjunto de datos esté integro.
- Mapa de calor: nos permite observar fácilmente la correlación entre dos variables.
- Clusterización jerárquica: podrá ver cómo de relacionadas están las diferentes clases de sus datos.
Particularidades
Enlace: GitHub - rafa-rod/pytrendseries
El código completo se muestra a continuación:
# Copyright 2021, MetaQuotes Ltd. # https://www.mql5.com import MetaTrader5 as mt import pandas as pd import pytrendseries as pts if not mt.initialize("D:\\Project\\mt\\MT5\\terminal64.exe"): print('initialize() failed!') else: print(mt.version()) sb=mt.symbols_total() rts=None if sb > 0: rts=mt.copy_rates_from_pos("GOLD_micro",mt.TIMEFRAME_M15,0,1000) mt.shutdown() rts_fm=pd.DataFrame(rts) rts_fm['time']=pd.to_datetime(rts_fm['time'], unit='s') td_data=rts_fm[['time','close']].set_index('time') # print(td_data.head(10)) td='downtrend' # or "uptrend" wd=120 limit=6 trends=pts.detecttrend(td_data,trend=td,limit=limit,window=wd) # print(trends.head(15)) # pts.vizplot.plot_trend(td_data,trends) rts_fm['trend']=0 rts_fm['trend_index']=0 max_len_rts=len(rts_fm) max_len=len(trends) last_start=0 last_end=0 for trend in trends.iterrows(): start=trend[1]['index_from'] end=trend[1]['index_to'] if trend[0]==1 and start!=0: # Since the rts_fm["trend"] itself has been initialized to 0, there is no need to change the "trend" column rts_fm['trend_index'][0:start]=list(range(0,start)) elif trend[0]==max_len and end!=max_len_rts-1: #we need to see if it ends in a downtrend at the end of the data rts_fm['trend_index'][last_end+1:len(rts_fm)]=list(range(0,max_len_rts-last_end-1)) else: #Process the uptrend segments other than the beginning and end of the data rts_fm["trend_index"][last_end+1:start]=list(range(0,start-last_end-1)) #Process each segments of the downtrend rts_fm["trend"][start:end+1]=1 rts_fm["trend_index"][start:end+1]=list(range(0,end-start+1)) last_start=start last_end=end #rts_fm=rts_fm.iloc[trends.iloc[0,:]['index_from']:end,:] rts_fm.to_csv('GOLD_micro_M15.csv')
Notas:
1. Recuerde que si añade una ruta a la función mt.initialize() de la forma siguiente: mt.initialize("D:\\Project\\mt\\MT5\\terminal64.exe"), deberá asegurarse de reemplazarla con la ubicación de su propio cliente ejecutable.
2. Si no puede encontrar el archivo GOLD_micro_M15.csv, búsquelo en la raíz del cliente. Por ejemplo, mi archivo se encuentra en: "D:\\Project\\mt\\MT5\\".
¡Gracias por su atención!
Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/13253
- 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