일반 클래스 라이브러리 - 버그, 설명, 질문, 사용 기능 및 제안 사항 - 페이지 12

 
세르게이 주블릭 :

유형 T에 대한 GetHashCode 함수의 명시적 구현이 없는 경우 코드가 수행하는 작업을 이해합니까?
답변: 구현 부족 문제가 숨겨져 있기 때문에 더러운 속임수입니다. 동일한 클래스의 모든 객체는 동일한 해시 값을 반환합니다.

그리고 구현(본문)은 어디에?! 여기에 추가됩니다

 int GetHashCode(T & value)

불도저에서 삽입된 본체.

 
fxsaber :

그리고 구현(본문)은 어디에?! 여기에 추가됩니다

불도저에서 삽입된 본체.


그들은 당신에게 파리에 대해 말하고(당신이 이것을 해서는 안 됩니다. 코드는 미래에 병들 수 있습니다), 당신은 커틀릿에 대해 계속합니다.
좋아, 식욕이 좋아.

 

제안된 솔루션의 속도 특성을 살펴보기로 했습니다. 테스터를 위한 고문

 #include <MT4Orders.mqh>
#include <Generic\HashMap.mqh>

CHashMap< ulong , double > DealsProfit;

// Создаем историю из Amount сделок в тестере
void CreateHistory( const int Amount, const double Lots = 0.1 )
{
   MqlTick Tick;
  
   if ( SymbolInfoTick ( _Symbol , Tick) && Tick.ask && Tick.bid)
     for ( int i = (Amount >> 1 ) - 1 ; i >= 0 ; i--)
       OrderClose ( OrderSend ( _Symbol , OP_BUY , Lots, Tick.ask, 0 , 0 , 0 ), Lots, Tick.bid, 0 );
}

// Заполняем массив случайно выбранными сделками
void GetDeals( const int Amount, const int MaxDealTicket, ulong &Deals[] )
{
   for ( int i = ArrayResize (Deals, Amount) - 1 ; i >= 0 ; i--)  
    Deals[i] = MathRand () * MaxDealTicket / SHORT_MAX ;
}

// Заполнили HashMap
void SetHashMap()
{
   if ( HistorySelect ( 0 , INT_MAX ))
     for ( int i = HistoryDealsTotal () - 1 ; i >= 0 ; i--)
    {
       const ulong DealTicket = HistoryDealGetTicket (i);
      
      DealsProfit.Add(DealTicket, HistoryDealGetDouble (DealTicket, DEAL_PROFIT ));
    }
}

double GetDealProfitHashClear( const ulong Deal )
{
   static double Profit = 0 ;
  
   return (DealsProfit.TryGetValue(Deal, Profit) ? Profit : 0 );
}

double GetDealProfitFull( const ulong Deal )
{
   return ( HistoryDealSelect (Deal) ? HistoryDealGetDouble (Deal, DEAL_PROFIT ) : 0 );
}

double GetDealProfitClear( const ulong Deal )
{
   return ( HistoryDealGetDouble (Deal, DEAL_PROFIT ));
}

typedef double (*GetDealProfit)( const ulong );

// Находим суммарный профит сделок из массива
double SumProfit( const ulong &Deals[], GetDealProfit DealProfit )
{
   double Profit = 0 ;
  
   for ( int i = ArraySize (Deals) - 1 ; i >= 0 ; i--)
    Profit += DealProfit(Deals[i]);
    
   return (Profit);
}

