English 中文 Español Deutsch 日本語 Português
preview
Эксперименты с нейросетями (Часть 7): Передаем индикаторы

Эксперименты с нейросетями (Часть 7): Передаем индикаторы

MetaTrader 5Торговые системы | 24 октября 2023, 15:41
1 657 5
Roman Poshtar
Roman Poshtar

Введение

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


Предыстория и наблюдения

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

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



Теория и понятия

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

  1. Дистанции – расстояния, какого-либо индикатора к другому индикатору или своему нулевому значению. Основным принципом, по моему мнению, является привязка текущей ситуации к стабильному значению на истории. Если мы передадим прямое значение индикатора MA 1 то получим непонятный разброс выборки так как значение цены меняется со временем и не «ходило» в определенном диапазоне что подразумевает классификацию или малейший намек на статистическое поведение. Иное дело, когда мы передадим разницу между двумя индикаторами MA 1 и MA 100 в пунктах, например. Или текущее расстояние на нулевой свече индикатора MACD с его значением 4 свечи назад. Таким образом, при помощи использования дистанций мы можем определить, далеко ли рынок ушел от своего среднего значения. Сильно ли он перекуплен, перепродан по сравнению с выборкой истории на текущий момент. Также при помощи дистанции мы определяем, куда движется рынок вверх или вниз, значение может принимать как положительное число, так и отрицательное.

  2. Накопление – подсчет суммарного значения индикатора или индикаторов относительно друг друга или своей нулевой точки. Или точки нулевого значения в некоторых индикаторах отличных от нуля. Таким образом, мы можем, определить при помощи накопления как долго происходит то или иное движение в определенную сторону. Если накопление маленькое возможно сейчас идет консолидация и наоборот, если накопление большое идет затяжной тренд. В зависимости от знака - или +, в какую сторону. То есть значения накоплений не имеют больших значений при «болтанке» - консолидации и имеют большие значения при трендах.

  3. Углы наклона – текущий угол наклона индикатора является очень хорошим средством сообщить нейросети об импульсном движении в данный момент или его отсутствия и затухании активности по инструменту. Возможность определения углов наклона индикаторов за определенную историю, например в 10 свечей неплохо себя зарекомендовало в анализе текущей ситуации по сравнению с результатами выборки на истории. Напомню, что углы наклона я измеряю в радианах, это единственный метод, который подошёл лично мне и не зависит от масштаба графика. 



Примеры

Примеры использования дистанций:

  • Передача дистанций на текущей нулевой свече. Индикатор MA 1 относительно MA 100. Индикатор MACD относительно своего текущего и нулевого значения. Индикатор CCI относительно своего текущего и нулевого значения.
#property copyright   "2023, Roman Poshtar"
#property link        "https://www.mql5.com/ru/users/romanuch"
#property strict
#property version   "1.0"

input int    x1 = 1;
input int    x2 = 1;
input int    x3 = 1;

int handle_In1S1;
int handle_In2S1;
int handle_In3S1;
int handle_In4S1;

double ind_In1S1[];
double ind_In2S1[];
double ind_In3S1[];
double ind_In4S1[];

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {

   handle_In1S1=iMA(Symbol(),PERIOD_CURRENT,1,0,MODE_SMA,PRICE_CLOSE);
//--- if the handle is not created
   if(handle_In1S1==INVALID_HANDLE)
     {
      return(INIT_FAILED);
     }
//---

   handle_In2S1=iMA(Symbol(),PERIOD_CURRENT,100,0,MODE_SMA,PRICE_CLOSE);
//--- if the handle is not created
   if(handle_In2S1==INVALID_HANDLE)
     {
      return(INIT_FAILED);
     }
//---

   handle_In3S1=iMACD(Symbol(),PERIOD_CURRENT,12,26,9,PRICE_CLOSE);
//--- if the handle is not created
   if(handle_In3S1==INVALID_HANDLE)
     {
      return(INIT_FAILED);
     }
//---

   handle_In4S1=iCCI(Symbol(),PERIOD_CURRENT,14,PRICE_CLOSE);
//--- if the handle is not created
   if(handle_In4S1==INVALID_HANDLE)
     {
      return(INIT_FAILED);
     }
//---

   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {

//--- get data from the three buffers of the i-Regr indicator
   ArraySetAsSeries(ind_In1S1,true);
   if(!iGetArray(handle_In1S1,0,0,1010,ind_In1S1))
     {
      return;
     }
//---

//--- get data from the three buffers of the i-Regr indicator
   ArraySetAsSeries(ind_In2S1,true);
   if(!iGetArray(handle_In2S1,0,0,1010,ind_In2S1))
     {
      return;
     }
//---

//--- get data from the three buffers of the i-Regr indicator
   ArraySetAsSeries(ind_In3S1,true);
   if(!iGetArray(handle_In3S1,0,0,1010,ind_In3S1))
     {
      return;
     }
//---

//--- get data from the three buffers of the i-Regr indicator
   ArraySetAsSeries(ind_In4S1,true);
   if(!iGetArray(handle_In4S1,0,0,1010,ind_In4S1))
     {
      return;
     }
//---

   perceptron1();

  }

//+------------------------------------------------------------------+
//|  The PERCEPRRON - a perceiving and recognizing function          |
//+------------------------------------------------------------------+
double perceptron1()
  {

   double w1 = x1 - 10.0;
   double w2 = x2 - 10.0;
   double w3 = x3 - 10.0;

   double a1 = ((ind_In1S1[0]-ind_In2S1[0])/Point());

   double a2 = ind_In3S1[0];

   double a3 = ind_In4S1[0];

   Print("a1 = ", a1);
   Print("a2 = ", a2);
   Print("a3 = ", a3);
   Print("Perceptron = ", (w1 * a1 + w2 * a2 + w3 * a3));
   Print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");

   return (w1 * a1 + w2 * a2 + w3 * a3);

  }

Выводимая информация в журнал:

Пример дистанции 1

a1 - разница в пунктах валютной пары между индикатором MA 1 и MA 100. Может принимать как положительное, так и отрицательное значение.

a2 - текущее значение индикатора MACD. Может принимать как положительное, так и отрицательное значение.

a3 - текущее значение индикатора CCI. Может принимать как положительное, так и отрицательное значение.

  • Передача дистанций на N-количества свечей назад. Индикатор MA 1. Индикатор MA 100. Индикатор MACD. Индикатор CCI.
#property copyright   "2023, Roman Poshtar"
#property link        "https://www.mql5.com/ru/users/romanuch"
#property strict
#property version   "1.0"

input int    Candles= 10;

input int    x1 = 1;
input int    x2 = 1;
input int    x3 = 1;
input int    x4 = 1;

int handle_In1S1;
int handle_In2S1;
int handle_In3S1;
int handle_In4S1;

double ind_In1S1[];
double ind_In2S1[];
double ind_In3S1[];
double ind_In4S1[];

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {

   handle_In1S1=iMA(Symbol(),PERIOD_CURRENT,1,0,MODE_SMA,PRICE_CLOSE);
//--- if the handle is not created
   if(handle_In1S1==INVALID_HANDLE)
     {
      return(INIT_FAILED);
     }
//---

   handle_In2S1=iMA(Symbol(),PERIOD_CURRENT,100,0,MODE_SMA,PRICE_CLOSE);
//--- if the handle is not created
   if(handle_In2S1==INVALID_HANDLE)
     {
      return(INIT_FAILED);
     }
//---

   handle_In3S1=iMACD(Symbol(),PERIOD_CURRENT,12,26,9,PRICE_CLOSE);
//--- if the handle is not created
   if(handle_In3S1==INVALID_HANDLE)
     {
      return(INIT_FAILED);
     }
//---

   handle_In4S1=iCCI(Symbol(),PERIOD_CURRENT,14,PRICE_CLOSE);
//--- if the handle is not created
   if(handle_In4S1==INVALID_HANDLE)
     {
      return(INIT_FAILED);
     }
//---

   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {

//--- get data from the three buffers of the i-Regr indicator
   ArraySetAsSeries(ind_In1S1,true);
   if(!iGetArray(handle_In1S1,0,0,1010,ind_In1S1))
     {
      return;
     }
//---

//--- get data from the three buffers of the i-Regr indicator
   ArraySetAsSeries(ind_In2S1,true);
   if(!iGetArray(handle_In2S1,0,0,1010,ind_In2S1))
     {
      return;
     }
//---

//--- get data from the three buffers of the i-Regr indicator
   ArraySetAsSeries(ind_In3S1,true);
   if(!iGetArray(handle_In3S1,0,0,1010,ind_In3S1))
     {
      return;
     }
//---

//--- get data from the three buffers of the i-Regr indicator
   ArraySetAsSeries(ind_In4S1,true);
   if(!iGetArray(handle_In4S1,0,0,1010,ind_In4S1))
     {
      return;
     }
//---

   perceptron1();

  }

//+------------------------------------------------------------------+
//|  The PERCEPRRON - a perceiving and recognizing function          |
//+------------------------------------------------------------------+
double perceptron1()
  {

   double w1 = x1 - 10.0;
   double w2 = x2 - 10.0;
   double w3 = x3 - 10.0;
   double w4 = x4 - 10.0;

   double a1 = ((ind_In1S1[0]-ind_In1S1[Candles])/Point());

   double a2 = ((ind_In2S1[0]-ind_In2S1[Candles])/Point());

   double a3 = ind_In3S1[0]-ind_In3S1[Candles];
   
   double a4 = ind_In4S1[0]-ind_In4S1[Candles];

   Print("a1 = ", a1);
   Print("a2 = ", a2);
   Print("a3 = ", a3);
   Print("a3 = ", a4);
   Print("Perceptron = ", (w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4));
   Print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");

   return (w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4);

  }

Выводимая информация в журнал:

Пример дистанции 2

a1 - разница в пунктах валютной пары индикатором MA 1 на свече 0 и свече 10. Может принимать как положительное, так и отрицательное значение.

a2 - разница в пунктах валютной пары индикатором MA 100 на свече 0 и свече 10. Может принимать как положительное, так и отрицательное значение.

a3 - разница в значении индикатора MACD на свече 0 и свече 10. Может принимать как положительное, так и отрицательное значение.

a4 -  разница в значении индикатора CCI на свече 0 и свече 10. Может принимать как положительное, так и отрицательное значение.

  • Передача дистанций от точки пересечения индикаторов MA1 и MA 100 относительно своего нулевого значения в прошлом. Индикатор MACD относительно своего нулевого значения в прошлом. Индикатор CCI относительно своего нулевого значения в прошлом.
#property copyright   "2023, Roman Poshtar"
#property link        "https://www.mql5.com/ru/users/romanuch"
#property strict
#property version   "1.0"

input int    Candles= 10;

input int    x1 = 1;
input int    x2 = 1;
input int    x3 = 1;
input int    x4 = 1;

int handle_In1S1;
int handle_In2S1;
int handle_In3S1;
int handle_In4S1;

double ind_In1S1[];
double ind_In2S1[];
double ind_In3S1[];
double ind_In4S1[];

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {

   handle_In1S1=iMA(Symbol(),PERIOD_CURRENT,1,0,MODE_SMA,PRICE_CLOSE);
//--- if the handle is not created
   if(handle_In1S1==INVALID_HANDLE)
     {
      return(INIT_FAILED);
     }
//---

   handle_In2S1=iMA(Symbol(),PERIOD_CURRENT,100,0,MODE_SMA,PRICE_CLOSE);
//--- if the handle is not created
   if(handle_In2S1==INVALID_HANDLE)
     {
      return(INIT_FAILED);
     }
//---

   handle_In3S1=iMACD(Symbol(),PERIOD_CURRENT,12,26,9,PRICE_CLOSE);
//--- if the handle is not created
   if(handle_In3S1==INVALID_HANDLE)
     {
      return(INIT_FAILED);
     }
//---

   handle_In4S1=iCCI(Symbol(),PERIOD_CURRENT,14,PRICE_CLOSE);
//--- if the handle is not created
   if(handle_In4S1==INVALID_HANDLE)
     {
      return(INIT_FAILED);
     }
//---

   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {

//--- get data from the three buffers of the i-Regr indicator
   ArraySetAsSeries(ind_In1S1,true);
   if(!iGetArray(handle_In1S1,0,0,1010,ind_In1S1))
     {
      return;
     }
//---

//--- get data from the three buffers of the i-Regr indicator
   ArraySetAsSeries(ind_In2S1,true);
   if(!iGetArray(handle_In2S1,0,0,1010,ind_In2S1))
     {
      return;
     }
//---

//--- get data from the three buffers of the i-Regr indicator
   ArraySetAsSeries(ind_In3S1,true);
   if(!iGetArray(handle_In3S1,0,0,1010,ind_In3S1))
     {
      return;
     }
//---

//--- get data from the three buffers of the i-Regr indicator
   ArraySetAsSeries(ind_In4S1,true);
   if(!iGetArray(handle_In4S1,0,0,1010,ind_In4S1))
     {
      return;
     }
//---

   perceptron1();

  }

//+------------------------------------------------------------------+
//|  The PERCEPRRON - a perceiving and recognizing function          |
//+------------------------------------------------------------------+
double perceptron1()
  {
  
  int c1=0;
  int c2=0;
  int c3=0;

   double w1 = x1 - 10.0;
   double w2 = x2 - 10.0;
   double w3 = x3 - 10.0;
   double w4 = x4 - 10.0;
   
   for(int i=0; i<=1000; i++){
   
    if(ind_In1S1[0]>ind_In2S1[0]){if (ind_In1S1[i]<ind_In2S1[i]){c1=i; break;}}
    
    if(ind_In1S1[0]<ind_In2S1[0]){if (ind_In1S1[i]>ind_In2S1[i]){c1=i; break;}}
   
   }   

   double a1 = ((ind_In1S1[0]-ind_In1S1[c1])/Point());
   
   double a2 = ((ind_In2S1[0]-ind_In2S1[c1])/Point());
   
   for(int i=0; i<=1000; i++){
   
    if(ind_In3S1[0]>0){if (ind_In3S1[i]<0){c2=i; break;}}
    
    if(ind_In3S1[0]<0){if (ind_In3S1[i]>0){c2=i; break;}}
   
   }      

   double a3 = ind_In3S1[0]-ind_In3S1[c2];
   
   for(int i=0; i<=1000; i++){
   
    if(ind_In4S1[0]>0){if (ind_In4S1[i]<0){c3=i; break;}}
    
    if(ind_In4S1[0]<0){if (ind_In4S1[i]>0){c3=i; break;}}
   
   }       
   
   double a4 = ind_In4S1[0]-ind_In4S1[c3];

   Print("a1 = ", a1);
   Print("a2 = ", a2);
   Print("a3 = ", a3);
   Print("a4 = ", a4);
   Print("Perceptron = ", (w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4));
   Print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");

   return (w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4);

  }

Выводимая информация в журнал:

Пример дистанции 3

a1 - разница в пунктах валютной пары индикатором MA 1 на свече 0 и свече где было последнее пересечение индикаторов MA1 и MA 100. Может принимать как положительное, так и отрицательное значение.

a2 -  разница в пунктах валютной пары индикатором MA 100 на свече 0 и свече где было последнее пересечение индикаторов MA1 и MA 100. Может принимать как положительное, так и отрицательное значение.

a3 - разница в значении индикатора MACD на свече 0 и свече где было последнее пересечение со значением 0. Может принимать как положительное, так и отрицательное значение.

a4 -  разница в значении индикатора CCI на свече 0  и свече где было последнее пересечение со значением 0 . Может принимать как положительное, так и отрицательное значение.

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


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

  • Передача накопления за N-количества свечей индикатора.
#property copyright   "2023, Roman Poshtar"
#property link        "https://www.mql5.com/ru/users/romanuch"
#property strict
#property version   "1.0"

input int    Candles= 10;

input int    x1 = 1;
input int    x2 = 1;
input int    x3 = 1;

int handle_In1S1;
int handle_In2S1;
int handle_In3S1;
int handle_In4S1;

double ind_In1S1[];
double ind_In2S1[];
double ind_In3S1[];
double ind_In4S1[];

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {

   handle_In1S1=iMA(Symbol(),PERIOD_CURRENT,1,0,MODE_SMA,PRICE_CLOSE);
//--- if the handle is not created
   if(handle_In1S1==INVALID_HANDLE)
     {
      return(INIT_FAILED);
     }
//---

   handle_In2S1=iMA(Symbol(),PERIOD_CURRENT,100,0,MODE_SMA,PRICE_CLOSE);
//--- if the handle is not created
   if(handle_In2S1==INVALID_HANDLE)
     {
      return(INIT_FAILED);
     }
//---

   handle_In3S1=iMACD(Symbol(),PERIOD_CURRENT,12,26,9,PRICE_CLOSE);
//--- if the handle is not created
   if(handle_In3S1==INVALID_HANDLE)
     {
      return(INIT_FAILED);
     }
//---

   handle_In4S1=iCCI(Symbol(),PERIOD_CURRENT,14,PRICE_CLOSE);
//--- if the handle is not created
   if(handle_In4S1==INVALID_HANDLE)
     {
      return(INIT_FAILED);
     }
//---

   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {

//--- get data from the three buffers of the i-Regr indicator
   ArraySetAsSeries(ind_In1S1,true);
   if(!iGetArray(handle_In1S1,0,0,1010,ind_In1S1))
     {
      return;
     }
//---

//--- get data from the three buffers of the i-Regr indicator
   ArraySetAsSeries(ind_In2S1,true);
   if(!iGetArray(handle_In2S1,0,0,1010,ind_In2S1))
     {
      return;
     }
//---

//--- get data from the three buffers of the i-Regr indicator
   ArraySetAsSeries(ind_In3S1,true);
   if(!iGetArray(handle_In3S1,0,0,1010,ind_In3S1))
     {
      return;
     }
//---

//--- get data from the three buffers of the i-Regr indicator
   ArraySetAsSeries(ind_In4S1,true);
   if(!iGetArray(handle_In4S1,0,0,1010,ind_In4S1))
     {
      return;
     }
//---

   perceptron1();

  }

//+------------------------------------------------------------------+
//|  The PERCEPRRON - a perceiving and recognizing function          |
//+------------------------------------------------------------------+
double perceptron1()
  {
   double sum1 = 0;
   double sum2 = 0;
   double sum3 = 0;

   double w1 = x1 - 10.0;
   double w2 = x2 - 10.0;
   double w3 = x3 - 10.0;

   for(int i=0; i<=Candles; i++)
     {

      sum1+=ind_In1S1[i]-ind_In2S1[i];

     }

   double a1 = sum1;

   for(int i=0; i<=Candles; i++)
     {

      sum2+=ind_In3S1[i];

     }

   double a2 = sum2;

   for(int i=0; i<=Candles; i++)
     {

      sum3+=ind_In4S1[i];

     }

   double a3 = sum3;

   Print("a1 = ", a1);
   Print("a2 = ", a2);
   Print("a3 = ", a3);
   Print("Perceptron = ", (w1 * a1 + w2 * a2 + w3 * a3));
   Print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");

   return (w1 * a1 + w2 * a2 + w3 * a3);

  }

Выводимая информация в журнал:

Пример накопления 1

a1 - накопление разницы между индикаторами MA1 и MA 100 за количество свечей параметра Candles. Может принимать как положительное, так и отрицательное значение.

a2 - накопление индикатора MACD за количество свечей параметра Candles. Может принимать как положительное, так и отрицательное значение.

a3 - накопление индикатора CCI за количество свечей параметра Candles. Может принимать как положительное, так и отрицательное значение.

  • Передача накопления от нулевой точки индикатора в прошлом или последнего пересечения индикаторов в прошлом.
#property copyright   "2023, Roman Poshtar"
#property link        "https://www.mql5.com/ru/users/romanuch"
#property strict
#property version   "1.0"

input int    Candles= 10;

input int    x1 = 1;
input int    x2 = 1;
input int    x3 = 1;

int handle_In1S1;
int handle_In2S1;
int handle_In3S1;
int handle_In4S1;

double ind_In1S1[];
double ind_In2S1[];
double ind_In3S1[];
double ind_In4S1[];

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {

   handle_In1S1=iMA(Symbol(),PERIOD_CURRENT,1,0,MODE_SMA,PRICE_CLOSE);
//--- if the handle is not created
   if(handle_In1S1==INVALID_HANDLE)
     {
      return(INIT_FAILED);
     }
//---

   handle_In2S1=iMA(Symbol(),PERIOD_CURRENT,100,0,MODE_SMA,PRICE_CLOSE);
//--- if the handle is not created
   if(handle_In2S1==INVALID_HANDLE)
     {
      return(INIT_FAILED);
     }
//---

   handle_In3S1=iMACD(Symbol(),PERIOD_CURRENT,12,26,9,PRICE_CLOSE);
//--- if the handle is not created
   if(handle_In3S1==INVALID_HANDLE)
     {
      return(INIT_FAILED);
     }
//---

   handle_In4S1=iCCI(Symbol(),PERIOD_CURRENT,14,PRICE_CLOSE);
//--- if the handle is not created
   if(handle_In4S1==INVALID_HANDLE)
     {
      return(INIT_FAILED);
     }
//---

   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {

//--- get data from the three buffers of the i-Regr indicator
   ArraySetAsSeries(ind_In1S1,true);
   if(!iGetArray(handle_In1S1,0,0,1010,ind_In1S1))
     {
      return;
     }
//---

//--- get data from the three buffers of the i-Regr indicator
   ArraySetAsSeries(ind_In2S1,true);
   if(!iGetArray(handle_In2S1,0,0,1010,ind_In2S1))
     {
      return;
     }
//---

//--- get data from the three buffers of the i-Regr indicator
   ArraySetAsSeries(ind_In3S1,true);
   if(!iGetArray(handle_In3S1,0,0,1010,ind_In3S1))
     {
      return;
     }
//---

//--- get data from the three buffers of the i-Regr indicator
   ArraySetAsSeries(ind_In4S1,true);
   if(!iGetArray(handle_In4S1,0,0,1010,ind_In4S1))
     {
      return;
     }
//---

   perceptron1();

  }

//+------------------------------------------------------------------+
//|  The PERCEPRRON - a perceiving and recognizing function          |
//+------------------------------------------------------------------+
double perceptron1()
  {
   double sum1 = 0;
   double sum2 = 0;
   double sum3 = 0;

   double w1 = x1 - 10.0;
   double w2 = x2 - 10.0;
   double w3 = x3 - 10.0;

   for(int i=0; i<=1000; i++)
     {

      if(ind_In1S1[0]>ind_In2S1[0])
        {
         if(ind_In1S1[i]<ind_In2S1[i])
           {
            break;
           };
         sum1+=(ind_In1S1[i]-ind_In2S1[i]);
        }

      if(ind_In1S1[0]<ind_In2S1[0])
        {
         if(ind_In1S1[i]>ind_In2S1[i])
           {
            break;
           };
         sum1+=(ind_In1S1[i]-ind_In2S1[i]);
        }

     }

   double a1 = sum1;

   for(int i=0; i<=1000; i++)
     {

      if(ind_In3S1[0]>0)
        {
         if(ind_In3S1[i]<0)
           {
            break;
           };
         sum2+=ind_In3S1[i];
        }

      if(ind_In3S1[0]<0)
        {
         if(ind_In3S1[i]>0)
           {
            break;
           };
         sum2+=ind_In3S1[i];
        }

     }

   double a2 = sum2;

   for(int i=0; i<=1000; i++)
     {

      if(ind_In4S1[0]>0)
        {
         if(ind_In4S1[i]<0)
           {
            break;
           };
         sum3+=ind_In4S1[i];
        }

      if(ind_In4S1[0]<0)
        {
         if(ind_In4S1[i]>0)
           {
            break;
           };
         sum3+=ind_In4S1[i];
        }

     }

   double a3 = sum3;

   Print("a1 = ", a1);
   Print("a2 = ", a2);
   Print("a3 = ", a3);
   Print("Perceptron = ", (w1 * a1 + w2 * a2 + w3 * a3));
   Print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");

   return (w1 * a1 + w2 * a2 + w3 * a3);

  }

Выводимая информация в журнал:

Пример накопления 2

a1 - накопление разницы между индикаторами MA1 и MA 100 с точки последнего пересечения. Может принимать как положительное, так и отрицательное значение.

a2 - накопление индикатора MACD с точки последнего пересечения значания 0. Может принимать как положительное, так и отрицательное значение.

a3 - накопление индикатора CCI с точки последнего пересечения значания 0. Может принимать как положительное, так и отрицательное значение.


Примеры использования углов наклона индикаторов:

  • Передача углов наклона за N-количества свечей индикатора.
#property copyright   "2023, Roman Poshtar"
#property link        "https://www.mql5.com/ru/users/romanuch"
#property strict
#property version   "1.0"

input int    Candles= 10;

input int    x1 = 1;
input int    x2 = 1;
input int    x3 = 1;
input int    x4 = 1;

int handle_In1S1;
int handle_In2S1;
int handle_In3S1;
int handle_In4S1;

double ind_In1S1[];
double ind_In2S1[];
double ind_In3S1[];
double ind_In4S1[];

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {

   handle_In1S1=iMA(Symbol(),PERIOD_CURRENT,1,0,MODE_SMA,PRICE_CLOSE);
//--- if the handle is not created
   if(handle_In1S1==INVALID_HANDLE)
     {
      return(INIT_FAILED);
     }
//---

   handle_In2S1=iMA(Symbol(),PERIOD_CURRENT,100,0,MODE_SMA,PRICE_CLOSE);
//--- if the handle is not created
   if(handle_In2S1==INVALID_HANDLE)
     {
      return(INIT_FAILED);
     }
//---

   handle_In3S1=iMACD(Symbol(),PERIOD_CURRENT,12,26,9,PRICE_CLOSE);
//--- if the handle is not created
   if(handle_In3S1==INVALID_HANDLE)
     {
      return(INIT_FAILED);
     }
//---

   handle_In4S1=iCCI(Symbol(),PERIOD_CURRENT,14,PRICE_CLOSE);
//--- if the handle is not created
   if(handle_In4S1==INVALID_HANDLE)
     {
      return(INIT_FAILED);
     }
//---

   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {

//--- get data from the three buffers of the i-Regr indicator
   ArraySetAsSeries(ind_In1S1,true);
   if(!iGetArray(handle_In1S1,0,0,1010,ind_In1S1))
     {
      return;
     }
//---

//--- get data from the three buffers of the i-Regr indicator
   ArraySetAsSeries(ind_In2S1,true);
   if(!iGetArray(handle_In2S1,0,0,1010,ind_In2S1))
     {
      return;
     }
//---

//--- get data from the three buffers of the i-Regr indicator
   ArraySetAsSeries(ind_In3S1,true);
   if(!iGetArray(handle_In3S1,0,0,1010,ind_In3S1))
     {
      return;
     }
//---

//--- get data from the three buffers of the i-Regr indicator
   ArraySetAsSeries(ind_In4S1,true);
   if(!iGetArray(handle_In4S1,0,0,1010,ind_In4S1))
     {
      return;
     }
//---

   perceptron1();

  }

//+------------------------------------------------------------------+
//|  The PERCEPRRON - a perceiving and recognizing function          |
//+------------------------------------------------------------------+
double perceptron1()
  {

   double w1 = x1 - 10.0;
   double w2 = x2 - 10.0;
   double w3 = x3 - 10.0;
   double w4 = x4 - 10.0;

   double a1 = (((ind_In1S1[0]-ind_In1S1[Candles])/Point())/Candles);

   double a2 = (((ind_In2S1[0]-ind_In2S1[Candles])/Point())/Candles);

   double a3 = ((ind_In3S1[0]-ind_In3S1[Candles])/Candles);

   double a4 = ((ind_In4S1[0]-ind_In4S1[Candles])/Candles);

   Print("a1 = ", a1);
   Print("a2 = ", a2);
   Print("a3 = ", a3);
   Print("a4 = ", a4);
   Print("Perceptron = ", (w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4));
   Print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");

   return (w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4);

  }

Выводимая информация в журнал:

Пример углов 1

a1 - угол наклона индикатора MA1 за количество свечей параметра Candles. Может принимать как положительное, так и отрицательное значение.

a2 - угол наклона индикатора MA100 за количество свечей параметра Candles. Может принимать как положительное, так и отрицательное значение.

a3 - угол наклона индикатора MACD за количество свечей параметра Candles. Может принимать как положительное, так и отрицательное значение.

a4 - угол наклона индикатора CCI за количество свечей параметра Candles. Может принимать как положительное, так и отрицательное значение.

  • Передача углов наклона от нулевой точки индикатора в прошлом или последнего пересечения индикаторов в прошлом.
#property copyright   "2023, Roman Poshtar"
#property link        "https://www.mql5.com/ru/users/romanuch"
#property strict
#property version   "1.0"

input int    x1 = 1;
input int    x2 = 1;
input int    x3 = 1;
input int    x4 = 1;

int handle_In1S1;
int handle_In2S1;
int handle_In3S1;
int handle_In4S1;

double ind_In1S1[];
double ind_In2S1[];
double ind_In3S1[];
double ind_In4S1[];

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {

   handle_In1S1=iMA(Symbol(),PERIOD_CURRENT,1,0,MODE_SMA,PRICE_CLOSE);
//--- if the handle is not created
   if(handle_In1S1==INVALID_HANDLE)
     {
      return(INIT_FAILED);
     }
//---

   handle_In2S1=iMA(Symbol(),PERIOD_CURRENT,100,0,MODE_SMA,PRICE_CLOSE);
//--- if the handle is not created
   if(handle_In2S1==INVALID_HANDLE)
     {
      return(INIT_FAILED);
     }
//---

   handle_In3S1=iMACD(Symbol(),PERIOD_CURRENT,12,26,9,PRICE_CLOSE);
//--- if the handle is not created
   if(handle_In3S1==INVALID_HANDLE)
     {
      return(INIT_FAILED);
     }
//---

   handle_In4S1=iCCI(Symbol(),PERIOD_CURRENT,14,PRICE_CLOSE);
//--- if the handle is not created
   if(handle_In4S1==INVALID_HANDLE)
     {
      return(INIT_FAILED);
     }
//---

   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {

//--- get data from the three buffers of the i-Regr indicator
   ArraySetAsSeries(ind_In1S1,true);
   if(!iGetArray(handle_In1S1,0,0,1010,ind_In1S1))
     {
      return;
     }
//---

//--- get data from the three buffers of the i-Regr indicator
   ArraySetAsSeries(ind_In2S1,true);
   if(!iGetArray(handle_In2S1,0,0,1010,ind_In2S1))
     {
      return;
     }
//---

//--- get data from the three buffers of the i-Regr indicator
   ArraySetAsSeries(ind_In3S1,true);
   if(!iGetArray(handle_In3S1,0,0,1010,ind_In3S1))
     {
      return;
     }
//---

//--- get data from the three buffers of the i-Regr indicator
   ArraySetAsSeries(ind_In4S1,true);
   if(!iGetArray(handle_In4S1,0,0,1010,ind_In4S1))
     {
      return;
     }
//---

   perceptron1();

  }

//+------------------------------------------------------------------+
//|  The PERCEPRRON - a perceiving and recognizing function          |
//+------------------------------------------------------------------+
double perceptron1()
  {

   int c1=0;
   int c2=0;
   int c3=0;

   double w1 = x1 - 10.0;
   double w2 = x2 - 10.0;
   double w3 = x3 - 10.0;
   double w4 = x4 - 10.0;

   for(int i=0; i<=1000; i++)
     {

      if(ind_In1S1[0]>ind_In2S1[0])
        {
         if(ind_In1S1[i]<ind_In2S1[i])
           {
            c1=i;
            break;
           }
        }

      if(ind_In1S1[0]<ind_In2S1[0])
        {
         if(ind_In1S1[i]>ind_In2S1[i])
           {
            c1=i;
            break;
           }
        }

     }

   double a1 = (((ind_In1S1[0]-ind_In1S1[c1])/Point())/c1);

   double a2 = (((ind_In2S1[0]-ind_In2S1[c1])/Point())/c1);

   for(int i=0; i<=1000; i++)
     {

      if(ind_In3S1[0]>0)
        {
         if(ind_In3S1[i]<0)
           {
            c2=i;
            break;
           }
        }

      if(ind_In3S1[0]<0)
        {
         if(ind_In3S1[i]>0)
           {
            c2=i;
            break;
           }
        }

     }

   double a3 = ((ind_In3S1[0]-ind_In3S1[c2])/c2);

   for(int i=0; i<=1000; i++)
     {

      if(ind_In4S1[0]>0)
        {
         if(ind_In4S1[i]<0)
           {
            c3=i;
            break;
           }
        }

      if(ind_In4S1[0]<0)
        {
         if(ind_In4S1[i]>0)
           {
            c3=i;
            break;
           }
        }

     }

   double a4 = ((ind_In4S1[0]-ind_In4S1[c3])/c3);

   Print("a1 = ", a1);
   Print("a2 = ", a2);
   Print("a3 = ", a3);
   Print("a4 = ", a4);
   Print("Perceptron = ", (w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4));
   Print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");

   return (w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4);

  }

Выводимая информация в журнал:

Пример углов 2

a1 - угол наклона индикатора MA1 с точки последнего пересечения индикаторов MA1 и MA100. Может принимать как положительное, так и отрицательное значение.

a2 - угол наклона индикатора MA100 с точки последнего пересечения индикаторов MA1 и MA100. Может принимать как положительное, так и отрицательное значение.

a3 - угол наклона индикатора MACD с точки последнего пересечения индикатором значения 0. Может принимать как положительное, так и отрицательное значение.

a4 - угол наклона индикатора CCI с точки последнего пересечения индикатором значения 0. Может принимать как положительное, так и отрицательное значение.


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

  • Комбинированая передача значений двух индикаторов MA1 и MA100.
#property copyright   "2023, Roman Poshtar"
#property link        "https://www.mql5.com/ru/users/romanuch"
#property strict
#property version   "1.0"

input int    Candles= 10;

input int    x1 = 1;
input int    x2 = 1;
input int    x3 = 1;
input int    x4 = 1;
input int    x5 = 1;
input int    x6 = 1;
input int    x7 = 1;

int handle_In1S1;
int handle_In2S1;

double ind_In1S1[];
double ind_In2S1[];

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {

   handle_In1S1=iMA(Symbol(),PERIOD_CURRENT,1,0,MODE_SMA,PRICE_CLOSE);
//--- if the handle is not created
   if(handle_In1S1==INVALID_HANDLE)
     {
      return(INIT_FAILED);
     }
//---

   handle_In2S1=iMA(Symbol(),PERIOD_CURRENT,100,0,MODE_SMA,PRICE_CLOSE);
//--- if the handle is not created
   if(handle_In2S1==INVALID_HANDLE)
     {
      return(INIT_FAILED);
     }
//---

   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {

//--- get data from the three buffers of the i-Regr indicator
   ArraySetAsSeries(ind_In1S1,true);
   if(!iGetArray(handle_In1S1,0,0,1010,ind_In1S1))
     {
      return;
     }
//---

//--- get data from the three buffers of the i-Regr indicator
   ArraySetAsSeries(ind_In2S1,true);
   if(!iGetArray(handle_In2S1,0,0,1010,ind_In2S1))
     {
      return;
     }
//---

   perceptron1();

  }

//+------------------------------------------------------------------+
//|  The PERCEPRRON - a perceiving and recognizing function          |
//+------------------------------------------------------------------+
double perceptron1()
  {

   int c1=0;
   double sum1 = 0;
   double sum2 = 0;

   double w1 = x1 - 10.0;
   double w2 = x2 - 10.0;
   double w3 = x3 - 10.0;
   double w4 = x4 - 10.0;
   double w5 = x5 - 10.0;
   double w6 = x6 - 10.0;
   double w7 = x7 - 10.0;

   double a1 = ((ind_In1S1[0]-ind_In2S1[0])/Point());

   for(int i=0; i<=Candles; i++)
     {

      sum1+=ind_In1S1[i]-ind_In2S1[i];

     }

   double a2 = sum1;

   for(int i=0; i<=1000; i++)
     {

      if(ind_In1S1[0]>ind_In2S1[0])
        {
         if(ind_In1S1[i]<ind_In2S1[i])
           {
            break;
           };
         sum2+=(ind_In1S1[i]-ind_In2S1[i]);
        }

      if(ind_In1S1[0]<ind_In2S1[0])
        {
         if(ind_In1S1[i]>ind_In2S1[i])
           {
            break;
           };
         sum2+=(ind_In1S1[i]-ind_In2S1[i]);
        }

     }

   double a3 = sum2;

   double a4 = (((ind_In1S1[0]-ind_In1S1[Candles])/Point())/Candles);

   double a5 = (((ind_In2S1[0]-ind_In2S1[Candles])/Point())/Candles);

   for(int i=0; i<=1000; i++)
     {

      if(ind_In1S1[0]>ind_In2S1[0])
        {
         if(ind_In1S1[i]<ind_In2S1[i])
           {
            c1=i;
            break;
           }
        }

      if(ind_In1S1[0]<ind_In2S1[0])
        {
         if(ind_In1S1[i]>ind_In2S1[i])
           {
            c1=i;
            break;
           }
        }

     }

   double a6 = (((ind_In1S1[0]-ind_In1S1[c1])/Point())/c1);

   double a7 = (((ind_In2S1[0]-ind_In2S1[c1])/Point())/c1);

   Print("a1 = ", a1);
   Print("a2 = ", a2);
   Print("a3 = ", a3);
   Print("a4 = ", a4);
   Print("a5 = ", a5);
   Print("a6 = ", a6);
   Print("a7 = ", a7);
   Print("Perceptron = ", (w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4 + w5 * a5 + w6 * a6 + w7 * a7));
   Print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");

   return (w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4 + w5 * a5 + w6 * a6 + w7 * a7);

  }

Выводимая информация в журнал:

Пример комбинированной передачи 1

a1 - дистанция между индикаторами MA1 и MA100 на текущей свече. Может принимать как положительное, так и отрицательное значение.

a2 - накопление между индикаторами MA1 и MA100 за количество свечей параметра Candles. Может принимать как положительное, так и отрицательное значение.

a3 - накопление между индикаторами MA1 и MA100 с точки последнего пересечения индикаторов. Может принимать как положительное, так и отрицательное значение.

a4 - угол наклона индикатора MA1 за количество свечей параметра Candles. Может принимать как положительное, так и отрицательное значение.

a5 - угол наклона индикатора MA100 за количество свечей параметра Candles. Может принимать как положительное, так и отрицательное значение.

a6 - угол наклона индикатора MA1 с точки последнего пересечения индикаторов. Может принимать как положительное, так и отрицательное значение.

a7 - угол наклона индикатора MA100 с точки последнего пересечения индикаторов. Может принимать как положительное, так и отрицательное значение.


Советники

 Сегодня мы разработаем 2 советника. В качестве примера будем использовать значения дистанций между индикаторами. Первый предназначен для проведения оптимизации и подбора параметров. Второй непосредственно для торговли полученными результатами первого. Почему так спросите Вы, все просто, мы уже рассматривали данный подход в моих предыдущих статьях. Данный метод помогает сделать перебор и использование в торговле всех доступных результатов оптимизации, а не один из них. Например, мы получили при оптимизации 50 хороших результатов. Согласитесь, что устанавливать советник на 50 графиков не очень удобно. Потому используем все результаты одновременно при помощи второго советника.

Более подробно про применяемый метод вы можете прочитать в моей статье Эксперименты с нейросетями (Часть 3): Практическое применение

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

Основной код на открытие позиций.

      //SELL++++++++++++++++++++++++++++++++++++++++++++++++
      if((perceptron1()<-Param) && (CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_SELL, EAComment)==0) && (SpreadS1<=MaxSpread))
        {
         OpenSell(symbolS1.Name(), LotsXSell, TP, SL, EAComment);
        }

      //BUY++++++++++++++++++++++++++++++++++++++++++++++++
      if((perceptron1()>Param) && (CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_BUY, EAComment)==0) && (SpreadS1<=MaxSpread))
        {
         OpenBuy(symbolS1.Name(), LotsXBuy, TP, SL, EAComment);
        }

Код перцептрона.  

  1. a1 - дистанция между индикаторoм MA1 на текущей свече и свече в параметре Candles.  
  2. a2 - дистанция между индикаторoм MA100 на текущей свече и свече в параметре Candles.  
  3. a3 - дистанция между индикаторoм CCI на текущей свече и свече в параметре Candles.  
  4. a4 - дистанция между индикаторoм StdDev на текущей свече и свече в параметре Candles. 

Параметр Candlesв данном случае не оптимизировался и имел значение 8.

//+------------------------------------------------------------------+
//|  The PERCEPRRON - a perceiving and recognizing function          |
//+------------------------------------------------------------------+
double perceptron1()
  {

   double w1 = x1 - 10.0;
   double w2 = x2 - 10.0;
   double w3 = x3 - 10.0;
   double w4 = x4 - 10.0;

   double a1 = ((ind_In1S1[0]-ind_In1S1[Candles])/PointS1);

   double a2 = ((ind_In2S1[0]-ind_In2S1[Candles])/PointS1);

   double a3 = (ind_In3S1[0]-ind_In3S1[Candles]);

   double a4 = (ind_In4S1[0]-ind_In4S1[Candles]);

   return (w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4);
  }


Тут я предоставлю, все параметры для оптимизации и тестирования что бы дальше в тексте не повторятся:

  • Рынок Forex;
  • Валютная пара EURUSD;
  • Период H1;
  • Индикаторы: MA 1 SMA CLOSE, MA 200 SMA CLOSE, CCI 42, StdDev 60.
  • СтопЛосс и ТейкПрофит, 400 и 830;
  • Режим оптимизации и тестирования «1 Minute OHLC» и «Максимальная прибыльность». Наш советник изначально работает по ценам открытия М1. Сегодня в качестве эксперимента используем режим «Максимальная прибыльность»;
  • Диапазон оптимизации 1 год. С 2021.10.10 по 2022.10.10. 1 год не является, каким-то критерием. Вы можете попробовать больше или меньше самостоятельно;
  • Диапазон форвард тестирования 1 год. С 2022.10.10 по 2023.10.10;
  • В форвард тестировании использовалось 50 первых лучших результатов оптимизации одновременно;
  • Начальный депозит 10000;
  • Плече 1:500.

Настройки оптимизации приведу на скриншоте ниже:

Настройки оптимизации

Результаты оптимизации на скриншотах ниже:

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


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

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

string EURUSD[][8]=
  {
   {"Profit","Trades","x1","x2","x3","x4","Param"},
   {"266.45","239","2","1","9","8","5000"},
   {"266.45","239","2","1","9","13","5000"},
   {"266.45","239","2","1","9","11","5000"},
   {"266.45","239","2","1","9","10","5000"},
   {"266.45","239","2","1","9","8","5000"},
   {"266.45","239","2","1","9","12","5000"},
   {"266.45","239","2","1","9","20","5000"},
   {"266.45","239","2","1","9","14","5000"},
   {"266.45","239","2","1","9","2","5000"},
   {"266.45","239","2","1","9","3","5000"},
   {"259.69","239","0","0","12","17","5500"},
   {"259.69","239","0","0","12","8","5500"},
   {"259.69","239","0","0","12","1","5500"},
   {"259.69","239","0","0","12","9","5500"},
   {"259.69","239","0","0","12","16","5500"},
   {"259.69","239","0","0","12","18","5500"},
   {"259.69","239","0","0","12","11","5500"},
   {"259.69","239","0","0","12","7","5500"},
   {"259.69","239","0","0","12","15","5500"},
   {"259.69","239","0","0","12","8","5500"},
   {"259.69","239","0","0","12","9","5500"},
   {"259.69","239","0","0","12","17","5500"},
   {"259.69","239","0","0","12","6","5500"},
   {"259.69","239","0","0","12","15","5500"},
   {"259.69","239","0","0","12","4","5500"},
   {"259.69","239","0","0","12","7","5500"},
   {"259.69","239","0","0","12","11","5500"},
   {"259.69","239","0","0","12","14","5500"},
   {"259.69","239","0","0","12","1","5500"},
   {"259.69","239","0","0","12","5","5500"},
   {"259.69","239","0","0","12","3","5500"},
   {"259.69","239","0","0","12","0","5500"},
   {"259.69","239","0","0","12","12","5500"},
   {"259.69","239","0","0","12","16","5500"},
   {"259.69","239","0","0","12","8","5500"},
   {"259.69","239","0","0","12","10","5500"},
   {"259.69","239","0","0","12","16","5500"},
   {"259.69","239","0","0","12","18","5500"},
   {"259.69","239","0","0","12","13","5500"},
   {"259.69","239","0","0","12","9","5500"},
   {"259.69","239","0","0","12","12","5500"},
   {"259.69","239","0","0","12","11","5500"},
   {"259.69","239","0","0","12","7","5500"},
   {"259.69","239","0","0","12","15","5500"},
   {"259.69","239","0","0","12","14","5500"},
   {"259.69","239","0","0","12","3","5500"},
   {"259.69","239","0","0","12","19","5500"},
   {"259.69","239","0","0","12","0","5500"},
   {"259.69","239","0","0","12","17","5500"},
   {"259.69","239","0","0","12","2","5500"}
  };

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

      for(int i=1; i<=(ArraySize(EURUSD)/8)-1; i++)
        {

         comm=(EURUSD[i][0]+EURUSD[i][1]);

         x1=(int)StringToInteger(EURUSD[i][2]);
         x2=(int)StringToInteger(EURUSD[i][3]);
         x3=(int)StringToInteger(EURUSD[i][4]);
         x4=(int)StringToInteger(EURUSD[i][5]);

         Param=(int)StringToInteger(EURUSD[i][6]);

         //SELL++++++++++++++++++++++++++++++++++++++++++++++++
         if((NewOpen==true) && (CalculateSeries(Magic)<MaxSeries) && (perceptron1()<-Param) && (CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_SELL, EAComment+" En_"+comm)==0) && (SpreadS1<=MaxSpread))
           {
            OpenSell(symbolS1.Name(), LotsXSell, TP, SL, EAComment+" En_"+comm);
           }

         //BUY++++++++++++++++++++++++++++++++++++++++++++++++
         if((NewOpen==true) && (CalculateSeries(Magic)<MaxSeries) && (perceptron1()>Param) && (CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_BUY, EAComment+" En_"+comm)==0) && (SpreadS1<=MaxSpread))
           {
            OpenBuy(symbolS1.Name(), LotsXBuy, TP, SL, EAComment+" En_"+comm);
           }

        }
//+------------------------------------------------------------------+
//| Calculate Positions                                              |
//+------------------------------------------------------------------+
int CalculateSeries(ulong mag)
  {
   int total=0;
   string com="";

   for(int i=PositionsTotal()-1; i>=0; i--)
     {
      if(position.SelectByIndex(i))
        {
         if(position.Magic()==mag)
           {
            if(com!=position.Comment())
              {
               com=position.Comment();
               total++;
              }
           }
        }
     }
//---
   return(total);
  }

Результат бэквард-тестирования:

Результат бэквард тестирования

Результат форвард-тестирования:

Результат форвард тестирования


Результат форвард тестирования 2


Заключение

Список файлов во вложении:

  1. Distance 1, Distance 2, Distance 3, - советники с примерами передачи дистанций в перцептрон;
  2. Accumulation 1, Accumulation 2 - советники с примерами передачи накопления в перцептрон;
  3. Angle 1, Angle 2 - советники с примерами передачи углов наклона индикаторов в перцептрон;
  4. Combo 1 - советник с примером передачи комбинированных данных индикаторов в перцептрон;
  5. Perceptron – opt - советник для оптимизации;
  6. Perceptron – trade – советник для торговли оптимизированными параметрами.

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

По всем вопросам вы можете обратиться на форуме или в личные сообщения. Я всегда буду рад Вам помочь.

Прикрепленные файлы |
EA.zip (23.2 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (5)
Maxim Kuznetsov
Maxim Kuznetsov | 24 окт. 2023 в 16:23

Новый термин в трейдинге : Canbles :-) 

Исправь опечатки Candles! от слова Candle, через d

Roman Poshtar
Roman Poshtar | 28 окт. 2023 в 14:00
Maxim Kuznetsov #:

Новый термин в трейдинге : Canbles :-) 

Исправь опечатки Candles! от слова Candle, через d

Исправили. Спасибо за наблюдательность )

Grigori.S.B
Grigori.S.B | 29 окт. 2023 в 07:42
Roman Poshtar #:

Исправили. 

Нифига не исправил. Так и осталось Canbles.


Rashid Umarov
Rashid Umarov | 30 окт. 2023 в 17:19

Теперь точно все места в статье исправили. 

Спасибо за сообщение.

Roman Poshtar
Roman Poshtar | 30 окт. 2023 в 19:06
Rashid Umarov #:

Теперь точно все места в статье исправили. 

Спасибо за сообщение.

Спасибо.

Готовим мультисимвольные мультипериодные индикаторы Готовим мультисимвольные мультипериодные индикаторы
В статье рассмотрим принципы создания мультисимвольных мультипериодных индикаторов и получение от них данных в советниках и индикаторах. Рассмотрим основные нюансы использования мульти-индикаторов в советниках и индикаторах, и их отрисовку через буферы пользовательского индикатора.
Нейросети — это просто (Часть 60): Онлайн Трансформер решений (Online Decision Transformer—ODT) Нейросети — это просто (Часть 60): Онлайн Трансформер решений (Online Decision Transformer—ODT)
Последние 2 статьи были посвящены методу Decision Transformer, который моделирует последовательности действий в контексте авторегрессионной модели желаемых вознаграждений. В данной статье мы рассмотрим ещё один алгоритм оптимизации данного метода.
Нейросети — это просто (Часть 61): Проблема оптимизма в офлайн обучении с подкреплением Нейросети — это просто (Часть 61): Проблема оптимизма в офлайн обучении с подкреплением
В процессе офлайн обучения мы оптимизируем политику Агента по данным обучающей выборки. Полученная стратегия придает Агенту уверенность в его действиях. Однако такой оптимизм не всегда оправдан и может привести к увеличению рисков в процессе эксплуатации модели. Сегодня мы рассмотрим один из методов снижения этих рисков.
Все, что вам нужно знать о структуре программы MQL5 Все, что вам нужно знать о структуре программы MQL5
Любая программа на любом языке программирования имеет определенную структуру. В этой статье вы изучите основные компоненты структуры программы на MQL5, что может быть очень полезно при создании торговой системы или торгового инструмента для MetaTrader 5.