Anotação de dados na análise de série temporal (Parte 2): Criação de conjuntos de dados com rótulos de tendência usando Python
Introdução
No artigo anterior, explicamos como rotular dados observando tendências no gráfico e salvando os dados em um arquivo csv. Nesta parte, faremos de maneira diferente: começaremos com os próprios dados.
Vamos processar os dados usando Python. Por que Python? É fácil trabalhar com ele. Além disso, a vasta biblioteca do Python pode nos ajudar a reduzir significativamente o ciclo de desenvolvimento.
Então, vamos começar!
Conteúdo:
- Escolhemos a biblioteca Python
- Obtemos dados do cliente MT5 usando a biblioteca MetaTrader 5
- Vamos converter o formato dos dados
- Anotação de dados
- Verificação manual
- Características
Escolhemos a biblioteca Python
Todos sabemos que o Python tem muitos ótimos desenvolvedores, que criam uma grande diversidade de bibliotecas que tornam o desenvolvimento mais fácil e mais rápido. A seguir, apresento minha coleção de bibliotecas Python. Algumas delas são baseadas em diferentes arquiteturas, algumas podem ser usadas para negociação, e outras para testes históricos. Isso inclui, entre outros, dados rotulados.
- statsmodels - módulo Python que permite aos usuários explorar dados, estimar modelos estatísticos e realizar testes estatísticos: http://statsmodels.sourceforge.net
- dynts - pacote Python para análise e gerenciamento de séries temporais: https://github.com/quantmind/dynts
- PyFlux - biblioteca Python para modelagem de séries temporais e inferência (frequencista e Bayesiana) em modelos: https://github.com/RJT1990/pyflux
- tsfresh - autoextração de características relevantes de séries temporais: https://github.com/blue-yonder/tsfresh
- hasura/quandl-metabase - inicialização rápida do Hasura para visualização de conjuntos de dados de séries temporais Quandl usando Metabase: https://platform.hasura.io/hub/projects/anirudhm/quandl-metabase-time-series
- Facebook Prophet - ferramenta para criar previsões de alta qualidade para dados de séries temporais com múltiplas sazonalidades e crescimento linear ou não linear: https://github.com/facebook/prophet
- tsmoothie - biblioteca Python para suavização de séries temporais e detecção de outliers de maneira vetorizada: https://github.com/cerlymarco/tsmoothie
- pmdarima - biblioteca estatística projetada para preencher as lacunas nas capacidades de análise de séries temporais do Python, incluindo um equivalente à função: https://github.com/alkaline-ml/pmdarima
- gluon-ts - modelagem probabilística de séries temporais em: https://github.com/awslabs/gluon-ts
- gs-quant - suíte de ferramentas Python para finanças quantitativas: https://github.com/goldmansachs/gs-quant
- willowtree - implementação robusta e flexível em Python da grade de árvore de salgueiro para precificação de derivativos: https://github.com/federicomariamassari/willowtree
- financial-engineering - aplicação de métodos de Monte Carlo a projetos de engenharia financeira em Python: https://github.com/federicomariamassari/financial-engineering
- optlib - biblioteca Python para precificação de opções financeiras: https://github.com/dbrojas/optlib
- tf-quant-finance - biblioteca de alto desempenho TensorFlow para finanças quantitativas: https://github.com/google/tf-quant-finance
- Q-Fin - biblioteca Python para matemática financeira: https://github.com/RomanMichaelPaolucci/Q-Fin
- Quantsbin - ferramentas para precificação e plotagem de preços de opções vanilla, gregas e outros tipos de análise: https://github.com/quantsbin/Quantsbin
- finoptions - implementação completa do pacote R fOptions em Python com implementação parcial de fExoticOptions para precificação de várias opções: https://github.com/bbcho/finoptions-dev
- pypme - cálculo do PME (Public Market Equivalent, equivalente ao mercado público): https://github.com/ymyke/pypme
- Blankly - teste totalmente integrado em dados históricos, negociação em papel e implantação ao vivo: https://github.com/Blankly-Finance/Blankly
- TA-Lib - wrapper Python para TA-Lib (http://ta-lib.org/): https://github.com/mrjbq7/ta-lib
- zipline - biblioteca Python para negociação algorítmica: https://github.com/quantopian/zipline
- QuantSoftware Toolkit - plataforma de software de código aberto baseada em Python, projetada para auxiliar na criação e gerenciamento de portfólios: https://github.com/QuantSoftware/QuantSoftwareToolkit
- finta - indicadores de análise técnica implementados em Pandas: https://github.com/peerchemist/finta
- Tulipy - biblioteca de indicadores de análise técnica financeira (bindings Python para tulipindicators):https://github.com/cirla/tulipy
- lppls - módulo Python para ajuste do modelo Log-Periodic Power Law Singularity (LPPLS, lei de potência log-periódica de singularidade): https://github.com/Boulder-Investment-Technologies/lppls
Obtemos dados do cliente MT5 usando a biblioteca MetaTrader 5
Se você ainda não tem o Python instalado, eu não recomendo instalar a versão oficial. É melhor usar o Anaconda, que é fácil de manter. A versão padrão do Anaconda é enorme e inclui muito conteúdo: gerenciamento visual, editor e muito mais. Para minha vergonha, quase não uso essa versão e recomendo fortemente a versão simplificada, miniconda. Você pode encontrá-la aqui - Miniconda :: Anaconda.org
1. Inicialização básica do ambiente
Comece criando um ambiente virtual e abra o tipo Anaconda Promote:
conda create -n Data_label python=3.10
Digite "y" e aguarde a criação do ambiente, depois digite:
conda activate Data_label
Nota: Ao criar um ambiente virtual conda, adicione python=x.xx, caso contrário, você enfrentará problemas durante o uso.
2. Instalação da biblioteca necessária
Vamos instalar nossa biblioteca necessária MetaTrader 5, digitando Promote no conda:
pip install MetaTrader5
Instale pytrendseries, digitando no conda Promote:
pip install pytrendseries
3. Criação de arquivo Python
No MetaEditor, vá para "Serviço" -> "Configurações", insira seu caminho para o Python na coluna Python da opção "Compiladores". Meu caminho é G:miniconda3\envs\Data_label:
Em seguida, selecione "Arquivo" -> "Novo arquivo" (ou pressione Ctrl + N) para criar um novo arquivo, e na janela que aparece, selecione "Script em Python":
Pressione "Próximo" e digite o nome do arquivo, por exemplo:
Após pressionar o botão "OK", a seguinte janela aparecerá:
4. Conexão do cliente e obtenção de dados
Vamos remover o código original automaticamente gerado e substituí-lo pelo seguinte:
# 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()
Compile e execute para verificar a presença de erros. Se não houver problemas, veremos o seguinte:
Se aparecer "initialize() failed!", adicione o caminho ao parâmetro na função initialize(), que é o caminho para o arquivo executável do cliente, como mostrado no seguinte código marcado:
# 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()Tudo pronto, vamos obter os dados:
# 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])
No código acima, adicionamos "sb=mt.symbols_total()" para evitar a mensagem de erro, já que os símbolos não foram encontrados, e "copy_rates_from_pos("GOLD_micro", mt. TIMEFRAME_M15,0,10000)" significa copiar 10.000 barras do período GOLD_micro M15. Após a compilação, obteremos o seguinte resultado:
Neste momento, obtivemos com sucesso os dados do cliente.
Vamos converter o formato dos dados
Embora tenhamos recebido os dados do cliente, o formato dos dados não é o que precisamos. Os dados estão no formato "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)]"
Vamos utilizar o pandas para a conversão. O código adicionado está marcado em 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)
Agora, vamos olhar novamente para o formato dos dados:
print(rts_fm.head(10))
Os dados de entrada devem ser em pandas. O formato DataFrame contém uma coluna como dados observados (em formato float ou int), então precisamos processar os dados no formato requisitado por pytrendseries, da seguinte maneira:
td_data=rts_fm[['time','close']].set_index('time')
Vamos ver como ficam as primeiras 10 linhas de dados:
print(td_data.head(10))
Nota: "td_data" não é o último estilo de dados, é apenas um produto intermediário para obter as tendências dos dados.
Nossos dados agora estão totalmente utilizáveis, mas, para realizar operações adicionais é melhor converter nosso formato de data em um frame de dados, então adicionaremos o seguinte código antes de "td_data=rts_fm[['time','close']].set_index('time')":
rts_fm['time']=pd.to_datetime(rts_fm['time'], unit='s')
A saída dos dados será assim:
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 de seção completo:
# 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))
Anotação de dados
1. Recuperação de dados de tendência
Primeiro, importamos o pacote pytrendseries:
import pytrendseries as pts
Usamos a função pts.detecttrend() para buscar a tendência, em seguida, definimos a variável td para essa função. Para este parâmetro, existem duas opções: "downtrend" (tendência descendente) e "uptrend" (tendência ascendente):
td='downtrend' # or "uptrend"
Precisamos de outro parâmetro "wd" como o período máximo de tendência:
wd=120
Existe também um parâmetro opcional, mas pessoalmente acho melhor defini-lo, pois este parâmetro determina o período mínimo de tendência:
limit=6
Agora podemos preencher os parâmetros da função para obter a tendência:
trends=pts.detecttrend(td_data,trend=td,limit=limit,window=wd)
Vamos verificar o resultado:
print(trends.head(15))
de | até | 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 |
Você também pode visualizar o resultado usando a função "pts.vizplot.plot_trend()":
pts.vizplot.plot_trend(td_data,trends)
Da mesma forma, podemos observar a tendência ascendente no 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)
O resultado será:
de | até | 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. Anotação de dados
1) Analisamos o formato dos dados
① indica o início dos dados até o começo do primeiro tendência descendente. Supomos que seja uma tendência ascendente;
② indica uma tendência descendente;
③ indica uma tendência ascendente no meio dos dados;
④ indica o fim da última tendência descendente.
Assim sendo, devemos implementar a lógica de rotulação para estas quatro partes.
2) Lógica de rotulação
Começaremos definindo algumas variáveis 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
Percorremos variável "trends" com um laço for para obter o início e o fim de cada fragmento de dados:
for trend in trends.iterrows():
pass
Recuperaremos os índices inicial e final para cada segmento:
for trend in trends.iterrows(): start=trend[1]['index_from'] end=trend[1]['index_to']
Como o próprio rts_fm["trend"] é inicializado como igual a 0, não há necessidade de alterar a coluna de tendência para uma tendência ascendente, mas precisamos verificar se o início dos dados é uma tendência descendente. Se não é, então assumimos uma tendência ascendente:
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))
Assim como no caso do início dos dados, precisamos verificar se ele termina com uma tendência descendente no final dos dados:
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))
Processamento dos segmentos de tendência ascendente, exceto o início e o fim dos dados:
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))
Processamos cada segmento de tendência descendente:
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) Adicionalmente
Assumimos que o início e o fim dos dados têm uma tendência ascendente. Se você achar que isso não é suficientemente preciso, você também pode remover as partes inicial e final. Para fazer isso, adicione o seguinte código após a conclusão do laço 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. Verificação
Agora, vamos verificar se nossos dados correspondem às expectativas (o exemplo considera apenas os primeiros 25 fragmentos de dados):
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 |
Você pode ver que conseguimos adicionar aos dados os tipos de tendências e os rótulos dos índices das tendências.
4. Armazenamento do arquivo
Podemos salvar os dados na maioria dos formatos. Por exemplo, podemos salvá-los como um arquivo JSON, usando o método to_json(), ou como um arquivo HTML, usando o método to_html(), etc. Como demonstração, usaremos o salvamento no formato CSV. No final do código, adicionamos:
rts_fm.to_csv('GOLD_micro_M15.csv')
Verificação manual
Até agora fizemos o trabalho principal, mas se quisermos obter dados mais precisos, precisaremos de mais intervenção manual no código. Eu destacarei aqui apenas algumas direções e não farei uma demonstração detalhada.
1. Verificação da integridade dos dados
Essa verificação pode encontrar informações sobre os dados que estão faltando, o que pode significar a ausência de todos os dados ou a ausência de um campo nos dados. A integridade dos dados é um dos critérios mais fundamentais para avaliar a qualidade dos dados. Por exemplo, se os dados anteriores do mercado de ações para o período M15 diferem em 2 horas dos dados seguintes, precisamos usar as ferramentas apropriadas para completar os dados. Claro, geralmente é difícil obter dados de taxas de câmbio ou dados do mercado de ações do nosso terminal cliente, mas se você está obtendo séries temporais de outras fontes, como dados de tráfego ou dados meteorológicos, você precisa prestar atenção especial a essa situação.
A integridade da qualidade dos dados é relativamente fácil de avaliar, e geralmente pode ser estimada pelos valores registrados e únicos na estatística dos dados. Por exemplo, se nos dados sobre o preço das ações no período anterior, o preço de fechamento foi de 1000, mas o preço de abertura se torna 10 no período seguinte, você precisa verificar se há dados faltando.
2. Verificação da precisão da rotulação de dados
O método de rotulação de dados implementado acima pode ter certas vulnerabilidades. Não podemos confiar apenas nos métodos apresentados na biblioteca pytrendseries para obter dados de rotulação precisos. É necessário visualizar adicionalmente os dados, observar se a classificação de tendências dos dados é muito sensível ou, ao contrário, insensível. Talvez seja necessário dividir os dados em partes ou combiná-los. Isso exige muito esforço e tempo, por isso, ainda não vale a pena dar exemplos específicos.
O indicador de precisão refere-se à informação registrada nos dados e pode detectar desvios nela. Ao contrário da sequência, dados com problemas de precisão não são apenas discrepâncias nas regras. Problemas de sequência podem ser causados por regras de registro de dados inconsistentes, mas não necessariamente por erros.
3. Faça uma verificação estatística básica para garantir que a rotulação seja justificada
- Distribuição da integridade: verifique de forma rápida e intuitiva se um conjunto de dados está completo.
- Mapa de calor: permite observar facilmente a correlação entre duas variáveis.
- Agrupamento hierárquico: você pode ver quão intimamente relacionadas estão as diferentes classes dos seus dados.
Características
Referência: GitHub - rafa-rod/pytrendseries
O código completo é mostrado abaixo:
# 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. Lembre-se de que se você adicionar um caminho na função mt.initialize() da seguinte maneira: mt.initialize("D:\\Project\\mt\\MT5\\terminal64.exe"), certifique-se de substituí-lo pelo local do seu próprio arquivo executável do cliente.
2. Se você não conseguir encontrar o arquivo GOLD_micro_M15.csv, procure-o na raiz do cliente. Por exemplo, meu arquivo está localizado em: "D:\\Project\\mt\\MT5\\".
Obrigado pela atenção!
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/13253
- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso