English 中文 Español Deutsch 日本語 Português
preview
Возможности Мастера MQL5, которые вам нужно знать (Часть 3): Энтропия Шеннона

Возможности Мастера MQL5, которые вам нужно знать (Часть 3): Энтропия Шеннона

MetaTrader 5Тестер | 8 ноября 2022, 14:46
1 211 1
Stephen Njuki
Stephen Njuki

1.0. Введение

В 1948 году Клод Шеннон представил свою статью "Математическая теория связи", в которой была выдвинута идея об информационной энтропии. Энтропия — понятие, пришедшее из физики. Это мера степени активности частиц внутри объекта. Например, если мы рассмотрим три состояния воды - лед, жидкость и газ, мы увидим, что кинетическая энергия частицы наибольшая в газообразном состоянии и наименьшая в виде льда. Понятие применяется в математике применительно к вероятности. Рассмотрим следующие три набора.

Набор 1: 

Набор 1


Набор 2: 

Набор 2


Набор 3: 

Набор 3


Какой из этих наборов имеет наибольшую энтропию? 
Если вы выбрали последний вариант, то вы правы, но как мы можем подтвердить правильность этого ответа? Самый простой способ ответить на этот вопрос — взять количество способов реорганизации каждого набора в качестве оценки энтропии, игнорируя при этом совпадения по цвету. Таким образом, для первого набора существует только один способ "реорганизовать" его. Однако если мы после этого посмотрим на наборы, то увидим, что количество перестановок относительно цвета значительно увеличивается, поэтому мы можем утверждать, что последний набор имеет самую высокую энтропию. 

Существует более точный способ определения энтропии, основанный на информации. Если бы вы произвольно выбрали шар из первого набора до того, как взяли бы его в руки, что бы вы узнали о нем? Поскольку в наборе только синие шары, вы можете быть уверены, что это будет синий шар. Таким образом, можно сказать, что у нас есть полная информация о том, что мы собираемся выбрать из набора 1. В случае с наборами 2 и 3 наша информация становится все менее и менее полной. Таким образом, в математике энтропия обратно пропорциональна информации. Чем выше энтропия, тем больше неизвестных.  

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

Набор 1: 

(1,0 x 1,0 x 1,0 x 1,0 x 1,0 x 1,0 x 1,0 x 1,0) = 1,0 


Набор 2: 

(0,625 x 0,625 x 0,625 x 0,625 x 0,625 x 0,375 x 0,375 x 0,375) ~ 0,0050 


Набор 3: 

(0,375 x 0,375 x 0,375 x 0,25 x 0,25 x 0,25 x 0,25 x 0,125) ~ 0,000025 


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


equation_1


Логарифм умножается на отрицательный, так как логарифм чисел меньше единицы отрицательный. Формула энтропии, согласно Википедии, выглядит так: 


equation_2


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


Набор 1: 

-(8 x 0,125 x log2(1,0)) = 0,0 


Набор 2: 

(-(0,625 x log2(0,625)) - (0,375 x log2(0,375))) ~ 0,9544 


Набор 3: 

(- (0,375 x log2(0,375)) - (2 x 0,25 x log2(0,25)) - (0,125 x log2(0,125))) ~ 1,906 


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

equation_3

Это максимальное значение будет полезно для нормализации значений энтропии при генерации сигналов в диапазоне от 0,0 до 1,0. Для трейдера энтропия ценовой истории может служить предвестником того, можно ли из этой истории выделить надежный торговый сигнал. Однако предположим, что мы хотим использовать саму энтропию для генерации сигналов. Предположим, мы рассматриваем идею о том, что энтропия падающих баров выше, чем энтропия растущих баров в фиксированном наборе недавних баров, что подразумевает сигнал на покупку и наоборот. Давайте посмотрим, как эту идею можно воплотить в коде сигнала для советника в Мастере MQL5.


2.0. Создание класса

В этой статье мы будем использовать класс Decision Forest ("лес решений") из библиотеки MQL5. В частности, мы будем абстрагироваться от идеи случайных лесов (Random Forest) при изучении эффективности сигнала энтропии Шеннона. Эта статья не о случайных лесах, а об энтропии Шеннона. 

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

f_d




Давайте рассмотрим пример, чтобы лучше проиллюстрировать, как она работает.

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

Направление цены кажется простым атрибутом для разделения, поскольку белый цвет представляет медвежьи свечи, а синий — бычьи. Итак, мы можем использовать вопрос "Снижается ли цена?", чтобы отделить первый узел. Узлом на дереве является точка, в которой ветвь разделяется на две — ветви "Да" и "Нет".

У всех ответвлений "Нет" (восходящие свечи) хвосты длиннее голов, но на ответвлении "Да" картина другая, поэтому предстоит проделать дополнительную работу. При использовании второго атрибута мы спрашиваем: "Голова длиннее хвоста?", чтобы сделать второе разделение.

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

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

Как следует из названия, Random Forest ("случайный лес") состоит из огромного количества отдельных деревьев решений, которые работают как группа. Для каждого дерева в случайном лесу делается прогноз класса, и класс с наибольшим количеством голосов выбирается в качестве прогноза модели. Основную концепцию случайного леса легко упустить из виду, но она очень мощная, так как выражает мудрость масс. Делая прогнозы, некоррелированные деревья превосходят отдельные деревья, независимо от того, на каком количестве данных производится обучение. Вся суть - в низкой корреляции. Причина этого в том, что деревья защищают друг друга от индивидуальных ошибок согласно Тону (до тех пор, пока они не ошибаются постоянно в одном и том же направлении). Чтобы случайные леса работали, сигнал прогнозирования должен быть лучше среднего, а предсказания/ошибки каждого дерева должны иметь низкую корреляцию друг с другом.

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

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

2.0.1. Бэггинг

Деревья решений очень чувствительны к обучающим данным, и небольшие изменения могут привести к значительному изменению леса. Случайные леса используют это, когда каждое дерево случайным образом выбирает набор данных при замене, в результате чего получаются разные деревья. Этот процесс известен как бэггинг (сокращение от "бутстреп-агрегирование" - bootstrap aggregating).

При бэггинге мы не заменяем тренировочные данные меньшими наборами, а вместо исходных тренировочных данных берем случайную выборку размера N с некоторыми заменами. Начальный размер набора N сохраняется. Например, если наши обучающие данные были [U, V, W, X, Y, Z], то мы могли бы дать одному из наших деревьев следующий список [U, U, V, X, X, Z]. В обоих списках сохраняется размер N (шесть), а в случайно выбранных данных повторяются "U" и "X".


2.0.2. Функция случайности (Feature Randomness)

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

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

Теперь давайте посмотрим на наш случайный лес. В этом примере мы рассмотрим только два дерева леса. Когда мы проверяем Дерево 1, мы обнаруживаем, что оно может учитывать только Атрибуты 2 и 3 (выбранные случайным образом) при принятии решения о разделении узлов. Из нашего традиционного дерева решений (обозначено синим цветом) мы знаем, что Атрибут 1 лучше всего подходит для разделения, но Дерево 1 не может видеть Атрибут 1, поэтому оно вынуждено использовать Атрибут 2 (черный и подчеркнутый). Дерево 2, с другой стороны, может видеть только Атрибуты 1 и 3, поэтому оно может выбрать Атрибут 1.

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



s_d



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

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

2.1. Сигнальный класс советника 

// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Signals of'Shannon Entropy'                                |
//| Type=SignalAdvanced                                              |
//| Name=Shannon Entropy                                             |
//| ShortName=SE                                                     |
//| Class=CSignalSE                                                  |
//| Page=signal_se                                                   |
//| Parameter=Reset,bool,false,Reset Training                        |
//| Parameter=Trees,int,50,Trees number                              |
//| Parameter=Regularization,double,0.15,Regularization Threshold    |
//| Parameter=Trainings,int,21,Trainings number                      |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| Class CSignalSE.                                                 |
//| Purpose: Class of generator of trade signals based on            |
//|          the 'Shannon Entropy' signals.                          |
//| Is derived from the CExpertSignal class.                         |
//+------------------------------------------------------------------+
class CSignalSE : public CExpertSignal
   {
      public:
         
         //Decision Forest objects.
         CDecisionForest               DF;                                                   //Decision Forest
         CMatrixDouble                 DF_SIGNAL;                                            //Decision Forest Matrix for inputs and output
         CDFReport                     DF_REPORT;                                            //Decision Forest Report for results
         int                           DF_INFO;                                              //Decision Forest feedback

         double                        m_out_calculations[2], m_in_calculations[__INPUTS];   //Decision Forest calculation arrays

         //--- adjusted parameters
         bool                          m_reset;
         int                           m_trees;
         double                        m_regularization;
         int                           m_trainings;
         //--- methods of setting adjustable parameters
         void                          Reset(bool value){ m_reset=value; }
         void                          Trees(int value){ m_trees=value; }
         void                          Regularization(double value){ m_regularization=value; }
         void                          Trainings(int value){ m_trainings=value; }
         
         //Decision Forest FUZZY system objects
         CMamdaniFuzzySystem           *m_fuzzy;
         
         CFuzzyVariable                *m_in_variables[__INPUTS];
         CFuzzyVariable                *m_out_variable;

         CDictionary_Obj_Double        *m_in_text[__INPUTS];
         CDictionary_Obj_Double        *m_out_text;

         CMamdaniFuzzyRule             *m_rule[__RULES];
         CList                         *m_in_list;

         double                        m_signals[][__INPUTS];
         
         CNormalMembershipFunction     *m_update;
         
         datetime                      m_last_time;
         double                        m_last_signal;
         double                        m_last_condition;

                                       CSignalSE(void);
                                       ~CSignalSE(void);
         //--- method of verification of settings
         virtual bool                  ValidationSettings(void);
         //--- method of creating the indicator and timeseries
         virtual bool                  InitIndicators(CIndicators *indicators);
         //--- methods of checking if the market models are formed
         virtual int                   LongCondition(void);
         virtual int                   ShortCondition(void);

         bool                          m_random;
         bool                          m_read_forest;
         int                           m_samples;

         //--- method of initialization of the oscillator
         bool                          InitSE(CIndicators *indicators);
         
         double                        Data(int Index){ return(Close(StartIndex()+Index)-Close(StartIndex()+Index+1)); }
         
         void                          ReadForest();
         void                          WriteForest();
         
         void                          SignalUpdate(double Signal);
         void                          ResultUpdate(double Result);
         
         double                        Signal(void);
         double                        Result(void);
         
         bool                          IsNewBar(void);
  };

 

2.1.1. Сигналы

Эта энтропия будет взвешена по индексу для определения новизны. 

            if(_data>0.0)
            {
               _long_entropy-=((1.0/__SIGNALS[i])*((__SIGNALS[i]-s)/__SIGNALS[i])*(fabs(_data)/_range)*(log10(1.0/__SIGNALS[i])/log10(2.0)));
            }
            else if(_data<0.0)
            {
               _short_entropy-=((1.0/__SIGNALS[i])*((__SIGNALS[i]-s)/__SIGNALS[i])*(fabs(_data)/_range)*(log10(1.0/__SIGNALS[i])/log10(2.0)));
            }

Также она будет взвешена по величине ценовых баров.

            if(_data>0.0)
            {
               _long_entropy-=((1.0/__SIGNALS[i])*((__SIGNALS[i]-s)/__SIGNALS[i])*(fabs(_data)/_range)*(log10(1.0/__SIGNALS[i])/log10(2.0)));
            }
            else if(_data<0.0)
            {
               _short_entropy-=((1.0/__SIGNALS[i])*((__SIGNALS[i]-s)/__SIGNALS[i])*(fabs(_data)/_range)*(log10(1.0/__SIGNALS[i])/log10(2.0)));
            }

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

Сигналы будут обновляться, когда состояние длинной или короткой позиции превысит порог открытия, поскольку это означает открытие позиции. Это произойдет по таймеру, поэтому мы изменим советник, собранный Мастером, чтобы учесть это.

//+------------------------------------------------------------------+
//| "Timer" event handler function                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
   if(PositionSelect(Symbol()) && Signal_ThresholdClose<=fabs(filter0.m_last_condition))
     {
      filter0.ResultUpdate(filter0.Result());
     }
   //
   if(!PositionSelect(Symbol()) && Signal_ThresholdOpen<=fabs(filter0.m_last_condition))
     {
      filter0.SignalUpdate(filter0.m_last_signal);
     }
   ExtExpert.OnTimer();
  }

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

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+  
void CSignalSE::SignalUpdate(double Signal)
   {
      if(MQLInfoInteger(MQL_OPTIMIZATION))
      {
         m_samples++;
         DF_SIGNAL.Resize(m_samples,__INPUTS+2);
         
         for(int i=0;i<__INPUTS;i++)
         {
            DF_SIGNAL[m_samples-1].Set(i,m_signals[0][i]);
         }
         //
         DF_SIGNAL[m_samples-1].Set(__INPUTS,Signal);
         DF_SIGNAL[m_samples-1].Set(__INPUTS+1,1-Signal);    
      }
   }

 

2.1.2. Результаты

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

      if(HistorySelect(0,m_symbol.Time()))
      {
         int _deals=HistoryDealsTotal();
         
         for(int d=_deals-1;d>=0;d--)
         {
            ulong _deal_ticket=HistoryDealGetTicket(d);
            if(HistoryDealSelect(_deal_ticket))
            {
               if(HistoryDealGetInteger(_deal_ticket,DEAL_ENTRY)==DEAL_ENTRY_OUT)
               {
                  _result=HistoryDealGetDouble(_deal_ticket,DEAL_PROFIT);
                  break;
               }
            }
         }
      }
   
      return(_result);

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

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+  
void CSignalSE::ResultUpdate(double Result)
   {
      if(MQLInfoInteger(MQL_OPTIMIZATION))
      {
         int _err;
         if(Result<0.0) 
         {
            double _odds = MathRandomUniform(0,1,_err);
            //
            DF_SIGNAL[m_samples-1].Set(__INPUTS,_odds);
            DF_SIGNAL[m_samples-1].Set(__INPUTS+1,1-_odds);
         }
      }
   }


2.1.3. Написание Forest

Лес будет записан на тике перед чтением, поэтому мы модифицируем советника, собранного Мастером, чтобы учесть это. 

//+------------------------------------------------------------------+
//| "Tick" event handler function                                    |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(!signal_se.m_read_forest) signal_se.WriteForest();
   
   ExtExpert.OnTick();
  }


2.1.4. Чтение Forest

Лес будет записан в тестере в конце прогона, поэтому мы модифицируем советника, собранного Мастером, чтобы учесть это. 

//+------------------------------------------------------------------+
//| "Tester" event handler function                                  |
//+------------------------------------------------------------------+  
double OnTester()
   {
    signal_se.ReadForest();
    return(0.0);
   }


2.2. Денежный класс советника

В этой статье мы также рассмотрим создание кастомного класса изменения размера позиции для использования с Мастером. Используем класс Money Size Optimized и изменим его, чтобы нормализовать размеры позиций на основе энтропии Шеннона. Наш новый интерфейс будет выглядеть так: 

// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Trading with 'Shannon Entropy' optimized trade volume      |
//| Type=Money                                                       |
//| Name=SE                                                          |
//| Class=CMoneySE                                                   |
//| Page=money_se                                                    |
//| Parameter=ScaleFactor,int,3,Scale factor                         |
//| Parameter=Percent,double,10.0,Percent                            |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| Class CMoneySE.                                                  |
//| Purpose: Class of money management with 'Shannon Entropy' optimized volume.          |
//|              Derives from class CExpertMoney.                    |
//+------------------------------------------------------------------+
class CMoneySE : public CExpertMoney
  {
protected:
   int               m_scale_factor;

public:
   double            m_absolute_condition;
   
                     CMoneySE(void);
                    ~CMoneySE(void);
   //---
   void              ScaleFactor(int scale_factor) { m_scale_factor=scale_factor; }
   void              AbsoluteCondition(double absolute_condition) { m_absolute_condition=absolute_condition; }
   virtual bool      ValidationSettings(void);
   //---
   virtual double    CheckOpenLong(double price,double sl);
   virtual double    CheckOpenShort(double price,double sl);

protected:
   double            Optimize(double lots);
  };

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

//+------------------------------------------------------------------+
//| Global expert object                                             |
//+------------------------------------------------------------------+
CExpert ExtExpert;
CSignalSE *signal_se;
CMoneySE *money_se;

Сделаем то же самое в тиковой функции:

//+------------------------------------------------------------------+
//| "Tick" event handler function                                    |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(!signal_se.m_read_forest) signal_se.WriteForest();
   
   money_se.AbsoluteCondition(fabs(signal_se.m_last_condition));
   
   ExtExpert.OnTick();
  }

Основные изменения будут внесены в функцию Optimize: 

//+------------------------------------------------------------------+
//| Optimizing lot size for open.                                    |
//+------------------------------------------------------------------+
double CMoneySE::Optimize(double lots)
  {
   double lot=lots;
   
      //--- normalize lot size based on magnitude of condition
      lot*=(20*m_scale_factor/fmax(20.0,((100.0-m_absolute_condition)/100.0)*20.0*m_scale_factor*m_scale_factor));
      
      //--- reduce lot based on number of losses orders without a break
      if(m_scale_factor>0)
      {
         //--- select history for access
         HistorySelect(0,TimeCurrent());
         //---
         int       orders=HistoryDealsTotal();  // total history deals
         int       losses=0;                    // number of consequent losing orders
         CDealInfo deal;
         //---
         for(int i=orders-1;i>=0;i--)
         {
            deal.Ticket(HistoryDealGetTicket(i));
            if(deal.Ticket()==0)
            {
               Print("CMoneySE::Optimize: HistoryDealGetTicket failed, no trade history");
               break;
            }
            //--- check symbol
            if(deal.Symbol()!=m_symbol.Name())
               continue;
            //--- check profit
            double profit=deal.Profit();
            if(profit>0.0)
               break;
            if(profit<0.0)
               losses++;
         }
         //---
         if(losses>1){
         lot*=m_scale_factor;
         lot/=(losses+m_scale_factor);
         lot=NormalizeDouble(lot,2);}
      }
      //--- normalize and check limits
      double stepvol=m_symbol.LotsStep();
      lot=stepvol*NormalizeDouble(lot/stepvol,0);
      //---
      double minvol=m_symbol.LotsMin();
      if(lot<minvol){ lot=minvol; }
      //---
      double maxvol=m_symbol.LotsMax();
      if(lot>maxvol){ lot=maxvol; }
//---
   return(lot);
  }

 

3.0. Мастер MQL5

Мы соберем два советника: один только с созданным нами классом сигналов плюс торговля минимальным объемом для управления капиталом, а второй — с созданными нами классами сигналов и управления капиталом.


4.0. Тестер стратегий

Оптимизация первого советника дает профит-фактор 2,89 и коэффициент Шарпа 4,87. При оптимизации второго советника получаем профит-фактор 3,65 и коэффициент Шарпа 5,79.

 

Первый отчет

 

s_r

 

Первая кривая эквити


s_c

 

Второй отчет

 

m_r

 

Вторая кривая эквити

 

m_c


5.0. Заключение

Приложенные советники были оптимизированы по ценам открытия 4-часового таймфрейма для идеальных уровней тейк-профита и стоп-лосса. Это означает, что вы не сможете воспроизвести эти результаты на реальном счете или даже в тестере стратегий в режиме каждого тика. Но смысл статьи не в этом. Вместо того, чтобы пытаться придумать грааль, который каждый должен воспроизвести, эта серия статей стремится раскрыть различные идеи, которые каждый трейдер может приспособить под свои нужды. Рынки в целом все еще слишком сильно коррелированы, поэтому поиск преимущества может сослужить вам хорошую службу в условиях высокой волатильности. Спасибо за внимание!

Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/11487

Прикрепленные файлы |
expert_se.mq5 (7.48 KB)
se.mq5 (7.75 KB)
SignalSE.mqh (24.84 KB)
MoneySE.mqh (6.55 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (1)
Aleksey Vyazmikin
Aleksey Vyazmikin | 24 мар. 2024 в 00:04

Прочитал статью, но толком не понял:

1. Что подаёте на вход случайному лесу.

2. Как считаете энтропию - по истории классификации леса?

Перевод статьи не высокого качества, к сожалению, что осложняет понимание.

Иногда кажется, что не хватает иллюстраций к статье, хотя в тексте идёт о них речь:

"

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

"

Разработка торговой системы на основе индикатора VIDYA Разработка торговой системы на основе индикатора VIDYA
Представляю вашему вниманию новую статью из серии, в которой мы учимся строить торговые системы на основе самых популярных индикаторов. В этой статье мы поговорим об индикаторе Скользящей средней с динамическим периодом усреднения (Variable Index Dynamic Average, VIDYA) и создадим торговую систему по его показателям.
Нейросети — это просто (Часть 32): Распределенное Q-обучение Нейросети — это просто (Часть 32): Распределенное Q-обучение
В одной из статей данной серии мы с вами уже познакомились с методом Q-обучения. Данный метод усредняет вознаграждения за каждое действие. В 2017 году были представлены сразу 2 работы, в которых большего успеха добиваются при изучении функции распределения вознаграждения. Давайте рассмотрим возможность использования подобной технологии для решения наших задач.
Управление рисками и капиталом с помощью советников Управление рисками и капиталом с помощью советников
Эта статья о том, чего вы не найдете в отчете о тестировании, чего следует ожидать при использовании советников, как управлять своими деньгами при использовании роботов и как покрыть значительный убыток, чтобы остаться в трейдинге при автоматизированной торговле.
Магия временных торговых интервалов с инструментом Frames Analyzer Магия временных торговых интервалов с инструментом Frames Analyzer
Что такое Frames Analyzer? Это подключаемый модуль к любому торговому эксперту для анализа фреймов оптимизации во время оптимизации параметров в тестере стратегий, а также вне тестера посредством чтения MQD-файла или базы данных, которая создаётся сразу после оптимизации параметров. Вы сможете делиться этими результатами оптимизации с другими пользователями, у которых есть инструмент Frames Analyzer, чтобы обсудить полученные результаты оптимизации вместе.