Библиотека Generic классов - ошибки, описание, вопросы, особенности использования и предложения - страница 13

 
Renat Fatkhullin:

Нельзя сопоставлять HistorySelect(ставит range доступа в тестере) и HistoryDealSelect(ticket), который реально ищет конкретный тикет и кеширует его.

Из-за понимания этого и был создан Clear-вариант сразу. Чтобы можно было сравнить Clear vs Full заодно.

 
fxsaber:
Так история (особенно в тестере) только дополняется, старые записи не изменяются. Речь про Clear-вариант.


На реале, вроде, даже когда ордер исполняется частично и порождает несколько сделок, он не попадет в историю, пока полностью не зафиллится или не будет отменен. Т.е. сохраняется правило замороженной истории.

Если бы мы писали софт без проверок, все давно развалили бы.

Финансовый софт не позволяет писать в режиме "срежу углы". Срежешь в одном месте, затем в другом, а потом разработчики уверуют в право пропускать жесткие проверки и провал неминуем.

В тестере еще можно ослабить проверки, но в реале вообще куча асинхронных процессов, работающих над постоянным изменением всего рыночного окружения параллельно работе вашего эксперта. Там даже подумать страшно о том, что между MQL5 вызовами что-то будет сохранено.

 
Renat Fatkhullin:

Если бы мы писали софт без проверок, все давно развалили бы.

Финансовый софт не позволяет писать в режиме "срежу углы". Срежешь в одном месте, затем в другом, а потом разработчики уверуют в право пропускать жесткие проверки и провал неминуем.

В тестере еще можно ослабить проверки, но в реале вообще куча асинхронных процессов, работающих над постоянным изменением всего рыночного окружения параллельно работе вашего эксперта. Там даже подумать страшно о том, что между MQL5 вызовами что-то будет сохранено.

Спасибо за разъяснение! Тестер, надеюсь, подкрутите немного.

 
fxsaber:

Из-за понимания этого и был создан Clear-вариант сразу. Чтобы можно было сравнить Clear vs Full заодно.

Вы неправильно понимаете, что тестировали. Это никак не Clear вариант и нет никакой связи с исходно заявленной ссылкой на HistorySelect.

Ваш Full вариант по сути означает двойной вызов(поиск тикета), первый из которого выбирает сделку в кеш, а второй доступается к кешированному результату. В конкретной задаче, где сделка заведомо существует, первый вызов select лишний. Get методы неявно поднимают в кеш затронутую запись.



Для информации: мы внутри обязаны выставлять детальные Last Error коды (под GetLastError() вызов), чтобы разработчики могли получить глубинные причины отказа. Обычно таких проверок несколько на один вызов вглубь платформы.
 
Renat Fatkhullin:

Вы неправильно понимаете, что тестировали. Это никак не Clear вариант и нет никакой связи с исходно заявленной ссылкой на HistorySelect.

Похоже, Вы этого не заметили

Или, может, мы о разных вещах говорим.
 
fxsaber:

Похоже, Вы этого не заметили

Или, может, мы о разных вещах говорим.

Заметил.

Какая предварительно загруженная история? Я же указал, что HistorySelect в тестере фейковый и не делает реального переноса в кеш всей указанной в запросе истории, а лишь помечает позиции from & to в существующей базе сделок. Поэтому и стоимость нулевая.

В GetDealProfitClear вы точно так же и точно туда же делаете запрос через  HistoryDealGetDouble(Deal, DEAL_PROFIT) как и в неправильно понятом вами методе GetDealProfitFull, где стоят два точно таких же по физической сути метода

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

То есть, доступ к истории в тестере очень оптимизирован и реально ориентируется на то, что никто не может поменять торговую историю кроме вашего эксперта(при этому проверки все равно есть).

В реальном терминале все не так и HistorySelect дорогой.

 
Renat Fatkhullin:

Понял, что Вы имели в виду. Спасибо за подробности! Интересно, что у Вас выйдет по итогу

А Generic-тема очень полезная, однако! Буду следить с интересом.
 

Ознакомился с реализацией CHashMap
Честно, понравилась.

//+------------------------------------------------------------------+
//| 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);
  };


Есть несколько предложений по возможному улучшению:

1) По скромному мнению реализация содержит не совсем корректный выбор capacity - как начальный размер 3, так и последующие при перестройке хеш-таблицы.
Да, все верно, что нужно выбирать простое число для равномерности распределения. 
Однако реализация CPrimeGenerator не отвечает ожиданиям и содержит пропуски простых чисел.
Цель такого "генератора" понятна - обеспечить коэффициент прироста порядка 1.2 с автоматическим получением простых чисел.
Однако, разве это не слишком маленький коэффициент? В C++ для vectors обычно коэффициент составляет 1.5-2.0 в зависимости от библиотеки (так как сильно влияет на среднюю сложность операции).
Выходом может быть константный коэффициент с последующим округлением числа до простого через бинарный поиск в списку простых чисел.
И начальный размер capacity в 3 - это уж слишком мало, мы же не в прошлом веке живем.

2) На данный момент перестройка хеш-таблицы (Resize) выполняется исключительно при 100% заполнении capacity (заполнении всех m_entries[])
В связи с чем возможно значительное количество коллизий для ключей с не очень равномерным распределением.
Как вариант рассмотреть возможность введение коэффициента заполнения, который уменьшит 100% на необходимый лимит для выполнения перестройки хеш-таблицы.

 
fxsaber:

А классический вариант сколько возвращает в Вашем случае?

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 микросекунд

Это время выполнения printf.

Вы как-то странно поняли мой пример. У меня нет цели что-либо сравнивать с штатным функционалом MetaTrader. Речь лишь о том, как на своем пользовательском уровне организовать эффективные алгоритмы ассоциаций и выборки чего угодно с чем угодно. Пример связи номера сделки с номером ордера нужно рассматривать лишь как пример, с низкой практической ценностью, т.к. есть системная HistoryDealGetInteger(Deal, DEAL_ORDER). 

 
fxsaber:

Ну вот сравниваем два выделенных показателя. Получается, что HashMap-доступ в 4 раза быстрее того, что у разработчиков. Но у разработчиков он уже включает историю...

По той же причине сравнение некорректное. Как можно сравнивать пользовательский CHashMap и работу с системными функциями для получения торгового окружения? 

Причина обращения: