Trabalhando com preços na biblioteca DoEasy (Parte 61): coleção de séries de ticks para símbolos
Sumário
Ideia
No último artigo criamos uma classe do objeto-lista de dados de ticks que coletava e armazenava ticks de um símbolo durante um determinado número de dias. Visto que diferentes símbolos podem ser usados durante a operação do programa, é necessário criar uma lista própria para cada um deles. Hoje vamos combinar essas listas numa coleção de dados de ticks. Na verdade, irá tratar-se de uma lista normal baseada numa classe de array dinâmico de ponteiros para instâncias da classe CObject e seus herdeiros da Biblioteca Padrão, que armazenará ponteiros para as listas de dados de ticks criadas segundo cada símbolo, cuja classe de objetos preparamos no último artigo.
Esta ideia, que é idêntica à de construção das classes-coleções anteriores na biblioteca, nos permitirá posteriormente salvar, armazenar, atualizar, receber e usar em estudos estatísticos dados de ticks de quaisquer símbolos disponíveis no banco de dados da biblioteca.
Classe-coleção de dados de ticks
No diretório da biblioteca \MQL5\Include\DoEasy\Collections\ criamos um novo arquivo da classe-coleção de dados de ticks com o nome TickSeriesCollection.mqh.
A classe será herdeira da classe de objeto base de todos os objetos da biblioteca.
Vamos examinar o corpo da classe e, em seguida, analisaremos suas variáveis e métodos:
//+------------------------------------------------------------------+ //| TickSeriesCollection.mqh | //| Copyright 2021, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2021, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "ListObj.mqh" #include "..\Objects\Ticks\TickSeries.mqh" #include "..\Objects\Symbols\Symbol.mqh" //+------------------------------------------------------------------+ //| Collection of symbol tick series | //+------------------------------------------------------------------+ class CTickSeriesCollection : public CBaseObj { private: CListObj m_list; // List of used symbol tick series //--- Return the tick series index by symbol name int IndexTickSeries(const string symbol); public: //--- Return (1) itself and (2) tick series collection list and (3) the number of tick series in the list CTickSeriesCollection *GetObject(void) { return &this; } CArrayObj *GetList(void) { return &this.m_list; } int DataTotal(void) const { return this.m_list.Total(); } //--- Return the pointer to the tick series object (1) by symbol and (2) by index in the list CTickSeries *GetTickseries(const string symbol); CTickSeries *GetTickseries(const int index); //--- Create a collection list of symbol tick series bool CreateCollection(const CArrayObj *list_symbols,const uint required=0); //--- Set the flag of using the tick series of (1) a specified symbol and (2) all symbols void SetAvailableTickSeries(const string symbol,const bool flag=true); void SetAvailableTickSeries(const bool flag=true); //--- Return the flag of using the tick series of (1) a specified symbol and (2) all symbols bool IsAvailableTickSeries(const string symbol); bool IsAvailableTickSeries(void); //--- Set the number of days of the tick history of (1) a specified symbol and (2) all symbols bool SetRequiredUsedDays(const string symbol,const uint required=0); bool SetRequiredUsedDays(const uint required=0); //--- Return the last tick object of a specified symbol (1) by index, (2) by time and (4) by time in milliseconds CDataTick *GetTick(const string symbol,const int index); CDataTick *GetTick(const string symbol,const datetime tick_time); CDataTick *GetTick(const string symbol,const long tick_time_msc); //--- Return the new tick flag of a specified symbol bool IsNewTick(const string symbol); //--- Create a tick series of (1) a specified symbol and (2) all symbols bool CreateTickSeries(const string symbol,const uint required=0); bool CreateTickSeriesAll(const uint required=0); //--- Update (1) a tick series of a specified symbol and (2) all symbols void Refresh(const string symbol); void Refresh(void); //--- Display (1) the complete and (2) short collection description in the journal void Print(void); void PrintShort(void); //--- Constructor CTickSeriesCollection(); }; //+------------------------------------------------------------------+
A variável-membro da classe m_list do tipo CListObj é uma classe herdeira da classe CArrayObj da biblioteca padrão, como muitas listas criadas nesta biblioteca. Tudo o que a classe CListObj faz é implementar o método virtual Type() da Classe CObject, isto é, a classe base de objetos da biblioteca padrão. O método deve retornar o identificador do tipo de classe. Aqui ele é o identificador do tipo de array.
É a implementação do método virtual Type() que é implementado na classe CListObj, que adicionamos à biblioteca há muito tempo:
//+------------------------------------------------------------------+ //| ListObj.mqh | //| Copyright 2019, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2019, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include <Arrays\ArrayObj.mqh> //+------------------------------------------------------------------+ //| Class of collection lists | //+------------------------------------------------------------------+ class CListObj : public CArrayObj { private: int m_type; // List type public: void Type(const int type) { this.m_type=type; } virtual int Type(void) const { return(this.m_type); } CListObj() { this.m_type=0x7778; } }; //+------------------------------------------------------------------+
Aqui o método Type() define para a variável m_type o valor passado, enquanto o método virtual Type() retorna o valor definido por esta variável.
Por padrão (no construtor da classe) para a variável é definido o valor do identificador de tipo de array, como para CArrayObj - 0x7778.
O objetivo de todos os métodos da classe é descrito nos comentários ao código e, a seguir, veremos a implementação desses métodos.
No construtor da classe limpamos a lista, definimos o sinalizador de lista classificada para a lista e
definimos o identificador da lista de coleção de dados de ticks:
//+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CTickSeriesCollection::CTickSeriesCollection() { this.m_list.Clear(); this.m_list.Sort(); this.m_list.Type(COLLECTION_TICKSERIES_ID); } //+------------------------------------------------------------------+
O método privado IndexTickSeries() retorna o índice da série de tick pelo nome do símbolo:
//+------------------------------------------------------------------+ //| Return the tick series index by symbol name | //+------------------------------------------------------------------+ int CTickSeriesCollection::IndexTickSeries(const string symbol) { const CTickSeries *obj=new CTickSeries(symbol==NULL || symbol=="" ? ::Symbol() : symbol); if(obj==NULL) return WRONG_VALUE; this.m_list.Sort(); int index=this.m_list.Search(obj); delete obj; return index; } //+------------------------------------------------------------------+
O método recebe o nome do símbolo cujo índice da série de ticks deve ser retornado a partir da lista.
Em seguida, criamos um objeto de série de ticks vazio temporário, enquanto definimos o nome do símbolo passado para o método,
definimos o sinalizador de lista classificada para a lista e procuramos o índice do objeto na lista.
Depois, removemos o objeto temporário e retornamos o índice resultante. Se o objeto não for encontrado ou não for possível criar um objeto temporário, o método retornará NULL.
Método que retorna um ponteiro para um objeto de séries de ticks com base no símbolo:
//+------------------------------------------------------------------+ //| Return the object of tick series of a specified symbol | //+------------------------------------------------------------------+ CTickSeries *CTickSeriesCollection::GetTickseries(const string symbol) { int index=this.IndexTickSeries(symbol); return this.m_list.At(index); } //+------------------------------------------------------------------+
O método recebe o nome do símbolo cujo objeto da série de ticks deve ser retornado a partir da lista.
Usando o método que acabamos de ver encontramos o índice do objeto da série de ticks na lista, obtemos um ponteiro para este objeto com base no índice encontrado e o retornamos. Se o índice não for encontrado, seu valor será -1, e o método At() da classe CArrayObj retornará NULL.
Método que define o sinalizador de uso da série de ticks do símbolo especificado:
//+------------------------------------------------------------------+ //| Set the flag of using the tick series of a specified symbol | //+------------------------------------------------------------------+ void CTickSeriesCollection::SetAvailableTickSeries(const string symbol,const bool flag=true) { CTickSeries *tickseries=this.GetTickseries(symbol); if(tickseries==NULL) return; tickseries.SetAvailable(flag); } //+------------------------------------------------------------------+
O método recebe o nome do símbolo para o objeto da série de ticks para o qual devemos definir o sinalizador de uso.
Usando o método GetTickseries() acima pegamos a partir da lista um ponteiro para um objeto da série de ticks e
definimos o sinalizador passado para o método.
Método que define o sinalizador de uso da série de ticks cobrindo todos os símbolos na coleção:
//+------------------------------------------------------------------+ //| Set the flag of using the tick series of all symbols | //+------------------------------------------------------------------+ void CTickSeriesCollection::SetAvailableTickSeries(const bool flag=true) { for(int i=0;i<this.m_list.Total();i++) { CTickSeries *tickseries=this.m_list.At(i); if(tickseries==NULL) continue; tickseries.SetAvailable(flag); } } //+------------------------------------------------------------------+
Num loop percorrendo o número total de séries de ticks na lista,
obtemos o próximo objeto da série de ticks segundo o índice de loop e
definimos o sinalizador passada para o método.
Método que retorna o sinalizador de uso da série de ticks do símbolo especificado:
//+------------------------------------------------------------------+ //| Return the flag of using the tick series of a specified symbol | //+------------------------------------------------------------------+ bool CTickSeriesCollection::IsAvailableTickSeries(const string symbol) { CTickSeries *tickseries=this.GetTickseries(symbol); if(tickseries==NULL) return false; return tickseries.IsAvailable(); } //+------------------------------------------------------------------+
O método recebe o nome do símbolo para o qual devemos retornar o sinalizador de uso do objeto da série ticks.
Usando o método GetTickseries() obtemos um ponteiro para o objeto da série de ticks do símbolo desejado e
retornamos o sinalizador de uso definido para este objeto. Se o objeto não puder ser recuperado da lista, o método retornará false.
Método que retorna o sinalizador de uso da série de ticks de todos os símbolos:
//+------------------------------------------------------------------+ //| Return the flag of using tick series of all symbols | //+------------------------------------------------------------------+ bool CTickSeriesCollection::IsAvailableTickSeries(void) { bool res=true; int total=this.m_list.Total(); for(int i=0;i<total;i++) { CTickSeries *tickseries=this.m_list.At(i); if(tickseries==NULL) continue; res &=tickseries.IsAvailable(); } return res; } //+------------------------------------------------------------------+
Declaramos uma variável res e a inicializamos com o valor true.
Em seguida, num loop percorrendo o número total de objetos na lista
obtemos um ponteiro para o próximo objeto da série de ticks e
ao valor da variável res adicionamos o sinalizador de uso definido para o objeto atual.
No final do loop retornamos o valor resultante da variável res.
Se o sinalizador de seu uso não estiver definido para pelo menos um dos objetos da lista (false), na variável res no final do loop, será armazenado o valor false. Assim, o método permite saber se o sinalizador de uso está marcado para todas as séries de ticks na coleção, e é retornado true apenas se o sinalizador de uso estiver definido como true para cada objeto de série de ticks na coleção.
Método que define o número de dias do histórico de ticks do símbolo especificado:
//+------------------------------------------------------------------+ //| Set the number of days of the tick history of a specified symbol | //+------------------------------------------------------------------+ bool CTickSeriesCollection::SetRequiredUsedDays(const string symbol,const uint required=0) { CTickSeries *tickseries=this.GetTickseries(symbol); if(tickseries==NULL) return false; tickseries.SetRequiredUsedDays(required); return true; } //+------------------------------------------------------------------+
O método recebe o nome do símbolo cujo número de dias de dados de ticks deve ser definido.
Obtemos um ponteiro para o objeto da série ticks usando o método discutido anteriormente,
definimos o número de dias para ele e retornamos true .
Se o ponteiro para o objeto da série ticks não puder ser obtido a partir da lista, o método retorna false,
Método que define o número de dias do histórico de ticks de todos os símbolos:
//+------------------------------------------------------------------+ //| Set the number of days of the tick history of all symbols | //+------------------------------------------------------------------+ bool CTickSeriesCollection::SetRequiredUsedDays(const uint required=0) { bool res=true; for(int i=0;i<this.m_list.Total();i++) { CTickSeries *tickseries=this.m_list.At(i); if(tickseries==NULL) { res &=false; continue; } tickseries.SetRequiredUsedDays(required); } return res; } //+------------------------------------------------------------------+
Declaramos uma variável res e a inicializamos com o valor true.
Em seguida, num loop percorrendo o número total de objetos na lista
obtemos um ponteiro para o próximo objeto da série de ticks e
se o ponteiro para o objeto não puder ser obtido, então
ao valor da variável res adicionamos o valor false e passamos para o próximo objeto na lista-coleção.
Caso contrário, definimos o número de dias de dados de ticks para o objeto atual..
No final do loop retornamos o valor resultante da variável res.
Se o número de dias de dados de ticks não for definido para pelo menos um dos objetos da lista, a variável res no final do loop armazenará o valor false. Assim, o método permite definir o número de dias para todas as séries de ticks na coleção e retorna execução bem sucedida apenas se definirmos o número de dias para cada um dos objetos de dados de ticks armazenados na lista.
Método que retorna o objeto-tick do símbolo especificado segundo o índice na lista de séries de ticks:
//+------------------------------------------------------------------+ //| Return the tick object of the specified symbol by index | //+------------------------------------------------------------------+ CDataTick *CTickSeriesCollection::GetTick(const string symbol,const int index) { CTickSeries *tickseries=this.GetTickseries(symbol); if(tickseries==NULL) return NULL; return tickseries.GetTickByListIndex(index); } //+------------------------------------------------------------------+
O método recebe a classe CTickSeries e o índice do objeto-tick armazenado na lista de séries de ticks.
Obtemos um ponteiro para um objeto da série de ticks a partir da lista-coleção segundo o símbolo usando o método GetTickseries() discutido anteriormente e
retornamos um ponteiro para o objeto-tick a partir da lista de séries de ticks usando o método GetTickByListIndex(), que consideramos no último artigo.
Se o objeto da série de ticks não puder ser obtido desde a lista-coleção, o método retorna NULL. Também, o método GetTickByListIndex() da classe CTickSeries também pode retornar NULL.
Método que retorna o último objeto-tick do símbolo especificado segundo o tempo a partir da lista da série de ticks:
//+------------------------------------------------------------------+ //| Return the last tick object of the specified symbol by time | //+------------------------------------------------------------------+ CDataTick *CTickSeriesCollection::GetTick(const string symbol,const datetime tick_time) { CTickSeries *tickseries=this.GetTickseries(symbol); if(tickseries==NULL) return NULL; return tickseries.GetTick(tick_time); } //+------------------------------------------------------------------+
O método recebe o símbolo da série de ticks da classe CTickSeries e a hora do objeto-tick desejado armazenado na lista da série de ticks.
Obtemos um ponteiro para um objeto da série de ticks a partir da lista-coleção segundo o símbolo usando o método GetTickseries() discutido anteriormente e
retornamos um ponteiro para o objeto-tick desde a lista da série de ticks usando o método GetTick(), que discutimos no último artigo.
Se o objeto da série de ticks não puder ser obtido desde a lista-coleção, o método retorna NULL. Além disso, o método GetTick() da classe CTickSeries também pode retornar NULL.
Método que retorna o último objeto-tick do símbolo especificado segundo o tempo em milissegundos a partir da lista de séries de ticks:
//+------------------------------------------------------------------+ //| Return the last tick object of the specified symbol | //| by time in milliseconds | //+------------------------------------------------------------------+ CDataTick *CTickSeriesCollection::GetTick(const string symbol,const long tick_time_msc) { CTickSeries *tickseries=this.GetTickseries(symbol); if(tickseries==NULL) return NULL; return tickseries.GetTick(tick_time_msc); } //+------------------------------------------------------------------+
O método recebe o símbolo da série de ticks da classe CTickSeries e o tempo em milissegundos do objeto-tick desejado armazenado na lista da série de ticks.
Obtemos um ponteiro para um objeto da série de ticks a partir da lista-coleção segundo o símbolo usando o método GetTickseries() discutido anteriormente e
retornamos um ponteiro para o objeto-tick desde a lista da série de ticks usando o método GetTick(), que discutimos no último artigo.
Se o objeto da série de ticks não puder ser obtido desde a lista-coleção, o método retorna NULL. Além disso, o método GetTick() da classe CTickSeries também pode retornar NULL.
Vale a pena esclarecer que, para os dois últimos métodos que retornam objetos-ticks por tempo, pode haver vários ticks ao mesmo tempo, por isso, o método GetTick() da classe CTickSeries retorna o mais recente deles - com o tempo mais recente como o mais relevante.
Método que retorna o sinalizador do novo tick do símbolo especificado:
//+------------------------------------------------------------------+ //| Return the new tick flag of a specified symbol | //+------------------------------------------------------------------+ bool CTickSeriesCollection::IsNewTick(const string symbol) { CTickSeries *tickseries=this.GetTickseries(symbol); if(tickseries==NULL) return false; return tickseries.IsNewTick(); } //+------------------------------------------------------------------+
O método recebe o nome do símbolo cujo sinalizador de aparecimento de novo tick deve ser retornado.
Obtemos um ponteiro para um objeto da série de ticks a partir da lista-coleção segundo o símbolo usando o método GetTickseries() discutido anteriormente e
retornamos o sinalizador do novo tick da série de ticks usando o método IsNewTick() da classe CTickSeries, que consideramos no último artigo.
Se o objeto da série de ticks não puder ser obtido a partir da lista-coleção, o método retorna false.
Quero observar que esse recurso ainda não foi implementado na classe CTickSeries, e isso será feito em artigos futuros.
Método que cria uma série de ticks do símbolo especificado:
//+------------------------------------------------------------------+ //| Create a tick series of a specified symbol | //+------------------------------------------------------------------+ bool CTickSeriesCollection::CreateTickSeries(const string symbol,const uint required=0) { CTickSeries *tickseries=this.GetTickseries(symbol); if(tickseries==NULL) return false; return(tickseries.Create(required)>0); } //+------------------------------------------------------------------+
O método recebe o nome do símbolo, cuja série de ticks deve ser criada, e o número de dias de dados de ticks.
Obtemos um ponteiro para um objeto da série de ticks a partir da lista-coleção segundo o símbolo usando o método GetTickseries() discutido anteriormente e
retornamos o sinalizador indicando que o método Create() da classe CTickSeries retornou um valor maior que zero (o número de objetos-tick criados não é zero).
Método que cria uma série de ticks cobrindo todos os símbolos usados:
//+------------------------------------------------------------------+ //| Create tick series of all symbols | //+------------------------------------------------------------------+ bool CTickSeriesCollection::CreateTickSeriesAll(const uint required=0) { bool res=true; int total=this.m_list.Total(); for(int i=0;i<total;i++) { CTickSeries *tickseries=this.m_list.At(i); if(tickseries==NULL) continue; res &=(tickseries.Create(required)>0); } return res; } //+------------------------------------------------------------------+
O número de dias de dados do tick é passado para o método.
Declaramos uma variável res e a inicializamos com valor true.
Em seguida, num loop percorrendo o número total de objetos na lista
obtemos um ponteiro para o próximo objeto da série de ticks e
ao valor da variável res adicionamos um sinalizador indicando que o valor retornado pelo método Create() da classe CTickSeries, maior que zero (série de ticks criada)
No final do loop, retornamos o valor resultante da variável res.
Se uma série de ticks não for criada para pelo menos um dos objetos na lista, então a variável res no final do loop armazenará o valor false. Assim, o método permite a criação de séries de ticks para todos os símbolos da coleção, e retorna execução bem sucedida apenas se a série de ticks for criada para cada um dos objetos de dados de ticks armazenados na lista.
Método que atualiza a série de ticks do símbolo especificado:
//+------------------------------------------------------------------+ //| Update a tick series of a specified symbol | //+------------------------------------------------------------------+ void CTickSeriesCollection::Refresh(const string symbol) { CTickSeries *tickseries=this.GetTickseries(symbol); if(tickseries==NULL) return; tickseries.Refresh(); } //+------------------------------------------------------------------+
O método recebe o nome do símbolo cuja série de ticks que precisa ser atualizada.
Obtemos um ponteiro para um objeto da série de ticks a partir da lista-coleção segundo o símbolo usando o método GetTickseries() discutido anteriormente e
a atualizamos usando o método Refresh() da classe CTickSeries.
Método que atualiza a série de ticks de todos os símbolos:
//+------------------------------------------------------------------+ //| Update tick series of all symbols | //+------------------------------------------------------------------+ void CTickSeriesCollection::Refresh(void) { for(int i=0;i<this.m_list.Total();i++) { CTickSeries *tickseries=this.m_list.At(i); if(tickseries==NULL) continue; tickseries.Refresh(); } } //+------------------------------------------------------------------+
No ciclo sobre o número total de objetos na lista
obtemos um ponteiro para o próximo objeto da série de ticks por índice de ciclo e
atualizamos a série usando o método Refresh() da classe CTickSeries.
Gostaria de ressaltar que ainda não desenvolvemos o recurso para atualizar a série de ticks na classe CTickSeries ainda, e isso será feito nos próximos artigos.
O método que registra no log uma descrição completa da coleção:
//+------------------------------------------------------------------+ //| Display complete collection description to the journal | //+------------------------------------------------------------------+ void CTickSeriesCollection::Print(void) { for(int i=0;i<this.m_list.Total();i++) { CTickSeries *tickseries=this.m_list.At(i); if(tickseries==NULL) continue; tickseries.Print(); } } //+------------------------------------------------------------------+
No ciclo sobre o número total de objetos na lista
obtemos um ponteiro para o próximo objeto da série de ticks/s3> por índice de ciclo e
exibimos uma descrição completa da série de ticks no log.
O método que registra no log uma breve descrição da coleção:
//+------------------------------------------------------------------+ //| Display the short collection description in the journal | //+------------------------------------------------------------------+ void CTickSeriesCollection::PrintShort(void) { for(int i=0;i<this.m_list.Total();i++) { CTickSeries *tickseries=this.m_list.At(i); if(tickseries==NULL) continue; tickseries.PrintShort(); } } //+------------------------------------------------------------------+
No ciclo sobre o número total de objetos na lista
obtemos um ponteiro para o próximo objeto da série de ticks por índice de ciclo e
exibimos uma breve descrição da série de ticks no log.
Os métodos discutidos acima são projetados para trabalhar com a já criada lista-coleção de ponteiros para objetos de dados de ticks de símbolos diferentes. Para que eles funcionem em nossos programas, podemos usar diferentes símbolos. Para criar o próprio objeto-coleção, de forma que possamos colocar todas as séries de ticks necessárias nele e, depois, obter ponteiros para elas a partir da lista-coleção, usaremos o seguinte método.
Método que cria uma lista-coleção de séries de ticks de símbolos:
//+------------------------------------------------------------------+ //| Create a collection list of symbol tick series | //+------------------------------------------------------------------+ bool CTickSeriesCollection::CreateCollection(const CArrayObj *list_symbols,const uint required=0) { //--- If an empty list of symbol objects is passed, exit if(list_symbols==NULL) return false; //--- Get the number of symbol objects in the passed list int total=list_symbols.Total(); //--- Clear the tick series collection list this.m_list.Clear(); //--- In a loop by all symbol objects for(int i=0;i<total;i++) { //--- get the next symbol object CSymbol *symbol_obj=list_symbols.At(i); //--- if failed to get a symbol object, move on to the next one in the list if(symbol_obj==NULL) continue; //--- Create a new empty tick series object CTickSeries *tickseries=new CTickSeries(); //--- If failed to create the tick series object, move on to the next symbol in the list if(tickseries==NULL) continue; //--- Set a symbol name for a tick series object tickseries.SetSymbol(symbol_obj.Name()); //--- Set the sorted list flag for the tick series collection list this.m_list.Sort(); //--- If the object with the same symbol name is already present in the tick series collection list, remove the tick series object if(this.m_list.Search(tickseries)>WRONG_VALUE) delete tickseries; //--- otherwise, there is no object with such a symbol name in the collection yet else { //--- Set the number of tick data days for a tick series object tickseries.SetRequiredUsedDays(required); //--- if failed to add the tick series object to the collection list, remove the tick series object if(!this.m_list.Add(tickseries)) delete tickseries; } } //--- Return the flag indicating that the created collection list has a size greater than zero return this.m_list.Total()>0; } //+------------------------------------------------------------------+
O método é simples - ele recebe uma lista de símbolos usados no programa (temos essa lista há muito tempo e é usada para criar uma coleção de séries temporais de símbolos), em seguida, num loop percorrendo o número total de símbolos, criamos outro novo objeto-série de ticks e definimos o nome do símbolo a partir da lista de símbolos na posição atual do loop. Se um objeto-série de ticks com esse símbolo ainda não estiver na lista, definimos para ele o número de dias de dados de ticks passados para o método e adicionamos o objeto à lista-coleção. E fazemos assim para cada símbolo da lista. Isso é em poucas palavras. Na verdade, isso se torna um pouco diferente quando verificamos se são bem-sucedidos a criação/adição de objetos-séries de ticks à lista e remoção de objetos desnecessários. Toda a lógica do método é descrita em detalhes em sua listagem, vamos deixá-la para uma análise independente.
Para conectar a coleção criada com o "mundo externo", usamos a classe da biblioteca principal CEngine,
localizada em \MQL5\Include\DoEasy\Engine.mqh.
Anexamos o arquivo da classe recém-criada a ele:
//+------------------------------------------------------------------+ //| Engine.mqh | //| Copyright 2020, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2020, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "Services\TimerCounter.mqh" #include "Collections\HistoryCollection.mqh" #include "Collections\MarketCollection.mqh" #include "Collections\EventsCollection.mqh" #include "Collections\AccountsCollection.mqh" #include "Collections\SymbolsCollection.mqh" #include "Collections\ResourceCollection.mqh" #include "Collections\TimeSeriesCollection.mqh" #include "Collections\BuffersCollection.mqh" #include "Collections\IndicatorsCollection.mqh" #include "Collections\TickSeriesCollection.mqh" #include "TradingControl.mqh" //+------------------------------------------------------------------+
Na seção privada da classe declaramos um objeto da classe-coleção da série de ticks:
//+------------------------------------------------------------------+ //| Library basis class | //+------------------------------------------------------------------+ class CEngine { private: CHistoryCollection m_history; // Collection of historical orders and deals CMarketCollection m_market; // Collection of market orders and deals CEventsCollection m_events; // Event collection CAccountsCollection m_accounts; // Account collection CSymbolsCollection m_symbols; // Symbol collection CTimeSeriesCollection m_time_series; // Timeseries collection CBuffersCollection m_buffers; // Collection of indicator buffers CIndicatorsCollection m_indicators; // Indicator collection CTickSeriesCollection m_tick_series; // Collection of tick series CResourceCollection m_resource; // Resource list CTradingControl m_trading; // Trading management object CPause m_pause; // Pause object CArrayObj m_list_counters; // List of timer counters
A classe tem um método SetUsedSymbols(), que permite definir na biblioteca uma lista de símbolos especificados para uso no programa.
Adicionamos a ele a transferência do número de dias para os quais é necessário ter dados de ticks na biblioteca:
//--- Set the list of used symbols in the symbol collection and create the collection of symbol timeseries bool SetUsedSymbols(const string &array_symbols[],const uint required=0);
Por padrão, é passado zero, o que significa um dia, e é especificado no arquivo \MQL5\Include\DoEasy\Defines.mqh pela constante TICKSERIES_DEFAULT_DAYS_COUNT.
Na implementação do método adicionamos a criação de uma coleção de séries de ticks.
//+------------------------------------------------------------------+ //| Set the list of used symbols in the symbol collection | //| and create the symbol timeseries collection | //+------------------------------------------------------------------+ bool CEngine::SetUsedSymbols(const string &array_symbols[],const uint required=0) { bool res=this.m_symbols.SetUsedSymbols(array_symbols); CArrayObj *list=this.GetListAllUsedSymbols(); if(list==NULL) return false; res&=this.m_time_series.CreateCollection(list); res&=this.m_tick_series.CreateCollection(list,required); return res; } //+------------------------------------------------------------------+
Agora, quando este método é chamado, duas coleções serão criadas a partir do programa - uma coleção de séries temporais e uma de séries de ticks.
Na seção pública da classe adicionamos métodos para acessar a classe da coleção da séries de ticks a partir de nossos programas:
//--- Copy the specified double property of the specified timeseries of the specified symbol to the array //--- Regardless of the array indexing direction, copying is performed the same way as copying to a timeseries array bool SeriesCopyToBufferAsSeries(const string symbol,const ENUM_TIMEFRAMES timeframe,const ENUM_BAR_PROP_DOUBLE property, double &array[],const double empty=EMPTY_VALUE) { return this.m_time_series.CopyToBufferAsSeries(symbol,timeframe,property,array,empty);} //--- Return (1) the tick series collection, (2) the list of tick series from the tick series collection CTickSeriesCollection *GetTickSeriesCollection(void) { return &this.m_tick_series; } CArrayObj *GetListTickSeries(void) { return this.m_tick_series.GetList(); } //--- Return (1) the buffer collection and (2) the buffer list from the collection
Por enquanto, basta retornar ao programa o próprio objeto de coleção das séries de ticks e a lista-coleção a partir dele.
Por hoje, isso é tudo de que precisamos para criar uma coleção de séries de ticks.
Teste
Para testar a criação de uma coleção de séries de ticks, pegaremos um Expert Advisor do artigo anterior e salvá-lo-emos numa nova pasta \MQL5\Experts\TestDoEasy\Part61\ com o nome TestDoEasyPart61.mq5.
Como agora todas as séries de ticks estão disponíveis na própria biblioteca, removemos a anexação de seu arquivo da classe a o programa:
//+------------------------------------------------------------------+ //| TestDoEasyPart60.mq5 | //| Copyright 2020, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2020, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //--- includes #include <DoEasy\Engine.mqh> #include <DoEasy\Objects\Ticks\TickSeries.mqh> //--- enums
Na área de variáveis globais do programa excluímos as variáveis do objeto "Novo Tick" e o objeto de dados da série de ticks do símbolo atual:
//--- global variables CEngine engine; SDataButt butt_data[TOTAL_BUTT]; string prefix; double lot; double withdrawal=(InpWithdrawal<0.1 ? 0.1 : InpWithdrawal); ushort magic_number; uint stoploss; uint takeprofit; uint distance_pending; uint distance_stoplimit; uint distance_pending_request; uint bars_delay_pending_request; uint slippage; bool trailing_on; bool pressed_pending_buy; bool pressed_pending_buy_limit; bool pressed_pending_buy_stop; bool pressed_pending_buy_stoplimit; bool pressed_pending_close_buy; bool pressed_pending_close_buy2; bool pressed_pending_close_buy_by_sell; bool pressed_pending_sell; bool pressed_pending_sell_limit; bool pressed_pending_sell_stop; bool pressed_pending_sell_stoplimit; bool pressed_pending_close_sell; bool pressed_pending_close_sell2; bool pressed_pending_close_sell_by_buy; bool pressed_pending_delete_all; bool pressed_pending_close_all; bool pressed_pending_sl; bool pressed_pending_tp; double trailing_stop; double trailing_step; uint trailing_start; uint stoploss_to_modify; uint takeprofit_to_modify; int used_symbols_mode; string array_used_symbols[]; string array_used_periods[]; bool testing; uchar group1; uchar group2; double g_point; int g_digits; //--- "New tick" object CNewTickObj check_tick; //--- Object of the current symbol tick series data CTickSeries tick_series; //+------------------------------------------------------------------+
No final do manipulador OnInit() removemos a configuração do símbolo atual para o objeto "Novo Tick":
//--- Wait for 600 milliseconds engine.Pause(600); engine.PlaySoundByDescription(TextByLanguage("Звук упавшей монетки 2","Falling coin 2")); //--- Set the current symbol for "New tick" object check_tick.SetSymbol(Symbol()); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+
Removemos na função OnInitDoEasy() o bloco de código usado para verificar a criação de uma série de ticks do símbolo atual:
//--- Check created timeseries - display descriptions of all created timeseries in the journal //--- (true - only created ones, false - created and declared ones) engine.GetTimeSeriesCollection().PrintShort(false); // Short descriptions //engine.GetTimeSeriesCollection().Print(true); // Full descriptions //--- Code block for checking the tick list creation and working with it Print(""); //--- Since the tick series object is created with the default constructor, //--- set a symbol, usage flag and the number of days (the default is 1) to copy the ticks //--- Create the tick series and printed data in the journal tick_series.SetSymbol(Symbol()); tick_series.SetAvailable(true); tick_series.SetRequiredUsedDays(); tick_series.Create(); tick_series.Print(); Print(""); //--- Get and display in the journal the data of an object with the highest Ask price in the daily price range int index_max=CSelect::FindTickDataMax(tick_series.GetList(),TICK_PROP_ASK); CDataTick *tick_max=tick_series.GetList().At(index_max); if(tick_max!=NULL) tick_max.Print(); //--- Get and display in the journal the data of an object with the lowest Bid price in the daily price range int index_min=CSelect::FindTickDataMin(tick_series.GetList(),TICK_PROP_BID); CDataTick *tick_min=tick_series.GetList().At(index_min); if(tick_min!=NULL) tick_min.Print(); //--- Create resource text files
Agora, neste lugar, precisamos colocar a criação de séries de ticks para todos os símbolos da coleção criada de dados de ticks:
//--- Check created timeseries - display descriptions of all created timeseries in the journal //--- (true - only created ones, false - created and declared ones) engine.GetTimeSeriesCollection().PrintShort(false); // Short descriptions //engine.GetTimeSeriesCollection().Print(true); // Full descriptions //--- Create tick series of all used symbols engine.GetTickSeriesCollection().CreateTickSeriesAll(); //--- Check created tick series - display descriptions of all created tick series in the journal engine.GetTickSeriesCollection().Print(); //--- Create resource text files
No manipulador OnTick(), quando um novo tick chegar, tentaremos encontrar na coleção de séries de ticks para cada símbolo um objeto-tick com o preço máximo Ask e preço mínimo Bid nas listas de dados de ticks, e exibir os parâmetros de cada objeto-tick encontrado no log:
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- Handle the NewTick event in the library engine.OnTick(rates_data); //--- If working in the tester if(MQLInfoInteger(MQL_TESTER)) { engine.OnTimer(rates_data); // Working in the timer PressButtonsControl(); // Button pressing control engine.EventsHandling(); // Working with events } //--- If the trailing flag is set if(trailing_on) { TrailingPositions(); // Trailing positions TrailingOrders(); // Trailing pending orders } //--- Check created tick data on the first tick //--- Get and display in the journal the data of an object with the highest Ask price and the lowest Bid price in the daily price range static bool check=false; if(!check) { Print(""); //--- Get the pointer to the list of tick data of all symbols from the tick collection CArrayObj* list=engine.GetTickSeriesCollection().GetList(); int total=engine.GetTickSeriesCollection().DataTotal(); //--- In the loop by the number of tick series in the collection for(int i=0;i<list.Type();i++) { //--- Get the next tick series from the collection by index CTickSeries *tick_series=engine.GetTickSeriesCollection().GetTickseries(i); if(tick_series!=NULL) { //--- In the obtained tick series, find the indices of tick objects with the highest Ask and the lowest Bid int index_max=CSelect::FindTickDataMax(tick_series.GetList(),TICK_PROP_ASK); int index_min=CSelect::FindTickDataMin(tick_series.GetList(),TICK_PROP_BID); //--- Display the data of the tick objects obtained from the tick series in the journal engine.GetTickSeriesCollection().GetTick(tick_series.Symbol(),index_max).Print(); engine.GetTickSeriesCollection().GetTick(tick_series.Symbol(),index_min).Print(); } } check=true; } } //+------------------------------------------------------------------+
Vamos compilar o Expert Advisor e iniciá-lo no gráfico de qualquer símbolo, tendo previamente definido nas configurações o uso do timeframe atual e dos símbolos de uma lista predefinida, na qual deixaremos os dois primeiros:
Após um curto período de tempo necessário para criar dados de tick para os dois símbolos usados no manipulador OnInit(), o log exibirá os dados sobre os parâmetros do programa, séries de tempo criadas e dados de ticks gerados, enquanto após a chegada do primeiro ticko log mostrará os dados de quatro ticks encontrados com máximo Ask e preço mínimo Bid para cada um dos dois símbolos:
Account 8550475: Artyom Trishkin (MetaQuotes Software Corp.) 10426.13 USD, 1:100, Hedge, MetaTrader 5 demo --- Initializing "DoEasy" library --- Working with predefined symbol list. The number of used symbols: 2 "AUDUSD" "EURUSD" Working with the current timeframe only: H1 AUDUSD symbol timeseries: - Timeseries "AUDUSD" H1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 6194 EURUSD symbol timeseries: - Timeseries "EURUSD" H1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 5675 Tick series "AUDUSD": Requested number of days: 1, Historical data created: 142712 Tick series "EURUSD": Requested number of days: 1, Historical data created: 113985 Library initialization time: 00:00:06.156 ============= Beginning of parameter list (Tick "AUDUSD" 2021.01.19 10:06:53.387) ============= Last price update time in milliseconds: 2021.01.19 10:06:53.387 Last price update time: 2021.01.19 10:06:53 Volume for the current Last price: 0 Flags: 6 Changed data on the tick: - Ask price change - Bid price change ------ Bid price: 0.77252 Ask price: 0.77256 Last price: 0.00000 Volume for the current Last price with greater accuracy: 0.00 Spread: 0.00004 ------ Symbol: "AUDUSD" ============= End of parameter list (Tick "AUDUSD" 2021.01.19 10:06:53.387) ============= ============= Beginning of parameter list (Tick "AUDUSD" 2021.01.18 11:51:48.662) ============= Last price update time in milliseconds: 2021.01.18 11:51:48.662 Last price update time: 2021.01.18 11:51:48 Volume for the current Last price: 0 Flags: 130 Changed data on the tick: - Bid price change ------ Bid price: 0.76589 Ask price: 0.76593 Last price: 0.00000 Volume for the current Last price with greater accuracy: 0.00 Spread: 0.00004 ------ Symbol: "AUDUSD" ============= End of parameter list (Tick "AUDUSD" 2021.01.18 11:51:48.662) ============= ============= Beginning of parameter list (Tick "EURUSD" 2021.01.19 10:05:07.246) ============= Last price update time in milliseconds: 2021.01.19 10:05:07.246 Last price update time: 2021.01.19 10:05:07 Volume for the current Last price: 0 Flags: 6 Changed data on the tick: - Ask price change - Bid price change ------ Bid price: 1.21189 Ask price: 1.21189 Last price: 0.00000 Volume for the current Last price with greater accuracy: 0.00 Spread: 0.00000 ------ Symbol: "EURUSD" ============= End of parameter list (Tick "EURUSD" 2021.01.19 10:05:07.246) ============= ============= Beginning of parameter list (Tick "EURUSD" 2021.01.18 14:57:53.847) ============= Last price update time in milliseconds: 2021.01.18 14:57:53.847 Last price update time: 2021.01.18 14:57:53 Volume for the current Last price: 0 Flags: 134 Changed data on the tick: - Ask price change - Bid price change ------ Bid price: 1.20536 Ask price: 1.20536 Last price: 0.00000 Volume for the current Last price with greater accuracy: 0.00 Spread: 0.00000 ------ Symbol: "EURUSD" ============= End of parameter list (Tick "EURUSD" 2021.01.18 14:57:53.847) =============
No log podemos ver que inicializar a biblioteca com a criação de listas de dados de ticks para dois símbolos demorou 16 segundos, e depois, após a chagada de um novo tick, encontramos dois ticks para cada um dos símbolos usados - com o preço máximo Ask e o preço mínimo Bid para o dia atual.
O que vem agora?
No próximo artigo, começaremos a criar atualizações em tempo real e monitorar eventos de dados na coleção de ticks criados hoje.
Todos os arquivos da versão atual da biblioteca e o arquivo do EA de teste para MQL5 estão anexados abaixo. Você pode baixá-los e testar tudo sozinho.
Gostaria de ressaltar que a classe-coleção das séries de tick está em desenvolvimento e, por isso, implementar essas classes neste estágio é extremamente desfavorável.
Se você tiver perguntas, comentários e sugestões, poderá expressá-los nos comentários do artigo.
Artigos desta série:
Trabalhando com séries temporais na biblioteca DoEasy (Parte 35): objeto "Barra" e lista-série temporal do símbolo
Trabalhando com séries temporais na biblioteca DoEasy (Parte 36): objeto das séries temporais de todos os períodos usados do símbolo
Trabalhando com séries temporais na biblioteca DoEasy (Parte 37): coleção de séries temporais - banco de dados de séries temporais para símbolos e períodos
Trabalhando com séries temporais na biblioteca DoEasy (Parte 38): coleção de séries temporais - atualização em tempo real e acesso aos dados do programa
Trabalhando com séries temporais na biblioteca DoEasy (Parte 39): indicadores com base na biblioteca - preparação de dados e eventos das séries temporais
Trabalhando com séries temporais na biblioteca DoEasy (Parte 40): indicadores com base na biblioteca - atualização de dados em tempo real
Trabalhando com séries temporais na biblioteca DoEasy (Parte 41): exemplo de indicador multissímbolo multiperíodo
Trabalhando com séries temporais na biblioteca DoEasy (Parte 42): classe de um objeto de buffer abstrato de indicador
Trabalhando com séries temporais na biblioteca DoEasy (Parte 43): classes de objetos de buffers de indicador
Trabalhando com séries temporais na biblioteca DoEasy (Parte 44): classe-coleção de objetos de buffers de indicador
Trabalhando com séries temporais na biblioteca DoEasy (Parte 45): buffers de indicador multiperíodo
Trabalhando com séries temporais na biblioteca DoEasy (Parte 46): buffers de indicador multiperíodos multissímbolos
Trabalhando com séries temporais na biblioteca DoEasy (Parte 47): indicadores padrão multiperíodos multissímbolos
Trabalhando com séries temporais na biblioteca DoEasy (Parte 48): indicadores multissímbolos multiperíodos num buffer de uma subjanela
Trabalhando com séries temporais na biblioteca DoEasy (Parte 49): indicadores padrão multiperíodos multissímbolos multibuffer
Trabalhando com séries temporais na biblioteca DoEasy (Parte 50): indicadores padrão multiperíodos multissímbolos com deslocamento
Trabalhando com séries temporais na biblioteca DoEasy (Parte 51): indicadores padrão multiperíodos multissímbolos compostos
Trabalhando com séries temporais na biblioteca DoEasy (Parte 52): natureza multiplataforma de indicadores padrão multiperíodos multissímbolos de buffer único
Trabalhando com séries temporais na biblioteca DoEasy (Parte 53): classe do indicador base abstrato
Trabalhando com séries temporais na biblioteca DoEasy (Parte 54): classes herdeiras do indicador base abstrato
Trabalhando com séries temporais na biblioteca DoEasy (Parte 55): classe-coleção de indicadores
Trabalhando com séries temporais na biblioteca DoEasy (Parte 56): objeto de indicador personalizado, obtenção de dados a partir de objetos-indicadores numa coleção
Trabalhando com séries temporais na biblioteca DoEasy (Parte 57): objeto de dados do buffer do indicador
Trabalhando com séries temporais na biblioteca DoEasy (Parte 58): séries temporais de dados de buffers de indicadores
Trabalhando com preços na biblioteca DoEasy (Parte 59): objeto para armazenar dados de um tick
Trabalhando com preços na biblioteca DoEasy (Parte 60): lista-série de dados de tick do símbolo
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/8952
- 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