#define BENCH(A)                                                              \
{                                                                             \
   const ulong StartTime = GetMicrosecondCount ();                              \
  A;                                                                          \
   Print ( "Time[" + #A + "] = " + ( string )( GetMicrosecondCount () - StartTime)); \
} 

int OnInit ()
{
   const int Amount = 100000 ;  
  CreateHistory(Amount); // Создаем историю из Amount сделок в тестере
  
   ulong Deals[];
  GetDeals(Amount, Amount, Deals); // Заполняем массив случайно выбранными сделками

   // Находим суммарный профит сделок из массива
  
  BENCH( Print (SumProfit(Deals, GetDealProfitFull))); // Полноценная классическая реализация
  
  BENCH(SetHashMap()); // Заполнили HashMap
  BENCH( Print (SumProfit(Deals, GetDealProfitHashClear))); // Реализация через HashMap
  
  BENCH( HistorySelect ( 0 , INT_MAX ));
  BENCH( Print (SumProfit(Deals, GetDealProfitClear))); // Реализация с предварительно загруженной историей
  
   return ( INIT_FAILED );
}

EA는 100,000 거래를 연 다음 다양한 방법을 사용하여 무작위 거래의 총 이익을 찾습니다(코멘트 참조). 결과

 2017.12 . 05 00 : 00 : 00    - 13133.19999999244
2017.12 . 05 00 : 00 : 00    Time [ Print (SumProfit(Deals,GetDealProfitFull))] = 38082
2017.12 . 05 00 : 00 : 00    Time [SetHashMap()] = 57849
2017.12 . 05 00 : 00 : 00    - 13133.19999999244
2017.12 . 05 00 : 00 : 00    Time [ Print (SumProfit(Deals,GetDealProfitHashClear))] = 7437
2017.12 . 05 00 : 00 : 00    Time [ HistorySelect ( 0 , INT_MAX )] = 1
2017.12 . 05 00 : 00 : 00    - 13133.19999999244
2017.12 . 05 00 : 00 : 00    Time [ Print (SumProfit(Deals,GetDealProfitClear))] = 31669

자, 선택한 두 지표를 비교해 보겠습니다. HashMap 액세스가 개발자보다 4배 빠른 것으로 나타났습니다. 그러나 개발자에게는 이미 역사가 포함되어 있습니다 ...

4번 - 이 상황에 많은가 아니면 적은가? 자, 여기 24밀리초입니다. 역사를 여러 번 돌리면 아마 많이 절약할 수 있을 것입니다. 하지만 확실하지 않습니다.


보다 현실적인 테스트 사례(2000개의 거래 및 1,000,000개의 단일 기록 액세스)의 경우 결과는 다음과 같습니다.

 2017.12 . 05 00 : 00 : 00    Time [ Print (SumProfit(Deals,GetDealProfitFull))] = 122969
2017.12 . 05 00 : 00 : 00    Time [SetHashMap()] = 816
2017.12 . 05 00 : 00 : 00    4829800340.792288
2017.12 . 05 00 : 00 : 00    Time [ Print (SumProfit(Deals,GetDealProfitHashClear))] = 23852
2017.12 . 05 00 : 00 : 00    Time [ HistorySelect ( 0 , INT_MAX )] = 1
2017.12 . 05 00 : 00 : 00    4829800340.792288
2017.12 . 05 00 : 00 : 00    Time [ Print (SumProfit(Deals,GetDealProfitClear))] = 114427

패스당 거의 100ms 절약! 예를 들어 10,000개의 전체 패스에 대해 최적화를 수행하면 해시 버전이 15분 더 빨리 종료됩니다.

개발자가 History를 사용한 작업 구현에 대해 5점을 주기에는 너무 이릅니다. MQL 솔루션도 가능하기 때문에 속도를 높일 수 있음을 알 수 있습니다.

 
fxsaber :

제안된 솔루션의 속도 특성을 살펴보기로 했습니다. 테스터의 전문가 고문

EA는 100,000 거래를 연 다음 다양한 방법을 사용하여 무작위 거래의 총 이익을 찾습니다(코멘트 참조). 결과

자, 선택한 두 지표를 비교해 보겠습니다. HashMap 액세스가 개발자보다 4배 빠른 것으로 나타났습니다. 그러나 개발자에게는 이미 역사가 포함되어 있습니다 ...

4번 - 이 상황에서는 많습니까, 조금입니까? 자, 여기 24밀리초입니다. 역사를 여러 번 돌리면 아마 많이 절약할 수 있을 것입니다. 하지만 확실하지 않습니다.

플랫폼을 통한 호출에서 GetDealProfitFull에서 두 번, GetDealProfitClear에서 한 번 동기화 개체를 통해 전달하고 각 반복에서 많은 필수 검사를 통과합니다.

따라서 속도는 사전 준비된 로컬 해시맵에 대한 인라인 작업으로 깨끗하고 최적화된 것보다 분명히 낮습니다.

 
레나트 파트훌린 :

플랫폼을 통한 호출에서 GetDealProfitFull에서 두 번, GetDealProfitClear에서 한 번 동기화 개체를 통해 전달하고 각 반복에서 많은 필수 검사를 통과합니다.

따라서 속도는 사전 준비된 로컬 해시맵에 대한 인라인 작업으로 깨끗하고 최적화된 것보다 분명히 낮습니다.

이전 게시물을 수정했습니다. 그래서 이중 확인을 Full이라고 합니다.

나는 우리가 HistoryDealGetDouble 에 대한 테스터에서 어떤 종류의 값비싼 동기화 개체와 많은 검사에 대해 이야기하고 있는지 잘 이해하지 못합니다.
 
fxsaber :

이전 게시물을 수정했습니다. 그래서 이중 확인을 Full이라고 합니다.

나는 우리가 HistoryDealGetDouble에 대한 테스터에서 어떤 종류의 값비싼 동기화 개체와 많은 검사에 대해 이야기하고 있는지 잘 이해하지 못합니다.

차이점은 무엇입니까?

  1. 해시맵 테스트를 위해 먼저 데이터를 동기화되지 않은 빠른 액세스로 로컬 스토리지로 전송했고 플랫폼 호출에서는 스토리지에 들어가야 합니다.
  2. 플랫폼에서 해시맵이 아닌 다른 종류의 저장소
  3. 플랫폼에서 단일 값을 추출할 때 요청을 "처음과 같이" 처리하여 모든 데이터의 정확성과 가용성을 다시 확인해야 합니다. 통화 간에 거의 변경되지 않음


나는 우리의 코드를 살펴보았다. 거래 작업의 데이터베이스에 대한 호출을 최적화하는 것이 가능하다. 다음 주 출시를 위해 구현하려고 합니다.

 

레나트 파트훌린 :

플랫폼에서 단일 값을 추출할 때 요청을 "처음으로" 처리하여 모든 데이터의 정확성과 가용성을 다시 확인해야 합니다.

TryGetValue를 호출할 때 유효성 검사가 수행되지 않습니까? 로그는 테스터에서 HistorySelect 가 무료임을 보여줍니다.

내가 전혀 이해하지 못하는 것은 거래에 대한 모든 데이터를 얻기 위해 값비싼 HistoryDealGet * 함수를 여러 개 호출해야 하는 이유입니다. 결국 MqlDeal 구조를 채우는 호출은 단 한 번뿐입니다.

사용자가 HashMap을 통해 히스토리 작업을 하고 싶을 때 CHashMap<ulong, MqlDeal>을 채우는 것은 자명합니다.

어쨌든 전체 기록 테이블이 테스터에 있기 때문에 값 비싼 단위 호출을 생성하지 않도록 MqlDealInteger, MqlDealDouble, MqlDealString 또는 이와 유사한 것으로 만들 수 있습니까? 그런 다음 DealTicket의 정확성을 매번 확인하는 것이 아니라 한 번만 확인하면 됩니다.

 
fxsaber :

TryGetValue를 호출할 때 유효성 검사가 수행되지 않습니까? 로그는 테스터에서 HistorySelect가 무료임을 보여줍니다.

어떻게 무료인가요? 전혀 무료가 아닙니다.


내가 전혀 이해하지 못하는 것은 거래에 대한 모든 데이터를 얻기 위해 값비싼 HistoryDealGet * 함수를 여러 개 호출해야 하는 이유입니다. 결국 MqlDeal 구조를 채우는 호출은 단 한 번뿐입니다.

사용자가 HashMap을 통해 히스토리 작업을 하고 싶을 때 CHashMap<ulong, MqlDeal>을 채우는 것은 자명합니다.

거래 기록 형식이 유동적이고 주기적으로 확장되기 때문에 MqlDeal 구조가 없습니다. 이것이 없으면 플랫폼의 기능을 확장하는 것이 불가능합니다.

따라서 유일한 옵션은 Get 함수를 통해 액세스하는 것입니다. 또한 이전에 영향을 받은 레코드의 나머지 필드에 대한 액세스는 레코드가 캐시로 이동하기 때문에 첫 번째 액세스보다 몇 배나 빠릅니다.

그런 다음 DealTicket의 정확성을 매번 확인하는 것이 아니라 한 번만 확인하면 됩니다.

위의 테스트에서 거래 번호는 매번 새로운 것으로 이전에 선택한 거래 의 캐시를 지속적으로 무너뜨립니다. 또한 호출 간에 변경되지 않았다는 보장도 없습니다. 결국 기록에 대한 요청 간에 거래할 수 있습니다.

 
레나트 팻쿨린 :
어떻게 무료인가요? 전혀 무료가 아닙니다.

거래, 자동 거래 시스템 및 거래 전략 테스트에 관한 포럼

일반 클래스 라이브러리 - 버그, 설명, 질문, 사용법 및 제안

fxsaber , 2017.12.08 22:46

EA는 100,000 거래를 연 다음 다양한 방법을 사용하여 무작위 거래의 총 이익을 찾습니다(코멘트 참조). 결과

 2017.12 . 05 00 : 00 : 00    Time [ HistorySelect ( 0 , INT_MAX )] = 1

100,000 거래(동일한 주문 수)의 경우 1마이크로초가 무료입니다. 테스터에 관한 모든 것입니다.

위의 테스트에서 거래 번호는 매번 새로운 것으로 이전에 선택한 거래 의 캐시를 지속적으로 무너뜨립니다. 또한 호출 간에 변경되지 않았다는 보장도 없습니다. 결국 기록에 대한 요청 간에 거래할 수 있습니다.

따라서 히스토리(특히 테스터에서)는 보완만 되며 이전 레코드는 변경되지 않습니다. 지우기 옵션에 관한 것입니다.


실생활에서 주문이 부분적으로 실행되어 여러 트랜잭션이 발생하더라도 완전히 채워지거나 취소될 때까지 내역에 입력되지 않는 것 같습니다. 저것들. 동결된 역사 규칙이 유지됩니다.

 
fxsaber :

100,000 거래(동일한 주문 수)의 경우 1마이크로초가 무료입니다. 테스터에 관한 모든 것입니다.

테스터의 HistorySelect는 특히 매개변수 0, INT_MAX 를 사용하여 절대적으로 가상/가상입니다. 이것은 오랫동안 최적화되었습니다.

HistorySelect(테스터에서 액세스 범위 설정)와 실제로 특정 티켓을 검색하고 캐시하는 HistoryDealSelect(티켓)를 비교할 수 없습니다.