Biblioteca de classes genéricas - bugs, descrição, perguntas, recursos de uso e sugestões - página 13

 
Renat Fatkhullin:

Você não pode comparar HistorySelect(coloca o intervalo de acesso no testador) e HistoryDealSelect(bilhete), que realmente procura por um bilhete específico e o armazena em cache.

Por causa da compreensão disto, a Clear-variant foi criada imediatamente. Ser capaz de comparar Clear vs Full ao mesmo tempo.

 
fxsaber:
Desta forma, a história (especialmente no testador) é apenas complementada, os registos antigos não são alterados. Refiro-me à variante Clear.


No real, parece que mesmo quando uma ordem é parcialmente executada e gera várias negociações, ela não entrará na história até que seja completamente preenchida ou cancelada. Isto é, a regra da história congelada é preservada.

Se tivéssemos escrito software sem cheques, tudo teria desmoronado há muito tempo.

O software financeiro não permite que você escreva em modo "cut corner". Você corta em um lugar, depois em outro, e então os desenvolvedores acreditarão no direito de pular checagens difíceis e o fracasso é inevitável.

No testador, você ainda pode relaxar as verificações, mas no EA real há muitos processos assíncronos trabalhando em mudanças constantes de todo o ambiente do mercado em paralelo com o trabalho do seu EA. É assustador pensar que algo vai ser salvo entre chamadas MQL5.

 
Renat Fatkhullin:

Se tivéssemos escrito software sem cheques, tudo teria desmoronado há muito tempo.

O software financeiro não permite que você escreva em modo "cut corner". Você corta em um lugar, depois em outro, e então os desenvolvedores acreditarão no direito de pular checagens difíceis e o fracasso é inevitável.

Você ainda pode soltar as verificações no testador, mas no mundo real há um monte de processos assíncronos trabalhando em constante mudança em todo o ambiente do mercado, em paralelo com o trabalho da sua EA. É assustador pensar que algo vai ser salvo entre chamadas MQL5.

Obrigado pelo esclarecimento! Esperemos que o testador o aperte um pouco.

 
fxsaber:

Devido a esse entendimento, a variante Clear foi criada imediatamente. Para que pudesses comparar Clear vs Full ao mesmo tempo.

Você entendeu mal o que está testando. Isto não é de forma alguma uma variante Clear e não há nenhuma relação com a referência originalmente indicada ao HistorySelect.

A sua variante completa significa essencialmente uma chamada dupla (procura de bilhetes), a primeira das quais selecciona a troca para a cache e a segunda acede ao resultado da cache. Em uma determinada tarefa, onde se sabe que existe uma troca, a primeira chamada selecionada é redundante. Obter métodos de cache implícito do registro afetado.



Para informação, nós internamente temos que expor os códigos detalhados do Último Erro (em GetLastError() call), para que os desenvolvedores possam obter as razões subjacentes para a falha. Normalmente há várias verificações deste tipo por chamada no fundo da plataforma.
 
Renat Fatkhullin:

Você entendeu mal o que está testando. Não é de forma alguma uma opção clara e não há nenhuma ligação com a referência original ao HistorySelect.

Parece que ainda não reparaste.

Fórum sobre negociação, sistemas de negociação automatizados e teste de estratégias de negociação

Biblioteca de classes genéricas - bugs, descrição, problemas, casos de uso e sugestões

fxsaber, 2017.12.08 22:46

  BENCH(HistorySelect(0, INT_MAX));
  BENCH(Print(SumProfit(Deals, GetDealProfitClear))); // Реализация с предварительно загруженной историей
Ou talvez estejamos a falar de coisas diferentes.
 
fxsaber:

Não parece ter reparado.

Ou talvez estejamos a falar de coisas diferentes.

Reparei nisso.

Que história pré-carregada? Salientei que o HistorySelect no testador é falso e não faz uma transferência real para o cache de todo o histórico especificado na consulta, mas apenas marca posições de & para na base de dados de negócios existente. Portanto, o custo é zero.

Em GetDealProfitClear, você faz exatamente um pedido para o mesmo lugar usando HistoryDealGetDouble(Deal, DEAL_PROFIT), como em seu método GetDealProfitFull mal entendido, que usa dois métodos que são exatamente os mesmos em sua essência física

return(HistoryDealSelect(Deal) ? HistoryDealGetDouble(Deal, DEAL_PROFIT) : 0)

Ou seja, o acesso ao histórico no testador é muito otimizado e realmente foca no fato de que ninguém pode mudar o histórico de negociação, exceto pelo seu Expert Advisor (e as verificações ainda estão lá).

No terminal real tudo é diferente e a HistorySelect é cara.

 
Renat Fatkhullin:

Estou a ver o que queres dizer. Obrigado pelos detalhes! Pergunto-me qual será o resultado.

Fórum sobre negociação, sistemas de negociação automatizados e testes estratégicos

Biblioteca de classes genéricas - erros, descrição, perguntas, peculiaridades de uso e sugestões

Renat Fatkhullin, 2017.12.08 23:19

Eu olhei para o nosso código - é possível optimizar as chamadas para a base comercial. Vamos tentar implementar até ao lançamento da próxima semana.

