English 中文 Español Deutsch 日本語 Português 한국어 Français Italiano Türkçe
Рецепты MQL5 - Записываем историю сделок в файл и строим графики балансов для каждого символа в Excel

Рецепты MQL5 - Записываем историю сделок в файл и строим графики балансов для каждого символа в Excel

MetaTrader 5Примеры | 16 июля 2013, 13:31
9 583 12
Anatoli Kazharski
Anatoli Kazharski

Введение

Общаясь на многих форумах, я довольно часто приводил в пример результаты тестов на скриншотах с графиков в Microsoft Excel. И многие просили меня объяснить, как же строить эти замечательные графики. Возможности построения диаграмм в Excel очень обширны, и по этой теме написано множество книг. В книге так сложно бывает что-то найти, что приходиться читать ее всю. Но, наконец-то, у меня появилось немного времени, чтобы написать статью об этом.

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

Поэтому сегодня я покажу простой способ, как можно в пару кликов получать одновременно графики всех балансов символов и совокупный результат мультивалютного эксперта на одной диаграмме в Excel. Для воспроизведения примера возьмем мультивалютного эксперта из предыдущей статьи и добавим в него функцию, которая будет по окончании теста записывать в CSV-файл историю сделок и кривые балансов всех символов по отдельности. Кроме того, добавим в отчет еще один столбец, в котором будут содержаться просадки депозита от всех локальных максимумов.

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


Процесс разработки эксперта

Особых изменений в эксперте не будет, всего лишь добавим несколько функций. Начнем с того, что в главный файл добавим структуру и массив для балансов символов.

//--- Массивы для балансов
struct Balance
  {
   double            balance[];
  };
//--- Массив балансов всех символов
Balance symbol_balance[];

Далее для функций, которые будут готовить отчеты тестов, создадим отдельный подключаемый файл Report.mqh и подключим его к основному файлу эксперта (выделенная строка в коде ниже):

//--- Подключаем свои библиотеки
#include "Include/Auxiliary.mqh"
#include "Include/Enums.mqh"
#include "Include/Errors.mqh"
#include "Include/FileFunctions.mqh"
#include "Include/InitializeArrays.mqh"
#include "Include/Report.mqh"
#include "Include/ToString.mqh"
#include "Include/TradeFunctions.mqh"
#include "Include/TradeSignals.mqh"

В первую очередь создадим структуру свойств сделок подобно тем, которые сейчас уже есть в проекте для свойств позиции и свойств символов. Для этого в файл Enums.mqh добавим перечисление идентификаторов свойств:

//+------------------------------------------------------------------+
//| Перечисление свойств сделки                                      |
//+------------------------------------------------------------------+
enum ENUM_DEAL_PROPERTIES
  {
   D_SYMBOL     = 0, // Имя символа, по которому произведена сделка
   D_COMMENT    = 1, // Комментарий к сделке
   D_TYPE       = 2, // Тип сделки
   D_ENTRY      = 3, // Направление сделки – вход в рынок, выход из рынка или разворот
   D_PRICE      = 4, // Цена сделки
   D_PROFIT     = 5, // Финансовый результат сделки (прибыль/убыток)
   D_VOLUME     = 6, // Объем сделки
   D_SWAP       = 7, // Накопленный своп при закрытии
   D_COMMISSION = 8, // Комиссия по сделке
   D_TIME       = 9, // Время совершения сделки
   D_ALL        = 10 // Все вышеперечисленные свойства сделки
  };

Затем в файле Report.mqh создадим структуру свойств сделки и функцию GetHistoryDealProperties(), которая возвращает свойство сделки. Функция принимает два параметра: тикет сделки и идентификатор свойства.

Ниже можно посмотреть код структуры и функции GetHistoryDealProperties():

//--- Свойства сделок в истории
struct HistoryDealProperties
  {
   string            symbol;     // Символ
   string            comment;    // Комментарий
   ENUM_DEAL_TYPE    type;       // Тип сделки
   ENUM_DEAL_ENTRY   entry;      // Направление
   double            price;      // Цена
   double            profit;     // Прибыль/убыток
   double            volume;     // Объем
   double            swap;       // Своп
   double            commission; // Комиссия
   datetime          time;       // Время
  };
//--- Переменная свойств сделки
HistoryDealProperties  deal;
//+------------------------------------------------------------------+
//| Получает свойства сделки по тикету                               |
//+------------------------------------------------------------------+
void GetHistoryDealProperties(ulong ticket_number,ENUM_DEAL_PROPERTIES history_deal_property)
  {
   switch(history_deal_property)
     {
      case D_SYMBOL     : deal.symbol=HistoryDealGetString(ticket_number,DEAL_SYMBOL);                 break;
      case D_COMMENT    : deal.comment=HistoryDealGetString(ticket_number,DEAL_COMMENT);               break;
      case D_TYPE       : deal.type=(ENUM_DEAL_TYPE)HistoryDealGetInteger(ticket_number,DEAL_TYPE);    break;
      case D_ENTRY      : deal.entry=(ENUM_DEAL_ENTRY)HistoryDealGetInteger(ticket_number,DEAL_ENTRY); break;
      case D_PRICE      : deal.price=HistoryDealGetDouble(ticket_number,DEAL_PRICE);                   break;
      case D_PROFIT     : deal.profit=HistoryDealGetDouble(ticket_number,DEAL_PROFIT);                 break;
      case D_VOLUME     : deal.volume=HistoryDealGetDouble(ticket_number,DEAL_VOLUME);                 break;
      case D_SWAP       : deal.swap=HistoryDealGetDouble(ticket_number,DEAL_SWAP);                     break;
      case D_COMMISSION : deal.commission=HistoryDealGetDouble(ticket_number,DEAL_COMMISSION);         break;
      case D_TIME       : deal.time=(datetime)HistoryDealGetInteger(ticket_number,DEAL_TIME);          break;
      case D_ALL        :
         deal.symbol=HistoryDealGetString(ticket_number,DEAL_SYMBOL);
         deal.comment=HistoryDealGetString(ticket_number,DEAL_COMMENT);
         deal.type=(ENUM_DEAL_TYPE)HistoryDealGetInteger(ticket_number,DEAL_TYPE);
         deal.entry=(ENUM_DEAL_ENTRY)HistoryDealGetInteger(ticket_number,DEAL_ENTRY);
         deal.price=HistoryDealGetDouble(ticket_number,DEAL_PRICE);
         deal.profit=HistoryDealGetDouble(ticket_number,DEAL_PROFIT);
         deal.volume=HistoryDealGetDouble(ticket_number,DEAL_VOLUME);
         deal.swap=HistoryDealGetDouble(ticket_number,DEAL_SWAP);
         deal.commission=HistoryDealGetDouble(ticket_number,DEAL_COMMISSION);
         deal.time=(datetime)HistoryDealGetInteger(ticket_number,DEAL_TIME);                           break;
         //---
      default: Print("Переданное свойство сделки не учтено в перечислении!");                          return;
     }
  }

Еще нам понадобится несколько функций, которые преобразуют некоторые свойства сделок в строковые значения. Эти простые функции возвращают строковое значение или прочерк ("-"), если переданное значение пустое или нулевое. Напишем их в файле ToString.mqh:

//+------------------------------------------------------------------+
//| Возвращает имя символа, иначе прочерк                            |
//+------------------------------------------------------------------+
string DealSymbolToString(string deal_symbol)
  {
   return(deal_symbol=="" ? "-" : deal_symbol);
  }
//+------------------------------------------------------------------+
//| Преобразует тип сделки в строку                                  |
//+------------------------------------------------------------------+
string DealTypeToString(ENUM_DEAL_TYPE deal_type)
  {
   string str="";
//---
   switch(deal_type)
     {
      case DEAL_TYPE_BUY                      : str="buy";                      break;
      case DEAL_TYPE_SELL                     : str="sell";                     break;
      case DEAL_TYPE_BALANCE                  : str="balance";                  break;
      case DEAL_TYPE_CREDIT                   : str="credit";                   break;
      case DEAL_TYPE_CHARGE                   : str="charge";                   break;
      case DEAL_TYPE_CORRECTION               : str="correction";               break;
      case DEAL_TYPE_BONUS                    : str="bonus";                    break;
      case DEAL_TYPE_COMMISSION               : str="commission";               break;
      case DEAL_TYPE_COMMISSION_DAILY         : str="commission daily";         break;
      case DEAL_TYPE_COMMISSION_MONTHLY       : str="commission monthly";       break;
      case DEAL_TYPE_COMMISSION_AGENT_DAILY   : str="commission agent daily";   break;
      case DEAL_TYPE_COMMISSION_AGENT_MONTHLY : str="commission agent monthly"; break;
      case DEAL_TYPE_INTEREST                 : str="interest";                 break;
      case DEAL_TYPE_BUY_CANCELED             : str="buy canceled";             break;
      case DEAL_TYPE_SELL_CANCELED            : str="sell canceled";            break;
      //--- Неизвестный тип сделки
      default : str="unknown";
     }
//---
   return(str);
  }
//+------------------------------------------------------------------+
//| Преобразует направление сделки в строку                          |
//+------------------------------------------------------------------+
string DealEntryToString(ENUM_DEAL_ENTRY deal_entry)
  {
   string str="";
//---
   switch(deal_entry)
     {
      case DEAL_ENTRY_IN    : str="in";            break;
      case DEAL_ENTRY_OUT   : str="out";           break;
      case DEAL_ENTRY_INOUT : str="in/out";        break;
      case DEAL_ENTRY_STATE : str="status record"; break;
      //--- Неизвестный тип направления
      default : str="unknown";
     }
//---
   return(str);
  }
//+------------------------------------------------------------------+
//| Преобразует объем в строку                                       |
//+------------------------------------------------------------------+
string DealVolumeToString(double deal_volume)
  {
   return(deal_volume<=0 ? "-" : DoubleToString(deal_volume,2));
  }
//+------------------------------------------------------------------+
//| Преобразует цену в строку                                        |
//+------------------------------------------------------------------+
string DealPriceToString(double deal_price,int digits)
  {
   return(deal_price<=0 ? "-" : DoubleToString(deal_price,digits));
  }
//+------------------------------------------------------------------+
//| Преобразует результат сделки в строку                            |
//+------------------------------------------------------------------+
string DealProfitToString(string deal_symbol,double deal_profit)
  {
   return((deal_profit==0 || deal_symbol=="") ? "-" : DoubleToString(deal_profit,2));
  }
//+------------------------------------------------------------------+
//| Преобразует своп в строку                                        |
//+------------------------------------------------------------------+
string DealSwapToString(double deal_swap)
  {
   return(deal_swap<=0 ? "-" : DoubleToString(deal_swap,2));
  }

Теперь все готово для написания функции CreateSymbolBalanceReport(), которая подготавливает данные для отчета и затем записывает их в файл LastTest.csv в общей папке терминала. Все довольно просто: сначала записывается заголовок (обратите внимание, как дополняется строка, если в тесте участвовало более одного символа), затем в цикле последовательно собирается строка с нужными свойствами сделки для отчета, после чего производится запись в файл.

Ниже представлен код этой функции CreateSymbolBalanceReport():

//+------------------------------------------------------------------+
//| Создает отчет тестирования по сделкам в формате CSV              |
//+------------------------------------------------------------------+
void CreateSymbolBalanceReport()
  {
   int    file_handle =INVALID_HANDLE; // Хэндл файла
   string path        ="";             // Путь к файлу

//--- Если ошибка при создании/получении директории, выходим
   if((path=CreateInputParametersFolder())=="")
      return;
//--- Создадим файл для записи данных в общей папке терминала
   file_handle=FileOpen(path+"\\LastTest.csv",FILE_CSV|FILE_WRITE|FILE_ANSI|FILE_COMMON);
//--- Если хэндл валиден (файл создался/открылся)
   if(file_handle>0)
     {
      int    digits          =0;   // Количество знаков в цене после запятой
      int    deals_total     =0;   // Количество сделок выбранной истории
      ulong  ticket          =0;   // Тикет сделки
      double drawdown_max    =0.0; // Максимальная просадка
      double balance         =0.0; // Баланс
      //---
      string delimeter       =","; // Разделитель
      string string_to_write ="";  // Для формирования строки для записи

      //--- Сформируем строку заголовков
      string headers="TIME,SYMBOL,DEAL TYPE,ENTRY TYPE,VOLUME,PRICE,SWAP($),PROFIT($),DRAWDOWN(%),BALANCE";
      //--- Если участвует больше одного символа, то дополним строку заголовков
      if(SYMBOLS_COUNT>1)
        {
         for(int s=0; s<SYMBOLS_COUNT; s++)
            StringAdd(headers,","+InputSymbols[s]);
        }
      //--- Запишем заголовки отчета
      FileWrite(file_handle,headers);
      //--- Получим всю историю
      HistorySelect(0,TimeCurrent());
      //--- Узнаем количество сделок
      deals_total=HistoryDealsTotal();
      //--- Установим размер массива балансов по кол-ву символов
      ArrayResize(symbol_balance,SYMBOLS_COUNT);
      //--- Установим размер массивов сделок для каждого символа
      for(int s=0; s<SYMBOLS_COUNT; s++)
         ArrayResize(symbol_balance[s].balance,deals_total);
      //--- Пройдемся в цикле и запишем данные
      for(int i=0; i<deals_total; i++)
        {
         //--- Получим тикет сделки
         ticket=HistoryDealGetTicket(i);
         //--- Получим все свойства сделки
         GetHistoryDealProperties(ticket,D_ALL);
         //--- Узнаем кол-во знаков в цене
         digits=(int)SymbolInfoInteger(deal.symbol,SYMBOL_DIGITS);
         //--- Посчитаем общий баланс
         balance+=deal.profit+deal.swap+deal.commission;
         //--- Сформируем строку для записи путем конкатенации
         StringConcatenate(string_to_write,
                           deal.time,delimeter,
                           DealSymbolToString(deal.symbol),delimeter,
                           DealTypeToString(deal.type),delimeter,
                           DealEntryToString(deal.entry),delimeter,
                           DealVolumeToString(deal.volume),delimeter,
                           DealPriceToString(deal.price,digits),delimeter,
                           DealSwapToString(deal.swap),delimeter,
                           DealProfitToString(deal.symbol,deal.profit),delimeter,
                           MaxDrawdownToString(i,balance,max_drawdown),delimeter,
                           DoubleToString(balance,2));

         //--- Если участвует больше одного символа, то запишем значения их баланса
         if(SYMBOLS_COUNT>1)
           {
            //--- Пройдемся по всем символам
            for(int s=0; s<SYMBOLS_COUNT; s++)
              {
               //--- Если символы равны и результат сделки ненулевой
               if(deal.symbol==InputSymbols[s] && deal.profit!=0)
                 {
                  //--- Отразим сделку в балансе с этим символом
                  //    Учтем своп и комиссию
                  symbol_balance[s].balance[i]=symbol_balance[s].balance[i-1]+
                                               deal.profit+
                                               deal.swap+
                                               deal.commission;
                  //--- Добавим к строке
                  StringAdd(string_to_write,","+DoubleToString(symbol_balance[s].balance[i],2));
                 }
               //--- Иначе запишем предыдущее значение
               else
                 {
                  //--- Если тип сделки "Начисление баланса" (первая сделка)
                  if(deal.type==DEAL_TYPE_BALANCE)
                    {
                     //--- для всех символов баланс одинаковый
                     symbol_balance[s].balance[i]=balance;
                     StringAdd(string_to_write,","+DoubleToString(symbol_balance[s].balance[i],2));
                    }
                  //--- Иначе запишем предыдущее значение в текущий индекс
                  else
                    {
                     symbol_balance[s].balance[i]=symbol_balance[s].balance[i-1];
                     StringAdd(string_to_write,","+DoubleToString(symbol_balance[s].balance[i],2));
                    }
                 }
              }
           }
         //--- Запишем сформированную строку
         FileWrite(file_handle,string_to_write);
         //--- Обязательное обнуление переменной для следующей строки
         string_to_write="";
        }
      //--- Закроем файл
      FileClose(file_handle);
     }
//--- Если файл не создался/открылся, выведем сообщение
   else
      Print("Ошибка создания файла: "+IntegerToString(GetLastError())+"");
  }

В коде выше в выделенной строке функция MaxDrawdownToString() рассчитывает все просадки от локальных максимумов и возвращает строковое представление времени появления нового локального максимума. Во всех остальных случаях функция возвращает строку "-" (прочерк).

//+------------------------------------------------------------------+
//| Возвращает максимальную просадку от локального максимума         |
//+------------------------------------------------------------------+
string MaxDrawdownToString(int deal_number,double balance,double &max_drawdown)
  {
//--- Строка для отображения в отчете
   string str="";
//--- Для расчета локального максимума и просадки
   static double max=0.0;
   static double min=0.0;
//--- Если первая сделка
   if(deal_number==0)
     {
      //--- Просадки еще нет
      max_drawdown=0.0;
      //--- Зададим начальную точку, как локальный максимум
      max=balance;
      min=balance;
     }
   else
     {
      //--- Если текущий баланс больше, чем в памяти
      if(balance>max)
        {
         //--- посчитаем просадку по предыдущим значениям
         max_drawdown=100-((min/max)*100);
         //--- обновим локальный максимум
         max=balance;
         min=balance;
        }
      else
        {
         //--- Возвратим нулевое значение просадки
         max_drawdown=0.0;
         //--- Обновим минимум
         min=fmin(min,balance);
        }
     }
//--- Определим строку для отчета
   if(max_drawdown==0)
      str="-";
   else
      str=DoubleToString(max_drawdown,2);
//--- Вернем результат
   return(str);
  }

Все функции для формирования отчета готовы. Осталось только разобраться, как это нужно использовать. А для этого понадобится функция OnTester(), которая вызывается по окончании тестирования. Обязательно прочитайте подробное описание этой функции.

В теле функции OnTester() нужно написать всего лишь пару строчек кода, чтобы указать программе, в каком случае следует формировать отчет. Ниже показан этот фрагмент кода:

//+------------------------------------------------------------------+
//| Обработчик события окончания тестирования                        |
//+------------------------------------------------------------------+
double OnTester()
  {
//--- Отчет записываем только после теста
   if(IsTester() && !IsOptimization() && !IsVisualMode())
      //--- Формирование отчета и запись в файл
      CreateSymbolBalanceReport();
//---
   return(0.0);
  }

Теперь, если запустить эксперта в тестере, по окончании теста будет создана папка эксперта в общей папке терминала в директории C:\ProgramData\MetaQuotes\Terminal\Common\Files, а в папке эксперта будет создан файл отчета LastTest.csv. Если открыть файл в Блокноте, то можно увидеть примерно такие записи:

Рис. 1. Файл отчета в формате CSV

Рис. 1. Файл отчета в формате CSV.

Строим графики в Excel

Созданный файл можно открыть в Excel: каждый тип данных будет расположен в отдельном столбце, что намного удобнее для просмотра. Можно построить графики уже сейчас и сохранить файл как книгу Excel в формате *.xlsx, но если затем провести тест и открыть книгу снова, мы увидим старые данные.

Если же попытаться обновить данные, когда в Excel загружен файл LastTest.csv, то файл также не обновится, так как эксперт не сможет открыть его для записи, когда он занят другим приложением.

Рис. 2. Файл отчета в формате CSV в Excel 2010

Рис. 2. Файл отчета в формате CSV в Excel 2010.

Для нашего случая есть решение. Сначала создайте и сохраните книгу Excel в формате *.xlsx в любом удобном для вас месте. После этого откройте ее и перейдите на вкладку Данные.

Рис. 3. Вкладка "Данные" в Excel 2010

Рис. 3. Вкладка "Данные" в Excel 2010.

На ленте этой вкладки выберите опцию Из текста. Открывается окно Импорт текстового файла, в котором нужно указать файл "LastTest.csv". Выделяем файл и нажимаем кнопку Открыть, после чего перед нами откроется окно Мастер текстов (импорт) - шаг 1 из 3:

Рис. 4. Окно "Мастер текстов (импорт) - шаг 1 из 3"

Рис. 4. Окно "Мастер текстов (импорт) - шаг 1 из 3".

Установите настройки так, как показано выше, и нажмите кнопку Далее >. На следующем шаге (2 из 3) нужно указать, какой разделитель используется в файле данных. В нашем файле это запятая ",".

Рис. 5. Окно "Мастер текстов (импорт) - шаг 2 из 3"

Рис. 5. Окно "Мастер текстов (импорт) - шаг 2 из 3".

Перейдите к следующему шагу (3 из 3), нажав кнопку Далее >. В этом диалоговом окне оставьте для всех столбцов формат Общий. Формат можно будет изменить позже.

