Структура SStatistic

Forex пазарите от гледна точка на Теорията на вероятностите

Модератор: Mateev

Mateev
Мнения: 205
Регистриран: 02 окт 2017, 10:04
34 получени
33 дадени

Структура SStatistic

Мнение от Mateev » 28 ное 2017, 06:53

Отварям тази тема като пример за обектно-ориентирано програмиране, което е желателно да се използва при програмирането на експерти за MetaTrader 4/5. В темата ще публикувам отворения код на една структура, която въпреки че е елементарна, се оказа, че я използвам под път и над път във всеки един написан от мене експерт.

Става въпрос за изчисляване на статистиките (агрегатните функции) на последователност от double числа. Такава последователност може да бъде например резултата от сделките, или пък например различни параметри на тиковете, баровете, спреда, гаповете и буквално всичко, което може да се представи като числова редица.

Най-масово използваните статистически и агрегатни функции съм ги оформил като структура, а не като клас, за да може лесно с тази структура да се правят статични или динамични масиви, както и лесно да се правят референции от/към външни функции.

Mateev
Мнения: 205
Регистриран: 02 окт 2017, 10:04
34 получени
33 дадени

Re: Структура SStatistic

Мнение от Mateev » 28 ное 2017, 06:55

Ето го кода на структурата:

Код: Избери всички

//+------------------------------------------------------------------+
//|                                              StructStatistic.mqh |
//|                                        Copyright 2017, Mateev SC |
//|                                            http://www.mateev.com |
//+------------------------------------------------------------------+

#property copyright "Copyright 2017, Mateev SC"
#property link      "http://www.mateev.com"
#property version   "1.04"
#property strict

//====================================================================
// Посредством тези дефиниции в кода се включват или изключват различни агрегатни функции
// Тези дефиниции се включват в кода на външния клас, който използва тази структура
// За изключване на някоя дефиниция се използва #undef
#define UseFirstLast // Изчисляват се First и Last
#define UseMinMax    // Изчисляват се Min и Max
#define UseAvg       // Изчислява се средно-аритметичната стойност
#define UseRMS       // Изчислява се средно-квадратичната стойност
#define UseMnH       // Изчислява се средно-хармоничната стойност
#define UseSumMinMax // Изчислява Min и Max на движението на сумата Sum (Min и Max на Equity-то)

//====================================================================
// Структура със статистиките (агрегатните функции) на определен брой double числа
//====================================================================

struct SStatistic
  {
    #ifdef UseFirstLast // Да се изчисляват ли First и Last 
      double First;     // 8 байта - Първа стойност
      double Last;      // 8 байта - Последна стойност
    #endif
 
    #ifdef UseMinMax // Да се изчисляват ли Min и Max   
      double Min;    // 8 байта - Минимална  стойност
      double Max;    // 8 байта - Максимална стойност
    #endif

    #ifdef UseAvg // Да се изчислява ли среднo-аритметичната стойност
      double Sum; // 8 байта - Сума на стойностите, образували статистиката   
      double Avg; // 8 байта - Arithmetic mean - Среднo-аритметична стойност
    #endif

    #ifdef UseRMS // Да се изчислява ли среднo-квадратичната стойност 
      double Sm2; // 8 байта - Сума от квадратите на стойностите, образували статисттиката
      double RMS; // 8 байта - Qudraic mean - Среднo-квадратична стойност
    #endif

    #ifdef UseMnH // Да се изчислява ли среднo-хармоничната стойност
      double Sm1; // 8 байта - Сума от 1/стойностите, образували статисттиката     
      double MnH; // 8 байта - Harmonic mean - Средно хармоничнa стойност (броя на числата, разделен на сумата от 1/числото)
    #endif
    
    #ifdef UseSumMinMax // Да се изчисляват ли SumMin и SumMax   
      double SumMin;    // 8 байта - Минимална  стойност на сумата Sum (минимална  стойнст на Equity-то)
      double SumMax;    // 8 байта - Максимална стойност на сумата Sum (максимална стойнст на Equity-то)
    #endif    
 
    int Count; // 4 байта - Брой на стойностите, образували статистиката (0..2 147 483 647)     
    
    // Методи за манипулация на данните в статистиката
    void Clear(void){ZeroMemory(this);} // Нулира структурата
    void Add  (double value); // Добавяне на число в статистиката   

    // Методи за запис и четене от бинарен файл
    bool Save(const int handle); // Записва структурата във файл
    bool Load(const int handle); // Чете структурата от файл
  };
  
//====================================================================
// Добавяне на число в статистиката  

void SStatistic::Add(double value)
  {
    Count++; // Броя на елементите в статистиката нараства с 1-ца
      
    #ifdef UseFirstLast // Да се изчисляват ли First и Last 
      if (Count==1) First = value; // Ако това е първата добавена стойност, то тя става First.
      Last = value; // Всяка новодобавена стойност автоматично става Last.
    #endif 
          
    #ifdef UseMinMax // Да се изчисляват ли Min и Max стойностите 
      if (Count==1)  // Ако това е първата добавена стойност, то:
        {
          Min = value;
          Max = value;
        }
      else // Ако вече има добавени стойности, то:
        {
          if (Min > value) Min = value;
          if (Max < value) Max = value;
        }
    #endif  
    
    #ifdef UseAvg // Да се изчислява ли среднo-аритметичната стойност    
      Sum = Sum + value;
      Avg = Sum / Count; 
      #ifdef UseSumMinMax // Да се изчисляват ли SumMin и SumMax
        if (Count==1) // Ако това е първата добавена стойност, то:
          {
            SumMin = Sum;
            SumMax = Sum;
          }
        else // Ако вече има добавени стойности, то:
          {
            if (SumMin > Sum) SumMin = Sum;
            if (SumMax < Sum) SumMax = Sum;
          }
      #endif     
    #endif

    #ifdef UseRMS // Да се изчислява ли среднo-квадратичната стойност     
      Sm2 = Sm2 + value*value;       
      RMS = MathSqrt(Sm2/Count);    
    #endif

    #ifdef UseMnH // Да се изчислява ли среднo-хармоничната стойност      
      if(value!=0) Sm1 = Sm1 + 1.0/value;
      if(Sm1==0) MnH=0; else MnH = double(Count)/Sm1;
    #endif      
  }

//====================================================================
// Записва структурата във файл
 
bool SStatistic::Save(const int handle)
  {
    if (handle==INVALID_HANDLE) return(false);
    else return(FileWriteStruct(handle,this,sizeof(SStatistic))==sizeof(SStatistic));
  } 

//====================================================================
// Чете структурата от файл

bool SStatistic::Load(const int handle)
  {
    if (handle==INVALID_HANDLE) return(false);
    else return(FileReadStruct(handle,this,sizeof(SStatistic))==sizeof(SStatistic));
  }

/*====================================================================
----------------------- ИСТОРИЯ НА ВЕРСИИТЕ --------------------------
======================================================================

24.11.2017 - v.1.003
  - Класът е копиран от библиотеката на MQL4 и е пригоден за нуждите на AITW
  - Посредством #define е създадена възможност за включване в кода на различни агрегатни функции
  - Добавен е код за изчисляване на Fisrt и Last
  
28.11.2017 - v.1.004
  - Поправен e бъг при изчисляването на средно-хармоничната стойност MnH
  - Добавен е код за изчисляване на SumMin и SumMax 

====================================================================*/    

Mateev
Мнения: 205
Регистриран: 02 окт 2017, 10:04
34 получени
33 дадени

Re: Структура SStatistic

Мнение от Mateev » 28 ное 2017, 07:08

Тъй като търсенето на някакви зависимости и изчисляването на някакви статистики е основополагащо във всеки един експерт, то и масовото използване на структура от описания тип също се явява основополагащо. Каквото и да си помислите да проверите с помощта на някакъв код, винаги стигате до реализирането на някаква статистика на някаква числова редица. Затова и реших да публикувам този код, който има не само образователна, но и реална практическа стойност.

Кода на структурата изчислява и съхранява следните статистически и агрегатни функции:
- Count - Брой на стойностите в статистиката
- First - Първа стойност от последователноста
- Last - Последна стойност от последователноста
- Min - Минимална стойност на числата в статистиката
- Max - Максимална стойност
- Sum - Сума на числата в статистиката
- Sm1 - Сума от 1/стойностите, образували статистиката
- Sm2 - Сума от квадратите на стойностите, образували статистиката
- Avg - Средно-аритметична стойност
- RMS - Средно-квадратична стойност
- MnH - Средно-хармонична стойност
- SumMin - Минимум на сумата (Equity-то)
- SumMax - Максимум на сумата (Equity-to)

С помощта на дефиниции в началото на кода на структурата се определя стойностите на кои точно статистически функции трябва да се изчисляват и съхраняват. При всяко едно използване на структурата и създаване на обект извикващия код трябва да се погрижи за правилното настройване на тези дефиниции.

Кода на структурата може да се компилира както под MQL4, така и под MQL5.

Ако имате някакви въпроси относно реализацията или относно практическото приложение на кода, с радост ще ви отговоря.

Mateev
Мнения: 205
Регистриран: 02 окт 2017, 10:04
34 получени
33 дадени

Re: Структура SStatistic

Мнение от Mateev » 28 ное 2017, 16:33

Публикувам новата версия на структурата. В нея са направени следните модификации:
- Добавен е код за съхраняване на FirstTime и LastTime (начално и крайно време на работа на стратегията)
- Добавени са методи за изчисляване на периода от време, през който е правена статистиката
- Добавен е метод Rating(), който изчислява комплексен рейтинг за сравняване на различни стратегии

Метода Rating() изчислява средногодишния ръст на Equity-то, но после го коригира с един КОЕФИЦИЕНТ НА ДОСТОВЕРНОСТ, който коефициент зависи от броя на сделките. Този коефициент представлява сигмоидална функция, която се променя от 0 до 1. При малък брой сделки тя клони към 0, а при голям брой клони към 1. Така стратегиите с по-голям брой сделки ще получат по-голям рейтинг спрямо тези с по-малък брой сделки, дори и те да са по-печеливши.

ПС: Тука vgc може да види каква сигмоидална функция използвам. Пиша го това защото преди няколко дена обсъждахме точно този проблем.

Код: Избери всички

//+------------------------------------------------------------------+
//|                                              StructStatistic.mqh |
//|                                        Copyright 2017, Mateev SC |
//|                                            http://www.mateev.com |
//+------------------------------------------------------------------+

#property copyright "Copyright 2017, Mateev SC"
#property link      "http://www.mateev.com"
#property version   "1.04"
#property strict

//====================================================================
// Посредством тези дефиниции в кода се включват или изключват различни агрегатни функции
// Тези дефиниции се включват в кода на външния клас, който използва тази структура
// За изключване на някоя дефиниция се използва #undef или се коментира дадения ред с #define
#define UseFirstLast // Изчисляват се First и Last
#define UseMinMax    // Изчисляват се Min и Max
#define UseAvg       // Изчислява се средно-аритметичната стойност
#define UseRMS       // Изчислява се средно-квадратичната стойност
#define UseMnH       // Изчислява се средно-хармоничната стойност
#define UseSumMinMax // Изчислява Min и Max на движението на сумата Sum (Min и Max на Equity-то)
#define UseTime      // Помни стойностите на FirstTime и LastTime (начално и крайно време на статистиката)

//====================================================================
// Структура със статистиките (агрегатните функции) на определен брой double числа
//====================================================================

