English 中文 Español Deutsch 日本語 Português 한국어 Français Italiano Türkçe
Создание собственных критериев оптимизации параметров эксперта

Создание собственных критериев оптимизации параметров эксперта

MetaTrader 5Трейдинг | 24 июня 2011, 10:33
11 401 15
Dmitriy Skub
Dmitriy Skub


Введение

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


1. Обзор возможностей тестера торговых стратегий

На эту тему уже написано достаточно много, поэтому приведем подборку статей с кратким описанием содержимого. Рекомендуется перед прочтением данной статьи ознакомиться с приведенной ниже подборкой.

  • "Основы тестирования в MetaTrader 5". Подробно рассматриваются все технические аспекты тестирования эксперта - режим генерации тиков, работа по ценам открытия и по минутным барам. Описывается использование индикаторов при тестировании, эмуляция переменных окружения и обработка стандартных событий. Также, рассмотрены основы мультивалютного тестирования.
  • "MQL5: Руководство по тестированию и оптимизации советников". Рассматриваются вопросы тестирования и оптимизации входных параметров советника. Описывается подбор параметров, интерпретация результатов тестирования и выбор наилучших значений параметров.
  • "Применение функции TesterWithdrawal для моделирования снятия прибыли". Рассматривается применение функции TesterWithdrawal для моделирования снятия средств со счета в тестере стратегий и показано, как применение данной функции влияет на алгоритм расчета просадки по средствам в тестере.

И конечно, в первую очередь рекомендуется ознакомиться с документацией, поставляемой вместе с терминалом.


2. Встроенные в тестер критерии оптимизации

Если обратиться к документации, то там дается следующее определение: Критерий оптимизации - некий показатель, значение которого определяет качество тестируемого набора входных параметров. Чем больше значение критерия оптимизации, тем лучше оценивается результат тестирования с данным набором параметров.

Здесь надо сделать важное замечание: критерий оптимизации может использоваться только в режиме тестирования с использованием генетического алгоритма. Понятно, что в режиме полного перебора всех комбинаций значений параметров, какой-либо критерий оптимальности параметров эксперта в тестере отсутствует. Другой вопрос, что мы можем сохранить результаты тестирования и затем уже обработать их на предмет подбора наилучшей комбинации параметров.

Как следует из документации, в тестере имеются следующие критерии оптимизации при использовании генетического алгоритма:

  • Balance max - максимальный баланс, показателем оптимальности является максимальное значение баланса;
  • Balance + max Profit Factor - баланс + максимальная прибыльность, показателем является максимальное значение произведения баланса на прибыльность;
  • Balance + max Expected Payoff - баланс + максимальное математическое ожидание выигрыша, показателем является произведение баланса на мат. ожидание выигрыша;
  • Balance + min Drawdown - баланс + минимальная просадка, в данном случае помимо значения баланса учитывается уровень просадки: (100% - Просадка)*Баланс;
  • Balance + max Recovery Factor - баланс + максимальный фактор восстановления, показателем является произведение баланса на фактор восстановления;
  • Balance + max Sharpe Ratio - баланс + максимальный коэффициент Шарпа, показателем является произведение баланса на коэффициент Шарпа;
  • Custom max - пользовательский критерий оптимизации, при выборе данного параметра в качестве критерия оптимизации будет учитываться значение функции OnTester() в советнике. Данный параметр позволяет пользователю использовать любой собственный показатель для оптимизации.

Критерий оптимизации выбирается на вкладке Настройки тестера стратегий, как показано на рис. 1:

Выбор критерия оптимизации эксперта

Рис. 1. Выбор критерия оптимизации эксперта

Последний в списке критерий Custom max интересует нас больше всего и его использование является предметом данной статьи.


3. Создание собственных критериев оптимизации

Первое, что напрашивается сделать - дать возможность пользователю произвольно комбинировать показатели (не только выбираемые на рис. 1, но и свои), вычисляемые тестером по результатам очередного прогона эксперта.

Например, интересным выглядит такой вариант: Balance max + min Drawdown + Trades Number - баланс + минимальная просадка + число трейдов (чем больше трейдов, тем достоверней результат). Или такой: Balance max + min Drawdown + max Profit Factor - баланс + минимальная просадка + максимальная прибыльность. Конечно, есть еще достаточно много интересных комбинаций, не охваченных в настройках тестера.

Назовем такие комбинации показателей простыми критериями оптимизации.

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

Назовем этот критерий критерием оптимизации по кривой баланса.

Следующий критерий оптимизации, который мы попробуем использовать - это коэффициент безопасности торговой системы. Данный коэффициент описан в статье "Будь в фазе". Характеризует соответствие торговой системы рынку, что нам и нужно выявить при оптимизации параметров. Назовем его критерием оптимизации по коэффициенту безопасности торговой системы (КБТС).

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


4. Функция OnTester()

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

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

Еще раз подчеркнем, что для использования функции OnTester() необходимо задать тип оптимизации Быстрая (генетический алгоритм), как показано на рис.1.

Данная функция имеет возвращаемый результат типа double, по которому и происходит оптимизация в тестере.

Снова обратимся к документации:

При генетической оптимизации сортировка результатов в пределах одного поколения производится по убыванию. То есть, лучшими с точки зрения критерия оптимизации считаются результаты с наибольшим значением. Худшие значения при такой сортировке помещаются в конец и впоследствии отбрасываются и не принимают участия в формировании следующего поколения.

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


5. Пишем "подопытный" эксперт

Теперь пришло время разработать эксперт, который мы будем использовать для оптимизации в тестере. В данном случае, основные требования к эксперту - простота и скорость работы, чтобы не тратить много времени на саму рутинную процедуру оптимизации. Желательно также, чтобы эксперт был не очень убыточный.

Возьмем в качестве "подопытного" эксперт, описанный в статье "Несколько способов определения тренда на MQL5" и доработаем его. А именно, эксперт, основанный на "веере" из трех скользящих средних. Доработка заключается в том, что мы избавились от использования индикатора для ускорения работы и перенесли всю необходимую расчетную часть кода в сам эксперт. Это позволило значительно (почти в три раза на двухлетнем интервале) ускорить один проход тестирования.

Блок задания входных параметров очень прост:

input double Lots = 0.1; 
input int  MA1Period = 200; // значение периода старшей скользящей средней
input int  MA2Period = 50;  // значение периода средней скользящей средней
input int  MA3Period = 21;  // значение периода младшей скользящей средней

Периоды скользящих средних мы и будем оптимизировать.

Структура и работа эксперта подробно описана в упомянутой выше статье, поэтому не будем на этом останавливаться. Главное нововведение - появился обработчик события о завершении очередного прохода тестирования - функция OnTester(). Пока она пустая и просто возвращает управление.

//---------------------------------------------------------------------
//  Обработчик события о завершении очередного прохода тестирования:
//---------------------------------------------------------------------
double OnTester()
{
  return(0.0);
}

Этот эксперт находится в файле FanExpert.mq5 и приложен к данной статье. Можно убедиться, что он полностью идентичен эксперту FanTrendExpert.mq5 с точки зрения совершаемых сделок. Проверка наличия и направления сигнала происходит при открытии нового бара на графике.

Для получения результатов тестирования, вычисляемых после каждого прохода, предназначена функция TesterStatistics(), которая возвращает значение запрошенного статистического показателя, рассчитанного по результатам тестирования. Она может вызываться только из функций OnTester() и OnDeinit(), в противном случае результат не определен.

Теперь добавим свой критерий оптимизации. Предположим, что нам нужно найти оптимальные результаты, ориентируясь на максимальное значение фактора восстановления - max Recovery Factor. Для этого нам надо знать значения макс. просадки баланса в деньгах и чистой прибыли по окончании тестирования. Фактор восстановления получается, если разделить профит на максимальную просадку.

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

Для этого добавим в функцию OnTester() следующий простой код:

//---------------------------------------------------------------------
//  Обработчик события о завершении очередного прохода тестирования:
//---------------------------------------------------------------------
double OnTester()
{
  double  profit = TesterStatistics(STAT_PROFIT);
  double  max_dd = TesterStatistics(STAT_BALANCE_DD);
  double  rec_factor = profit/max_dd;

  return(rec_factor);
}

Для упрощения кода здесь отсутствует проверка деления на ноль. Поскольку максимальная просадка может быть нулевой, то такую проверку в реальном эксперте нужно делать обязательно.

Теперь создадим упомянутый выше критерий: Balance max + min Drawdown + Trades Number - баланс + минимальная просадка + число трейдов.

Для этого изменим тело функции OnTester() следующим образом:

double OnTester()
{
  double  param = 0.0;

//  Balance max + min Drawdown + Trades Number:
  double  balance = TesterStatistics(STAT_PROFIT);
  double  min_dd = TesterStatistics(STAT_BALANCE_DD);
  if(min_dd > 0.0)
  {
    min_dd = 1.0 / min_dd;
  }
  double  trades_number = TesterStatistics(STAT_TRADES);
  param = balance * min_dd * trades_number;

  return(param);
}

Здесь мы берем величину, обратную просадке, т.к. чем меньше просадка, при прочих равных условиях, тем лучше. Проведем оптимизацию эксперта FanExpert с разработанным нами критерием оптимизации по входному параметру MA1Period в интервале 2009.06.01 - 2011.06.03 на таймфрейме Н1. Значения периода скользящей средней берем в диапазоне от 100 до 2000.

После оптимизации получаем следующую таблицу значений отсортированных наилучших параметров:

Таблица наилучших параметров

Рис. 2. Наилучшие результаты оптимизации по критерию Balance max + min Drawdown + Trades Number

Здесь приведены наилучшие параметры (по столбцу Результат).

Теперь посмотрим наихудшие параметры:

Таблица наихудших параметров

Рис. 3. Наихудшие результаты оптимизации по критерию Balance max + min Drawdown + Trades Number

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

График оптимизации

Рис. 4. График оптимизации по критерию Balance max + min Drawdown + Trades Number

Здесь по горизонтальной оси откладывается оптимизируемый параметр, а по вертикальной - критерий оптимизации. Видим явный максимум по заданному нами критерию - он приходится на интервал периодов примерно от 980 до 1200.

Следует понимать и всегда помнить, что это генетическая оптимизация параметра, а не полный перебор. Поэтому, в таблицах на рис. 2 и рис. 3 присутствуют наиболее "жизнеспособные" параметры, прошедшие естественный отбор в нескольких поколениях. Вполне возможно, что были отбракованы достаточно удачные варианты.

Для периода 1106 получается кривая баланса/средств следующего вида:

Кривая баланса и эквити

Рис. 5. Кривая баланса/средств для периода MA1Period = 1106


6. Создаем классы пользовательских критериев оптимизации

Итак, мы научились создавать и использовать простые критерии оптимизации. Теперь разработаем класс для упрощения использования в экспертах. Одно из основных требований к такому классу, кроме удобства использования - высокая скорость работы. Вычисления критерия оптимизации должны производиться быстро, иначе можно не дождаться результатов.

MetaTrader 5 позволяет задействовать при проведении оптимизации технологию "облачных" вычислений. Это большой шаг вперед, поскольку перебор значительного числа вариантов параметров требует гигантских вычислительных мощностей. Поэтому, при разработке нашего класса будем отбирать наиболее простые и быстрые решения, пусть и не самые изящные с точки зрения программирования.

При разработке будем использовать стандартные классы для организации данных, которые поставляются вместе с терминалом.

Для начала, классифицируем виды рассчитываемых статистических результатов тестирования:

  • Плавающего или целого вида с прямой пропорциональностью между величиной результата тестирования и величиной критерия оптимизации.

То есть, чем больше величина результата тестирования, тем лучше и тем больше величина критерия оптимизации. Яркий пример такого результата тестирования - Чистая прибыль по окончании тестирования STAT_PROFIT. Значение числа имеет плавающий формат и может меняться от минус бесконечности (на самом деле снизу ограничено размером депозита) до плюс бесконечности.

Другим примером результата тестирования такого вида может быть Количество трейдов STAT_TRADES. Чем больше трейдов, тем достоверней результат оптимизации, в общем случае. Значение числа имеет целый формат и может меняться от нуля до плюс бесконечности.

  • Плавающего или целого вида с обратной пропорциональностью между величиной результата тестирования и величиной критерия оптимизации.

То есть, чем меньше величина результата тестирования, тем лучше и тем больше величина критерия оптимизации. Пример такого результата тестирования - Максимальная просадка баланса в деньгах STAT_BALANCE_DD, а также любая другая просадка.

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

Базовый класс для создания пользовательских критериев оптимизации TCustomCriterion очень прост. Его назначение - определить базовую функциональность. Он имеет следующий вид:

class TCustomCriterion : public CObject
{
protected:
  int     criterion_level;        // вид критерия

public:
  int   GetCriterionLevel();
  virtual double  GetCriterion();  // получить значение результата оптимизации
};

Виртуальный метод TCustomCriterion::GetCriterion необходимо переопределять в классах-наследниках. Это основной метод, который возвращает значение интегрального результата тестирования эксперта после завершения очередного прохода.

Член класса TCustomCriterion::criterion_level хранит вид пользовательского критерия, присущий объекту данного класса. Это будет использовано в дальнейшем для того чтобы различать объекты между собой по их видам.

Теперь от базового класса можно наследовать все необходимые нам при оптимизации классы.

Класс TSimpleCriterion предназначен для создания "простого" пользовательского критерия, совпадающего с заданным статистическим результатом тестирования. Его определение выглядит следующим образом:

class TSimpleCriterion : public TCustomCriterion
{
protected:
  ENUM_STATISTICS  stat_param_type;

public:
  ENUM_STATISTICS  GetCriterionType();     // получить тип оптимизируемого стат параметра

public:
  virtual double   GetCriterion();           // получить значение результата оптимизации
  TSimpleCriterion(ENUM_STATISTICS _stat); // конструктор
};

Здесь мы используем конструктор с параметром, который имеет следующую реализацию:

//---------------------------------------------------------------------
//  Конструктор:
//---------------------------------------------------------------------
TSimpleCriterion::TSimpleCriterion(ENUM_STATISTICS _stat)
:
stat_param_type( _stat )
{
  criterion_level = 0;
}

Это новшество в языке MQL5, которое удобно использовать при создании объектов класса. Также, мы переопределили виртуальный метод TSimpleCriterion::GetCriterion, с помощью которого мы получаем значение результата оптимизации после очередного прохода тестирования. Его реализация очень проста:

//---------------------------------------------------------------------
//  Получить значение результата оптимизации:
//---------------------------------------------------------------------
double  TSimpleCriterion::GetCriterion()
{
  return(TesterStatistics(stat_param_type));
}

Как видим, он просто возвращает соответствующий статистический результат тестирования.

Следующий вид пользовательского "простого" критерия оптимизации создается с помощью класса TSimpleDivCriterion. Он предназначен для критериев с обратной пропорциональностью между величиной результата тестирования и величиной критерия оптимизации.

Метод TSimpleDivCriterion::GetCriterion выглядит следующим образом:

//---------------------------------------------------------------------
//  Получить значение результата оптимизации:
//---------------------------------------------------------------------
double  TSimpleDivCriterion::GetCriterion()
{
  double  temp = TesterStatistics(stat_param_type);
  if(temp>0.0)
  {
    return(1.0/temp);
  }
  return(0.0);
}

Особых пояснений данный код не требует.

Еще два вида пользовательского "простого" критерия оптимизации создаются с помощью классов TSimpleMinCriterion и TSimpleMaxCriterion. Они предназначены для создания критериев с ограничением значения статистического результата тестирования по минимальному и максимальному значению, соответственно.

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

Описание класса TSimpleMinCriterion выглядит следующим образом:

class TSimpleMinCriterion : public TSimpleCriterion
{
  double  min_stat_param;

public:
  virtual double  GetCriterion();    // получить значение результата оптимизации
  TSimpleMinCriterion(ENUM_STATISTICS _stat, double _min);
};

Здесь мы использовали конструктор с двумя параметрами. Параметр _min - это минимальное значение статистического результата тестирования. Если после очередного прохода тестирования мы получаем значение, меньшее заданного, то такой результат отбраковывается.

Реализация метода TSimpleMinCriterion ::GetCriterion выглядит следующим образом:

//---------------------------------------------------------------------
//  Получить значение результата оптимизации:
//---------------------------------------------------------------------
double  TSimpleMinCriterion::GetCriterion()
{
  double  temp = TesterStatistics(stat_param_type);
  if(temp<this.min_stat_param)
  {
    return(-1.0);
  }
  return(temp);
}

Класс TSimpleMaxCriterion построен аналогично и особых пояснений не требует. Остальные классы "простых" пользовательских критериев построены аналогично описанным выше и содержатся в файле CustomOptimisation.mqh, который приложен к данной статье. По этому же принципу можно разработать любой необходимый класс для использования в оптимизации.


Прежде чем использовать описанные выше классы для оптимизации, разработаем класс-контейнер для более удобной манипуляции набором критериев. Также используем для этого стандартные классы для организации данных. Поскольку нам нужен простой последовательный перебор критериев, то наиболее подходит для этой цели класс CArrayObj, который позволяет организовать динамический массив объектов-потомков класса CObject.

Описание класса-контейнера TCustomCriterionArray очень простое:

class TCustomCriterionArray : public CArrayObj
{
public:
  virtual double  GetCriterion( );  // получить значение результата оптимизации
};

Единственный его метод - TCustomCriterionArray::GetCriterion, который возвращает значение критерия оптимизации после очередного прохода тестирования. Его реализация выглядит следующим образом:

double  TCustomCriterionArray::GetCriterion()
{
  double  temp = 1.0;
  int     count = this.Total();
  if(count == 0)
  {
    return(0.0);
  }
  for(int i=0; i<count; i++)
  {
    temp *= ((TCustomCriterion*)(this.At(i))).GetCriterion();
    if(temp <= 0.0)
    {
      return(temp);
    }
  }

  return(temp);
}

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


7. Используем классы пользовательских критериев оптимизации

Итак, у нас есть все необходимое, чтобы использовать "простые" пользовательские критерии при оптимизации экспертов. Рассмотрим последовательность шагов при добавлении в "подопытный" эксперт FanExpert:

  • Добавляем включаемый файл с описаниями классов пользовательских критериев:
#include <CustomOptimisation.mqh>
  • Добавляем указатель на объект класса-контейнера для использования пользовательских критериев:
TCustomCriterionArray*  criterion_Ptr;
  • Инициализируем указатель на объект класса-контейнера для использования пользовательских критериев:
  criterion_array = new TCustomCriterionArray();
  if(CheckPointer(criterion_array) == POINTER_INVALID)
  {
    return(-1);
  }

Это делается в функции OnInit. В случае неудачного создания объекта, возвращаемся с отрицательным значением. В этом случае, эксперт прекращает свою работу.

  • Добавляем необходимые нам критерии оптимизации эксперта:
  criterion_Ptr.Add(new TSimpleCriterion(STAT_PROFIT));
  criterion_Ptr.Add(new TSimpleDivCriterion(STAT_BALANCE_DD));
  criterion_Ptr.Add(new TSimpleMinCriterion(STAT_TRADES, 20.0));

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

  • Добавляем соответствующий вызов в функцию OnTester:
  return(criterion_Ptr.GetCriterion());
  • В функцию OnDeinit добавляем код для удаления объекта-контейнера:
  if(CheckPointer(criterion_Ptr) == POINTER_DYNAMIC)
  {
    delete(criterion_Ptr);
  }

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

Настройка тестера стратегий

Рис. 6. Настройка тестера стратегий

Затем задаем диапазоны оптимизации входных параметров на вкладке Входные параметры тестера стратегий, как показано на рис. 7:

Оптимизируемые входнаые параметры

Рис. 7. Оптимизируемые входные параметры

Используем при оптимизации "облачных" агентов. Для этого на вкладке Агенты зададим следующие параметры:

Параметры агентов

Рис. 8. Параметры агентов тестирования

Теперь нажимаем кнопку Старт (рис.6) и ждем окончания оптимизации параметров. С использованием "облачной" технологии оптимизация происходит достаточно быстро. Получаем следующие результаты оптимизации по заданным нами критериям:

Результаты оптимизации

Рис. 9. Результаты оптимизации

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


8. Создаем класс пользовательского критерия оптимизации на основе анализа кривой баланса

Основа для создания данного класса - статья "Контроль наклона кривой баланса во время работы торгового эксперта". Идея данного критерия оптимизации - добиться кривой баланса, максимально приближенной к прямой линии. Степень близости к прямой линии будем оценивать по величине среднеквадратичного отклонения результатов трейдов от нее. Уравнение прямой будем рассчитывать для линии регрессии, построенной по результатам сделок в тестере.

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

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

Для реализации критерия оптимизации на основе кривой баланса нам понадобится класс TBalanceSlope из указанной выше статьи. Мы его модернизируем на предмет использования конструкторов с параметрами (для большего удобства) и добавим вычисление среднеквадратичного отклонения при расчете линейной регрессии. Данный код находится в файле BalanceSlope.mqh, который приложен к статье.

Последовательность шагов добавления в "подопытный" эксперт данного критерия оптимизации такая же, как описана выше. Критерии оптимизации выглядят теперь так:

criterion_Ptr.Add(new TBalanceSlopeCriterion(Symbol( ), 10000.0));

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

Проведем оптимизацию по заданным критериям. Чтобы получить побольше трейдов, оптимизацию проведем на таймфрейме Н4 в интервале 2010.01.01 - 2011.01.01 на инструменте EURUSD. Получим некоторый набор результатов:

Результаты оптимизации по кривой баланса

Рис. 10. Результаты оптимизации по кривой баланса

Теперь нужно оценить качество проведенной оптимизации. Пожалуй, основной критерий - работа эксперта вне периода оптимизации. Для этого запускаем одиночное тестирование в интервале 2010.01.01-2011.06.14.

Сравним два результата (имеющие примерно одинаковую результирующую прибыль) из набора оптимальных параметров - наилучший результат с результатом из середины. Результаты за пределами интервала оптимизации отделены красной чертой:

Лучший результат оптимизации

Рис. 11. Лучший результат оптимизации

В целом, характер кривой почти не ухудшился. Прибыльность лишь слегка уменьшилась - с 1.60 до 1.56.

Средний результат оптимизации

Рис. 12. Средний результат оптимизации

Вне пределов оптимизации эксперт практически не принес прибыли. Прибыльность значительно уменьшилась - с 2.17 до 1.75.

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

Скорей всего, для данного критерия оптимизации надо использовать максимально возможный период (в разумных пределах). Эксперт для проверки данного критерия находится в файле FanExpertBalance.mq5, приложенном к статье.


9. Создаем класс пользовательского критерия оптимизации на основе коэффициента безопасности торговой системы (КБТС)

Как показано в статье "Будь в фазе", коэффициент безопасности торговой системы (дальше КБТС) можно рассчитать по следующей формуле:

КБТС = Avg.Win / Avg.Loss ((110% - %Win) / (%Win-10%) + 1)

Здесь,

  • Avg.Win - средняя величина прибыльной сделки;
  • Avg.Loss - средняя величина убыточной сделки;
  • %Win - процент прибыльных сделок;

Если значение КБТС меньше единицы, то торговая система переходит в зону повышенного торгового риска или, при еще более низких значениях, в зону убыточной торговли. Чем больше значение КБТС, тем лучше торговая система соответствует рынку и тем она прибыльней.

Все статистические величины, необходимые для расчета КБТС, рассчитываются в тестере после очередного прохода тестирования. Нам остается создать класс TTSSFCriterion, потомок TCustomCriterion и реализовать в нем метод GetCriterion(). Реализация данного метода в коде выглядит следующим образом:

double  TTSSFCriterion::GetCriterion()
{
  double  avg_win = TesterStatistics(STAT_GROSS_PROFIT) / TesterStatistics(STAT_PROFIT_TRADES);
  double  avg_loss = -TesterStatistics(STAT_GROSS_LOSS) / TesterStatistics(STAT_LOSS_TRADES);
  double  win_perc = 100.0 * TesterStatistics(STAT_PROFIT_TRADES) / TesterStatistics(STAT_TRADES);

//  Вычислим безопасное отношение для данного процента профитных сделок:
  double  teor = (110.0 - win_perc) / (win_perc - 10.0) + 1.0;

//  Вычислим реальное отношение:
  double  real = avg_win / avg_loss;

//  КБТС:
  double  tssf = real / teor;

  return(tssf);
}

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

Предоставим читателям возможность провести оптимизацию самостоятельно. Эксперт для проверки данного критерия находится в файле FanExpertTSSF.mq5, приложенном к статье.


Заключение

Надо признать, что столь простое решение в реализации возможности создания пользовательских критериев оптимизации (с помощью единственного интегрального показателя) практически не имеет особых недостатков, по сравнению с другими возможными вариантами и позволяет поднять на новый уровень планку в разработке устойчивых торговых систем. Использование "облачной" технологии понижает ограничения на сложность проводимой оптимизации на несколько порядков.

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


Прикрепленные файлы |
balanceslope.mqh (14.57 KB)
fanexperttssf.mq5 (8.87 KB)
fanexpert.mq5 (8.82 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (15)
Vladimir Gomonov
Vladimir Gomonov | 21 июл. 2012 в 15:06
sigma7i:

как быть с пропуском бесполезных результатов, в отчете?

В стандартном отчёте никак.  И не нужно (я против).  Делай свой отчёт.

Сейчас отчёт можно формировать уже на этапе оптимизации  (https://www.mql5.com/ru/docs/optimization_frames)  в любом формате, в котором тебе нужно.

А скоро (тьху-тьху)  и генетикой управлять можно будет самостоятельно.

Иван
Иван | 13 окт. 2014 в 12:12

Кто может подсказать будет ли эта статья применима для МТ4? Вроде бы он уже многие свойства перенял от МТ5.

В общем моя задача стоит в получение просто значений LR Correlation и LR Standard Error в тестере МТ4, как это возможно легко видеть в тестере МТ5.

Хочу просто в функции deinit() по окончанию прогона в тесте считать эти же значения и записывать например в файл вместе со значением оптимизируемого параметра.

Может быть кто-то подобные вещи уже делал и поделится со мной готовым результатом (необходимой функцией расчёта значений LR Correlation и LR Standard Error), чтобы не изобретать велосипед?

Automated-Trading
Automated-Trading | 13 окт. 2014 в 12:16
solandr:

Кто может подсказать будет ли эта статья применима для МТ4? Вроде бы он уже многие свойства перенял от МТ5.

В общем моя задача стоит в получение просто значений LR Correlation и LR Standard Error в тестере МТ4, как это возможно легко видеть в тестере МТ5.

Хочу просто в функции deinit() по окончанию прогона в тесте считать эти же значения и записывать например в файл вместе со значением оптимизируемого параметра.

Может быть кто-то подобные вещи уже делал и поделится со мной готовым результатом (необходимой функцией расчёта значений LR Correlation и LR Standard Error ), чтобы не изобретать велосипед?

Пример расчета LR Correlation и LR Standard Error по сделкам в истории есть в AlgLib (MQL4\Scripts\Alglib\UseAlglib.mq4).
Иван
Иван | 13 окт. 2014 в 13:28
Automated-Trading:
Пример расчета LR Correlation и LR Standard Error по сделкам в истории есть в AlgLib (MQL4\Scripts\Alglib\UseAlglib.mq4).
Спасибо! Буду разбираться.
Иван
Иван | 13 окт. 2014 в 22:19
solandr:
Спасибо! Буду разбираться.

Разобрался. Вроде корреляция рассчитывается.

Единственный момент, над которым пришлось подумать, это тот факт, что в тестере МТ4 Build 670 не работает вот этот момент:

//--- получение первоначального баланса
      if(order_type==6) // OP_BALANCE=6
        {
         if(NormalizeDouble(OrderProfit()+OrderSwap(),2)>=0.0)
            if(balance==0.0)
               balance=OrderProfit();
        }

В тестере просто нет ордеров с типом 6.

То есть на прогоне в тестере МТ4 и использовании кода из UseAlglib.mq4, входящего в состав скачиваемого zip файла, через вызов из функции deinit() 

balance остаётся равен 0. И далее печатается ошибка "Торговые операции при нулевом балансе".

Пришлось просто вставить в сам код необходимое значение начального баланса в тестере МТ4 и тогда всё прекрасно стало считаться.

Возможно разработчики смогут этот момент учесть в дальнейших версиях библиотеки.

Как добавить новые языки интерфейса в платформу MetaTrader 5 Как добавить новые языки интерфейса в платформу MetaTrader 5
Пользовательский интерфейс платформы MetaTrader 5 переведен на большинство самых распространенных языков. Не беда, если вашего родного языка не окажется в списке поддерживаемых. В MetaTrader 5 изначально была заложена полная поддержка Unicode, а для перевода пользовательского интерфейса была создана специальная утилита MultiLanguage Pack. С ее помощью любой пользователь по своему желанию может перевести интерфейс клиентских компонентов платформы MetaTrader 5 на любой язык мира. В этой статье мы детально рассмотрим весь процесс добавления новых языков интерфейса.
Платежи и методы оплаты Платежи и методы оплаты
MQL5.community предлагает широкие возможности заработка трейдерам и разработчикам торговых приложений для терминала MetaTrader. В этой статье мы расскажем, как происходит оплата сервисов MQL5 и вывод заработанных денег, а также как обеспечивается безопасность операций.
Чтение новостей в формате RSS средствами MQL4 Чтение новостей в формате RSS средствами MQL4
В данной статье рассматривается пример чтения RSS-разметки средствами MQL4 с использованием функций анализа HTML-тегов. Мы попытаемся сделать заготовку, на базе которой можно будет сделать новостной индикатор или просто RSS-читалку на языке MQL4.
Механическая торговая система "Треугольник Чувашова" Механическая торговая система "Треугольник Чувашова"
Вашему вниманию предлагается обзор и программный код стратегии механической торговой системы по методике Станислава Чувашова. Основой построения треугольника является пересечение двух трендовых линий, построенных по верхним и нижним фракталам.