#property copyright "me" #property link "http://www.me.net" int start() { double SOM[15][8][36]; OpenSOM(SOM); // циклы обучения int cycles = 100; // количество циклов int c; for (c = 0; c < cycles; c++) { Print("Начало цикла ", c); // затухающая скорость обучения double alpha = 0.5 * (1 - c / cycles); // перебор моментов времени int t; int start_date = 2000; int end_date = 500; for (t = start_date; t > end_date; t--) { // получение входного вектора и результирующего значения, вычисление класса double input[1]; ArrayResize(input, ArrayRange(SOM, 2)); double output; int k; for (k = 0; k < ArrayRange(SOM, 2); k++) { input[k] = iClose("EURUSD", PERIOD_H1, t + k) - iOpen("EURUSD", PERIOD_H1, t + k); } output = iClose("EURUSD", PERIOD_H1, t - 2) - iOpen("EURUSD", PERIOD_H1, t); int class; if (output <= -0.0020) { class = 0; } if ((output < -0.0005) && (output > -0.0020)) { class = 1; } if ((output <= +0.0005) && (output >= -0.0005)) { class = 2; } if ((output < +0.0020) && (output > + 0.0005)) { class = 3; } if (output >= +0.0020) { class = 4; } // находим ближайжий к вектору узел карты double min_dist = 1000000; double calc_dist; int min_i, min_j; int i, j; for (i = 0; i < ArrayRange(SOM, 0); i++) for (j = 0; j < ArrayRange(SOM, 1); j++) { calc_dist = 0; for (k = 0; k < ArrayRange(SOM, 2); k++) { calc_dist += (SOM[i][j][k] - input[k]) * (SOM[i][j][k] - input[k]); } calc_dist = MathSqrt(calc_dist); if (calc_dist < min_dist) { min_dist = calc_dist; min_i = i; min_j = j; } } // конец поиска ближайшего узла // теперь коррекция узла и его окрестности радиусом 2 double elastic; for (i = min_i - 2; i <= min_i + 2; i++) for (j = min_j - 2; j<= min_j + 2; j++) { // если индексы за границами массива, то пропускаем итерацию if ((i < 0) || (i > ArrayRange(SOM, 0) - 1) || (j < 0) || (j > ArrayRange(SOM, 1) - 1)) { continue; } // коэффициент эластичности elastic = MathMin((1 / (1 + MathAbs(min_i - i))), (1 / (1 + MathAbs(min_j - j)))); for (k = 0; k < ArrayRange(SOM, 2); k++) { if (min_i / (ArrayRange(SOM, 0) / 5) == class) { // если класс входного вектора совпадает с классом ближайшего узла, то придвигаем SOM[i][j][k] += alpha * elastic * (input[k] - SOM[i][j][k]); } else { // а если не совпадает, то отодвигаем SOM[i][j][k] -= alpha * elastic * (input[k] - SOM[i][j][k]); } if (MathAbs(SOM[i][j][k]) > 1000) { if (SOM[i][j][k] < 0) { SOM[i][j][k] = -1000; } else { SOM[i][j][k] = 1000; } } } } // конец коррекции узлов сетки } // конец перебора моментов времени } // конец циклов обучения SaveSOM(SOM); Print("Обучение завершено, файл сохранён"); return(0); } void OpenSOM(double& map[][][]) { int handle = FileOpen("eurusd.som", FILE_BIN|FILE_READ); FileReadArray(handle, map, 0, ArrayRange(map, 0) * ArrayRange(map, 1) * ArrayRange(map, 2)); FileClose(handle); } void SaveSOM(double map[][][]) { int handle = FileOpen("eurusd.som", FILE_BIN|FILE_WRITE); FileWriteArray(handle, map, 0, ArrayRange(map, 0) * ArrayRange(map, 1) * ArrayRange(map, 2)); FileClose(handle); // текстовый файл для контроля handle = FileOpen("eurusd.txt", FILE_CSV|FILE_WRITE); int i, j; for (i = 0; i < ArrayRange(map, 0); i++) for (j = 0; j < ArrayRange(map, 1); j++) { FileWrite(handle, map[i][j][0], map[i][j][1], map[i][j][2], map[i][j][3], map[i][j][4], map[i][j][5], map[i][j][6], map[i][j][7], map[i][j][8], map[i][j][9], map[i][j][10], map[i][j][11], map[i][j][12], map[i][j][13], map[i][j][14], map[i][j][15], map[i][j][16], map[i][j][17], map[i][j][18], map[i][j][19], map[i][j][20], map[i][j][21], map[i][j][22], map[i][j][23], map[i][j][24], map[i][j][25], map[i][j][26], map[i][j][27], map[i][j][28], map[i][j][29], map[i][j][30], map[i][j][31], map[i][j][32], map[i][j][33], map[i][j][34], map[i][j][35]); } FileClose(handle); }
А зачем насильно в классы определяете? При обучении классы должны сами сформироваться.
В таком случае SOM не нужен
Вы упускаете торговые возможности:
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Регистрация
Вход
Вы принимаете политику сайта и условия использования
Если у вас нет учетной записи, зарегистрируйтесь
Казалось бы, алгоритмы там все элементарные. Однако при реализации на любых платформах (то есть явно что-то недоработано в самом алгоритме, а не какой-то локальный глюк) сталкиваюсь с такой проблемой, что в некоторых (иногда достаточно многих) узлах значения векторов принимают очень большие значения, переходящие в бесконечность. Игры с коэффициентом скорости обучения ничего в сущности не меняют, в узлах сети значения, в миллиарды раз превышающие те, которые должны быть.
Алгоритм используется тот, что в книге Кохонена описан под названием LVQ1.
Карта инициализируется со случайными значениями примерно того же порядка, что и обучающие примеры. Обучающие примеры - временные серии, разность Close - Open. То есть, там во входных векторах практически нет чисел больше, чем 0.01.
Алгоритм обучения:
1) Карта заранее разбита на области, соответствующие классам входных значений.
2) Для обучающего примера ищем такой узел, где эвклидово расстояние от примера до этого узла минимально.
3) Если найденный узел попадает в область карты того класса, к которому относиться обучающий пример, тогда значение этого узла (а также окружающих узлов) придвигается к значению обучающего примера. Иначе - отодвигается.
Формула: map[i][j][k] (+=/-=) alpha * elastic * (input[k] - map[i][j][k]);
i, j - координаты узла карты, k - номер значения в векторе. Альфа - затухающий коэффициент обучения, эластик - коэффициент эластичности карты (для самого корректируемого узла 1, на шаг дальше 0.5, на два шага дальше 0.3).
Прибавляем, когда сдвигаем узел в сторону целевого вектора, отнимаем, когда отодвигаем.
Алгоритм, казалось бы, элементарен и ошибиться негде. Однако не работает - не приводит к появлению гладкой кластеризованной карты, а приводит к каше.
Может я чего-то не знаю?