Использование библиотеки FANN2MQL в MetaTrader
Для начала пожалуйста установите библиотеку Fann2MQL. Она нам понадобится в дальнейшем. Ее можно загрузить здесь.
Введение
До настоящего времени был опубликован только один пример использования библиотеки Fann2MQL (Используем нейронные сети в MetaTrader), которая позволяет трейдерам использовать библиотеку "FANN" (также доступную в виде исходных кодов) в программах на MQL. Но этот пример, предложенный создателем библиотеки Fann2MQL, не так просто понять новичкам.
Поэтому я написал другой пример, более легкий для понимания и полностью документированный. Он не связан напрямую с торговлей, и не использует никакие финансовые данные, изменяющиеся во времени.
В этом примере мы собираемся обучить простую нейронную сеть распознавать простейший паттерн.
Мы обучим сеть распознавать паттерн такого типа: он содержит 3 числа: a, b и с, значения выходного параметра output следующие:
если (a < b) и (b < c), то output = 1
если (a < b) и (b > c), то output = 0
если (a > b) и (b > c), то output = 0
если (a > b) и (b < c), то output = 1
Можно представить эти числа как координаты вектора, с которым можно ассоциировать направление движения рынка.
В данном случае, паттерн может быть интерпретирован как:
ВВЕРХ ВВЕРХ = ВВЕРХ
ВВЕРХ ВНИЗ = ВНИЗ
ВНИЗ ВНИЗ = ВНИЗ
ВНИЗ ВВЕРХ = ВВЕРХ
Для начала мы создадим нейронную сеть.
Затем мы покажем нейросети несколько примеров паттернов, чтобы она смогла обучиться и вывести правила.
Наконец, мы покажем нейросети новые паттерны, которые нейросеть никогда не видела и получим результаты. Если сеть поняла правила, то она будет способна распознать указанные паттерны.
Код с комментариями:
// Включаем библиотеку Fann2MQl #include <Fann2MQL.mqh> #property copyright "Copyright © 2009, Julien Loutre" #property link "http://www.forexcomm.com" #property indicator_separate_window #property indicator_buffers 0 // полное число слоев. в данном случае 1 входной слой, 2 скрытых слоя, // и один выходной слой - всего 4 слоя int nn_layer = 4; int nn_input = 3; // число нейронов входного слоя. Наш паттерн состоит из 3 чисел // это значит у нас 3 нейрона во входном слое int nn_hidden1 = 8; // число нейронов в первом скрытом слое int nn_hidden2 = 5; // число нейронов во втором скрытом слое int nn_output = 1; // число нейронов выходном слое // массив trainingData[][] будет содержать примеры, которые // мы собираемся использовать для обучения нейронной нейросети double trainingData[][4]; // ВАЖНО! size = nn_input + nn_output int maxTraining = 500; // максимальное число итераций // для обучения нейросети на примерах double targetMSE = 0.002; // среднеквадратичная ошибка (Mean-Square Error) нейронов // которую мы должны получить (далее станет понятно) int ann; // эта переменная будет идентификатором нейронной сети // когда индикатор снимается с графика, // мы удаляем все нейронные сети из памяти. int deinit() { f2M_destroy_all_anns(); return(0); } int init() { int i; double MSE; Print("=================================== НАЧАЛО ВЫПОЛНЕНИЯ ================================"); IndicatorBuffers(0); IndicatorDigits(6); // изменяем размер массива trainingData, чтобы использовать его далее. // мы собираемся изменить его размер один раз. ArrayResize(trainingData,1); Print("##### ИНИЦИАЛИЗАЦИЯ #####"); // Cоздаем нейронную сеть ann = f2M_create_standard(nn_layer, nn_input, nn_hidden1, nn_hidden2, nn_output); // проверяем успешность ее создания: 0 = OK, -1 = ошибка debug("f2M_create_standard()",ann); // Задаем активационную функцию. f2M_set_act_function_hidden (ann, FANN_SIGMOID_SYMMETRIC_STEPWISE); f2M_set_act_function_output (ann, FANN_SIGMOID_SYMMETRIC_STEPWISE); // Опыт показывает, что наилучшие результаты получаются, если для начальных весов // используются случайные числа в этом диапазоне, однако вы можете его изменить // и посмотреть станут ли они лучше или хуже f2M_randomize_weights (ann, -0.77, 0.77); // Здесь я просто вывожу на консоль число входных и выходных нейронов // Это проверка для отладки. debug("f2M_get_num_input(ann)",f2M_get_num_input(ann)); debug("f2M_get_num_output(ann)",f2M_get_num_output(ann)); Print("##### ПОДГОТОВКА ДАННЫХ #####"); // Теперь мы подготовим некоторые примеры данных (с известным результатом) // и добавим их в обучаемый набор // Поскольку мы добавили все примеры которые нужно, // мы собираемся предоставить этот обучаемый набор нейронам нейросети, чтобы они могли обучиться // У функция prepareData() есть несколько аргументов: // - действие, которое нужно выполнить - обучение(train) или расчет(compute) // - данные (в нашем случае каждый набор содержит 3 числа) // - последний аргумент - это переменная для выходного значения нейросети. // В данном случае эта функция принимает набор данных и выходное значение, // и добавляет его в обучаемое множество. // См. комментарии к функции. // // В нашем случае паттерн который мы собираемся обучать следующий: // Есть 3 числа. Пусть это будут a, b и c. // Эти числа можно представить как координаты некоторого вектора, // с которым ассоциируется направление рынка // например (рыночное направление вверх или вниз) // если (a < b) и (b < c), то output = 1 // если (a < b) и (b > c), то output = 0 // если (a > b) и (b > c), то output = 0 // если (a > b) и (b < c), то output = 1 // ВВЕРХ ВВЕРХ = ВВЕРХ / если (a < b) и (b < c), то output = 1 prepareData("train",1,2,3,1); prepareData("train",8,12,20,1); prepareData("train",4,6,8,1); prepareData("train",0,5,11,1); // ВВЕРХ ВНИЗ = ВНИЗ / если (a < b) и (b > c), то output = 0 prepareData("train",1,2,1,0); prepareData("train",8,10,7,0); prepareData("train",7,10,7,0); prepareData("train",2,3,1,0); // ВНИЗ ВНИЗ = ВНИЗ / если (a > b) и (b > c), то output = 0 prepareData("train",8,7,6,0); prepareData("train",20,10,1,0); prepareData("train",3,2,1,0); prepareData("train",9,4,3,0); prepareData("train",7,6,5,0); // ВНИЗ ВВЕРХ = ВВЕРХ / если (a > b) и (b < c), то output = 1 prepareData("train",5,4,5,1); prepareData("train",2,1,6,1); prepareData("train",20,12,18,1); prepareData("train",8,2,10,1); // Теперь для проверки выведем на консоль все обучаемые примеры. // Это для отладки. printDataArray(); Print("##### ОБУЧЕНИЕ #####"); // Нам нужно обучить нейроны много раз так, чтобы результат был такой как требуется. // Здесь я буду обучать нейросеть с одними и теми же данными (нашими примерами) снова и снова, // пока она полностью не научится правилам обучения либо // пока число обучений 'maxTraining' не превысит максимально заданное нами // (в нашем случае maxTraining = 500) // Чем лучше нейросеть обучена, тем меньше будет среднеквадратичная ошибка. // Функция teach() возвращает сренеквадратичную ошибку (MSE, Mean-Square Error) // 0.1 или меньше достаточно для простых правил // 0.02 или меньше лучше использовать для сложных правил вроде нашего примера // мы пытаемся обучить нейросеть этим правилам (ведь распознавание паттернов непростая задача) for (i=0;i<maxTraining;i++) { MSE = teach(); // каждый раз в цикле вызываем функцию обучения // детали см. комментарии к фунции teach(). if (MSE < targetMSE) { // если среднеквадратичное отклонение (MSE) меньше чем задано (было задано targetMSE = 0.02) debug("training finished. Trainings ",i+1); // то выведем на консоль сообщение // о количестве итераций за которое обучились i = maxTraining; // и выходим из цикла } } // выводим значение среднеквадратичного отклонения (MSE) после окончания обучения debug("MSE",f2M_get_MSE(ann)); Print("##### ЗАПУСК #####"); // А теперь мы можем попросить нейросеть проанализировать данные, // которые она никогда не видела. Распознает ли она их правильно?. // Как видно, здесь я использовал ту же функцию prepareData(), // но с первым аргументом "compute". // Последний аргумент - это выходное значение, мы уже использовали его // выше для обучения, когда предоставляли правильные ответы // Теперь он не используется, поэтому оставим его нулевым. // Если хотите, вы можете напрямую вызывать функцию compute(). // В нашем случае, она имеет вид: compute(inputVector[]); // Так что вместо вызова prepareData("compute",1,3,1,0); вы можете сделать следующее: // описываем новый массив // double inputVector[]; // изменяем размерность массива // ArrayResize(inputVector,f2M_get_num_input(ann)); // добавляем в массив данные // inputVector[0] = 1; // inputVector[1] = 3; // inputVector[2] = 1; // вызываем функцию compute() с входными параметрами, которые в массиве InputVector // result = compute(inputVector); // Функция prepareData() вызывает функцию compute(), // которая выводит результат на консоль, // что дает возможность проследить работу. debug("1,3,1 = ВВЕРХ DOWN = DOWN. Правильный output 0.",""); prepareData("compute",1,3,1,0); debug("1,2,3 = ВВЕРХ ВВЕРХ = ВВЕРХ. Правильный output 1.",""); prepareData("compute",1,2,3,0); debug("3,2,1 = ВНИЗ ВНИЗ = ВНИЗ. Правильный output 0.",""); prepareData("compute",3,2,1,0); debug("45,2,89 = ВНИЗ ВВЕРХ = ВВЕРХ. Правильный output 1.",""); prepareData("compute",45,2,89,0); debug("1,3,23 = ВВЕРХ ВВЕРХ = ВВЕРХ. Правильный output 1.",""); prepareData("compute",1,3,23,0); debug("7,5,6 = ВНИЗ ВВЕРХ = ВВЕРХ. Правильный output 1.",""); prepareData("compute",7,5,6,0); debug("2,8,9 = ВВЕРХ ВВЕРХ = ВВЕРХ. Правильный output 1.",""); prepareData("compute",2,8,9,0); Print("=================================== КОНЕЦ РАБОТЫ ================================"); return(0); } int start() { return(0); } /************************* ** Функция printDataArray() ** Выводит данные, используемые для обучения нейронов ** Она не используется, сделана для отладки. *************************/ void printDataArray() { int i,j; int bufferSize = ArraySize(trainingData)/(f2M_get_num_input(ann)+f2M_get_num_output(ann))-1; string lineBuffer = ""; for (i=0;i<bufferSize;i++) { for (j=0;j<(f2M_get_num_input(ann)+f2M_get_num_output(ann));j++) { lineBuffer = StringConcatenate(lineBuffer, trainingData[i][j], ","); } debug("DataArray["+i+"]", lineBuffer); lineBuffer = ""; } } /************************* ** Функция prepareData() ** Подготавливает данные для обучения либо для вычисления. ** Берет данные и заносит их в массив, ** затем отдает их нейросети для обучения или для вычисления ** Мы можете модифицировать ее под вашу задачу. *************************/ void prepareData(string action, double a, double b, double c, double output) { double inputVector[]; double outputVector[]; // we resize the arrays to the right size ArrayResize(inputVector,f2M_get_num_input(ann)); ArrayResize(outputVector,f2M_get_num_output(ann)); inputVector[0] = a; inputVector[1] = b; inputVector[2] = c; outputVector[0] = output; if (action == "train") { addTrainingData(inputVector,outputVector); } if (action == "compute") { compute(inputVector); } // если в вашей задаче входных данных больше чем 3, // просто измените струкутру этой функции } /************************* ** Функция addTrainingData() ** Добавляет образец для обучения в обучаемый набор ** (пример данных + правильный ответ) в глобальный набор обучаемого множества *************************/ void addTrainingData(double inputArray[], double outputArray[]) { int j; int bufferSize = ArraySize(trainingData)/(f2M_get_num_input(ann)+f2M_get_num_output(ann))-1; // записываем входные данные for (j=0;j<f2M_get_num_input(ann);j++) { trainingData[bufferSize][j] = inputArray[j]; } // записываем выходные данные for (j=0;j<f2M_get_num_output(ann);j++) { trainingData[bufferSize][f2M_get_num_input(ann)+j] = outputArray[j]; } ArrayResize(trainingData,bufferSize+2); } /************************* ** Функция teach() ** Берет все обучаемые данные и использует их для однократного обучения ** Для того, чтобы обучить нейроны как полагается, вы должны запускать ** эту функцию много раз, пока значение среднеквадратичной ошибки (MSE) ** уменьшится до заданного значения. *************************/ double teach() { int i,j; double MSE; double inputVector[]; double outputVector[]; ArrayResize(inputVector,f2M_get_num_input(ann)); ArrayResize(outputVector,f2M_get_num_output(ann)); int call; int bufferSize = ArraySize(trainingData)/(f2M_get_num_input(ann)+f2M_get_num_output(ann))-1; for (i=0;i<bufferSize;i++) { for (j=0;j<f2M_get_num_input(ann);j++) { inputVector[j] = trainingData[i][j]; } outputVector[0] = trainingData[i][3]; //f2M_train() однократно показывает нейросети один пример. call = f2M_train(ann, inputVector, outputVector); } // Мы показали нейросети пример, // то, как хорошо она обучилась можно проверить при помощи MSE (среднеквадратичная ошибка). // Если она небольшая, значит сеть неплохо обучилась! MSE = f2M_get_MSE(ann); return(MSE); } /************************* ** Функция compute() ** Выдает результат вычисления нейросети ** на основе предоставленных входных данных (InputVector) *************************/ double compute(double inputVector[]) { int j; int out; double output; ArrayResize(inputVector,f2M_get_num_input(ann)); // Даем нейросети новые входные данные out = f2M_run(ann, inputVector); // и спрашиваем нейросеть о результате используя f2M_get_output(). output = f2M_get_output(ann, 0); debug("Computing()",MathRound(output)); return(output); } /************************* ** Функция debug() ** Печатает данные *************************/ void debug(string a, string b) { Print(a+" ==> "+b); }
Результат
Рис 1. Результат работы программы.
Выводы
Также можно почитать статью "Используем нейронные сети в MetaTrader", написанную Mariusz Woloszyn, автором библиотеки Fann2MQL.
Мне понадобилось 4 дня на то, чтобы разобраться, как использовать библиотеку Fann в MetaTrader, при этом я использовал информацию отсюда и результаты поиска Google.
Надеюсь что этот пример будет полезным для вас, и позволит сэкономить много времени.
Если у вас есть вопросы, пожалуйста задавайте и я отвечу.
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/1574
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Привет всем !
Прочитал про Нер Сет и придлогаемый советник и понял что не зню с чего начать как обучать и вобще мне бы для начала понять как первый щаг делать
Прошу скинуть мне инфо или Адрес пошагового начала Библиотеку на диск поставил
Теперь не знаю как ее наполнять знаниями ???
Одним словом помогите кто меня понял !!!
Написано же русским языком:
Цель статьи - показать, как использовать библиотеку FANN2MQL для программирования нейронных сетей в MetaTrader на простом примере: обучение и распознавание простейших паттернов.
Что Вы хотите от этой статьи? Чтобы был исходник реального прибыльного нейронного советника?
Целью было не написание советника, а показать как и зачем пользоваться библиотекой.
Критиковать все могут! Если Вы считаете, что автор написал недостойную статью, то напишите лучше!
Доброго дня.
А как адаптировать под MT5?
Автору огромное спасибо! Первое внятное описание работы с библиотекой!
Только не могу понять смысл этого выражения в функции "addTrainingData".
int bufferSize = ArraySize(trainingData) / (f2M_get_num_input(ann)+f2M_get_num_output(ann))-1; //???????????????????
Так понимаю в нашем случае trainingData = 4
(f2M_get_num_input(ann)+f2M_get_num_output(ann) тоже = 4
И они всегда будут одинаковыми. Какой смысл делить одно и тоже на себя само? Не проще просто поставить единицу?