- Direção de Indexação em Arrays, Buffers e Séries Temporais
- Organizando Acesso aos Dados
- SeriesInfoInteger
- Bars
- BarsCalculated
- IndicatorCreate
- IndicatorParameters
- IndicatorRelease
- CopyBuffer
- CopyRates
- CopySeries
- CopyTime
- CopyOpen
- CopyHigh
- CopyLow
- CopyClose
- CopyTickVolume
- CopyRealVolume
- CopySpread
- CopyTicks
- CopyTicksRange
- iBars
- iBarShift
- iClose
- iHigh
- iHighest
- iLow
- iLowest
- iOpen
- iTime
- iTickVolume
- iRealVolume
- iVolume
- iSpread
Organizando Acesso aos Dados
Nesta seção, questões associados a obtenção, armazenamento e solicitação de dados de preços (séries de tempo) são consideradas.
Recebendo Dados de um Servidor de Negociação
Antes de dados de preços ficarem disponíveis no terminal MetraTrader 5, eles devem ser recebidos e processados. Para receber dados, uma conexão com o servidor de negociação MetaTrader 5 deve ser estabelecida. Dados são recebidos na forma de blocos empacotados de barras de um minuto do servidor sob a solicitação de um terminal.
O mecanismo de referência de servidor para solicitar dados não depende de como a solicitação foi iniciada - por um usuário ao navegar em um gráfico ou por meio de um programa na linguagem MQL5.
Armazenando Dados Intermediários
Dados recebidos de um servidor são automaticamente desempacotados e salvos no formato intermediário HCC. Os dados de cada ativo são escritos em uma pasta separada: terminal_directory\bases\server_name\history\symbol_name. Por exemplo, dados sobre EURUSD recebidos do servidor MetaQuotes-Demo serão armazenados em terminal_directory\bases\MetaQuotes-Demo\history\EURUSD\.
Os dados são escritos em arquivos com extensão .hcc. Cada arquivo armazena dados de barras de um minuto para um ano. Por exemplo, o arquivo nomeado 2009.hcc na pasta EURUSD contém barras de um minuto de EURUSD para o ano de 2009. Estes arquivos são usados para preparar dados de preço para todas as janelas de tempo e não são destinados para acesso direto.
Obtendo Dados em uma Janela de Tempo Necessária a partir dos Dados Intermediários
Os arquivo HCC intermediários são usados como fonte de dados para construir dados de preço para janelas de tempo solicitadas no formato HC. Dados de formato HC são séries de tempo que são maximamente preparados para acesso rápido. Eles são criados sob solicitação de um gráfico ou um programa MQL5. O volume de dados não deve exceder o valor do parâmetro "Máx. barras no gráfico". Os dados são armazenados para posterior uso em arquivos com extensão hc.
Para economizar recursos, os dados em uma janela de tempo são armazenados e guardamos em RAM somente se necessário. Se não for chamado por um longo tempo, eles são liberados da RAM e salvos em um arquivo. Para cada janela de tempo, os dados são preparados independentemente se existem dados prontos ou não para outras janelas de tempo. Regras para formação e acesso aos dados são as mesmas para todas as janelas de tempo. Isso significa que apesar da unidade de dados armazenada em HCC ser de um minuto, a disponibilidade de dados HCC não significa a disponibilidade de dados na janela de tempo M1 como HC no mesmo volume.
O recebimento de novos dados de um servidor chama automaticamente a atualização de dados de preço usados em formato HC de todas as janelas de tempo. Isso também leva ao recálculo de todos os indicadores que implicitamente usam estes dados como dados de entrada para cálculos.
Parâmetro "Máx. barras no gráfico"
O parâmetro "Máx bars no gráfico" restringe o número de barras em formato HC disponível para gráficos, indicadores e programas mql5. Isso é válido para todas as janelas de tempo disponíveis e serve, primeiramente, para economizar recursos do computador.
Ao definir um grande valor para este parâmetro, deve ser lembrado que se dados de preço de histórico longo para pequenas janelas de tempo estiverem disponíveis, a memória usada para armazenadas a série de preços e buffers de indicadores podem se tornar centenas de megabytes e alcançar a restrição de RAM do programa terminal cliente (2Gb para aplicativos 32-bit do MS Windows).
A alteração do parâmetro "Máx. barras no gráfico" produz efeito após o terminal cliente ser reiniciado. A alteração deste parâmetro não causa referência automática a um servidor por dados adicionais, e nem formação de barras adicionais de séries de tempo. Dados de preço adicionais são solicitados ao servidor, e séries de preço são atualizadas levando em conta a nova limitação, em caso de rolagem de um gráfico para uma área sem dados, ou quando dados são solicitado por um programas MQL5 .
O volume de dados solicitados ao servidor corresponde ao número solicitado de barras de uma da janela de tempo com o parâmetro "Max. barras em gráfico" levado em consideração. A restrição definida por este parâmetro não é absoluta, e em alguns casos o número de barras disponíveis para uma janela de tempo pode ser um pouco maior que o valor corrente do parâmetro.
Disponibilidade de Dados
A presença de dados no formato HCC ou mesmo no formato preparado HC não significa sempre a absoluta disponibilidade destes dados para serem exibidos em um gráfico ou usados em um programa mql5.
Ao acessar dados de preços ou valores de indicadores a partir de um programa mql5 deve ser lembrado que a sua disponibilidade em um certo momento do tempo ou iniciando a partir de um certo momento de tempo não é garantida. Isso está relacionado com fato de que para economizar recursos, a cópia completa dos dados necessários para um programa mql5 não é armazenada no MetaTrader 5; apenas um acesso direto à base de dados do terminal é fornecida.
O histórico de preços para todas as janelas de tempo é construído a partir de dados comuns em formato HCC, e qualquer atualização dos dados a partir de um servidor conduz à atualização de dados para todas as janelas de tempo e ao recálculo dos indicadores. Devido a isso, o acesso aos dados pode ficar fechado, mesmo se estes dados estiverem disponíveis a um momento atrás.
Sincronização dos Dados do Terminal com os Dados do Servidor #
Já que um programa mql5 pode chamar dados de qualquer ativo e janela de tempo, existe a possibilidade que os dados de uma série de tempo necessária não esteja formado ainda no terminal ou o preço necessário não esteja sincronizado com o servidor de negociação. Neste caso é difícil predizer o tempo de latência.
Algoritmos usando ciclos de latência não são a melhor solução. A única exceção neste caso são os scripts, porque eles não nenhuma escolha de algoritmo alternativo porque eles não tem manipuladores de evento. Para indicadores customizados tais algoritmos, bem como quaisquer outros ciclos de latência são fortemente não recomendados, porque levam a finalização do cálculo de todos os indicadores e qualquer outro manipulador de dados de preço do ativo.
Para Expert Advisor e indicadores, é melhor usar o modelo de eventos de manipulação. Se durante a manipulação dos eventos OnTick() ou OnCalculate(), o recebimento de dados para a janela de tempo requerida falhar, você deve sair do manipulador de evento, confiando na disponibilidade de acesso durante a próxima chamada do manipulador.
Exemplo de um Script para Adicionar Histórico
Vamos considerar um exemplo de um script que executa uma solicitação para receber histórico para o ativo selecionado de um servidor de negociação. O script é projetado para executar em um gráfico de um ativo selecionado; a janela de tempo não importa, porque como foi mencionado acima, dados de preço são recebidos de um servidor de negociação como pacotes de dados de um minuto, a partir dos quais qualquer série de tempo predefinida é construída.
Escreve todas as ações relacionadas a recepção de dados como uma função separada, CheckLoadHistory(symbol, timeframe, start_date):
int CheckLoadHistory(string symbol,ENUM_TIMEFRAMES period,datetime start_date)
|
A função CheckLoadHistory() é projetada como uma função universal que pode ser chamada de qualquer programa (Expert Advisor, script ou indicador); e portanto ela solicita três parâmetros de entrada: nome do ativo, período e data de inicio para indicar o começo do histórico de preço que você necessita.
Insira as verificações necessárias no código da função antes de solicitar o histórico faltante. Primeiramente, nós devemos assegurar que o nome do ativo e valor de período estão corretos:
if(symbol==NULL || symbol=="") symbol=Symbol();
|
Então vamos nos assegurar que o ativo está disponível na janela Observador de Mercado, isto é, o histórico para o ativo estará disponível durante o envio de uma solicitação a um servidor de negociação. Se não houver tal ativo no Observador de Mercado, adicionar ele usando a função SymbolSelect().
if(!SymbolInfoInteger(symbol,SYMBOL_SELECT))
|
Agora nós devemos receber a data de início do histórico disponível para o par ativo/período indicado. Talvez, o valor do parâmetro de entrada startdate, passado para CheckLoadHistory(), já esteja disponível no histórico; então a solicitação a um servidor de negociação não é necessária. A fim de obter a primeira data para o ativo-período, a função SeriesInfoInteger() com o modificador SERIES_FIRSTDATE é usada.
SeriesInfoInteger(symbol,period,SERIES_FIRSTDATE,first_date);
|
A próxima importante verificação é o tipo do programa, a partir do qual a função é chamada. Note que enviar uma solicitação de atualização de série de tempo com o mesmo período do indicador, que chama a atualização, não é desejável. O problema de solicitar dados sobre o mesmo ativo-período que o do indicador está relacionado ao fato de que a atualização de dados de histórico é realizada na mesma thread onde o indicador opera. Assim a possibilidade de ocorrência de conflito é alta. Para verificar isso use a função MQL5InfoInteger() com o modificador MQL5_PROGRAM_TYPE.
if(MQL5InfoInteger(MQL5_PROGRAM_TYPE)==PROGRAM_INDICATOR && Period()==period && Symbol()==symbol)
|
Se todas as verificações tiverem passado com sucesso, faça a última tentativa de acesso sem se referir ao servidor de negociação Primeiramente, descubra a data de início, para qual dados de minuto no formato HCC estão disponíveis. Solicite este valor usando a função SeriesInfoInteger() com o modificador SERIES_TERMINAL_FIRSTDATE e compare novamente ele com o valor do parâmetro start_date.
if(SeriesInfoInteger(symbol,PERIOD_M1,SERIES_TERMINAL_FIRSTDATE,first_date))
|
Se após todas as verificações, a thread de execução estiver ainda no corpo da função CheckLoadHistory(), isso significa que existe uma necessidade de solicitar os dados de preço faltantes ao servidor de negociação. Primeiro, retorne o valor de "Máx. barras no gráfico" usando a função TerminalInfoInteger():
int max_bars=TerminalInfoInteger(TERMINAL_MAXBARS); |
Nós precisaremos dele para evitar solicitar dados extra. Então encontre a primeira data no sistema do ativo no servidor de negociação (independentemente do período) usando a já conhecida função SeriesInfoInteger() com o modificador SERIES_SERVER_FIRSTDATE.
datetime first_server_date=0;
|
Já que a solicitação é uma operação assíncrona, a função é chamada no ciclo com uma espera de 5 milissegundos até a variável first_server_date receber um valor, ou a execução do ciclo ser terminada por um usuário (IsStopped() retornará true neste caso). Vamos indicar um valor correto da data de início, começando a partir do qual nós solicitamos dados de preço de um servidor de negociação.
if(first_server_date>start_date) start_date=first_server_date;
|
Se a data de início first_server_date do servidor for menor que o data de início first_date do ativo em formato HCC, a correspondente entrada será impressa no diário.
Agora nós estamos prontos para fazer uma solicitação a um servidor de negociação por dados de preço faltantes. Faça a solicitação na forma de um ciclo e comece preenchendo seu corpo:
while(!IsStopped())
|
Os primeiros três pontos estão implementados pelos meios já conhecidos.
while(!IsStopped())
|
Sobrou o quarto último ponto - solicitar histórico. Nós não podemos referenciar a um servidor diretamente, mas toda função-Copy inicia automaticamente uma solicitação de envio a um servidor, se o histórico em formato HCC não for suficiente. Já que a hora da primeira data de início na variável first_date é um simples e natural critério para avaliar o grau de execução de uma solicitação, então a forma mais fácil é usar a função CopyTime().
Ao chamar funções que copiam quaisquer dados de séries de tempo, deve ser notado que o parâmetro start (número da barra, começando a partir do qual dados de preço devem ser copiados) deve sempre estar dentro do histórico de terminal disponível. Se você tiver somente 100 barras, é inútil tentar copiar 300 barras começando da barra com o índice 500. Tal solicitação será entendida como um error e não será tratada, isto é, nenhum histórico adicional será carregado de um servidor de negociação.
Esta é a razão porque nós copiaremos 100 barras começando da barra com o índice bars. Isso fornecerá uma carga suave de histórico faltando doe um servidor de negociação. Na verdade, um pouco mais que as 100 barras solicitadas serão carregadas, já que o servidor envia um histórico superdimensionado.
int copied=CopyTime(symbol,period,bars,100,times); |
Após a operação de cópia, nós devemos analizar o número de elementos copiados. Se a tentativa falhar, então o valor copiado será igual a null e o valor do contador fail_cnt será aumentado em 1. Após 100 tentativas com falha, a operação da função será interrompida.
int fail_cnt=0;
|
Então, não somente manipulação correta da situação corrente em cada momento de execução está implementada na função, mas também o código de finalização é retornado, que pode ser tratado depois chamando a função CheckLoadHistory() para obtenção de informações adicionais. Por exemplo, desta forma:
int res=CheckLoadHistory(InpLoadedSymbol,InpLoadedPeriod,InpStartDate);
|
O código completo da função pode ser encontrado no exemplo de um script que mostra a correta organização de acesso de quaisquer dados com a manipulação de resultados de solicitação.
Code:
//+------------------------------------------------------------------+
|