E o tema genérico é muito útil, no entanto! Vou segui-lo com interesse.
 

Confira a implementação doCHashMap
Eu gostei, honestamente.

//+------------------------------------------------------------------+
//| Class CHashMap<TKey, TValue>.                                    |
//| Usage: Represents a collection of keys and values.               |
//+------------------------------------------------------------------+
template<typename TKey,typename TValue>
class CHashMap: public IMap<TKey,TValue>
  {
protected:
   int               m_buckets[];                        
   Entry<TKey,TValue>m_entries[];
   int               m_count;
   int               m_free_list;
   int               m_free_count;
   IEqualityComparer<TKey>*m_comparer;
   bool              m_delete_comparer;

public:
                     CHashMap(void);
                     CHashMap(const int capacity);
                     CHashMap(IEqualityComparer<TKey>*comparer);
                     CHashMap(const int capacity,IEqualityComparer<TKey>*comparer);
                     CHashMap(IMap<TKey,TValue>*map);
                     CHashMap(IMap<TKey,TValue>*map,IEqualityComparer<TKey>*comparer);
                    ~CHashMap(void);
   //--- methods of filling data 
   bool              Add(CKeyValuePair<TKey,TValue>*pair);
   bool              Add(TKey key,TValue value);
   //--- methods of access to protected data
   int               Count(void)                                       { return(m_count-m_free_count); }
   IEqualityComparer<TKey>*Comparer(void)                        const { return(m_comparer);           }
   bool              Contains(CKeyValuePair<TKey,TValue>*item);
   bool              Contains(TKey key,TValue value);
   bool              ContainsKey(TKey key);
   bool              ContainsValue(TValue value);
   //--- methods of copy data from collection   
   int               CopyTo(CKeyValuePair<TKey,TValue>*&dst_array[],const int dst_start=0);
   int               CopyTo(TKey &dst_keys[],TValue &dst_values[],const int dst_start=0);
   //--- methods of cleaning and deleting
   void              Clear(void);
   bool              Remove(CKeyValuePair<TKey,TValue>*item);
   bool              Remove(TKey key);
   //--- method of access to the data
   bool              TryGetValue(TKey key,TValue &value);
   bool              TrySetValue(TKey key,TValue value);

private:
   void              Initialize(const int capacity);
   void              Resize(int new_size,bool new_hash_codes);
   int               FindEntry(TKey key);
   bool              Insert(TKey key,TValue value,const bool add);
  };


Há algumas sugestões para possíveis melhorias:

1) Na minha humilde opinião, a implementação não contém uma escolha muito correcta da capacidade - tanto o tamanho inicial 3 como os subsequentes quando se reconstrói a tabela de hash.
Sim, é correcto que deve ser escolhido um número primo para a uniformidade da distribuição.
No entanto, a implementação do CPrimeGenerator não corresponde às expectativas e contém omissões de números primos.
O propósito de tal "gerador" é claro - fornecer um fator de incremento da ordem de 1,2 com geração automática de números primos.
No entanto, isto não é um coeficiente muito pequeno? Em C++ para vetores, o coeficiente é normalmente de 1,5-2,0, dependendo da biblioteca (pois afeta fortemente a complexidade média da operação).
A saída poderia ser um coeficiente constante seguido de arredondamento do número para prime através de uma pesquisa binária de uma lista de números primos.
E um tamanho inicial de 3 é muito pequeno, nós não vivemos no século passado.

2) Atualmente a tabela de hash é reconstruída (Redimensionada) somente quando a capacidade está 100% cheia (todos os m_entries[] são preenchidos).
Devido a isso, pode haver uma quantidade significativa de colisões de chaves que não estão muito bem distribuídas.
Como opção, considere a introdução de um fator de preenchimento que reduza em 100% o limite necessário para realizar uma reconstrução da tabela de hash.

 
fxsaber:

E a versão clássica de quanto retorna no seu caso?

ulong GetDealOrder( const ulong Deal )
{
  return(HistoryDealSelect(Deal) ? HistoryDealGetInteger(Deal, DEAL_ORDER) : 0);
}
2017.12.08 17:56:05.184 OrdersID (SBRF Splice,M1)       Время выполнения запроса: 9 микросекунд

É o tempo de execução do printf.

De alguma forma, você entendeu o meu exemplo de forma estranha. Não tenho o objetivo de comparar nada com a funcionalidade do MetaTrader padrão. Trata-se apenas de como organizar algoritmos eficientes de associações e amostragem de qualquer coisa com qualquer coisa no seu nível de usuário. O exemplo de associação de um número de transação com um número de ordem deve ser considerado apenas como um exemplo de baixo valor prático, porque existe umHistoryDealGetInteger(Deal, DEAL_ORDER) do sistema.

 
fxsaber:

Bem, aqui está uma comparação das duas métricas destacadas. Acontece que o acesso ao HashMap é 4 vezes mais rápido do que o dos desenvolvedores. Mas os criadores já o têm, incluindo a história...

Pela mesma razão, a comparação é incorrecta. Como você pode comparar o CHashMap personalizado e trabalhar com funções de sistema para obter um ambiente de negociação?