Алгоритм расчёта просадки, или Самостоятельная оценка результатов тестирования эксперта - страница 2

 

Да еще и каждый отчет весит метр семьдесят. Судя по содержимому пользуют какой-то микрософтовский компонент, который как всегда отличается тем, что генерит кучу никому не нужного мусора. А сколько их будет в режиме оптимизации?!!

 
TedBeer:

А сколько их будет в режиме оптимизации?!!


Вопрос в том, что всего один. По окончании работы оптимизатора. А нужно столько, столько тестов прошло в нём. Если 500 тестов, то 500 отчётов. Каждому прогону теста должен соответствовать файл, тест же был, где его результат?

Прошу разработчиков MetaQuotes подключиться к ответу. Думаю, расчёт просадки из кода интересен не только мне одному. Многие оценивают работу экспертов по множеству показателей, просадка и прибыль - основные из них.
 
А если просто прицепить в deinit() функцию расчета и вывода в файл из скрипта в статье Самостоятельная оценка результатов тестирования эксперта ?
 
Rosh:
А если просто прицепить в deinit() функцию расчета и вывода в файл из скрипта в статье Самостоятельная оценка результатов тестирования эксперта ?
Даже я, просматривая тему по диагонали, понял, что надо просадка по эквити.
ВнимательнЕе надо ;)
 
А если еще внимательнее читать, то я давал уже скрипт для расчета просадки по эквити. Тщительнее надо, не по диагонали.
 
Rosh:
А если еще внимательнее читать, то я давал уже скрипт для расчета просадки по эквити. Тщительнее надо, не по диагонали.
chv 23.12.2007 23:39

Уважаемый Рашид, снова возвращаюсь к этой теме после тестов.

По результатам темы был собран файл SummaryReport.mq4 из кода первоначального SummaryReport.mq4 С. Старикова и кода темы Скрипт для расчета MAE и MFE.
Тесты показали, что чаще всего новый скрипт считает просадку чуть жёстче, чем показатели терминала в закладке Отчёт (что подходит). Однако не всегда, были тесты эксперта на M5 GBPJPY, на которых терминал показал раза в два большую просадку, чем выдал скрипт.
Кто-то из нас неправ ;)
 
komposter, автопилота включил? Неужели необходимо все разжевывать? :)
Уже упоминалось, что указанный срикпт SummaryReport.mq4 не считает просадку по эквити, и кроме того, не делает сортировку по времени закрытия. Я показал вариант, как это обойти своим скриптом -  скрипт для расчета MAE и MFE - на который уже давал два раза ссылку в этой ветке. Скрещиваешь все необходимые алгоритмы в одну функцию, делаешь в ней вывод значений в файл, и вставляешь ее в deinit().
 
"Молчу, молчу, а то по морде получу, и подвиг свой не совершу. .. " (с)
Не в тему влез, каюсь ;)
 

Рашид, скажите, пожалуйста, верно ли я использую Ваш скрипт MAE_MFE_DrawDowns.mq4?

1. Все декларации и функции из него я добавил в SummaryReport.mq4.
2. Взамен функции void CalculateSummary(double initial_deposit) из старого SummaryReport.mq4 тот код, которы был в start() из MAE_MFE_DrawDowns.mq4, добавил и сохранил в новую функцию в новый единый SummaryReport.mq4:

// start: added by CHV, 25.12.2007
void CalculateSummary2()
{
  int ClosedOrders, CancelledOrders;      // количество открытых и отмененных ордеров
  int ClosedTickets[],CancelledTickets[]; // масивы, содержащие тикеты закрытых и отмененных ордеров
  int AllOpenedOrdersTickets[];           // массив заркытых ордеров из истории + текущие незакрытые ордера
  string Symbols[];                       // массив, в котором хранятся имена символов, по которым были сделки
  double Swaps[];                         // собственно, свопы
  double Profits[],NormalizedProfits[];   // массивы, хранящие изначальные профиты и нормализованные к 0.1 лоту
  double MFE[];                           // массив, содержащий данные о максимальной потенциальной прибыли для каждого ордера
  double MAE[];                           // массив, содержащий данные о максимальной просадке для каждого ордера
  double AccountDetails[][9]; 
  double MinimalEquity;                   // минимальное историческое значение Эквити
  double MoneyDrawDown;                   // максимальная денежная просадка
  double MoneyDrawDownInPercent;          // процентное выражение для максимальной денежной просадки
  double RelativeDrawDown;                // максимальная процентная просадка
  double RelativeDrawDownInMoney;         // денежное выражение максимальной процентной просадки
 
//----
   
   if (!GetNumberOfOrders(ClosedOrders, CancelledOrders,Symbols))
      {
      Print("Ордера в истории не найдены, обработка прекращена");
      }
 
   ArrayResize(ClosedTickets,ClosedOrders);
   ArrayResize(CancelledTickets,CancelledOrders);
   ArrayResize(AccountDetails,ClosedOrders);
   ArrayResize(Swaps ,ClosedOrders);
  
   LoadSortedTickets(ClosedTickets);
   FillOrderProfits(Profits,NormalizedProfits,Swaps,ClosedTickets);
      
   if (CheckHistoryOnClosedOrders(ClosedTickets,Symbols))   // проверим на наличие дыр в истории
      {
      SetMAEAndMFE(MFE,MAE,ClosedTickets);                  // и если дыр нет - заполним MAE и MFE
      //WriteMAE_MFE(MFE,MAE,ClosedTickets,"MAE_MFE_reports\\"+AccountNumber()+"_MAE_MFE.csv");
      }
   else return;
   
//   CalculateDD(ClosedTickets,Symbols,MinimalEquity,MoneyDrawDown,MoneyDrawDownInPercent,RelativeDrawDown,RelativeDrawDownInMoney);
   CalculateDD(ClosedTickets,Symbols,MinimalEquity
      ,/*MoneyDrawDown*/MaxDrawdown
      ,/*MoneyDrawDownInPercent*/MaxDrawdownPercent
      ,/*RelativeDrawDown*/RelDrawdownPercent
      ,/*RelativeDrawDownInMoney*/RelDrawdown);
   Print("AbsDD=",10000-MinimalEquity," MoneyDrawDown=",MoneyDrawDown,"  MoneyDrawDownInPercent=",MoneyDrawDownInPercent,
      "  RelativeDrawDown=",RelativeDrawDown," RelativeDrawDownInMoney=",RelativeDrawDownInMoney);
//----
   //return(0);
}
// end: added by CHV, 25.12.2007

Декларации переменных остались из старого SummaryReport.mq4, в них и помещены результаты, вместо заремленных локальных переменных (MoneyDrawDown, MoneyDrawDownInPercent и т.д.)

 

//+------------------------------------------------------------------+
//|                                                SummaryReport.mq4 |
//|                 Copyright © 2006/2007, MetaQuotes Software Corp. |
//|                                        https://www.metaquotes.net/ |
//| Edited by CHV, 25.12.2007                                        |
//+------------------------------------------------------------------+
#define OP_BALANCE 6
#define OP_CREDIT  7
 
double InitialDeposit;
double SummaryProfit;
double GrossProfit;
double GrossLoss;
double MaxProfit;
double MinProfit;
double ConProfit1;
double ConProfit2;
double ConLoss1;
double ConLoss2;
double MaxLoss;
double MaxDrawdown;
double MaxDrawdownPercent;
double RelDrawdownPercent;
double RelDrawdown;
double ExpectedPayoff;
double ProfitFactor;
double AbsoluteDrawdown;
int    SummaryTrades;
int    ProfitTrades;
int    LossTrades;
int    ShortTrades;
int    LongTrades;
int    WinShortTrades;
int    WinLongTrades;
int    ConProfitTrades1;
int    ConProfitTrades2;
int    ConLossTrades1;
int    ConLossTrades2;
int    AvgConWinners;
int    AvgConLosers;

добавил CalculateSummary2() в новый SummaryReport.mq4. И в эксперте-клиенте вызов в deinit() сделал вызов:

      //CalculateSummary(ExtInitialDeposit);
      CalculateSummary2(); // try new code

Затем сделал вызов эксперта в тестере. Результаты были сохранены в XML файл и сравнены с показателями эксперта.

Видно, что показания по просадке не сходятся, и в терминале максимальная просадка выше, чем в расчётном XML.

Если же я в эксперте в deinit() возвращаю вызов старой CalculateSummary():

      CalculateSummary(ExtInitialDeposit); // call old code
      //CalculateSummary2(); // try new code

То показатели получаются более правдоподобными, но всё же отличными от терминала, и зачастую сильно разнятся с ним, в этом и вопрос.

Может быть, именно я в сугубо извращённой форме использую Ваш код скрипта MAE_MFE_DrawDowns.mq4 совместно с SummaryReport.mq4 по расчёту просадки и других показателей? Честно, не догоняю, как его эксплуатировать совместно с кодом эксперта.
Помогите, пожалуйста, примером.

 
Не могу сказать. Я превратил тот скрипт в простой инклюдник простым переименованием функции start() в startCalculate():

   
//+------------------------------------------------------------------+
//| script program start function                                    |
//+------------------------------------------------------------------+
int startCalculate()
  {
  int ClosedOrders, CancelledOrders;      // количество открытых и отмененных ордеров
  int ClosedTickets[],CancelledTickets[]; // масивы, содержащие тикеты закрытых и отмененных ордеров
  int AllOpenedOrdersTickets[];           // массив заркытых ордеров из истории + текущие незакрытые ордера
  string Symbols[];                       // массив, в котором хранятся имена символов, по которым были сделки
  double Swaps[];                         // собственно, свопы
  double Profits[],NormalizedProfits[];   // массивы, хранящие изначальные профиты и нормализованные к 0.1 лоту
  double MFE[];                           // массив, содержащий данные о максимальной потенциальной прибыли для каждого ордера
  double MAE[];                           // массив, содержащий данные о максимальной просадке для каждого ордера
  double AccountDetails[][9]; 
  double MinimalEquity;                   // минимальное историческое значение Эквити
  double MoneyDrawDown;                   // максимальная денежная просадка
  double MoneyDrawDownInPercent;          // процентное выражение для максимальной денежной просадки
  double RelativeDrawDown;                // максимальная процентная просадка
  double RelativeDrawDownInMoney;         // денежное выражение максимальной процентной просадки
 
//----
   
   if (!GetNumberOfOrders(ClosedOrders, CancelledOrders,Symbols))
      {
      Print("Ордера в истории не найдены, обработка прекращена");
      }
 
   ArrayResize(ClosedTickets,ClosedOrders);
   ArrayResize(CancelledTickets,CancelledOrders);
   ArrayResize(AccountDetails,ClosedOrders);
   ArrayResize(Swaps ,ClosedOrders);
  
   LoadSortedTickets(ClosedTickets);
   FillOrderProfits(Profits,NormalizedProfits,Swaps,ClosedTickets);
      
   if (CheckHistoryOnClosedOrders(ClosedTickets,Symbols))   // проверим на наличие дыр в истории
      {
      SetMAEAndMFE(MFE,MAE,ClosedTickets);                  // и если дыр нет - заполним MAE и MFE
      WriteMAE_MFE(MFE,MAE,ClosedTickets,"MAE_MFE_reports\\"+AccountNumber()+"_MAE_MFE.csv");
      }
   else return;
   
   CalculateDD(ClosedTickets,Symbols,MinimalEquity,MoneyDrawDown,MoneyDrawDownInPercent,RelativeDrawDown,RelativeDrawDownInMoney);
   Print("AbsDD=",10000-MinimalEquity," MoneyDrawDown=",MoneyDrawDown,"  MoneyDrawDownInPercent=",MoneyDrawDownInPercent,
      "  RelativeDrawDown=",RelativeDrawDown," RelativeDrawDownInMoney=",RelativeDrawDownInMoney);
//----
   return(0);
  }
//+------------------------------------------------------------------+
положил инклюдник в нужную директорию, а в deinit() просто добавил вызов этой функции в deinit()
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
   {
   if (IsTesting()&&!IsOptimization())
      {
      startCalculate(); // вывод результатов бектеста
      }
   return(0);
   }
Причина обращения: