Матрицы и векторы в MQL5

 

Это сводная тема о матрицах и векторах в MQL5

Matrices and vectors in MQL5
Matrices and vectors in MQL5
  • www.mql5.com
By using special data types 'matrix' and 'vector', it is possible to create code which is very close to mathematical notation. With these methods, you can avoid the need to create nested loops or to mind correct indexing of arrays in calculations. Therefore, the use of matrix and vector methods increases the reliability and speed in developing complex programs.
 

Форум о трейдинге, автоматических торговых системах и тестировании торговых стратегий

Матрицы и векторы в MQL5. Поделитесь своим мнением

Слава, 2023.06.02 16:00

В конце 2021 года мы начали внедрять в MQL5 новые сущности - матрицы и векторы. В январе 2022 года в документации появился новый раздел "Типы данных - матрицы и векторы" и первый анонс "Новая версия платформы MetaTrader 5 build 3180: Векторы и матрицы в MQL5 и улучшенное удобство использования". Летом 2022 года в документации появился полноценный раздел "Методы матриц и векторов".

И работа продолжается. Мы пишем коды приложений (для внутреннего потребления и для статей) и сразу видим, что удобно, что неудобно, что нужно прямо сейчас, что в принципе необходимо, но может подождать. Однако нам нужно больше обратной связи. Возможно, у членов MQL5-сообщества есть идеи и предложения. Делитесь!


В свою очередь, я могу показать компактный код модели классификации

 //+------------------------------------------------------------------+
//|                                  NeuralNetworkClassification.mqh |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| neural network for classification model                          |
//+------------------------------------------------------------------+
class CNeuralNetwork
  {
protected :
   int                m_layers;                           // layers count
   ENUM_ACTIVATION_FUNCTION m_activation_functions[];     // layers activation functions
   matrix             m_weights[];                         // weights matrices between layers
   vector             m_values[];                         // layer values
   vector             m_values_a[];                       // layer values after activation
   vector             m_errors[];                         // error values for back propagation

public :
   //+------------------------------------------------------------------+
   //| Constructor                                                      |
   //+------------------------------------------------------------------+
   CNeuralNetwork( const int layers, const int & layer_sizes[], const ENUM_ACTIVATION_FUNCTION & act_functions[])
     {
      m_layers=layers;
       ArrayCopy (m_activation_functions,act_functions);
       ArrayResize (m_weights,layers- 1 );
       ArrayResize (m_values,layers);
       ArrayResize (m_values_a,layers);
       ArrayResize (m_errors,layers);

       //--- init weight matrices with uniform random
       for ( int i= 0 ; i<m_layers- 1 ; i++)
        {
         double div= 32767.0 * layer_sizes[i];   // divider

         m_weights[i].Init(layer_sizes[i],layer_sizes[i+ 1 ]);
         for ( ulong j= 0 ; j<m_weights[i].Rows()*m_weights[i].Cols(); j++)
            m_weights[i].Flat(j, rand ()/div);
        }
     }

   //+------------------------------------------------------------------+
   //| Forward pass                                                                 |
   //+------------------------------------------------------------------+
   void ForwardFeed( const vector & input_data, vector & vector_pred)
     {
      m_values_a[ 0 ]=input_data;

       for ( int i= 0 ; i<m_layers- 1 ; i++)
        {
         m_values[i+ 1 ]=m_values_a[i].MatMul(m_weights[i]);
         m_values[i+ 1 ].Activation(m_values_a[i+ 1 ],m_activation_functions[i+ 1 ]);
        }

       //--- predicted class probabilities
      vector_pred=m_values_a[m_layers- 1 ];
     }

   //+------------------------------------------------------------------+
   //| error back propagation                                           |
   //+------------------------------------------------------------------+
   void BackPropagation( const vector & vector_true, double learning_rate)
     {
       //--- categorical cross entropy loss gradient
      m_errors[m_layers- 1 ]=vector_true-m_values_a[m_layers- 1 ];

       for ( int i=m_layers- 1 ; i> 0 ; i--)
         m_errors[i- 1 ].GeMM(m_errors[i],m_weights[i- 1 ], 1 , 0 , TRANSP_B );

       //--- weights update
       for ( int i=m_layers- 1 ; i> 0 ; i--)
        {
         vector back;
         m_values[i].Derivative(back,m_activation_functions[i]);
         back*=m_errors[i]*learning_rate;

         m_weights[i- 1 ].GeMM(m_values_a[i- 1 ],back, 1 , 1 );
        }
     }
  };
//+------------------------------------------------------------------+

Всего 60 строк чистого кода. Исключительно (кроме ArrayResize) матричные и векторные операции и методы. Это было сделано для нейронной сети "Hello world" - распознавание рукописных цифр на наборе картинок MNIST.

Вот конец журнала обучения и тестирования скрипта нейронной сети.

...
2023.06 . 02 16 : 54 : 21.608 mnist_original (GBPUSD,H1)      Epoch # 15
2023.06 . 02 16 : 54 : 24.523 mnist_original (GBPUSD,H1)      Time: 2.907 seconds. Right answers: 98.682 %
2023.06 . 02 16 : 54 : 24.523 mnist_original (GBPUSD,H1)      Total time: 71 seconds
2023.06 . 02 16 : 54 : 24.558 mnist_original (GBPUSD,H1)      Read 10000 images. Test begin
2023.06 . 02 16 : 54 : 24.796 mnist_original (GBPUSD,H1)      Time: 0.234 seconds. Right answers: 96.630 %

Исходный код скрипта и исходные данные MNIST - во вложении


Файлы:
MQL5.zip  10508 kb
 

Форум о трейдинге, автоматизированных торговых системах и тестировании торговых стратегий

Как начать работать с Metatrader 5

Сергей Голубев, 2022.02.12 07:49

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

Используя специальные типы данных 'matrix' и 'vector', можно создавать код, очень близкий к математической нотации, избегая при этом необходимости создавать вложенные циклы или учитывать правильную индексацию массивов в вычислениях. В этой статье мы рассмотрим, как создавать, инициализировать и использовать объекты матрицы и вектора в MQL5.


 

Форум о трейдинге, автоматизированных торговых системах и тестировании торговых стратегий

Как начать работать с Metatrader 5

Сергей Голубев, 2023.02.11 03:41

Matrix Utils, расширение функционала стандартной библиотеки матриц и векторов - статья

Matrix Utils, расширение функциональности стандартной библиотеки матриц и векторов

В python класс Utils - это класс утилиты общего назначения с функциями и строками кода, которые мы можем использовать повторно, не создавая экземпляр класса.

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


 

Форум о трейдинге, автоматизированных торговых системах и тестировании торговых стратегий

Как начать работать с Metatrader 5

Сергей Голубев, 2023.04.12 06:48



Нейронные сети с обратным распространением с использованием матриц MQL5

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

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


 

Матрицы и векторы в MQL5: Функции активации

Матрицы и векторы в MQL5

Здесь мы опишем только один из аспектов машинного обучения - функции активации. Мы углубимся во внутреннюю работу этого процесса.

Matrices and vectors in MQL5: Activation functions
Matrices and vectors in MQL5: Activation functions
  • www.mql5.com
Here we will describe only one of the aspects of machine learning - activation functions. In artificial neural networks, a neuron activation function calculates an output signal value based on the values of an input signal or a set of input signals. We will delve into the inner workings of the process.
 

Хотелось бы узнать, кто использует объекты векторов и матриц в MQL5?

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

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

https://www.mql5.com/en/docs/matrix/matrix_initialization

Где говорится следующее:


Серьезно???

Какой в этом смысл или сценарий использования???? - Это можно было бы реализовать с помощью AVX. - Я вообще не представляю, какой крайний случай это должно покрыть, есть идеи?

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

То есть вот так:

template <typename T>
const T next_value(const ulong current_count, const T last_value)
{
        return(last_value + 1.0);
};


И BTW, как создать указатель на шаблонизированную функцию в MQL5? - Компилятор был расширен для специальной поддержки объектных типов матриц и векторов.

Еще одна аннотация, векторы можно использовать как массивы, даже со списками инициализации, они выделяются динамически. - К сожалению, они ограничены только типами double, float и сложными скалярными типами. - Это не имеет смысла.


Также тот факт, что матрица по умолчанию равна matrix<double> - это концепция, которая не поддерживается MQL5, а значит, для нас недоступна. - Почему??? - Какой смысл реализовывать объект таким "из ряда вон выходящим" способом?

