Прогнозирование временных рядов в MetaTrader 5 при помощи библиотеки машинного обучения ENCOG
Введение
В этой статье мы познакомим MetaTrader 5 с библиотекой ENCOG - пакетом для работы с нейросетями и системой машинного обучения, разработанной Heaton Research. Практические аспекты использования пакетов FANN, NeuroSolutions, Matlab и NeuroShell для работы с терминалом MetaTrader уже рассматривались ранее. Я надеюсь, что ENCOG также станет достойным решением благодаря своей устойчивости и хорошо спроектированному коду.
Почему я выбрал ENCOG? Есть несколько причин.
- Пакет ENCOG используется в двух других коммерческих торговых системах. Один из них основан на C#, другой на Java. Это означает, что он уже был протестирован на предмет способности прогнозирования финансовых временных рядов.
- Библиотека ENCOG является бесплатной, ее исходные коды доступны. Если вы захотите посмотреть что происходит внутри нейросети, можно посмотреть исходники. В процессе работы над задачей прогнозирования временных рядов мне пришлось с этим столкнуться. Язык программирования C# чистый и легкий для понимания.
- Пакет ENCOG очень хорошо документирован. Mr. Heaton, основатель компании Heaton Research, предоставил в открытый доступ онлайн курс по нейронным сетям, машинному обучению и использовании ENCOG для предсказания будущих данных. Перед написанием статьи я изучил множество его уроков, которые помогли мне лучше понять искусственные нейронные сети. В дополнение к этому, на сайте Heaton Research доступны книги по программированию с использованием ENCOG на языках Javа и C#. На сайте разработчика также доступна онлайн-документация по ENCOG.
- ENCOG не является "мертвым" проектом. Во процессе написания статьи разрабатывалась ENCOG 2.6, недавно была опубликована карта разработки (roadmap) ENCOG 3.0.
- Библиотека ENCOG является робастной. Она очень хорошо спроектирована, поддерживает работу с несколькими процессорами/потоками для ускорения нейросетевых расчетов. Некоторые коды уже начали портироваться в OpenCL для расчета на графических процессорах (GPU).
- На текущий момент ECNOG предоставляет следующие возможности:
Методы машинного обучения (Machine Learning Types)
- Прямое и простейшее рекуррентное обучение Элмана-Джордана (Feedforward and Simple Recurrent, Elman/Jordan)
- Генетические алгоритмы (Genetic Algorithms)
- Алгоритм нейроэволюции нарастающей топологии (NEAT)
- Вероятностная нейронная сеть/Нейросеть с общей регрессией (Probablistic Neural Network/General Regression Neural Network, PNN/GRNN)
- Самоорганизующиеся карты (Self Organizing Map, SOM/Kohonen)
- Метод Метрополиса/Алгоритм имитации отжига (Simulated Annealing)
- Метод опорных векторов (Support Vector Machine)
Архитектуры нейронных сетей (Neural Network Architectures)
Методы обучения (Training Techniques)
- Адаптивная линейная нейросеть (ADALINE Neural Network)
- Адаптивная резонансная теория (Adaptive Resonance Theory 1, ART1)
- Двунаправленная ассоциативная память (Bidirectional Associative Memory, BAM)
- Машина Больцмана (Boltzmann Machine)
- Нейросети встречного распространения (Counterpropagation Neural Network, CPN)
- Рекуррентные нейросети Элмана (Elman Recurrent Neural Network)
- Сеть прямого распространения/Многослойный персептрон (Feedforward Neural Network, Perceptron)
- Нейронные сети Хопфилда (Hopfield Neural Network)
- Рекуррентные сети Джордана (Jordan Recurrent Neural Network)
- Нейроэволюция нарастающей топологии (Neuroevolution of Augmenting Topologies, NEAT)
- Нейросеть на базе радиальных базисных функций (Radial Basis Function Network)
- Рекуррентные самоорганизующие карты (Recurrent Self Organizing Map, RSOM)
- Самоорганизующиеся карты Кохонена (Kohonen Self Organizing Map)
Активационные функции (Activation Functions)
- Backpropagation
- Resilient Propagation (RPROP)
- Scaled Conjugate Gradient (SCG)
- Manhattan Update Rule Propagation
- Competitive Learning
- Hopfield Learning
- Levenberg Marquardt, LMA
- Genetic Algorithm Training
- Instar Training
- Outstar Training
- ADALINE Training
- Training Data Models
- Supervised
- Unsupervised
- Temporal (Prediction)
- Financial (загрузка данных с Yahoo Finance)
- SQL
- XML
- CSV
- Image Downsampling
Генераторы случайных чисел (Randomization Techniques)
- Competitive
- Sigmoid
- Hyperbolic Tangent
- Linear
- SoftMax
- Tangential
- Sin Wave
- Step
- Bipolar
- Gaussian
- Range Randomization
- Gaussian Random Numbers
- Fan-In
- Nguyen-Widrow
Планируемые к реализации (Planned features):
- HyperNEAT
- Restrictive Boltzmann Machine (RBN/Deep Belief)
- Spiking Neural Networks
Как видите, список довольно внушительный.
В этой вводной статье мы будем использовать нейронную сеть прямого распространения (feed forward Neural Network architecture) с обучением при помощи эластичного распространения (Resilient Propagation, RPROP). Также мы рассмотрим основы подготовки данных (метод timeboxing и нормализацию).
При написании статьи в основном были использованы учебники по ENCOG, доступные на сайте Heaton Research и свежие статьи по предсказанию временных рядов в NinjaTrader. Отметим, что библиотека ENCOG реализована на Java и C#, поэтому эта работа не могла бы быть сделана без использования методики, описанной в моей предыдущей статье Как открыть мир C# из MQL5 путем экспорта неуправляемого кода. Это позволило использовать DLL, написанную на C# в качестве моста между индикатором MetaTrader 5 и системой предсказания временных рядов, построенной на базе ENCOG.
1. Использование значений технических индикаторов в качестве входных параметров нейросети
Искусственная нейронная сеть представляет собой алгоритм, разработанный человеком, при помощи которого моделируется работа нейронов мозга.
Существует много различных алгоритмов работы нейросетей, есть множество нейросетевых архитектур. Область исследований настолько широка, что отдельным типам нейронных сетей посвящены целые книги. Детальное их описание выходит за рамки этой статьи, я лишь могу порекомендовать пройтись по учебникам от Heaton Research или почитать специализированную литературу. В статье мы рассмотрим работу с входными и выходными параметрами нейросети прямого распространения (feed forward neural network) и разберем практический пример решения задачи предсказания финансовых временных рядов.
Для начала прогнозирования финансовых временных рядов нужно определиться с тем, какие данные следует передавать нейросети и что мы рассчитываем получить в итоге. С точки зрения "черного ящика", прибыль или убыток получается в результате открытия длинных или коротких позиций по контракту данного финансового инструмента и закрытием сделки спустя некоторое время.
Наблюдая за прошлыми ценами финансового инструмента и значениями технических индикаторов, мы пытаемся предсказать ситуацию в будущем или направление движения цены для покупки или продажи контракта и быть уверены в том, что способ принятия нашего решения отличается от подбрасывания монетки.
Ситуация выглядит следующим образом:
Рисунок 1. Прогноз финансовых временных рядов при помощи технических индикаторов
Мы попытаемся получить то же самое с использованием искусственного интеллекта. Нейронная сеть попытается распознать значения индикатора и оценит шансы повышения или понижения цены. Как мы это сделаем? Поскольку мы будем иметь дело с нейросетями прямого распространения (feed forward), я полагаю, нам нужно познакомиться с их архитектурой.
Нейронная сеть прямого распространения состоит из нейронов, которые сгруппированы в слоях. Должно присутствовать как минимум 2 слоя: входной слой, содержащий входные нейроны и выходной слой с нейронами выходного слоя. Между входным и выходным слоями также могут присутствовать и скрытые слои. Входной слой может быть обычным массивом из чисел типа double, выходной слой может содержать один или более нейронов, которые (в общем случае) также представляют собой одномерный массив из чисел типа double.
Посмотрим на рисунок:
Рисунок 2. Слои нейронной сети прямого распространения
Для упрощения мы не отметили здесь связи между нейронами. Каждый из нейронов входного слоя связан с нейронами скрытого слоя (h1 и h2). Каждый из нейронов скрытого слоя связан с нейроном выходного слоя (o1).
Каждая связь имеет свой вес, который также представляет собой число типа double, и функцию активации с порогом, который отвечает за активацию нейрона и прохождение информации к следующему нейрону. По этой причине такая сеть называется сетью прямого распространения (feed forward network) - информация с выходов активированных нейронов проходит вперед к следующему слою нейронов. Более подробные вводные видеоматериалы по нейросетям прямого распространения вы можете найти по ссылкам:
- Neural Network Calculation (Part 1): Feedforward Structure
- Neural Network Calculation (Part 2): Activation Functions & Basic Calculation
- Neural Network Calculation (Part 3): Feedforward Neural Network Calculation
Возможно, вопросы останутся даже после изучения архитектуры и механизмов работы нейросети прямого распространения.
Основные проблемы:
- Какие данные нужно предоставить нейросети?
- Как мы их должны предоставлять?
- Как подготовить входные данные нейросети?
- Как выбрать архитектуру нейросети? Сколько нам потребуется нейронов во входном, выходном и скрытых слоях?
- Как обучать сеть?
- Что мы ожидаем получить на выходе?
2. Какие данные предоставлять нейронной сети
Поскольку мы будем строить предсказания с использованием индикаторов, мы должны снабдить нейросеть значениями индикаторов. Для этой статьи в качестве входных параметров нейросети я выбрал значения линий %K и %D индикатора Stochastic, а также значения индикатора %R Вильямса.
Рисунок 3. Технические индикаторы, используемые для предсказания
Для получения значений индикаторов мы можем использовать функции iStochastic и iWPR языка MQL5:
double StochKArr[], StochDArr[], WilliamsRArr[]; ArraySetAsSeries(StochKArr, true); ArraySetAsSeries(StochDArr, true); ArraySetAsSeries(WilliamsRArr, true); int hStochastic = iStochastic(Symbol(), Period(), 8, 5, 5, MODE_EMA, STO_LOWHIGH); int hWilliamsR = iWPR(Symbol(), Period(), 21); CopyBuffer(hStochastic, 0, 0, bufSize, StochKArr); CopyBuffer(hStochastic, 1, 0, bufSize, StochDArr); CopyBuffer(hWilliamsR, 0, 0, bufSize, WilliamsRArr);
После выполнения этого кода три массива (StochKArr, StochDArr и WilliamsRArr) должны быть заполнены значениями индикаторов. В зависимости от размера обучающей выборки может понадобится несколько тысяч значений. Имейте ввиду, что эти два технических индикатора мы взяли лишь в качестве иллюстрации.
Вы можете экспериментировать с любыми другими индикаторами, которые найдете пригодными для предсказания. Можно дать нейросети данные по золоту или нефти для предсказания индексов фондового рынка или же вы можете использовать скоррелированные валютные пары для предсказания другой валютной пары.
3. Подготовка исходных данных (Timeboxing)
После сбора значений нескольких индикаторов нам нужно подготовить для нейросети. Для этого мы используем метод timeboxing, который позволяет представить входные параметры нейросети в виде наборов данных скользящего окна временного ряда. Можно представить это в виде скользящего окна данных, сдвигающегося по оси времени. Приведем два основных шага для осуществления данной процедуры:
1. С каждого индикаторного буфера собираем данные. Нам нужно скопировать INPUT_WINDOW элементов с начальной позиции - это число баров, которое будет использоваться предсказания.
Рисунок 4. Собираем данные индикаторного буфера для входного окна
Как видно из рисунка 4, в данном случае размер входного окна (INPUT_WINDOW) равен 4 барам и мы скопировали их в массив I1. Первым элементом данного массива является I1[0], последний элемент - I[3]. Аналогичным образом следует скопировать данные других индикаторных буферов в массивы размера INPUT_WINDOW. Схема, представленная на рис. 4, корректна для случая, если в индикаторных буферах используется индексация как в таймсериях (флаг AS_SERIES для буфера установлен в true).
2. Собирем массивы размером INPUT_WINDOW в один массив, который будет передан нейросети в качестве входного слоя.
Рисунок 5. Timeboxed input window arrays
У нас 3 индикатора, сначала мы берем первое значение с каждого из индикаторов, потом берем второе значение, и так продолжаем до тех пор, пока входное окно не заполниться данными, как показано на рис. 5. Такой массив объединенных данных индикаторов может быть передан нейросети в качестве входных значений. При появлении нового бара данные сдвигаются на один элемент и вся процедура повторяется снова. Если вас интересуют подробности подготовки данных для предсказания, посмотрите видео.
4. Нормализация входных данных
Чтобы нейросеть была эффективной, мы должны нормализовать данные. Эта процедура необходима для правильного расчета функций активации. Нормализация данных представляет собой математическое преобразование данных в диапазон [0..1] или [-1,1]. Нормализованные данные могут быть денормализованы, т.е. преобразованы обратно в начальный диапазон.
Денормализация требуется для преобразования выходных данных нейросети в вид, воспринимаемый человеком. К счастью, ENCOG может самостоятельно позаботиться о нормализации и денормализации, поэтому не требуется реализация данных методов.
Если интересно как это делается, посмотрите на код:
/** * Возвращает нормализованное значение числа. * @param value Число для нормализации. * @return Нормализованное значение. */ public static double normalize(final int value) { return ((value - INPUT_LOW) / (INPUT_HIGH - INPUT_LOW)) * (OUTPUT_HIGH - OUTPUT_LOW) + OUTPUT_LOW; } /** * Возвращает денормализованное значение числа. * @param value Число для денормализации. * @return Денормализованное значение. */ public static double deNormalize(final double data) { double result = ((INPUT_LOW - INPUT_HIGH) * data - OUTPUT_HIGH * INPUT_LOW + INPUT_HIGH * OUTPUT_LOW) / (OUTPUT_LOW - OUTPUT_HIGH); return result; }
и прочитайте статью по нормализацию.
5. Выбираем архитектуру нейросети и число нейронов
Для новичка выбор правильной архитектуры нейросети представляет собой сложную задачу. В этой статье я ограничусь трехслойной архитектурой нейронной сети прямого распространения: входной слой, один скрытый слой и выходной слой. Вы можете экспериментировать с большим числом слоев.
Для входного и выходного слоя мы cможем точно рассчитать количество требуемых нейронов. Для скрытого слоя мы попытаемся минимизировать ошибку нейросети при помощи алгоритма "forward selection". Вы можете попробовать использовать другие методы для определения количества нейронов в скрытом слое, например, генетические алгоритмы.
Другой метод, используемый в ENCOG называется "backward selection", или "обрезкой", в основном он имеет дело с оптимизацией связей между слоями и удаляет нейроны скрытых слоев с нулевыми весами, вы также можете его попробовать.
5.1. Входной слой
Поскольку данные подготавливались алгоритмом timeboxing, число нейронов входного слоя должно быть равно числу индикаторов, умноженному на число баров, используемых для предсказания следующего бара.
Если мы используем значения 3-х индикаторов и размер входного окна в 6 баров, входной слой нейросети будет содержать 18 нейронов. Данные, подготовленные алгоритмом timeboxing, затем предоставляются нейросети в качестве входных параметров.
5.2. Скрытый слой
Количество нейронов скрытого слоя должно определяться на основе погрешности расчета нейронной сети. Явного математического выражения для числа нейронов скрытого слоя не существует. До написания этой статьи, методом проб и ошибок я испробовал множество различных подходов, затем на сайте Heaton Research я нашел алгоритм, который помогает понять метод "forward selection":
Рисунок 6. Алгоритм "Forward selection" для определения числа нейронов скрытого слоя
5.3. Выходной слой
Для наших целей число нейронов выходного слоя - это количество баров, которые мы пытаемся предсказать. Запомните, что с увеличением количества нейронов скрытого и выходного слоев увеличивается и время обучения сети. В этой статье мы пытаемся предсказать один бар будущего, поэтому выходной слой содержит один нейрон.
6. Экспортируем данные для обучения из MetaTrader 5 в ENCOG
Для обучения нейросети библиотека Encog принимает файлы формата CSV.
Рассмотрев формат данных, экспортируемый для ENCOG другими программами, я реализовал в MQL5 скрипт для подготовки данных для обучения нейросети в том же формате. Сначала я приведу вариант с одним индикатором, далее рассмотрим случай работы с несколькими индикаторами.
Первая строка представляет собой заголовок, разделенный запятыми:
DATE,TIME,CLOSE,Indicator_Name1,Indicator_Name2,Indicator_Name3
Первые три колонки содержат дату, время и цену закрытия бара, следующие колонки содержат имена индикаторов. Строки файла с данными для обучения нейросети представляют собой данные, разделенные запятыми, значения индикаторов должны быть записаны в виде:
20110103,0000,0.93377000,-7.8970208860e-002
Вот готовый скрипт для экспорта данных одного индикатора:
//+------------------------------------------------------------------+ //| ExportToEncog.mq5 | //| Copyright 2011, Investeo.pl | //| http:/Investeo.pl | //+------------------------------------------------------------------+ #property copyright "Copyright 2011, Investeo.pl" #property link "http:/Investeo.pl" #property version "1.00" //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ // Экспортирует значения индикатора для обучения нейросети в ENCOG extern string IndExportFileName = "mt5export.csv"; extern int trainSize = 400; extern int maPeriod = 210; MqlRates srcArr[]; double expBullsArr[]; void OnStart() { //--- ArraySetAsSeries(srcArr, true); ArraySetAsSeries(expBullsArr, true); int copied = CopyRates(Symbol(), Period(), 0, trainSize, srcArr); if (copied!=trainSize) { Print("Недостаточно данных по символу " + Symbol()); return; } int hBullsPower = iBullsPower(Symbol(), Period(), maPeriod); CopyBuffer(hBullsPower, 0, 0, trainSize, expBullsArr); int hFile = FileOpen(IndExportFileName, FILE_CSV | FILE_ANSI | FILE_WRITE | FILE_REWRITE, ",", CP_ACP); FileWriteString(hFile, "DATE,TIME,CLOSE,BullsPower\n"); Print("Экспортирую значения индикатора в файл " + IndExportFileName); for (int i=trainSize-1; i>=0; i--) { string candleDate = TimeToString(srcArr[i].time, TIME_DATE); StringReplace(candleDate,".",""); string candleTime = TimeToString(srcArr[i].time, TIME_MINUTES); StringReplace(candleTime,":",""); FileWrite(hFile, candleDate, candleTime, DoubleToString(srcArr[i].close), DoubleToString(expBullsArr[i], -10)); } FileClose(hFile); Print("Данные индикатора экспортированы."); } //+------------------------------------------------------------------+
Результирующий файл, готовый для обучения нейросети, должен выглядеть следующим образом:
DATE,TIME,CLOSE,BullsPower 20110103,0000,0.93377000,-7.8970208860e-002 20110104,0000,0.94780000,-6.4962292188e-002 20110105,0000,0.96571000,-4.7640374727e-002 20110106,0000,0.96527000,-4.4878854587e-002 20110107,0000,0.96697000,-4.6178012364e-002 20110110,0000,0.96772000,-4.2078647318e-002 20110111,0000,0.97359000,-3.6029181466e-002 20110112,0000,0.96645000,-3.8335729509e-002 20110113,0000,0.96416000,-3.7054869514e-002 20110114,0000,0.96320000,-4.4259373120e-002 20110117,0000,0.96503000,-4.4835729773e-002 20110118,0000,0.96340000,-4.6420936126e-002 20110119,0000,0.95585000,-4.6868984125e-002 20110120,0000,0.96723000,-4.2709941621e-002 20110121,0000,0.95810000,-4.1918330800e-002 20110124,0000,0.94873000,-4.7722659418e-002 20110125,0000,0.94230000,-5.7111591557e-002 20110126,0000,0.94282000,-6.2231529077e-002 20110127,0000,0.94603000,-5.9997865295e-002 20110128,0000,0.94165000,-6.0378312069e-002 20110131,0000,0.94414000,-6.2038328069e-002 20110201,0000,0.93531000,-6.0710334438e-002 20110202,0000,0.94034000,-6.1446445012e-002 20110203,0000,0.94586000,-5.2580791504e-002 20110204,0000,0.95496000,-4.5246755566e-002 20110207,0000,0.95730000,-4.4439392954e-002
В нашем примере с индикаторами Stochastic и Williams' R, требуется экспортировать три колонки данных, разделенных запятыми. Каждая из них содержит значения индикаторов, поэтому нам нужно расширить файл и добавить дополнительные буферы:
//+------------------------------------------------------------------+ //| ExportToEncog.mq5 | //| Copyright 2011, Investeo.pl | //| http:/Investeo.pl | //+------------------------------------------------------------------+ #property copyright "Copyright 2011, Investeo.pl" #property link "http:/Investeo.pl" #property version "1.00" //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ // Индикатор экспорта значений для обучения нейросети в ENCOG extern string IndExportFileName = "mt5export.csv"; extern int trainSize = 2000; MqlRates srcArr[]; double StochKArr[], StochDArr[], WilliamsRArr[]; void OnStart() { //--- ArraySetAsSeries(srcArr, true); ArraySetAsSeries(StochKArr, true); ArraySetAsSeries(StochDArr, true); ArraySetAsSeries(WilliamsRArr, true); int copied = CopyRates(Symbol(), Period(), 0, trainSize, srcArr); if (copied!=trainSize) { Print("Недостаточно данных по символу " + Symbol()); return; } int hStochastic = iStochastic(Symbol(), Period(), 8, 5, 5, MODE_EMA, STO_LOWHIGH); int hWilliamsR = iWPR(Symbol(), Period(), 21); CopyBuffer(hStochastic, 0, 0, trainSize, StochKArr); CopyBuffer(hStochastic, 1, 0, trainSize, StochDArr); CopyBuffer(hWilliamsR, 0, 0, trainSize, WilliamsRArr); int hFile = FileOpen(IndExportFileName, FILE_CSV | FILE_ANSI | FILE_WRITE | FILE_REWRITE, ",", CP_ACP); FileWriteString(hFile, "DATE,TIME,CLOSE,StochK,StochD,WilliamsR\n"); Print("Экспортирую данные индикатора в файл " + IndExportFileName); for (int i=trainSize-1; i>=0; i--) { string candleDate = TimeToString(srcArr[i].time, TIME_DATE); StringReplace(candleDate,".",""); string candleTime = TimeToString(srcArr[i].time, TIME_MINUTES); StringReplace(candleTime,":",""); FileWrite(hFile, candleDate, candleTime, DoubleToString(srcArr[i].close), DoubleToString(StochKArr[i], -10), DoubleToString(StochDArr[i], -10), DoubleToString(WilliamsRArr[i], -10) ); } FileClose(hFile); Print("Данные индикатора экспортированы."); } //+------------------------------------------------------------------+
Выходной файл должен содержать значения всех индикаторов:
DATE,TIME,CLOSE,StochK,StochD,WilliamsR 20030707,0000,1.37370000,7.1743119266e+001,7.2390220187e+001,-6.2189054726e-001 20030708,0000,1.36870000,7.5140977444e+001,7.3307139273e+001,-1.2500000000e+001 20030709,0000,1.35990000,7.3831775701e+001,7.3482018082e+001,-2.2780373832e+001 20030710,0000,1.36100000,7.1421933086e+001,7.2795323083e+001,-2.1495327103e+001 20030711,0000,1.37600000,7.5398313027e+001,7.3662986398e+001,-3.9719626168e+000 20030714,0000,1.37370000,7.0955352856e+001,7.2760441884e+001,-9.6153846154e+000 20030715,0000,1.38560000,7.4975891996e+001,7.3498925255e+001,-2.3890784983e+000 20030716,0000,1.37530000,7.5354107649e+001,7.4117319386e+001,-2.2322435175e+001 20030717,0000,1.36960000,7.1775345074e+001,7.3336661282e+001,-3.0429594272e+001 20030718,0000,1.36280000,5.8474576271e+001,6.8382632945e+001,-3.9778325123e+001 20030721,0000,1.35400000,4.3498596819e+001,6.0087954237e+001,-5.4946524064e+001 20030722,0000,1.36130000,2.9036761284e+001,4.9737556586e+001,-4.5187165775e+001 20030723,0000,1.34640000,1.6979405034e+001,3.8818172735e+001,-6.5989159892e+001 20030724,0000,1.34680000,1.0634573304e+001,2.9423639592e+001,-7.1555555556e+001 20030725,0000,1.34400000,9.0909090909e+000,2.2646062758e+001,-8.7500000000e+001 20030728,0000,1.34680000,1.2264922322e+001,1.9185682613e+001,-8.2705479452e+001 20030729,0000,1.35250000,1.4960629921e+001,1.7777331716e+001,-7.2945205479e+001 20030730,0000,1.36390000,2.7553336360e+001,2.1035999930e+001,-5.3979238754e+001 20030731,0000,1.36990000,4.3307839388e+001,2.8459946416e+001,-4.3598615917e+001 20030801,0000,1.36460000,5.6996412096e+001,3.7972101643e+001,-5.2768166090e+001 20030804,0000,1.34780000,5.7070193286e+001,4.4338132191e+001,-8.1833910035e+001 20030805,0000,1.34770000,5.3512705531e+001,4.7396323304e+001,-8.2006920415e+001 20030806,0000,1.35350000,4.4481132075e+001,4.6424592894e+001,-7.1972318339e+001 20030807,0000,1.35020000,3.3740028156e+001,4.2196404648e+001,-7.7681660900e+001 20030808,0000,1.35970000,3.0395426394e+001,3.8262745230e+001,-6.1245674740e+001 20030811,0000,1.35780000,3.4155781326e+001,3.6893757262e+001,-6.4532871972e+001 20030812,0000,1.36880000,4.3488943489e+001,3.9092152671e+001,-4.5501730104e+001 20030813,0000,1.36690000,5.1160443996e+001,4.3114916446e+001,-4.8788927336e+001 20030814,0000,1.36980000,6.2467599793e+001,4.9565810895e+001,-2.5629290618e+001 20030815,0000,1.37150000,6.9668246445e+001,5.6266622745e+001,-2.1739130435e+001 20030818,0000,1.38910000,7.9908906883e+001,6.4147384124e+001,-9.2819614711e+000
На базе второго примера вы легко сможете построить скрипт, который вам требуется.
7. Обучение нейронной сети
Алгоритм обучения нейросети уже реализован разработчиками ENOG на языке C#.
ENCOG 2.6 использует пространство имен Encog.App.Quant в качестве основы для предсказания финансовых временных рядов. Скрипт обучения очень гибкий и легко может быть адаптирован на любое количество входных индикаторов. Вам лишь следует заменить константу DIRECTORY местом расположения каталога терминала MetaTrader 5.
Архитектура нейросети и параметры обучения могут быть легко настроены изменением следующих переменных:
/// <summary> /// Размер входного окна. Представляет собой количество баров, используемых для предсказания следующего бара. /// </summary> public const int INPUT_WINDOW = 6; /// <summary> /// Количество баров в будущем, которые пытаемся предсказать. Обычно это всего 1 бар. /// Предсказание будущего на 1 бар работает лучше всего. /// </summary> public const int PREDICT_WINDOW = 1; /// <summary> /// Количество баров вперед, используемых для получения лучшего результата. /// </summary> public const int RESULT_WINDOW = 5; /// <summary> /// Количество нейронов в первом скрытом слое. /// </summary> public const int HIDDEN1_NEURONS = 12; /// <summary> /// Ошибка обучения нейросети. /// </summary> public const double TARGET_ERROR = 0.01;
Код не нуждается в комментариях, поэтому лучше внимательно его посмотреть:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Encog.App.Quant.Normalize; using Encog.Util.CSV; using Encog.App.Quant.Indicators; using Encog.App.Quant.Indicators.Predictive; using Encog.App.Quant.Temporal; using Encog.Neural.NeuralData; using Encog.Neural.Data.Basic; using Encog.Util.Simple; using Encog.Neural.Networks; using Encog.Neural.Networks.Layers; using Encog.Engine.Network.Activation; using Encog.Persist; namespace NetworkTrainer { public class Program { /// <summary> /// Каталог, в котором храняться все файлы. /// </summary> public const String DIRECTORY = "d:\\mt5\\MQL5\\Files\\"; /// <summary> /// Входной файл, с которого все начинается. /// </summary> public const String STEP1_FILENAME = DIRECTORY + "mt5export.csv"; /// <summary> /// мы применили индикатор предсказания будущего и сгенерировали второй файл с дополнительным полем. /// </summary> public const String STEP2_FILENAME = DIRECTORY + "step2_future.csv"; /// <summary> /// Теперь все данные нормализованы и размешены в этом файле. /// </summary> public const String STEP3_FILENAME = DIRECTORY + "step3_norm.csv"; /// <summary> /// Подготовленный (time-boxed) для создания данных обучения. /// </summary> public const String STEP4_FILENAME = DIRECTORY + "step4_train.csv"; /// <summary> /// Окончательный файл с обученной нейросетью содержится в этом файле. /// </summary> public const String STEP5_FILENAME = DIRECTORY + "step5_network.eg"; /// <summary> /// Размер входного окна. Это число баров, используемое для предсказания следующего бара. /// </summary> public const int INPUT_WINDOW = 6; /// <summary> /// Количество баров в будущем, которые пытаемся предсказать. Обычно это всего 1 бар. /// Предсказание будущего на 1 бар работает лучше всего. /// </summary> public const int PREDICT_WINDOW = 1; /// <summary> /// Используемое количество баров будущего. /// </summary> public const int RESULT_WINDOW = 5; /// <summary> /// Количество нейронов в первом скрытом слое. /// </summary> public const int HIDDEN1_NEURONS = 12; /// <summary> /// Ошибка обучения нейросети. /// </summary> public const double TARGET_ERROR = 0.01; static void Main(string[] args) { // Step 1: Create future indicators Console.WriteLine("Step 1: Analyze MT5 Export & Create Future Indicators"); ProcessIndicators ind = new ProcessIndicators(); ind.Analyze(STEP1_FILENAME, true, CSVFormat.DECIMAL_POINT); int externalIndicatorCount = ind.Columns.Count - 3; ind.AddColumn(new BestReturn(RESULT_WINDOW,true)); ind.Process(STEP2_FILENAME); Console.WriteLine("External indicators found: " + externalIndicatorCount); //Console.ReadKey(); // Шаг 2: Нормализация и подготовка данных (Step 2: Normalize) Console.WriteLine("Step 2: Create Future Indicators"); EncogNormalize norm = new EncogNormalize(); norm.Analyze(STEP2_FILENAME, true, CSVFormat.ENGLISH); norm.Stats[0].Action = NormalizationDesired.PassThrough; // дата (Date) norm.Stats[1].Action = NormalizationDesired.PassThrough; // время (Time) norm.Stats[2].Action = NormalizationDesired.Normalize; // цена закрытия бара(Close) norm.Stats[3].Action = NormalizationDesired.Normalize; // значение линии Stoch K norm.Stats[4].Action = NormalizationDesired.Normalize; // значение линии Stoch Dd norm.Stats[5].Action = NormalizationDesired.Normalize; // значение индикатора WilliamsR norm.Stats[6].Action = NormalizationDesired.Normalize; // best return [RESULT_WINDOW] norm.Normalize(STEP3_FILENAME); // расчет количества нейронов входного слоя int inputNeurons = INPUT_WINDOW * externalIndicatorCount; int outputNeurons = PREDICT_WINDOW; // Step 3: Time-box Console.WriteLine("Step 3: Timebox"); //Console.ReadKey(); TemporalWindow window = new TemporalWindow(); window.Analyze(STEP3_FILENAME, true, CSVFormat.ENGLISH); window.InputWindow = INPUT_WINDOW; window.PredictWindow = PREDICT_WINDOW; int index = 0; window.Fields[index++].Action = TemporalType.Ignore; // дата date window.Fields[index++].Action = TemporalType.Ignore; // время time window.Fields[index++].Action = TemporalType.Ignore; // цена закрытия бара close for(int i=0;i<externalIndicatorCount;i++) window.Fields[index++].Action = TemporalType.Input; // external indicators window.Fields[index++].Action = TemporalType.Predict; // PredictBestReturn window.Process(STEP4_FILENAME); // Шаг 4: обучение нейронной сети Console.WriteLine("Step 4: Train"); Console.ReadKey(); INeuralDataSet training = (BasicNeuralDataSet)EncogUtility.LoadCSV2Memory(STEP4_FILENAME, inputNeurons, outputNeurons, true, CSVFormat.ENGLISH); BasicNetwork network = new BasicNetwork(); network.AddLayer(new BasicLayer(new ActivationTANH(), true, inputNeurons)); network.AddLayer(new BasicLayer(new ActivationTANH(), true, HIDDEN1_NEURONS)); network.AddLayer(new BasicLayer(new ActivationLinear(), true, outputNeurons)); network.Structure.FinalizeStructure(); network.Reset(); //EncogUtility.TrainToError(network, training, TARGET_ERROR); EncogUtility.TrainConsole(network, training, 3); // Шаг 5: Сохранение нейросети и статистики (Step 5: Save neural network and stats) EncogMemoryCollection encog = new EncogMemoryCollection(); encog.Add("network", network); encog.Add("stat", norm.Stats); encog.Save(STEP5_FILENAME); Console.ReadKey(); } } }
Возможно, вы заметили, что я закомментировал строку обучения EncogUtility.TrainToError() и заменил ее на EncogUtility.TrainConsole().
EncogUtility.TrainConsole(network, training, 3);
Метод TrainConsole указывает количество минут для обучения нейронной сети. В данном примере я произвожу обучение в течение трех минут. В зависимости от сложности нейросети и размера обучающей выборки, процесс обучения может занимать от нескольких минут до часов или даже дней. Рекомендую почитать о расчете ошибки и алгоритмах обучения на сайте Heaton Research или в книгах по нейросетям.
Метод EncogUtility.TrainToError() останавливает процесс обучения после получения заданной погрешности расчетов. Вы можете закомментировать вызов EncongUtiliy.TrainConsole() и раскомментировать EncogUtility.TrainToError() для обучения нейросети до заданной погрешности, как в нашем примере.
EncogUtility.TrainToError(network, training, TARGET_ERROR);
Имейте ввиду, что возможны случаи, когда нейронная сеть не может быть обучена до некоторой точности из-за того, что количество нейронов слишком мало.
8. Используем обученную нейронную сеть для построения индикатора в MetaTrader 5
Обученная нейронная сеть может быть использована в нейросетевом индикаторе, который будет пытаться предсказать изменение цены (best return on investment).
Нейросетевой индикатор ENCOG для MetaTrader 5 состоит из двух частей. Первая часть написана на MQL5, главным образом, она берет значения тех же самых индикаторов, которые использовались нами для обучения нейросети и отдает их нейронной сети в качестве входных параметров.
Вторая часть написана на C#, она подготавливает входные данные, осуществляет timeboxing, производит расчет и возвращает результат работы нейросети в MQL5. Код индикатора на C# основан на моей предыдущей статье Как открыть мир C# из MQL5 путем экспорта неуправляемого кода.
using System; using System.Collections.Generic; using System.Text; using RGiesecke.DllExport; using System.Runtime.InteropServices; using Encog.Neural.Networks; using Encog.Persist; using Encog.App.Quant.Normalize; using Encog.Neural.Data; using Encog.Neural.Data.Basic; namespace EncogNeuralIndicatorMT5DLL { public class NeuralNET { private EncogMemoryCollection encog; public BasicNetwork network; public NormalizationStats stats; public NeuralNET(string nnPath) { initializeNN(nnPath); } public void initializeNN(string nnPath) { try { encog = new EncogMemoryCollection(); encog.Load(nnPath); network = (BasicNetwork)encog.Find("network"); stats = (NormalizationStats)encog.Find("stat"); } catch (Exception e) { Console.WriteLine(e.StackTrace); } } }; class UnmanagedExports { static NeuralNET neuralnet; [DllExport("initializeTrainedNN", CallingConvention = CallingConvention.StdCall)] static int initializeTrainedNN([MarshalAs(UnmanagedType.LPWStr)]string nnPath) { neuralnet = new NeuralNET(nnPath); if (neuralnet.network != null) return 0; else return -1; } [DllExport("computeNNIndicator", CallingConvention = CallingConvention.StdCall)] public static int computeNNIndicator([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t1, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t2, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t3, int len, [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 5)] double[] result, int rates_total) { INeuralData input = new BasicNeuralData(3 * len); int index = 0; for (int i = 0; i <len; i++) { input[index++] = neuralnet.stats[3].Normalize(t1[i]); input[index++] = neuralnet.stats[4].Normalize(t2[i]); input[index++] = neuralnet.stats[5].Normalize(t3[i]); } INeuralData output = neuralnet.network.Compute(input); double d = output[0]; d = neuralnet.stats[6].DeNormalize(d); result[rates_total-1]=d; return 0; } } }
Если вам требуется использование большего количества индикаторов, чем три, измените метод computeNNIndicator():
[DllExport("computeNNIndicator", CallingConvention = CallingConvention.StdCall)] public static int computeNNIndicator([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t1, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t2, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t3, int len, [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 5)] double[] result, int rates_total)
В этом случае три первых входных параметра представляют собой таблицы, содержащие входные значения индикаторов, четвертый параметр - длина входного окна.
Значение SizeParamIndex = 3 указывает на длину входного окна, входные переменные нумеруются (индексируются) с 0. Пятый параметр представляет собой таблицу, которая содержит результаты работы нейросети.
Для части индикатора, написанной на MQL5, требуется импорт C#-библиотеки EncogNNTrainDLL.dll и использование экспортированных функций initializeTrainedNN() и computeNNIndicator().
//+------------------------------------------------------------------+ //| NeuralEncogIndicator.mq5 | //| Copyright 2011, Investeo.pl | //| http:/Investeo.pl | //+------------------------------------------------------------------+ #property copyright "Copyright 2011, Investeo.pl" #property link "http:/Investeo.pl" #property version "1.00" #property indicator_separate_window #property indicator_plots 1 #property indicator_buffers 1 #property indicator_color1 Blue #property indicator_type1 DRAW_LINE #property indicator_style1 STYLE_SOLID #property indicator_width1 2 #import "EncogNNTrainDLL.dll" int initializeTrainedNN(string nnFile); int computeNNIndicator(double& ind1[], double& ind2[],double& ind3[], int size, double& result[], int rates); #import int INPUT_WINDOW = 6; int PREDICT_WINDOW = 1; double ind1Arr[], ind2Arr[], ind3Arr[]; double neuralArr[]; int hStochastic; int hWilliamsR; int hNeuralMA; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping SetIndexBuffer(0, neuralArr, INDICATOR_DATA); PlotIndexSetInteger(0, PLOT_SHIFT, 1); ArrayResize(ind1Arr, INPUT_WINDOW); ArrayResize(ind2Arr, INPUT_WINDOW); ArrayResize(ind3Arr, INPUT_WINDOW); ArrayInitialize(neuralArr, 0.0); ArraySetAsSeries(ind1Arr, true); ArraySetAsSeries(ind2Arr, true); ArraySetAsSeries(ind3Arr, true); ArraySetAsSeries(neuralArr, true); hStochastic = iStochastic(NULL, 0, 8, 5, 5, MODE_EMA, STO_LOWHIGH); hWilliamsR = iWPR(NULL, 0, 21); Print(TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\Files\step5_network.eg"); initializeTrainedNN(TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\Files\step5_network.eg"); //--- return(0); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime& time[], const double& open[], const double& high[], const double& low[], const double& close[], const long& tick_volume[], const long& volume[], const int& spread[]) { //--- int calc_limit; if(prev_calculated==0) // First execution of the OnCalculate() function after the indicator start calc_limit=rates_total-34; else calc_limit=rates_total-prev_calculated; ArrayResize(neuralArr, rates_total); for (int i=0; i<calc_limit; i++) { CopyBuffer(hStochastic, 0, i, INPUT_WINDOW, ind1Arr); CopyBuffer(hStochastic, 1, i, INPUT_WINDOW, ind2Arr); CopyBuffer(hWilliamsR, 0, i, INPUT_WINDOW, ind3Arr); computeNNIndicator(ind1Arr, ind2Arr, ind3Arr, INPUT_WINDOW, neuralArr, rates_total-i); } //Print("neuralArr[0] = " + neuralArr[0]); //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+
Результат работы индикатора, обученного на дневных данных пары USDCHF и данных индикаторов Stochastic и Williams %R приведен на рисунке:
Рисунок 7. Нейросетевой индикатор на базе Encog
Индикатор показывает предсказанные приращения цены (returns on investment) для следующего бара.
Возможно, вы заметили что я сдвинул индикатор на 1 бар в будущее:
PlotIndexSetInteger(0, PLOT_SHIFT, 1);
Это сделано для того, чтобы подчеркнуть предсказательную способность индикатора. Нейросетевой индикатор готов, теперь мы готовы для создания советника на базе этого индикатора.
9. Советник, основанный на нейросетевом индикаторе
Советник берет выходные значения нейросетевого индикатора и принимает решение о покупке или продаже финансового инструмента. Сначала я думал, что покупать следует, пока индикатор больше нулевой линии, и продавать при отрицательных значениях индикатора. Смысл заключается в покупке при предсказании положительного приращения цены и продаже в случае предсказания отрицательного изменения цены.
После некоторого тестирования выяснилось, что эффективность можно повысить, поэтому я ввел переменные "strong uptrend" and "strong downtrend", используемые для того чтобы не выходить с рынка в случаях сильных трендов, в соответствии с правилом "trend is your friend".
Кроме того, на форуме Heaton Research мне посоветовали использовать ATR для скользящих уровней stop-loss, поэтому я использовал индикатор Chandelier ATR, опубликованный на форуме по MQL5. Код советника приведен ниже.
//+------------------------------------------------------------------+ //| NeuralEncogAdvisor.mq5 | //| Copyright 2011, Investeo.pl | //| http:/Investeo.pl | //+------------------------------------------------------------------+ #property copyright "Copyright 2011, Investeo.pl" #property link "http:/Investeo.pl" #property version "1.00" double neuralArr[]; double trend; double Lots=0.3; int INPUT_WINDOW=8; int hNeural,hChandelier; //+------------------------------------------------------------------+ #include <Trade\Trade.mqh> //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- ArrayResize(neuralArr,INPUT_WINDOW); ArraySetAsSeries(neuralArr,true); ArrayInitialize(neuralArr,0.0); hNeural=iCustom(Symbol(),Period(),"NeuralEncogIndicator"); Print("hNeural = ",hNeural," код ошибки= ",GetLastError()); if(hNeural<0) { Print("Ошибка создания индикатора ENCOG: Код ошибки =",GetLastError()); //--- принудительное завершение работы return(-1); } else Print("Индикатор ENCOG инициализирован"); hChandelier=iCustom(Symbol(),Period(),"Chandelier"); Print("hChandelier = ",hChandelier," код ошибки = ",GetLastError()); if(hChandelier<0) { Print("Ошибка создания индикатора Chandelier: Код ошибки =",GetLastError()); //--- принудительное завершение работы return(-1); } else Print("Индикатор Chandelier инициализирован"); //--- return(0); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- long tickCnt[1]; int ticks=CopyTickVolume(Symbol(),0,0,1,tickCnt); if(tickCnt[0]==1) { if(!CopyBuffer(hNeural,0,0,INPUT_WINDOW,neuralArr)) { Print("Copy1 error"); return; } // Print("neuralArr[0] = "+neuralArr[0]+"neuralArr[1] = "+neuralArr[1]+"neuralArr[2] = "+neuralArr[2]); trend=0; if(neuralArr[0]<0 && neuralArr[1]>0) trend=-1; if(neuralArr[0]>0 && neuralArr[1]<0) trend=1; Trade(); } } //+------------------------------------------------------------------+ //| Tester function | //+------------------------------------------------------------------+ double OnTester() { //--- //--- return(0.0); } //+------------------------------------------------------------------+ void Trade() { double bufChandelierUP[2]; double bufChandelierDN[2]; double bufMA[2]; ArraySetAsSeries(bufChandelierUP,true); ArraySetAsSeries(bufChandelierUP,true); ArraySetAsSeries(bufMA,true); CopyBuffer(hChandelier,0,0,2,bufChandelierUP); CopyBuffer(hChandelier,1,0,2,bufChandelierDN); MqlRates rates[]; ArraySetAsSeries(rates,true); int copied=CopyRates(Symbol(),PERIOD_CURRENT,0,3,rates); bool strong_uptrend=neuralArr[0]>0 && neuralArr[1]>0 && neuralArr[2]>0 && neuralArr[3]>0 && neuralArr[4]>0 && neuralArr[5]>0 && neuralArr[6]>0 && neuralArr[7]>0; bool strong_downtrend=neuralArr[0]<0 && neuralArr[1]<0 && neuralArr[2]<0 && neuralArr[3]<0 && neuralArr[4]<0 && neuralArr[5]<0 && neuralArr[6]<0 && neuralArr[7]<0; if(PositionSelect(_Symbol)) { long type=PositionGetInteger(POSITION_TYPE); bool close=false; if((type==POSITION_TYPE_BUY) && (trend==-1)) if(!(strong_uptrend) || (bufChandelierUP[0]==EMPTY_VALUE)) close=true; if((type==POSITION_TYPE_SELL) && (trend==1)) if(!(strong_downtrend) || (bufChandelierDN[0]==EMPTY_VALUE)) close=true; if(close) { CTrade trade; trade.PositionClose(_Symbol); } else // adjust s/l { CTrade trade; if(copied>0) { if(type==POSITION_TYPE_BUY) { if(bufChandelierUP[0]!=EMPTY_VALUE) trade.PositionModify(Symbol(),bufChandelierUP[0],0.0); } if(type==POSITION_TYPE_SELL) { if(bufChandelierDN[0]!=EMPTY_VALUE) trade.PositionModify(Symbol(),bufChandelierDN[0],0.0); } } } } if((trend!=0) && (!PositionSelect(_Symbol))) { CTrade trade; MqlTick tick; MqlRates rates[]; ArraySetAsSeries(rates,true); int copied=CopyRates(Symbol(),PERIOD_CURRENT,0,INPUT_WINDOW,rates); if(copied>0) { if(SymbolInfoTick(_Symbol,tick)==true) { if(trend>0) { trade.Buy(Lots,_Symbol,tick.ask); Print("Покупка по цене "+tick.ask+" trend = "+trend+" neuralArr = "+neuralArr[0]); } if(trend<0) { trade.Sell(Lots,_Symbol,tick.bid); Print("Продажа по цене "+tick.ask+" trend = "+trend+" neuralArr = "+neuralArr[0]); } } } } } //+------------------------------------------------------------------+
Советник был протестирован на дневных барах пары USDCHF. Для обучения нейросети было использовано около 50% данных.
10. Результаты тестирования советника на истории
Ниже я приведу результаты тестирования на истории. Тест проводился с 2000.01.01 по 2011.03.26.
Рисунок 8. Результаты тестирования нейросетевого советника на исторических данных
Рисунок 9. График Баланса/Средств нейросетевого советника
Имейте ввиду, что результаты могут различаться для других таймфреймов и других финансовых инструментов.
Просьба использовать данный советник лишь в образовательных целях как отправную точку для дальнейших исследований. Лично я думаю, что для повышения устойчивости нейронную сеть можно переобучать через некоторые промежутки времени, возможно кто-то уже нашел или найдет лучший способ для достижения этой цели. Вероятно, также существует лучший способ использования данных, предсказанных нейросетью. Я призываю читателей к экспериментам.
Выводы
В данной статье я представил способ создания нейросетевого прогнозирующего индикатора, созданного при помощи библиотеки машинного обучения ENCOG и советника, построенного на базе данного индикатора. Все исходные коды, скомпилированные библиотеки и примеры обученной сети прилагаются к статье.
Из-за реализации в виде "двойной DLL-обертки под .NET", файлы Cloo.dll, encog-core-cs.dll и log4net.dll нужно скопировать в каталог установки клиентского терминала.
Файл EncogNNTrainDLL.dll нужно скопировать в каталог папка_данных_клиентского_терминала\MQL5\Libraries\.
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/252
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
В файле step2_future.csv, созданным на базе mt5export.csv отсутствуют необходимые столбцы с данными, что является следствием неправильной обработки mt5export.csv . Это происходит в случае, если в настройках ОС в качестве разделителя целой и дробной части чисел задана",".
Установите разделитель целой и дробной части "." в разделе "Язык и региональные стандарты".
После этих действий почти заработало, теперь повисает на тренировке, при этом ошибок не вылетает.
NET у меня 4й. Win 7 x64 sp1
NeuralEncogIndicator (EURUSD,M5) Access violation read to 0x00000000 продолжаются
После этих действий почти заработало, теперь повисает на тренировке, при этом ошибок не вылетает.
NET у меня 4й. Win 7 x64 sp1
NeuralEncogIndicator (EURUSD,M5) Access violation read to 0x00000000 продолжаются
Подскажите в каких других коммерческих торговых системах используется ENCOG ?
Потенциал супер просто и хотелось бы увидеть что то типа трейдинг солюшенс
Подскажите что такое RESULT_WINDOW . Правильно ли я понял, это бары которые подаются только при обучении сети ? Ведь при работе баров будущего взять негде
public const int RESULT_WINDOW = 5;
// Количество баров вперед, используемых для получения лучшего результата.
что-то резко закончилось обсуждение...
Кто-нибудь работает с данной библиотекой? Стоит ли изучать её?
Статья очень понравилась. Респект автору!