Raspagem de dados da web sobre a rentabilidade dos títulos públicos

30 abril 2019, 08:59
Steven Brown
0
549

Introdução

A negociação automatizada é baseada quase inteiramente em indicadores técnicos que usam a ação do preço anterior para prever a ação futura do preço. No entanto, o trader que ignora as forças fundamentais que movem os mercados está em desvantagem para os traders que tomam os dados fundamentais em suas decisões de negociação. Um indicador baseado na coleta automática de dados fundamentalistas pode melhorar o desempenho de um Expert Advisor. Os dados fundamentalistas que mais afetam as taxas de câmbio são as taxas de juros, que afetam o sentimento de valor sobre as moedas. Enquanto as taxas do banco central não são voláteis, os títulos públicos do governo como a nota do tesouro americano de 10 anos, flutua a todo tempo nos mercados globais de títulos. Esses retornos refletem a expectativa do mercado quanto ao futuro das taxas do banco central. A rentabilidade dos títulos são, frequentemente, um indicador importante das taxas de juro e das taxas de câmbio. No mercado forex, a métrica que se aplica à um par de moedas é o diferencial da taxa de juros, especialmente o delta, ou a alteração no diferencial da taxa de juros, em vários vencimentos. A Figura 1 mostra um caso em que o movimento do diferencial de taxa de juros, expresso em pontos base, na direção positiva, foi um importante indicador do movimento do par de moeda EUR/USD na mesma direção. Este artigo mostra como coletar os dados da rentabilidade dos títulos públicos da Web e derivar a partir desses dados as expressões do diferencial da taxa de juros e o delta.


Indicador principal do diferencial de taxa de juros

Figura 1. Indicador do diferencial da taxa de juros no gráfico de 60 minutos do EUR/USD.

Raspagem 101

Uma página da Web exibida em um navegador geralmente consiste de vários elementos: o texto formatado, gráficos, imagens, som e vídeo. Todos esses elementos estão em arquivos localizados no servidores da Web e são baixados sequencialmente pelo navegador usando endereços ou URLs específicos para acessá-los. No entanto, é possível que um programa baixe um elemento da página, ignorando o resto, porque esse elemento tem informações úteis. A obtenção de informações dessa maneira é chamada de "raspagem". Para fazer isso, o programa scraper deve ter a URL para o arquivo que contém o elemento, que pode ser um número exibido em uma página da web. Ele pode baixar esse arquivo, buscar pelo texto que representa o número e convertê-lo em um valor numérico.

Como obter a URL

A primeira tarefa na extração é obter a URL do arquivo que contém o elemento a ser baixado. Esta pode ser a URL da página da web se o elemento estiver incorporado no texto html da página. Nesse caso, o elemento pode ser analisado a partir do texto html da página. Ou a URL pode ser incorporada em um link na página, que o navegador usa para buscar o elemento e que o programa scraper pode usar para buscar o texto html e analisar o elemento. Ou a URL pode ser passada para o navegador por um script vinculado à página, que o navegador executa depois de baixar a página e o script. Nesse caso, o programa scraper não precisa executar o script, mas pode usar a URL gerada pelo script. Essa URL pode ser descoberta usando as Ferramentas do desenvolvedor disponíveis no Internet Explorer ou no Google Chrome. Qualquer que seja a origem da URL, o programa scraper usa-a para baixar o arquivo do servidor Web e analisa-o para obter as informações desejadas. Existem vários sites financeiros que relatam a rentabilidade dos títulos. Primeiro, vamos olhar o site https://www.marketwatch.com/investing/bond/tmubmusd10y?countrycode=bx, para criar um exemplo de raspagem de dados.

Primeiro, vamos examinar o arquivo html que o navegador baixa do servidor web quando o link acima é clicado. Com a página exibida no navegador Chrome, clique no botão ferramentas no canto superior direito, mova o cursor do mouse para "Mais ferramentas", selecione "Salvar página como", baixe o arquivo html e abra-o em um editor de texto como o bloco de notas. Torna-se evidente que este site facilitou para os bots obterem a cotação, porque ele está incluído em uma das meta tags no cabeçalho do arquivo em html. Os metadados não são exibidos pelos navegadores e não há efeito sobre o que é exibido, mas ele é acessível por qualquer programa que baixe o arquivo html. A cotação aparece na meta tag <meta name="price" content="3.066">, 28 caracteres desde o início da tag e este é o mesmo valor que é exibido de forma destacada na página pelo navegador. O programa scraper pode buscar o arquivo pela string de texto [<meta name="price" content=], adicionar 28 para o índice de início da meta tag e converter o texto na localização do resultado para o número de ponto flutuante. Para evitar confusão, os colchetes são usados neste artigo para citar o texto html que faz uso frequente das aspas.

Criação de um robô melhor

O arquivo html vinculado acima, quando baixado do servidor, contém grandes blocos de informações da folha de estilo e o tamanho total é de 295 kilobytes. No entanto, a meta tag de interesse é de apenas 3 kilobytes do início do arquivo. Um robô bem comportado não baixa mais dados do que o necessário, portanto, seria razoável baixar apenas os primeiros 4 kilobytes cada vez que ele receber a cotação. Infelizmente, não é possível limitar a quantidade de dados a serem baixados pela função mql WebRequest(). O array que contém os dados de resposta do servidor deve ser um array dinâmico. Se for usado um array estático, com um tamanho específico, o programa será compilado, mas ocorrerá um erro durante a execução, travando o terminal. O cabeçalho Range poderia ser incluído na requisição para o servidor, mas a maioria dos servidores não suporta o cabeçalho Range. Portanto, a quantidade de dados baixados de um servidor Web é quase sempre o tamanho do arquivo html solicitado. A melhor maneira é utilizar as funções da wininet.dll, um componente do Windows. Uma dessas funções, InternetReadFile(), pode baixar um número especificado de bytes, mesmo quando o cabeçalho Range não é suportado e o download começa no início do arquivo. As funções do WinINet podem ser importadas para um script em mql ou Expert Advisor. O arquivo ScraperBot01.mq5 anexado a este artigo é um script que baixa os primeiros 4 kilobytes do arquivo html, localiza a meta tag de interesse no texto baixado, localiza o texto nessa tag que representa a última cotação do retorno da nota do tesouro de 10 anos, converte esse texto em um número de ponto flutuante e imprime seu valor no terminal.

ScraperBot 01

O arquivo de código-fonte ScraperBot01.mq5 começa importando a dll wininet.dll e prototipando as funções que serão chamadas, declarando todos os parâmetros que possuem tipos compatíveis com a mql5. As funções da WinINet estão documentadas em https://docs.microsoft.com/en-us/windows/desktop/wininet/wininet-reference.

#import "wininet.dll"
  int InternetCheckConnectionW(string& lpszUrl, uint dwFlags, uint dwReserved);
  int InternetOpenW(string& lpszAgent, uint dwAccessType, string& lpszProxyName, string& lpszProxyBypass, uint dwFlags);
  int InternetOpenUrlW(int hInternetSession, string& lpszUrl, string& lpszHeaders, uint dwHeadersLength, uint dwFlags, uint dwContext);
  int InternetReadFile(int hFile, uchar& lpBuffer[], uint dwNumberOfBytesToRead, uint& lpdwNumberOfBytesRead);
  int InternetCloseHandle(int hInternet);
#import

uchar uc_Buffer[4096]; // InternetReadFile() expects a static buffer.
float f_US;

O array estático uc_Buffer que receberá o texto html baixado do servidor web, e a variável f_US que será definida para o valor numérico analisado a partir do texto, são declaradas em escopo global. A convenção utilizada neste e em outros arquivos anexados neste artigo é denotar as variáveis globais por meio de um sublinhado entre o especificador do tipo e o nome. O tamanho do uc_Buffer é definido para acomodar o número específico de bytes que serão baixados.

Algumas variáveis locais são declaradas no início da OnStart(), e outras são declaradas conforme necessário, para maior clareza quanto ao seu propósito. Primeiro, nós verificamos se há uma conexão com a Internet disponível. Os valores retornados pelas funções chamadas neste script são impressos no terminal, para indicar sucesso ou falha, e, se ocorrer um erro, as manipulações abertas são fechadas e o script é finalizado pela instrução "return". Se uma conexão com a Internet estiver disponível, o identificador iNet1 é inicializado para as chamadas subsequentes às funções da WinINet. O valor de u manipulador válido é maior que zero.

void OnStart() 
{ bool bResult;  int i, iNet1, iNet2;  

  string stURL = "http://www.msn.com"; 
  bResult = InternetCheckConnectionW(stURL, 1, 0); // 1 == FLAG_ICC_FORCE_CONNECTION
  Print("InternetCheckConnectionW() returned ", bResult);
  if(!bResult) return;
  
  string stAgent = "Mozilla/5.0", stNull = "";
  iNet1 = InternetOpenW(stAgent, // _In_ LPCTSTR lpszAgent 
                        1,       // 1 == INTERNET_OPEN_TYPE_DIRECT
                        stNull,  // _In_ LPCTSTR lpszProxyName
                        stNull,  // _In_ LPCTSTR lpszProxyBypass
                        NULL);   // _In_ DWORD dwFlags
  Print("iNet1 == ", iNet1);
  if(iNet1==0) return;


Em seguida, é estabelecido uma conexão com o servidor web, inicializando o identificador iNet2 para baixar o arquivo html.

  stURL = "https://www.marketwatch.com/investing/bond/tmubmusd10y?countrycode=bx";
  string stHdr = "Accept: text/*";
  iNet2 = InternetOpenUrlW(iNet1,            // HINTERNET hInternet,
                           stURL,            // LPCWSTR   lpszUrl,
                           stHdr,            // LPCWSTR   lpszHeaders,
                           StringLen(stHdr), // DWORD     dwHeadersLength,
                           0x00080000,       // DWORD     dwFlags, 0x00080000 == INTERNET_FLAG_NO_COOKIES
                           NULL);            // DWORD_PTR dwContext
  Print("iNet2 == ", iNet2);
  if(iNet2==0) 
  { InternetCloseHandle(iNet1);
    return;
  }


Agora nós podemos baixar os dados do servidor web.

  uint uGet, uGot;
  uGet = 4080; // número de bytes para baixar
  bResult = InternetReadFile(iNet2,     // _In_  HINTERNET hFile
                             uc_Buffer, // _Out_ LPVOID lpBuffer
                             uGet,      // _In_  DWORD dwNumberOfBytesToRead
                             uGot);     // _Out_ LPDWORD lpdwNumberOfBytesRead

  Print("InternetReadFile() returned ", bResult, ". Number of bytes read: ", uGot);
  InternetCloseHandle(iNet2);  // download completo
  if(!bResult) {InternetCloseHandle(iNet1); return;}
  uc_Buffer[uGot] = 0// Termina a string uc_Buffer ao colocar um caractere nulo.


Agora, nós procuramos a meta tag de interesse no texto baixado e, se ele for encontrado, adicione um deslocamento de 28 caracteres para que possamos usá-lo como o índice em uc_Buffer para o texto que representa o número. Esse texto é acessado chamando a função StringSubstr(), passando o índice para ele na variável "i". Se o texto nesse índice não representar um número, StringToDouble() retornará zero, indicando um erro, a menos que a rentabilidade do título seja exatamente igual a zero. Observe que uma aspa dentro de uma string é codificada como \" para distingui-la das aspas no início e no final de uma string.

  i = StringFind(CharArrayToString(uc_Buffer), "<meta name=\"price\" content=", 0); // 0 == posição que a busca inicia 
  Print("Offset of \'<meta name=\"price\" content=\' == ", i); 
  if(i == -1) {Print("String not found.");  InternetCloseHandle(iNet1);  return;} 
  i += 28; // Avança o índice para a localização conhecida do texto que representa a rentabilidade do título.
  f_US = StringToDouble(StringSubstr(CharArrayToString(uc_Buffer), i, 8));
  Print("US 10-year T-note yield, stored in variable f_US: ", f_US);
  InternetCloseHandle(iNet1); // Uso da wininet finalizado.
}//END void OnStart()

O script ScraperBot01 pode ser executado em qualquer gráfico, relatar o seu progresso no terminal e imprimir o valor extraído da web.

Uma alternativa

Agora que o procedimento para a raspagem de dados de uma página web foi demonstrado, vamos considerar o que fazer se os dados da rentabilidade do título não estiverem presentes em uma meta tag. Nesse caso, nós examinaríamos o arquivo html da página web para obter a origem do número exibido na página. Conhecendo a última cotação do rendimento do título, nós podemos usar o recurso de busca de um editor de texto para encontrar uma sequência de texto que representa o número. No arquivo html que nós baixamos, a cotação pode ser encontrada em três outros locais além da meta tag. O primeiro desses três é um fragmento de dados estruturados JSON-LD, um elemento html projetado para tornar as informações sobre uma página web facilmente acessível aos mecanismos de busca e aos web crawlers. Aqui está esse fragmento de dados, formatado com quebras de linha para maior clareza.

<script type="application/ld+json">
{ "@context":"http://schema.org/",
  "@type":"Intangible/FinancialQuote",
  "url":"https://www.marketwatch.com/investing/bond/tmubmusd10y?countrycode=bx",
  "name":"U.S. 10 Year Treasury Note",
  "tickerSymbol":"TMUBMUSD10Y",
  "exchange":"Tullett Prebon",
  "price":"3.061",
  "priceChange":"0.007",
  "priceChangePercent":"0.22%",
  "quoteTime":"Sep 28, 2018 5:07 p.m.",
  "priceCurrency":"PERCENT"
}
</script>

O algoritmo buscará primeiro o deslocamento da tag <script type="application/ld+json">, e a partir dessa localização encontrar e deslocar de ["price":"] e </script>. Se o deslocamento de ["price":"] for menor que o deslocamento de </script>, indicando que está dentro do fragmento de dados, deslocamos 9 caracteres de ["price":"] para chegar ao número que representa a cotação. Esse procedimento é demonstrado no script anexado ScraperBot02.mq5.

ScraperBot 02

Este script faz baixa o arquivo html até o tamanho especificado por uMax. A primeira vez que ele é executado, o uMax deve ser configurado para um valor que é maior que o tamanho esperado do arquivo baixado, como 1 milhão. O script informa o número de bytes baixados e, se estiver próximo ou igual a uMax, o valor de uMax deve ser incrementado. O script também informa o deslocamento no arquivo da tag <script type=\"application/ld+json\">. O valor de uMax pode então ser definido um pouco mais alto que o deslocamento da tag. Nesse caso, o deslocamento é 166696, então uMax é definido como 180224 para baixar o suficiente do arquivo para incluir uma parde do JSON-LD, mas não o arquivo inteiro. O script usa um array estático para fazer o download dos blocos de 16 kilobytes, que são copiados e acumulados em uma matriz dinâmica. Esses arrays são declarados como escopo global.

uchar uc_Buffer[16400], uc_DynBuf[];

O ScraperBot02 é o mesmo que o ScraperBot01 até a parte em que os dados são baixados do servidor web, que distribui os dados em partes. O InternetReadFile é chamado repetidamente em um loop do-while até que a quantidade desejada de dados seja baixada.

  uint uGet, uGot, uDst, uMax;
  uGet = 16384;    // número de bytes para baixar por chamada da InternetReadFile, deve ser pelo menos 1 byte menor que o tamanho de uc_Buffer
  uGot = uDst = 0; // uGot é o número de bytes baixados na chamada da InternetReadFile; uDst é o número total de bytes baixados.
  uMax = 180224;   // número máximo de bytes para baixar.

  do
  { bResult = InternetReadFile(iNet2,     // _In_  HINTERNET hFile
                               uc_Buffer, // _Out_ LPVOID lpBuffer
                               uGet,      // _In_  DWORD dwNumberOfBytesToRead
                               uGot);     // _Out_ LPDWORD lpdwNumberOfBytesRead

    uc_Buffer[uGot] = 0; // Termina a string uc_Buffer ao colocar um caractere nulo.

    ArrayCopy(uc_DynBuf, // array de destino 
              uc_Buffer, // array de origem 
              uDst,      // índice no qual se inicia a escrita para o array de destino 
              0,         // índice no qual se inicia a cópia do array de origem 
              uGot);     // número de elementos para copiar 
    uDst += uGot; // avança o índice do array de destino para a próxima iteração do loop
  }while(bResult && uGot > 0 && uDst < uMax);
 
  Print("Size of uc_DynBuf == ", ArraySize(uc_DynBuf));
  Print("Bytes downloaded  == ", uDst);

Agora o ScraperBot02 localiza a tag <script type=\"application/ld+json\"> e armazena o deslocamento no índice da variável i. A partir desse deslocamento, ele localiza o ["price":"] e armazena esse deslocamento em j. Então, ele localiza o </script> no final do trecho e armazena o deslocamento em k. Se j for menor que k, j é incrementado por 9, tornando o deslocamento do texto que representa o número, que é convertido em seguida por um valor de ponto flutuante em f_US e impresso no terminal.

  int i, j, k; // índices

  i = StringFind(CharArrayToString(uc_DynBuf), "<script type=\"application/ld+json\">", 0); // 0 == position from which search starts 
  Print("Offset of <script type=\"application/ld+json\"> == ", i); 
  if(i == -1) {Print("<script type=\"application/ld+json\"> not found.");  InternetCloseHandle(iNet1);  return;}

  j = StringFind(CharArrayToString(uc_DynBuf), "\"price\":\"", i); // i == position from which search starts 
  if(j == -1) {Print("\"price\":\" not found.");  InternetCloseHandle(iNet1);  return;}
  Print("Offset of \"price\":\" == ", j); 

  k = StringFind(CharArrayToString(uc_DynBuf), "</script>", i); // i == position from which search starts
  Print("Offset of </script> == ", k); 
  if(j > k) {Print("Offset of \"price\":\" is greater than offset of </script>");  InternetCloseHandle(iNet1);  return;}

  j += 9; // Avança o índice para a localização conhecida do texto que representa a rentabilidade do título.
  f_US = StringToDouble(StringSubstr(CharArrayToString(uc_DynBuf), j, 8));
  Print("US 10-year T-note yield, stored in variable f_US: ", f_US);
  InternetCloseHandle(iNet1); // Uso da wininet finalizado.
}//END void OnStart()

Uso das ferramentas do desenvolvedor

Outra fonte de cotação desse servidor web pode ser encontrada usando as ferramentas do desenvolvedor no navegador Google Chrome. No botão de menu no canto superior direito, abra as ferramentas do desenvolvedor e digite https://www.marketwatch.com/investing/bond/tmubmusd10y?countrycode=bx na barra de endereço. Selecione a guia Rede no painel central e selecione "XHR" como o tipo de evento a ser monitorado. A seleção de qualquer um desses eventos abre um painel à direita, mostrando os detalhes como cabeçalhos e a resposta. O evento chamado "quoteByDialect ..." tem uma resposta interessante, que pode ser destacada clicando com o botão direito do mouse no painel e selecionando "Selecionar tudo". Pressione Ctrl+C para copiar o texto realçado para a área de transferência e cole-o em um editor de texto. A cotação pode ser encontrada no bloco de texto após a string ["CompositeTrading":{"Last":{"Price":{"Iso":"PERCENT","Value":]. A URL para buscar esse bloco de texto pode ser encontrada na guia Cabeçalhos. Neste caso, ela é bem extensa: https://api.wsj.net/api/dylan/quotes/v2/comp/quoteByDialect?dialect=official&needed=CompositeTrading|BluegrassChannels&MaxInstrumentMatches=1&accept=application/json&EntitlementToken=cecc4267a0194af89ca343805a3e57af&ckey=cecc4267a0&dialects=Charting&id=Bond-BX-TMUBMUSD10Y,Bond-BX-TMBMKDE-10Y. Ao clicar nesse link diretamente deste artigo, é exibido o bloco de texto em uma janela do navegador. Na verdade, são dois blocos de texto, um após o outro, porque há dois instrumentos, separadas por uma vírgula, no final da URL. O primeiro, "Bond-BX-TMUBMUSD10Y", é para a nota do tesouro de 10 anos dos EUA, e o segundo, "Bond-BX-TMBMKDE-10Y", é para o título do governo alemão de 10 anos. A exclusão do segundo instrumento da URL reduz o tamanho do texto baixado de 7.1 kilobytes para 3.6 kilobytes.

O script anexado ScraperBot03 faz o download do bloco de texto para o símbolo "TMUBMUSD10Y", localiza a string ["CompositeTrading":{"Last":{"Price":{"Iso":"PERCENT","Value":], desloca 61 caracteres do início da string, usa isso como o índice para o texto que representa o número, converte o texto em um número de ponto flutuante e imprime-o no terminal. O script é modelado após o ScrapterBot01, portanto, o código não é citado aqui. Uma vantagem deste recurso é o pequeno tamanho do arquivo baixado. Como o arquivo endereçado pela URL é de apenas 3.6 kilobytes, a função mql5 WebRequest, em vez das funções da wininet.dll, pode ser usada para baixá-lo, sem baixar mais dados que o necessário.

ScraperBot 04

Este script faz o download dos mesmos dados do ScraperBot 03, utilizando a função WebRequest em vez das funções do WinINet. Para que a WebRequest funcione, a URL base do servidor, neste caso "https://api.wsj.net", precisa ser incluída na lista de servidores permitidos em "Ferramentas\Opções\Expert Advisors" na Plataforma MetaTrader. O array char global ch_Data não transmite nenhum dado para a WebRequest e existe apenas para satisfazer o requisito de um parâmetro desse tipo.

char ch_Buffer[], ch_Data[16];
float f_US;

void OnStart() 
{ int i;   
  string stURL = "https://api.wsj.net/api/dylan/quotes/v2/comp/quoteByDialect?dialect=official&needed=CompositeTrading|BluegrassChannels&"
                 "MaxInstrumentMatches=1&accept=application/json&EntitlementToken=cecc4267a0194af89ca343805a3e57af&ckey=cecc4267a0&"
                 "dialects=Charting&id=Bond-BX-TMUBMUSD10Y";
  string stHdr = "Accept: text/*, User-Agent: Mozilla/5.0";
  string stRspHdr; // cabeçalho de resposta
  
  i = WebRequest("GET",     // const string  method,    método HTTP 
                 stURL,     // const string  url,       URL 
                 stHdr,     // const string  headers,  
                 1024,      // int           timeout, 
                 ch_Data,   // const char    &data[],   o array do corpo da mensagem HTTP 
                 ch_Buffer, // char          &result[], um array contendo os dados de resposta do servidor 
                 stRspHdr); // string        &result_headers 

  Print("Server response code: ", i);
  if(i == -1) {Print("GetLastError == ", GetLastError());  return;}
  Print("Size of ch_Buffer (bytes downloaded) == ", ArraySize(ch_Buffer));
  Print("Response header:\n", stRspHdr);   
 
  string stSearch = "\"CompositeTrading\":{\"Last\":{\"Price\":{\"Iso\":\"PERCENT\",\"Value\":";
  i = StringFind(CharArrayToString(ch_Buffer), stSearch, 0); // 0 == posição que a busca inicia 
  Print("Offset of ", stSearch, " == ", i); 
  if(i == -1) {Print(stSearch, " not found.");  return;}
  i += 61; // Avança o índice para a localização conhecida do texto que representa a rentabilidade do título.
  f_US = StringToDouble(StringSubstr(CharArrayToString(ch_Buffer), i, 8));
  Print("US 10-year T-note yield, stored in variable f_US: ", f_US);
}//END void OnStart()


Outros títulos

Para obter um diferencial de taxa de juros, é preciso haver duas taxas de juros. Os scripts que obtêm a rentabilidade da nota do tesouro americano de 10 anos podem ser adaptados para obter a rentabilidade do título do governo alemão de 10 anos, substituindo o símbolo "TMBMKDE-10Y" por "TMUBMUSD10Y" nas URLs. Os símbolos de outras nações podem ser usados também. Outros sites financeiros podem usar diferentes símbolos, mas o mesmo princípio se aplica. O título alemão é frequentemente usado como um aproximador da taxa de juros do euro, mas isso negligencia a influência de outras nações da União Europeia. No entanto, uma taxa de juros composta para o euro que pode ser derivada de dois ou mais títulos do governo europeu. Neste exemplo, a rentabilidade de títulos públicos de 10 anos dos três principais países membros da UE, em termos de PIB, cuja moeda é o euro, serão usados para derivar uma taxa composta de "títulos europeus". Essas três nações são a Alemanha, França e Itália. A rentabilidade de seus títulos serão ponderados de acordo com os tamanhos relativos de suas economias, mostrados na tabela a seguir.


Produto Interno Bruto de 2017, bilhões de Euros

Alemanha3,197
França2,241
Itália1,681
Total7,119


O fator de ponderação de cada país será a razão do seu PIB em relação ao total dos três. Para a Alemanha é de 0.449, França é de 0.315 e Itália é de 0.236. Esses fatores somam 1 e são utilizados como coeficientes no cálculo do valor composto da rentabilidade dos títulos do euro, de acordo com a seguinte equação.

f_EU = 0.449*f_DE + 0.315*f_FR + 0.236*f_IT

onde f_EU é a rentabilidade da composição de títulos europeus, f_DE é a rentabilidade dos títulos alemães, f_FR é a rentabilidade dos títulos franceses e f_IT é a rentabilidade do títulos italianos.

Diferencial da taxa de juros

O par de moedas EUR/USD é cotado como o valor do euro em termos do dólar dos EUA, por isso ele tende a se mover na mesma direção que o valor do euro e na direção oposta ao dólar. Para o movimento do diferencial da taxa de juros prever o movimento do par de moedas na mesma direção, um aumento na rentabilidade da composição de títulos europeus deve mover o diferencial da taxa de juros na direção positiva, enquanto a rentabilidade da nota do tesouro americano aumento na direção negativa. Portanto, o diferencial da taxa de juros é calculado como f_EU - f_US. No momento da escrita deste artigo, o valor calculado de f_EU é 1.255 e o valor de f_US é 3.142. Portanto, a diferença da taxa de juros é 1.255 - 3.142 = -1.887. O movimento na direção positiva, digamos de -1.887 para -1.798, previa o movimento ascendente de EUR/USD. O movimento na direção negativa, de -1.887 para -1.975, previa uma queda do EUR/USD. A força ou confiabilidade do indicador depende do tamanho do movimento do diferencial da taxa de juros. O movimento das taxas de juros é geralmente denotado em pontos base ou um centésimo de um ponto percentual. O movimento do diferencial da taxa de juros de -1.887 para -1.975 seria um movimento de 8.8 pontos base na direção negativa, um movimento razoavelmente forte com base intradiária, provavelmente indicando um movimento descendente do par de moedas no período gráfico de uma hora. Um movimento de apenas um ou dois pontos base está no reino do ruído do mercado e é improvável que seja um indicador confiável do movimento do par de moedas.

ScraperBot 05

Esse script busca todos as quatro rentabilidades de títulos, calcula a rentabilidade da composição de títulos europeus e imprime o diferencial da taxa de juros no terminal. Ele foi desenvolvido após o ScraperBot 04, mas em vez de fazer uma solicitação separada para o servidor para cada rentabilidade de títulos, todos os quatro símbolos são anexados à URL e todas as quatro cotações são retornadas em um arquivo de 14 kilobytes contendo quatro blocos sequenciais de texto. O ScraperBot 05 localiza o símbolo arquivo antes de localizar a string que precede a cotação, e retorna com uma mensagem de erro se uma string não for encontrada.

char ch_Buffer[], ch_Data[16];      // buffers globais
float f_US, f_DE, f_FR, f_IT, f_EU; // variáveis globais para armazenar a rentabilidade do título

void OnStart() 
{ int i;   
  string stURL = "https://api.wsj.net/api/dylan/quotes/v2/comp/quoteByDialect?dialect=official&needed=CompositeTrading|BluegrassChannels&"
                 "MaxInstrumentMatches=1&accept=application/json&EntitlementToken=cecc4267a0194af89ca343805a3e57af&ckey=cecc4267a0&"
                 "dialects=Charting&id=Bond-BX-TMUBMUSD10Y,Bond-BX-TMBMKDE-10Y,Bond-BX-TMBMKFR-10Y,Bond-BX-TMBMKIT-10Y"; // four ticker symbols

  string stHdr = "Accept: text/*, User-Agent: Mozilla/5.0";
  string stRspHdr; // cabeçalho de resposta

  i = WebRequest("GET",     // const string  method,    método HTTP 
                 stURL,     // const string  url,       URL 
                 stHdr,     // const string  headers,  
                 1024,      // int           timeout, 
                 ch_Data,   // const char    &data[],   o array do corpo da mensagem HTTP 
                 ch_Buffer, // char          &result[], um array contendo os dados de resposta do servidor 
                 stRspHdr); // string        &result_headers 

  Print("Server response code: ", i);
  if(i == -1) {Print("GetLastError == ", GetLastError());  return;}
  Print("Size of ch_Buffer (bytes downloaded) == ", ArraySize(ch_Buffer));
   
  string stSearch = "\"CompositeTrading\":{\"Last\":{\"Price\":{\"Iso\":\"PERCENT\",\"Value\":";

// Obtém a rentabilidade da nota do tesouro americano de 10 anos.
  i = StringFind(CharArrayToString(ch_Buffer),"\"Ticker\":\"TMUBMUSD10Y\"", 0); // 0 == position from which search starts 
  if(i == -1) {Print("\"Ticker\":\"TMUBMUSD10Y\" not found.");  return;}
  i = StringFind(CharArrayToString(ch_Buffer), stSearch, i); // i == posição que a busca inicia 
  Print("Offset of ", stSearch, " == ", i); 
  if(i == -1) {Print(stSearch, " not found.");  return;}
  i += 61; // Avança o índice para a localização conhecida do texto que representa a rentabilidade do título.
  f_US = StringToDouble(StringSubstr(CharArrayToString(ch_Buffer), i, 8));
  Print("US 10-year T-note yield, stored in variable f_US: ", f_US);

// Obtém a rentabilidade do título público alemão de 10 anos.
  i = StringFind(CharArrayToString(ch_Buffer),"\"Ticker\":\"TMBMKDE-10Y\"", i); // i == position from which search starts 
  if(i == -1) {Print("\"Ticker\":\"TMBMKDE-10Y\" not found.");  return;}
  i = StringFind(CharArrayToString(ch_Buffer), stSearch, i); // i == posição que a busca inicia 
  Print("Offset of ", stSearch, " == ", i); 
  if(i == -1) {Print(stSearch, " not found.");  return;}
  i += 61; // Avança o índice para a localização conhecida do texto que representa a rentabilidade do título.
  f_DE = StringToDouble(StringSubstr(CharArrayToString(ch_Buffer), i, 8));
  Print("German 10-year government bond yield, stored in variable f_DE: ", f_DE);

// Obtém a rentabilidade do título público francês de 10 anos.
  i = StringFind(CharArrayToString(ch_Buffer),"\"Ticker\":\"TMBMKFR-10Y\"", i); // i == posição que a busca inicia 
  if(i == -1) {Print("\"Ticker\":\"TMBMKFR-10Y\" not found.");  return;}
  i = StringFind(CharArrayToString(ch_Buffer), stSearch, i); // i == posição que a busca inicia 
  Print("Offset of ", stSearch, " == ", i); 
  if(i == -1) {Print(stSearch, " not found.");  return;}
  i += 61; // Avança o índice para a localização conhecida do texto que representa a rentabilidade do título.
  f_FR = StringToDouble(StringSubstr(CharArrayToString(ch_Buffer), i, 8));
  Print("French 10-year government bond yield, stored in variable f_FR: ", f_FR);

// Obtém a rentabilidade do título público italiano de 10 anos.
  i = StringFind(CharArrayToString(ch_Buffer),"\"Ticker\":\"TMBMKIT-10Y\"", i); // i == position from which search starts 
  if(i == -1) {Print("\"Ticker\":\"TMBMKIT-10Y\" not found.");  return;}
  i = StringFind(CharArrayToString(ch_Buffer), stSearch, i); // i == posição que a busca inicia 
  Print("Offset of ", stSearch, " == ", i); 
  if(i == -1) {Print(stSearch, " not found.");  return;}
  i += 61; // Avança o índice para a localização conhecida do texto que representa a rentabilidade do título.
  f_IT = StringToDouble(StringSubstr(CharArrayToString(ch_Buffer), i, 8));
  Print("Italian 10-year government bond yield, stored in variable f_IT: ", f_IT);

// Calcula a rentabilidade da composição de títulos públicos europeus.
  f_EU = 0.449*f_DE + 0.315*f_FR + 0.236*f_IT;
  Print("European composite bond yield: ", f_EU);

// Calcula o diferencial da taxa de juros.
  Print("Interest rate differential, f_EU-f_US = ", f_EU-f_US);
}//END void OnStart()

O ScraperBot06.mq4 implementa o ScraperBot05.mq5 usando a WinINet em vez da WebRequest, que não é confiável na plataforma MT4.


Delta

Alterações no diferencial da taxa de juros são mais relevantes para a negociação de um par de moedas do que o próprio diferencial da taxa de juros. O delta pode ser expresso como o valor do diferencial de taxa de juros no fechamento de uma barra menos seu valor no fechamento da barra anterior. Embora esse delta de período único possa ser útil em períodos gráficos mais longos, uma média móvel exponencial do delta é mais útil em períodos gráficos mais curtos, uma vez que leva em consideração a alteração em muitas barras. Um EMA é calculada aplicando-se um fator de suavização ou alfa ao delta atual e adicionando isso para (1-alfa) vezes o valor anterior da EMA, designado por EMAp.

EMA = a*Delta + (1-a)*EMAp

Como o delta pode ser positivo ou negativo e tem um valor médio igual a zero, o EMAp pode ser inicializado para zero no caso de nenhum valor anterior de EMA estar disponível. O valor de alfa pode ser atribuído arbitrariamente ou pode ser calculado a partir de um número arbitrariamente atribuído aos períodos da média móvel. Nesse caso,

a = 2.0 / (n+1)

onde n é o número de períodos de EMA, que pode ser um número inteiro ou fracionário. O intervalo normal de alfa é maior que zero, menor que ou igual a 1 ou 0 < a <= 1 Quando o valor de alfa é 1, o cálculo da EMA não considera o valor anterior de EMA e a EMA se torna o delta atual.

Se um banco de dados histórico do diferencial da taxa de juros estiver disponível, o indicador pode ser codificado para exibir uma série temporal do diferencial da taxa de juros ou de uma EMA do delta em um gráfico de um par de moedas. Os indicadores não têm permissão para buscar os dados da Internet, mas um indicador pode buscar os dados de um arquivo de disco local atualizado por um script que busca os dados de rendimento de títulos públicos da Internet. Programar esse indicador é um tópico para outro artigo.

Conclusão

O código-fonte dos scripts anexados pode ser copiado para os Expert Advisors para automatizar a coleta de dados fundamentalistas. As técnicas demonstradas neste artigo para coletar os dados do rendimento de títulos públicos da Web podem ser aplicados a outros sites financeiros e a outros pares de moedas além do usado nos exemplos. Se um recurso endereçado por uma URL mudar e não funcionar mais, o programador terá o conhecimento e os meios para descobrir o que está errado e encontrar uma solução. Um robô bem comportado não faz o download de mais dados do que o necessário e não faz solicitações muito frequentes, e certamente não em cada tick de um par de moedas. A rentabilidade dos títulos públicos são menos voláteis do que as taxas de câmbio e a maior frequência necessária é, provavelmente, uma vez a cada cinco minutos para atualizar a rentabilidade dos títulos usados como um indicador para a negociação. Da mesma forma, informações obtidas de sites não são necessariamente de domínio público e não devem ser redistribuídas. Se usado sabiamente, a coleta automatizada de dados fundamentalistas têm o potencial de tornar a negociação automatizada lucrativa.

Traduzido do Inglês pela MetaQuotes Software Corp.
Artigo original: https://www.mql5.com/en/articles/5204

Arquivos anexados |
ScraperBot01.mq5 (4.23 KB)
ScraperBot02.mq5 (5.66 KB)
ScraperBot03.mq5 (4.54 KB)
ScraperBot04.mq5 (2.59 KB)
ScraperBot05.mq5 (5.02 KB)
ScraperBot06.mq4 (7.48 KB)
Estudo de técnicas de análise de velas (parte III): Biblioteca para trabalhar com os padrões Estudo de técnicas de análise de velas (parte III): Biblioteca para trabalhar com os padrões

O objetivo deste artigo é criar uma ferramenta personalizada que permita aos usuários receber e usar todo o array de informações sobre os padrões discutidos anteriormente. Nós vamos criar uma biblioteca de funções relacionadas aos padrões que você poderá usar em seus próprios indicadores, painéis de negociação, Expert Advisors, etc.

Biblioteca para desenvolvimento fácil e rápido de programas para a MetaTrader (parte II). Coleção do histórico de ordens e negócios Biblioteca para desenvolvimento fácil e rápido de programas para a MetaTrader (parte II). Coleção do histórico de ordens e negócios

Na primeira parte, nós começamos a criar uma grande biblioteca multi-plataforma, simplificando o desenvolvimento de programas para as plataformas MetaTrader 5 e MetaTrader 4. Nós criamos o objeto abstrato COrder, que é um objeto base para o armazenamento de dados do histórico de ordens e negócios, bem como as ordens à mercado e posições. Agora nós vamos desenvolver todos os objetos necessários para o armazenamento de dados do histórico da conta em coleções.

Usando os recursos computacionais do MATLAB 2018 no MetaTrader 5 Usando os recursos computacionais do MATLAB 2018 no MetaTrader 5

Depois da atualizar o pacote MATLAB em 2015, é necessário considerar a maneira moderna de criar bibliotecas DLL. Como o exemplo de um indicador preditivo, o artigo ilustra os recursos de vinculação do MetaTrader 5 e do MATLAB usando versões modernas de plataformas de 64 bits. Ao analisar toda a sequência de conexão do MATLAB, o desenvolvedor MQL5 criará rapidamente aplicativos com recursos computacionais avançados, evitando riscos.

Indicadores MTF como ferramenta de análise técnica Indicadores MTF como ferramenta de análise técnica

A maioria de nós concorda com a opinião de que o processo de análise da situação atual do mercado começa com uma revisão dos períodos gráficos maiores, o que acontece até passarmos para o gráfico em que fazemos trading. Esta análise é uma das condições para uma negociação bem-sucedida e uma abordagem profissional. O artigo discute indicadores multiperíodo, formas de criá-los com exemplos de código MQL5. Além disso, avalia as desvantagens e vantagens de cada versão e propõe uma nova abordagem de indicadores usando o modo MTF.