Рис. 6. Окно "Мастер текстов (импорт) - шаг 3 из 3"

Рис. 6. Окно "Мастер текстов (импорт) - шаг 3 из 3".

После нажатия кнопки Готово откроется диалоговое окно Импорт данных, в котором будет предложено выбрать лист и ячейку для импорта данных.

Рис. 7. Выбор ячейки для импорта данных в Excel 2010

Рис. 7. Выбор ячейки для импорта данных в Excel 2010.

Обычно нужно выбрать левую верхнюю ячейку A1. Прежде чем нажать кнопку OK, сначала нажмите кнопку Свойства... для настройки свойств внешнего диапазона. Откроется диалоговое окно, как показано на рисунке ниже.

Рис. 8. Свойства внешнего диапазона при импорте данных их текста в Excel 2010

Рис. 8. Свойства внешнего диапазона при импорте данных их текста в Excel 2010.

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

В итоге вы увидите данные в том же виде, как если бы вы просто загрузили файл в формате CSV. Но теперь вы можете многократно проводить тест в MetaTrader 5, не закрывая книгу Excel. Все, что нужно сделать после теста - просто обновить данные нажатием горячих клавиш Ctrl+Alt+F5 или кнопки Обновить все на ленте вкладки Данные.

С помощью опций раздела Условное форматирование на ленте вкладки Главная можно настроить более наглядное представление данных.

Рис. 9. Условное форматирование данных в Excel 2010

Рис. 9. Условное форматирование данных в Excel 2010.

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

Сначала создадим диаграмму для графиков балансов. Выделите заголовки всех балансов и весь массив данных вниз до конца (удерживая клавишу Shift, нажмите сначала клавишу End, а затем Стрелка вниз). Теперь на вкладке Вставка нужно выбрать тип диаграммы для отображения данных:

Рис. 10. Выбор типа диаграммы в Excel 2010

Рис. 10. Выбор типа диаграммы в Excel 2010.

Будет создана диаграмма, которую для удобства лучше перенести на другой лист. Для этого просто выделите диаграмму и нажмите Ctrl+X (вырезать). Затем перейдите на только что созданный лист, выделите ячейку A1 и нажмите Ctrl+V (вставить).

На рисунке ниже показан внешний вид диаграммы с настройками по умолчанию:

Рис. 11. Внешний вид диаграммы с настройками по умолчанию

Рис. 11. Внешний вид диаграммы с настройками по умолчанию.

Каждый элемент диаграммы можно настроить: изменить размер, цвет, стиль и т.д.

На рисунке выше видно, что горизонтальная ось показывает количество сделок. Сделаем так, чтобы там отображались даты. Для этого нажмите на диаграмме правой кнопкой мыши и в контекстном меню выберите опцию Выбрать данные. Откроется диалоговое окно Выбор источника данных. Нажмите кнопку Изменить, затем выделите диапазон данных в столбце TIME и нажмите OK.

Рис. 12. Диалоговое окно "Выбор источника данных"

Рис. 12. Диалоговое окно "Выбор источника данных".

Диаграмму для просадок попробуйте создать самостоятельно, а затем расположите ее под первой диаграммой. Осталось только настроить внешний вид диаграмм, если есть такая необходимость. Лично я обычно так и делаю:

Рис. 13. Настроенный внешний вид диаграмм в Excel 2010

Рис. 13. Настроенный внешний вид диаграмм в Excel 2010.


Заключение

Мы получили графики с результатами тестирования в Excel, и выглядят они неплохо. В одной из будущих статей я покажу, как сделать еще более информативные отчеты. В приложении к статье можно скачать архив с файлами эксперта для изучения.

После распаковки архива поместите папку ReportInExcel в директорию MetaTrader 5\MQL5\Experts. Индикатор EventsSpy.mq5 нужно поместить в директорию MetaTrader 5\MQL5\Indicators.

Прикрепленные файлы |
eventsspy__1.mq5 (7.79 KB)
reportinexcel.zip (29.39 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (12)
Aleksey Vyazmikin
Aleksey Vyazmikin | 19 авг. 2014 в 15:49
tol64:

Посмотрите вот эту статью: Визуализируй стратегию в тестере MetaTrader 5 >>>

Для MT4, средствами MQL (насколько я знаю), нет такой возможности.

Статью я эту уже изучал - спасибо. У меня несколько более сложные критерии отбора результатов теста, с учетом особенности стратегии, ну и на MT4 я пока что...

Видимо выход один - делать две программы(советника) для MT4 и MT5, одна для работы, а другая для оптимизации...


marketeer:

Что касается обработки результатов оптимизации, то судя по коду из статьи, вам нужно лишь убрать проверку !IsOptimization() из OnTester и учесть в генерации имени файла какой-нибудь меняющийся параметр (или просто номер прогона), например см. Работа с результатами оптимизации.

Я делал себе аналогичную штуку на JavaScript, и смотрю в браузере, подгружая отчеты тестирования (html-файлы). Соответственно, из оптимизатора мой подход не работает. Зато без экселя.

Буду знать о возможности - спасибо.

А поподробней о вашей штуке на JavaScript можно? Что она (штука) умеет делать?

Stanislav Korotky
Stanislav Korotky | 19 авг. 2014 в 16:01
-Aleks-:

Буду знать о возможности - спасибо.

А поподробней о вашей штуке на JavaScript можно? Что она (штука) умеет делать?

Рендерит в браузере странички вот с таким содержимым:

Сравнение балансов тестовых прогонов по символам

 А также:

Общий баланс 

Anatoli Kazharski
Anatoli Kazharski | 19 авг. 2014 в 16:08
-Aleks-:

Статью я эту уже изучал - спасибо. У меня несколько более сложные критерии отбора результатов теста, с учетом особенности стратегии, ну и на MT4 я пока что...

...

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

Stanislav Korotky
Stanislav Korotky | 19 авг. 2014 в 19:56
-Aleks-:

Статью я эту уже изучал - спасибо. У меня несколько более сложные критерии отбора результатов теста, с учетом особенности стратегии, ну и на MT4 я пока что...

Видимо выход один - делать две программы(советника) для MT4 и MT5, одна для работы, а другая для оптимизации...

В MT4 точно так же есть OnTester, можете там высчитывать свои критерии. Два советника под разные платформы будут скорее всего работать с разными котировками, так что оптимизация по одному даст лишь приблизительно пригодные (а может и не очень) результаты для второго.
Эдуард
Эдуард | 9 мар. 2023 в 15:30
В коде ошибки, не компилируется ReportInExcel. 
CheckTradingPermission возвращать должно bool, но предпринимается попытка возвратить int.
Генератор торговых сигналов пользовательского индикатора Генератор торговых сигналов пользовательского индикатора
Как сделать генератор торговых сигналов основанный на пользовательском индикаторе. Как создать пользовательский индикатор. Как получить доступ к данным пользовательского индикатора. Зачем нужна конструкция IS_PATTERN_USAGE(0) и model 0.
Социальный трейдинг в торговых платформах MetaTrader 4 и MetaTrader 5 Социальный трейдинг в торговых платформах MetaTrader 4 и MetaTrader 5
Что такое социальный трейдинг? Это совместная и взаимовыгодная работа трейдеров и инвесторов: успешные трейдеры выставляют свою торговлю на мониторинг, а потенциальные инвесторы таким образом могут следить за их успехами и копировать сделки того трейдера, который им понравился.
Интерактивная площадка для моделирования случайных результатов Интерактивная площадка для моделирования случайных результатов
В статье представлена интерактивная площадка, реализованная в виде файла Excel, которая моделирует результаты тестирования советников на исторических данных. Она поможет читателям в исследовании и получении более четкого представления о показателях эффективности отчетов MetaTrader, которые служат для оценки работы торговых систем. Изложение материала организовано таким образом, чтобы дать пользователю возможность окунуться в атмосферу практического опыта.
Рецепты MQL5 - Разработка мультивалютного эксперта с неограниченным количеством параметров Рецепты MQL5 - Разработка мультивалютного эксперта с неограниченным количеством параметров
В этой статье мы создадим схему, в которой для оптимизации торговой системы будет использоваться единый набор параметров, а количество символов можно использовать сколько угодно. Список символов будем составлять в обычном текстовом файле (*.txt). Входные параметры для каждого символа также теперь будут храниться в файлах. Так мы сможем обойти ограничение терминала на количество входных параметров эксперта.