struct SStatistic
  {
    #ifdef UseFirstLast // Да се изчисляват ли First и Last 
      double First;     // 8 байта - Първа стойност
      double Last;      // 8 байта - Последна стойност
    #endif
 
    #ifdef UseMinMax // Да се изчисляват ли Min и Max   
      double Min;    // 8 байта - Минимална  стойност
      double Max;    // 8 байта - Максимална стойност
    #endif

    #ifdef UseAvg // Да се изчислява ли среднo-аритметичната стойност
      double Sum; // 8 байта - Сума на стойностите, образували статистиката   
      double Avg; // 8 байта - Arithmetic mean - Среднo-аритметична стойност
    #endif

    #ifdef UseRMS // Да се изчислява ли среднo-квадратичната стойност 
      double Sm2; // 8 байта - Сума от квадратите на стойностите, образували статисттиката
      double RMS; // 8 байта - Qudraic mean - Среднo-квадратична стойност
    #endif

    #ifdef UseMnH // Да се изчислява ли среднo-хармоничната стойност
      double Sm1; // 8 байта - Сума от 1/стойностите, образували статисттиката     
      double MnH; // 8 байта - Harmonic mean - Средно хармоничнa стойност (броя на числата, разделен на сумата от 1/числото)
    #endif
    
    #ifdef UseSumMinMax // Да се изчисляват ли SumMin и SumMax   
      double SumMin;    // 8 байта - Минимална  стойност на сумата Sum (минимална  стойнст на Equity-то)
      double SumMax;    // 8 байта - Максимална стойност на сумата Sum (максимална стойнст на Equity-то)
    #endif
    
    #ifdef UseTime // Да се запомня ли First и Last Тиме
      datetime FirstTime; // 8 байта - Време на първата стойност в статистиката
      datetime LastTime;  // 8 байта - Време на последната стойност в статистиката
    #endif   
 
    int Count; // 4 байта - Брой на стойностите, образували статистиката (0..2 147 483 647)     
    
    // Методи за манипулация на данните в статистиката
    void Clear(void){ZeroMemory(this);} // Нулира структурата
    void Add  (double value); // Добавяне на стойност в статистиката 
    
    // Методи, свързани с времето, през което е правена статистиката
    #ifdef UseTime // Да се запомня ли First и Last Тиме 
      void   Add(double value, datetime time); // Добавяне на стойност в статистиката, заедно с времето на тази стойност
      double StatSeconds() {return(double(LastTime-FirstTime));} // Връща броя на секундите, в които е правена статистика на стойностите
      double StatDays()    {return(StatSeconds()/86400.0);}      // Връща броя на дните, в които е правена статистика на стойностите
      double StatYears()   {return(StatDays()/365.25);}          // Връща броя на годините, в които е правена статистика на стойностите
      double Rating(int center, int slope); // Изчислява комплексен рейтинг, ако статистиката представлява сделки от дадена стратегия
    #endif  

    // Методи за запис и четене от бинарен файл
    bool Save(const int handle); // Записва структурата във файл
    bool Load(const int handle); // Чете структурата от файл
  };
  
//====================================================================
// Добавяне на стоиност в статистиката  

void SStatistic::Add(double value)
  {
    Count++; // Броя на елементите в статистиката нараства с 1-ца
      
    #ifdef UseFirstLast // Да се изчисляват ли First и Last 
      if (Count==1) First = value; // Ако това е първата добавена стойност, то тя става First.
      Last = value; // Всяка новодобавена стойност автоматично става Last.
    #endif 
          
    #ifdef UseMinMax // Да се изчисляват ли Min и Max стойностите 
      if (Count==1)  // Ако това е първата добавена стойност, то:
        {
          Min = value;
          Max = value;
        }
      else // Ако вече има добавени стойности, то:
        {
          if (Min > value) Min = value;
          if (Max < value) Max = value;
        }
    #endif  
    
    #ifdef UseAvg // Да се изчислява ли среднo-аритметичната стойност    
      Sum = Sum + value;
      Avg = Sum / Count; 
      #ifdef UseSumMinMax // Да се изчисляват ли SumMin и SumMax
        if (Count==1) // Ако това е първата добавена стойност, то:
          {
            SumMin = Sum;
            SumMax = Sum;
          }
        else // Ако вече има добавени стойности, то:
          {
            if (SumMin > Sum) SumMin = Sum;
            if (SumMax < Sum) SumMax = Sum;
          }
      #endif     
    #endif

    #ifdef UseRMS // Да се изчислява ли среднo-квадратичната стойност     
      Sm2 = Sm2 + value*value;       
      RMS = MathSqrt(Sm2/Count);    
    #endif

    #ifdef UseMnH // Да се изчислява ли среднo-хармоничната стойност      
      if(value!=0) Sm1 = Sm1 + 1.0/value;
      if(Sm1==0) MnH=0; else MnH = double(Count)/Sm1;
    #endif      
  }
  
//====================================================================
// Добавяне на стойност в статистиката, заедно с времето на тази стойност   
#ifdef UseTime // Да се запомня ли First и Last Тиме 
void SStatistic::Add(double value, datetime time)
  {
    Add(value); // Добавяне на стойноста без информация за времето
    if (Count==1) // Ако това е първата добавена стойност, то:
      {
        FirstTime = time;
        LastTime  = time;
      }
    else // Ако вече има добавени стойности, то:
      {
        LastTime  = time;
      }
  }
 
//====================================================================
// Изчислява и връща комплексен рейтинг, ако статистиката се използва за сделките на дадена стратегия
// Рейтинга представлява средногодишния ръст на капитала в проценти,
// който е коригиран надолу с коефициент на редукция, отчитащ ниската достоверност поради малък брой сделки.
// Коефициента на редукция е сигмоидална функция от броя на сделките и се изменя от 0 до 1.
// Параметъра center указва какъв е броя на сделките, при който коефициента на редукция приема стойност 0.5.
// Параметъра slope указва наклона на сигмоидалната функция. Препоръчителни стойности между 2 (полегат наклон) и 10 (стръмен наклон).

double SStatistic::Rating(int center, int slope)
  {
    // Изчисляване на сигмоидална функция в зависимост от броя на сделките (променя се от 0 до 1)
    // При брой на сделките, равен на center, приема стойност 0.5.
    // При по-малко от center сделки клони към 0.
    // При по-много от center сделки клони към 1.
    // Параметъра slope указва наклона на сигмоидалната функция.
    // Препоръчителните стойности за параметъра slope са между 2 (полегат наклон) и 10 (стръмен наклон).
    // Най-добри резултати се получават при center = 100 сделки и slope = 5, но това може да се развърти с оптимизации.
    double koeficient = slope / center;
    double sigmoid = 1.0 / (1.0 + MathExp(-koeficient * (Count - center)));
    
    // Изчисляване на средногодишния ръст на печалбата от една стратегия.
    // Ако статистиката е заредена с проценти на нарастване, то и резултата ще се получи в проценти.
    // Ако статистиката е заредена с абсолютни стойности на печалбите/загубите, то и резултата ще се получи в абсолютни стойности.
    double yearlyPL = Sum / StatYears();
    
    // Връща рейтинг, който представлява средногодищния ръст, коригиран с коефициента на достоверност, зависещ от броя на сделките.
    return(yearlyPL*sigmoid);
  }
#endif 

//====================================================================
// Записва структурата във файл
 
bool SStatistic::Save(const int handle)
  {
    if (handle==INVALID_HANDLE) return(false);
    else return(FileWriteStruct(handle,this,sizeof(SStatistic))==sizeof(SStatistic));
  } 

//====================================================================
// Чете структурата от файл

bool SStatistic::Load(const int handle)
  {
    if (handle==INVALID_HANDLE) return(false);
    else return(FileReadStruct(handle,this,sizeof(SStatistic))==sizeof(SStatistic));
  }

/*====================================================================
----------------------- ИСТОРИЯ НА ВЕРСИИТЕ --------------------------
======================================================================

24.11.2017 - v.1.003
  - Структурата е копирана от моя библиотека на MQL4 и е пригодена за нуждите на експерта AITW
  - Посредством #define е създадена възможност за включване в кода на различни агрегатни функции
  - Добавен е код за изчисляване на Fisrt и Last
  
28.11.2017 - v.1.004
  - Поправен e бъг при изчисляването на средно-хармоничната стойност MnH
  - Добавен е код за изчисляване на SumMin и SumMax (минимална и максимална стойност на Equity-то)
  - Добавен е код за съхраняване на FirstTime и LastTime
  - Добавени са методи за изчисляване на времето, през което е правена статистиката
  - Добавен е метод Rating(), който изчислява комплексен рейтинг за сравняване на различни стратегии

====================================================================*/    

Отговори

Върни се в “Mateev”

Кой е на линия

Потребители, разглеждащи този форум: Няма регистрирани потребители и 2 госта