Início Negociação Sistemática Postagem

Baixe Todo o Histórico de Ticks de um Símbolo no MetaTrader 5

Anexo
56324.zip (3.28 KB, Baixar 0 vezes)

Se você é trader e utiliza o MetaTrader 5, vai adorar essa dica! Com um sistema de download que desenvolvemos, você pode escanear a lista de símbolos do seu corretor e baixar todos os ticks disponíveis, ou até mesmo até uma data específica.

Isso é extremamente útil para quem quer fazer backtests ou criar gráficos personalizados a partir desses dados de ticks.

Lembre-se de que os ticks serão armazenados na pasta de dados do terminal, então, não esqueça de verificar se há espaço suficiente no seu HD.

Para facilitar o download dos símbolos, começamos com um gerenciador de downloads. A estrutura CDownloadManager contém todas as informações necessárias que vamos utilizar.

struct CDownloadManager
  {
   bool m_started, m_finished;
   string m_symbols[], m_current;
   int m_index;
}

O que essa estrutura guarda?

  • O estado do download (iniciado/terminado)
  • A lista de símbolos a serem escaneados
  • O símbolo atual
  • O índice do símbolo que está sendo escaneado

Precisaremos também de funções para ler e escrever no HD, pois estamos lidando com símbolos. Então, criamos duas funções rápidas para gravar e ler strings de arquivos binários.

Função para salvar uma string em um arquivo:

void writeStringToFile(int f, string thestring)
  {
   //salva a string do símbolo
   char sysave[];
   int charstotal = StringToCharArray(thestring, sysave, 0, StringLen(thestring), CP_ACP);
   FileWriteInteger(f, charstotal, INT_VALUE);
   for(int i = 0; i < charstotal; i++)
     {
      FileWriteInteger(f, sysave[i], CHAR_VALUE);
     }
}

Essa função recebe:

  • O manipulador do arquivo f, que deve estar aberto para escrita e com a flag binária FILE_WRITE|FILE_BIN
  • A string que você deseja escrever no arquivo

Ela grava um inteiro que representa a quantidade de caracteres na string e depois armazena cada um deles.

Função para carregar uma string de um arquivo:

string readStringFromFile(int f)
  {
   string result = "";
   //carrega a string do símbolo
   char syload[];
   int charstotal = (int)FileReadInteger(f, INT_VALUE);
   if(charstotal > 0)
     {
      ArrayResize(syload, charstotal, 0);
      for(int i = 0; i < charstotal; i++)
        {
         syload[i] = (char)FileReadInteger(f, CHAR_VALUE);
        }
      result = CharArrayToString(syload, 0, charstotal, CP_ACP);
    }
   return(result);
}

Essa função recebe:

  • O manipulador do arquivo f, que deve estar aberto para leitura como binário, com as flags FILE_READ|FILE_BIN

Ela lê um inteiro que representa a quantidade de caracteres que você pode esperar naquele ponto do arquivo. Em seguida, lê cada caractere e o coloca em um array de caracteres, criando uma string a partir desse array, que é retornada como resultado.

Agora, vamos voltar à estrutura CDownloadManager. Precisamos de uma forma de inicializar o gerenciador e preenchê-lo a partir da lista de símbolos:

//+------------------------------------------------------------------+
//| Captura os símbolos da lista de mercado                           |
//+------------------------------------------------------------------+
void grab_symbols()
  {
    //! apenas da lista de mercado!
    int s = SymbolsTotal(true);
    ArrayResize(m_symbols, s, 0);
    for(int i = 0; i < ArraySize(m_symbols); i++)
      {
         m_symbols[i] = SymbolName(i, true);
      }
  }

É bem simples:

  • Pede quantos símbolos estão na lista de mercado (ativos)
  • Redimensiona nosso array m_symbols para acomodá-los
  • Faz um loop pelos símbolos e solicita o nome de cada um

Agora, precisamos gerenciar o download dos dados dos símbolos, então, precisamos de uma função que seja essencialmente o gerenciador:

//+------------------------------------------------------------------+
//| Gerencia o processo de download dos símbolos                      |
//+------------------------------------------------------------------+
void manage(string folder, string filename)
  {
    // essencialmente, isso inicia ou navega para o próximo símbolo
    // caso esteja definido
    if(ArraySize(m_symbols) > 0)
    {
      // se não começou
      if(!m_started)
        {
        m_started = true;
        // vai para o primeiro símbolo
        m_current = m_symbols[0];
        m_index = 1;
        save(folder, filename);
        if(_Symbol != m_current)
          {
            ChartSetSymbolPeriod(ChartID(), m_current, _Period);
        }
        else
        {
          ENUM_TIMEFRAMES new_period = PERIOD_M1;
          for(int p = 0; p < ArraySize(TFS); p++)
             {
              if(_Period != TFS[p])
                {
                 new_period = TFS[p];
                 break;
                }
            }
          ChartSetSymbolPeriod(ChartID(), m_current, new_period);
        }
        return;
    }
    // se começou
    else
      {
        m_index++;
        if(m_index <= ArraySize(m_symbols))
          {
            m_current = m_symbols[m_index - 1];
            save(folder, filename);
            if(_Symbol != m_current)
              {
                ChartSetSymbolPeriod(ChartID(), m_current, _Period);
            }
          return;
      }
      else
      {
            m_finished = true;
            FileDelete(folder + "\" + filename);
            Print("Finalizado");
            ExpertRemove();
            return;
    }
    }
    else
    {
      Print("Por favor, capture os símbolos primeiro");
    }
    // fim do set
  }

Como o sistema funciona:

  • O gráfico é aberto, precisamos de apenas um gráfico, e um timer é definido.
  • Esse timer executa, cancelamos o timer.
  • Verificamos se é um download novo ou um download contínuo.
  • Se for um download novo, configuramos tudo pegando todos os símbolos.
  • Se for um download contínuo, baixamos os dados do símbolo atual.

Essa parte do código realiza o download no timer:

//+------------------------------------------------------------------+
//| Timer                                                        |
//+------------------------------------------------------------------+
void OnTimer()
  {
   //--- se sincronizado
   if(SymbolIsSynchronized(_Symbol) && TerminalInfoInteger(TERMINAL_CONNECTED) == 1)
     {
      EventKillTimer();
      //--- carrega o sistema aqui
      if(MANAGER.load(MANAGER_FOLDER, MANAGER_STATUS_FILE))
        {
        //--- sistema carregado, então estamos escaneando um símbolo aqui
        Comment("Sistema carregado e estamos processando " + MANAGER.m_current);
        //--- carregamento de ticks

        //--- encontra o tick mais antigo disponível no corretor primeiro
        int attempts = 0;
        int ping = -1;
        datetime cursor = flatten(TimeTradeServer());
        long cursorMSC = ((long)cursor) * 1000;
        long jump = 2592000000;//60*60*24*30*1000;

        MqlTick receiver[];
        long oldest = LONG_MAX;
        Comment("Por favor, aguarde");
        while(attempts < 5)
           {
            ping = CopyTicks(_Symbol, receiver, COPY_TICKS_ALL, cursorMSC, 1);
            if(ping == 1)
              {
               if(receiver[0].time_msc == oldest)
                 {
                  attempts++;
                }
               else
                 {
                  attempts = 0;
                }
               if(receiver[0].time_msc < oldest)
                 {
                  oldest = receiver[0].time_msc;
                }
               cursorMSC -= jump;
               if(limitDate && receiver[0].time <= oldestLimit)
                 {
                  break;
                }
          }
            else
              {
               attempts++;
              }

            Sleep(44);
            Comment("Tick mais antigo: " + TimeToString((datetime)(oldest / 1000), TIME_DATE | TIME_MINUTES | TIME_SECONDS) + "\nCursor(" + TimeToString((datetime)(cursorMSC / 1000), TIME_DATE | TIME_MINUTES | TIME_SECONDS) + ")\nTentativas(" + IntegerToString(attempts) + ")\nPor favor, aguarde a resposta...");
        }
        //--- nesse ponto temos o tick mais antigo
        //--- comece a solicitar ticks do mais antigo para o mais novo
        if(oldest != LONG_MAX)
           {
            ArrayFree(receiver);
            datetime newest_tick = 0;
            //--- recebe o tempo do último tick para este símbolo armazenado em symbol_time
            datetime most_recent_candle = (datetime)SymbolInfoInteger(_Symbol, SYMBOL_TIME);
            while(newest_tick < most_recent_candle)
              {
               //--- solicita um novo lote a partir do tempo mais antigo com o limite de ticks especificado
               int pulled = CopyTicks(_Symbol, receiver, COPY_TICKS_ALL, oldest, tick_packets);
               if(pulled > 0)
                 {
                   //--- se puxarmos um novo lote, atualizamos nossos tempos baixados
                  newest_tick = receiver[pulled - 1].time;
                  oldest = receiver[pulled - 1].time_msc;
                  ArrayFree(receiver);
                }
               //--- tempo limite para solicitações ao servidor, altere se quiser
               Sleep(44);
               Comment("Puxamos até " + TimeToString(newest_tick, TIME_DATE | TIME_MINUTES | TIME_SECONDS) + " até agora");
          }
      }
      else
       {
            Alert("Por favor, feche o terminal \n vá até a pasta de ticks \n e delete as pastas vazias");
            ExpertRemove();
      }
      //--- atualiza o gerenciador e segue em frente
      MANAGER.manage(MANAGER_FOLDER, MANAGER_STATUS_FILE);
    }
    else
    {
      //--- capturando os símbolos da lista de mercado para iniciar o download
      Comment("Capturando a lista de mercado e iniciando");
      MANAGER.grab_symbols();
      MANAGER.manage(MANAGER_FOLDER, MANAGER_STATUS_FILE);
    }
  }

Com essas dicas, você estará pronto para baixar todos os ticks de um símbolo e aprimorar suas análises e estratégias de trading. Aproveite e bons trades!

Publicações relacionadas

Comentário (0)