И еще, пока я не забыл об этом: ALGLIB на CodeBase https://www.mql5.com/en/code/1146 не поддерживает матричные или векторные типы, у него есть свой объект представления для работы с матрицами..... Как следствие, реализация того, чем славится ALGLIB (скорость и гибкость), была более или менее обделена, векторы и матрицы должны поддерживать AVX при использовании, но для преобразования ALGLIB эти возможности пришлось убрать из библиотеки, так как они недоступны в MQL5 напрямую.

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

Documentation on MQL5: Matrix and Vector Methods / Initialization
Documentation on MQL5: Matrix and Vector Methods / Initialization
  • www.mql5.com
Initialization - Matrix and Vector Methods - MQL5 Reference - Reference on algorithmic/automated trading language for MetaTrader 5
 
Dominik Egert #:

Хотелось бы узнать, кто использует объекты векторов и матриц в MQL5?

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

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

https://www.mql5.com/en/docs/matrix/matrix_initialization

Где говорится следующее:


Серьезно???

Какой в этом смысл или сценарий использования???? - Это можно было бы реализовать с помощью AVX. - Я вообще не представляю, какой крайний случай это должно покрыть, есть идеи?

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

То есть вот так:


И BTW, как создать указатель на шаблонизированную функцию в MQL5? - Компилятор был расширен для специальной поддержки объектных типов матриц и векторов.

Еще одна аннотация, векторы можно использовать как массивы, даже со списками инициализации, они выделяются динамически. - К сожалению, они ограничены только типами double, float и сложными скалярными типами. - Не имеет смысла.


Также тот факт, что матрица по умолчанию равна matrix<double> - это концепция, которая не поддерживается MQL5, а значит, для нас недоступна. - Почему??? - Какой смысл реализовывать объект таким "из ряда вон выходящим" способом?

И еще, пока я не забыл об этом: ALGLIB на CodeBase https://www.mql5.com/en/code/1146 не поддерживает матричные или векторные типы, у него есть свой объект представления для работы с матрицами..... Как следствие, реализация того, чем славится ALGLIB (скорость и гибкость), была более или менее обделена, векторы и матрицы должны поддерживать AVX при использовании, но для преобразования ALGLIB эти возможности пришлось удалить из библиотеки, потому что они недоступны в MQL5 напрямую.

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

Я думаю, что вы передаете имя функции, опускаете матрицу / вектор, который она будет корректировать (или инициировать), но добавляете остальные параметры функции. (и вектор матрицы, который она будет корректировать / инициировать, должен быть в параметрах функции первым)

Я работал с этим недавно, дайте мне 5, чтобы откопать код

Это мутация между кодированием на c++ и python

 

нашёл его

template <typename T>
void init_based_on_values(vector<T> &out,//the vector you will init / adjust you omit this on the init call 
                          vector &source,//you can have any other params which you add sep by commas on the init call
                          vector &controller,
                          double allow_value){
int total=0;
for(int i=0;i<(int)source.Size();i++){
   if(controller[i]==allow_value){
     total++;
     out[total-1]=source[i];
     }
   }
out.Resize(total,0);
}

template <typename T>
void your_function(vector<T> &out){
out.Fill(3);
}
int OnInit()
  {
//---
  vector source={1,2,3,4,5,6,7};
  vector pass={0,1,0,1,0,1,0};
  vector result(7,init_based_on_values,source,pass,1.0);
  Print(result);
  return(INIT_SUCCEEDED);
  }


Итак, что это делает, извините, надо было написать это изначально:

  • у нас есть исходный вектор (мы используем вектор, потому что это просто) со значениями
  • у нас есть вектор фильтра пропуска, не то чтобы он был нужен, но для проверки многочисленных и разнообразных параметров, когда он равен 1.0, мы передаем значение в вектор out
  • мы не передаем ссылку на вектор out в параметрах конструктора (init), потому что то, что мы "конструируем", является первым параметром, на который ссылаемся.

Это действительно аккуратно, я не тестировал это на скорости, но это удобно.

Однако вы, должно быть, потратили много времени на компилятор python в тот день, чтобы понять, что они хотели сделать здесь.
 
Lorentzos Roussos тестировал это на скорости, но это удобно.

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

  vector source={1,2,3,4,5,6,7};
  vector pass={0,1,0,1,0,1,0};
  vector result=source*pass;
Причина обращения: