Generic Class Library - bugs, description, questions, usage and suggestions - page 13

 
Renat Fatkhullin:

You can not compare HistorySelect(puts access range in the tester) and HistoryDealSelect(ticket), which actually searches for a specific ticket and caches it.

Because of this understanding, the Clear variant was created at once. To be able to compare Clear vs Full at the same time.

 
fxsaber:
Thus, the history (especially in the tester) is only updated, the old records are not changed. I mean the Clear variant.


On the real market, it seems that even when an order is partially executed and generates several deals, it does not get into the history until it is completely filled or cancelled. That is, the rule of frozen history is maintained.

If we wrote software without inspections, everything would have fallen apart long ago.

Financial software does not allow you to write in "cut corners" mode. You cut in one place, then in another, and then the developers will believe in the right to skip hard checks and failure is inevitable.

In the tester, you can still relax checks, but in reality there are a lot of asynchronous processes working on constant changes of the whole market environment in parallel with the work of your EA. It's scary there to think that something will be saved between MQL5 calls.

 
Renat Fatkhullin:

If we wrote software without inspections, everything would have fallen apart long ago.

Financial software does not allow you to write in "cut corners" mode. You cut in one place, then another, and then the developers will believe in the right to skip hard checks and failure is inevitable.

In the tester, you can still loosen the checks, but in the real world there are a lot of asynchronous processes working on constant changes of the whole market environment, parallel to the work of your Expert Advisor. It's scary to think that something will be saved between MQL5 calls.

Thanks for the clarification! The tester will hopefully tighten it up a bit.

 
fxsaber:

Because of this understanding, the Clear variant was created at once. So we could compare Clear vs Full at the same time.

You misunderstood what you were testing. This is in no way Clear variant and there is no relation to the original reference to HistorySelect.

Your Full variant essentially means a double call(ticket search), the first of which selects the deal into the cache and the second accesses the cached result. In a particular task, where a trade is known to exist, the first select call is superfluous. Get methods implicitly cache the affected record.



For information: we have to expose detailed Last Error codes inside (under GetLastError() call), so that developers can get the underlying reasons for the failure. Usually there are several such checks per call deep into the platform.
 
Renat Fatkhullin:

You misunderstand what you are testing. This is in no way a Clear option and there is no connection to the originally stated link to HistorySelect.

It seems that you have not noticed this

Forum on trading, automated trading systems and strategy testing

Generic classes library - bugs, description, issues, usage features and suggestions

fxsaber, 2017.12.08 22:46

  BENCH(HistorySelect(0, INT_MAX));
  BENCH(Print(SumProfit(Deals, GetDealProfitClear))); // Реализация с предварительно загруженной историей
Or maybe we are talking about different things.
 
fxsaber:

You don't seem to have noticed that.

Or maybe we're talking about different things.

Noticed it.

What preloaded history? I pointed out that HistorySelect in the tester is fake and does not make a real transfer to the cache all of the history specified in the query, but only marks the positions from & to in the existing database of deals. Therefore, the cost is zero.

In GetDealProfitClear, you exactly make a request to the same place using HistoryDealGetDouble(Deal, DEAL_PROFIT), as in your incorrectly understood GetDealProfitFull method, which uses two methods that are exactly the same in their physical essence

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

That is, access to the history in the tester is very optimized and really focuses on the fact that no one can change the trading history except for your Expert Advisor (with checks anyway).

In the real terminal, everything is different and HistorySelect is expensive.

 
Renat Fatkhullin:

I see what you mean. Thanks for the details! I want to know what will be the result.

Forum on trading, automated trading systems and strategy testing

Generic classes library - errors, description, questions, peculiarities of usage and suggestions

Renat Fatkhullin, 2017.12.08 23:19

I looked at our code - there is an opportunity to optimize calls to the trade base. We will try to implement by next week's release.

And Generic topic is very useful, though! I will follow it with interest.
 

Got acquainted with the implementation ofCHashMap
Honestly, I liked it.

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


There are a few suggestions for possible improvement:

1) In my humble opinion, the implementation contains not quite correct choice of capacity - both initial size 3 and subsequent ones when rebuilding the hash table.
Yes, it is true that you need to choose a prime number for uniformity of distribution.
However, the CPrimeGenerator implementation does not meet expectations and contains omissions of prime numbers.
The purpose of such a "generator" is clear - to provide an increment factor of the order of 1.2 with automatic generation of prime numbers.
However, isn't this too small a coefficient? In C++ for vectors, the coefficient is usually 1.5-2.0, depending on the library (because it strongly affects the average complexity of the operation).
The way out could be a constant coefficient followed by rounding the number to prime through a binary search of a list of prime numbers.
And an initial size of 3 is way too small, we don't live in the last century.

2) Currently hash table rebuilding (Resize) is executed only when 100% capacity is filled (all m_entries[] are filled).
In this regard, there may be a significant number of collisions for keys with not very evenly distributed.
As an option, consider introducing a fill factor, which will reduce 100% by the necessary limit to perform hash table rebuilding.

 
fxsaber:

How much does the classical version return in your case?

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

This is the execution time of printf.

You have somehow understood my example strangely. I do not have the goal to compare anything with the standard MetaTrader's functionality. It is only about how to arrange efficient algorithms of associations and selections of anything with anything at your user level. The connection of a deal number with the order number should be considered only as an example with low practical value, since there is the systemHistoryDealGetInteger(Deal, DEAL_ORDER).

 
fxsaber:

Well, here we compare the two highlighted indicators. It turns out that HashMap access is 4 times faster than that of the developers. But the developers have it already includes history...

For the same reason the comparison is incorrect. How can you compare custom CHashMap and working with system functions to get a trading environment?