Машинное обучение и Data Science (Часть 40): Использование уровней Фибоначчи в данных машинного обучения
Содержание
- Происхождение чисел Фибоначчи
- Понимание уровней коррекции Фибоначчи в трейдинге
- Создание целевой переменной с использованием уровней коррекции Фибоначчи.
- Обучение модели классификатора на основе целевой переменной по уровням Фибоначчи
- Обучение модели регрессора на основе целевой переменной по уровням Фибоначчи
- Тестирование моделей машинного обучения с уровнями Фибоначчи в тестере стратегий
- Заключительные итоги
Происхождение чисел Фибоначчи
Числа Фибоначчи восходят к древнему математику Леонардо Пизанскому, также известному как Фибоначчи.
В своей книге "Liber Abaci", опубликованной в 1202 году, Фибоначчи представил последовательность чисел, ныне известную как последовательность Фибоначчи. Эта последовательность начинается с 0 и 1, а каждое последующее число является суммой двух предыдущих.
Эта последовательность имеет особую значимость, так как проявляется во многих природных явлениях, включая рост растений и животных.
В биологии (хотя и не идеально) логарифмическая спираль, наблюдаемая в раковинах некоторых животных и насекомых, приближенно соответствует числам Фибоначчи.
Предположение о росте по законам Фибоначчи также можно заметить в популяции кроликов и семейных деревьях пчел.
Числа Фибоначчи также обнаруживаются в структуре ДНК некоторых млекопитающих и человека.

Эти числа универсальны, так как встречаются практически повсеместно. Ниже приведены некоторые общие термины, относящиеся к работе с числами Фибоначчи.
Последовательность Фибоначчи
В математике последовательность Фибоначчи — это последовательность, в которой каждый элемент является суммой двух предыдущих. Числа, участвующие в последовательности Фибоначчи, называются числами Фибоначчи.

Последовательность Фибоначчи можно выразить с помощью следующей формулы:
![]()
Где n больше единицы (n>1).
Золотое сечение
Это математическая концепция, описывающая отношение между двумя величинами, при котором отношение меньшей величины к большей равно отношению большей величины к их сумме.
Золотое сечение приблизительно равно 1,6180339887 и обозначается греческой буквой Фи (φ).
Золотое сечение не идентично Фи, но близко! Оно отражает соотношение между двумя последовательными числами в последовательности Фибоначчи.
Если разделить большее число на меньшее, результат будет близок к числу Фи. Чем дальше по последовательности Фибоначчи, тем ближе значение к Фи. Однако оно никогда не будет точно равно Фи, так как Фи невозможно выразить в виде дроби. Это иррациональное число.

Это число наблюдается в различных природных и созданных людьми структурах и считается универсальным принципом красоты и гармонии.
Понимание уровней коррекции Фибоначчи в трейдинге
Уровни коррекции Фибоначчи — это горизонтальные линии, указывающие потенциальные уровни поддержки и сопротивления, на которых цена может развернуться. Они строятся с использованием принципов чисел Фибоначчи, описанных выше.
Этот инструмент часто используется трейдерами в MetaTrader 5 для различных целей, таких как установка торговых целей (stop loss и take profit) и определение линий поддержки и сопротивления, где цены, вероятнее всего, развернутся.
В MetaTrader 5 инструмент находится в меню Вставка > Объекты > Фибоначчи.
Ниже показаны уровни коррекции Фибоначчи на графике EURUSD с таймфреймом 1 час.

На первый взгляд эти уровни коррекции выглядят надежным инструментом для определения торговых уровней и разворотов рынка. Мы же пойдем дальше и исследуем эффективность уровней Фибоначчи в машинном обучении и искусственном интеллекте (AI), особенно золотого сечения (61,8% или 0,618).
Рассмотрим различные способы математического построения уровней Фибоначчи, а также будем использовать их для создания целевой переменной, которую модели машинного обучения могут использовать для изучения и прогнозирования направления рынка.
Создание целевой переменной с использованием уровней Фибоначчи
Для обучения модели, которая понимает взаимосвязи в данных с помощью машинного обучения с учителем, нам нужна правильно сформированная целевая переменная. Поскольку уровень Фибоначчи — это просто число, представляющее определенный ценовой уровень, мы можем собрать цену рынка на нужном уровне Фибоначчи и использовать ее в качестве целевой переменной для задачи регрессии.
Для задачи классификации мы создаем классы на основе движения рынка относительно линий Фибоначчи. Например, если рынок движется вверх и превышает рассчитанный уровень Фибоначчи, это может считаться бычьим сигналом (обозначается 1), а если рынок движется вниз и проходит определенный уровень Фибоначчи, это медвежий сигнал (обозначается 0). Другие случаи можно пометить как None (обозначается -1).
Для задачи классификации
Импорт.
import pandas as pd import numpy as np
Функции.
def create_fib_clftargetvar(price: pd.Series, lookback_window: int=10, lookahead_window: int=10, fib_level: float=0.618): """ Creates a target variable based on Fibonacci breakthroughs in price data. Parameters: - price: pd.Series of price data (close, open, high, or low) - lookback_window: int - number of past periods to calculate high/low - lookahead_window: int - number of future periods to assess breakout - fib_level: float - Fibonacci retracement level (e.g. 0.618) Returns: - pd.Series: with values 1 => Bullish fib level reached 0 => Bearish fib level reached -1 => False breakthrough or no fib hit """ high = price.rolling(lookback_window).max() low = price.rolling(lookback_window).min() fib_level_value = high - (high - low) * fib_level # calculate the Fibonacci level in market price price_ahead = price.shift(-lookahead_window) # future price values target_var = [] for i in range(len(price)): if np.isnan(price_ahead.iloc[i]) or np.isnan(fib_level_value.iloc[i]) or np.isnan(price.iloc[i]): target_var.append(np.nan) continue # let's detect bull and bearish movement afterwards if price_ahead.iloc[i] > price.iloc[i]: # The market went bullish if price_ahead.iloc[i] >= fib_level_value.iloc[i]: target_var.append(1) # bullish Fibonacci target reached else: target_var.append(-1) # false breakthrough else: # The market went bearish if price_ahead.iloc[i] <= fib_level_value.iloc[i]: target_var.append(0) # bearish Fibonacci target reached else: target_var.append(-1) # false breakthrough return target_var
Уровень Фибоначчи применительно к рыночным данным рассчитывается по формуле:
fib_level_value = high - (high - low) * fib_level
Поскольку это задача классификации, где нужно предсказать реакцию рынка на основе предыдущего уровня Фибоначчи, нужно заглянуть в будущее и определить тренд. Затем проверяется, пересекла ли будущая цена уровень Фибоначчи (для восходящего тренда — сверху, для нисходящего — снизу) и при необходимости сгенерировать сигнал на покупку или продажу. Сигнал удержания устанавливается, если цена не достигла уровня Фибоначчи в обоих направлениях.
Создадим целевую переменную с помощью этой функции и добавим результат в DataFrame.
df["Fib signals"] = create_fib_clftargetvar(price=df["Close"], lookback_window=10, lookahead_window=5, fib_level=0.618) df.dropna(inplace=True) # drop nan(s) caused by the shifting operation df
Результат.
| Open | High | Low | Close | Fib signals | |
|---|---|---|---|---|---|
| 9 | 1.3492 | 1.3495 | 1.3361 | 1.3362 | 0.0 |
| 10 | 1.3364 | 1.3405 | 1.3350 | 1.3371 | 0.0 |
| 11 | 1.3370 | 1.3376 | 1.3277 | 1.3300 | 0.0 |
| 12 | 1.3302 | 1.3313 | 1.3248 | 1.3279 | -1.0 |
| 13 | 1.3279 | 1.3293 | 1.3260 | 1.3266 | 0.0 |
Для задачи регрессии
def create_fib_regtargetvar(price: pd.Series, lookback_window: int=10, fib_level: float=0.618): """ This function helps us in calculating the target variable based on fibonacci breakthroughs given a price price: Can be close, open, high, low """ high = price.rolling(lookback_window).max() low = price.rolling(lookback_window).min() return high - (high - low) * fib_level
Для задачи регрессии сдвиг значений для получения будущей информации не требуется, так как при ручной торговле мы сравниваем будущие цены с уровнем Фибоначчи, рассчитанным на предыдущем окне (lookback_window), и определяем, было ли пересечение вверх или вниз.
Цель — обучить регрессионную модель прогнозировать следующее значение уровня Фибоначчи на основе предыдущих данных.
df["Fibonacci Level"] = create_fib_regtargetvar(price=df["Close"], lookback_window=10, fib_level=0.618) df.dropna(inplace=True) df.head(5)
Ниже представлен итоговый Dataframe - в него добавили столбец с уровнями Фибоначчи.
| Open | High | Low | Close | Fibonacci Level | |
|---|---|---|---|---|---|
| 9 | 1.3492 | 1.3495 | 1.3361 | 1.3362 | 1.343840 |
| 10 | 1.3364 | 1.3405 | 1.3350 | 1.3371 | 1.342923 |
| 11 | 1.3370 | 1.3376 | 1.3277 | 1.3300 | 1.339015 |
| 12 | 1.3302 | 1.3313 | 1.3248 | 1.3279 | 1.337717 |
| 13 | 1.3279 | 1.3293 | 1.3260 | 1.3266 | 1.335195 |
Обучение классификатора на целевой переменной Фибоначчи
Начнем с целевой переменной классификации "Fib signals" и обучим данные на простой модели RandomForestClassifier.
Импорт.
from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report from sklearn.utils.class_weight import compute_class_weight from sklearn.pipeline import Pipeline from sklearn.preprocessing import RobustScaler
Разделение на обучающую и тестовую выборки.
X = df.drop(columns=[ "Fib signals" ]) y = df["Fib signals"] X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42, shuffle=False)
Модель.
class_weights = compute_class_weight('balanced', classes=np.unique(y_train), y=y_train) weight_dict = dict(zip(np.unique(y_train), class_weights)) model = RandomForestClassifier(n_estimators=100, min_samples_split=2, max_depth=10, class_weight=weight_dict, random_state=42 ) clf_pipeline = Pipeline(steps=[ ("scaler", RobustScaler()), ("rfc", model) ]) clf_pipeline.fit(X_train, y_train)
Модель случайного леса, основанная на деревьях решений, не требует масштабирования, но так как значения Open, High, Low и Close (OHLC) являются непрерывными и подвержены выбросам, мы используем RobustScaler, чтобы убрать влияние этих выбросов.
После обучения модель тестируем на обучающих и тестовых данных.
y_train_pred = clf_pipeline.predict(X_train) print("Train Classification report\n",classification_report(y_train, y_train_pred)) y_test_pred = clf_pipeline.predict(X_test) print("Test Classification report\n",classification_report(y_test, y_test_pred))
Результат.
Train Classification report precision recall f1-score support -1.0 0.53 0.55 0.54 4403 0.0 0.59 0.64 0.61 7122 1.0 0.67 0.60 0.64 8294 accuracy 0.61 19819 macro avg 0.60 0.60 0.60 19819 weighted avg 0.61 0.61 0.61 19819 Test Classification report precision recall f1-score support -1.0 0.22 0.22 0.22 1810 0.0 0.38 0.60 0.46 3181 1.0 0.42 0.20 0.27 3504 accuracy 0.35 8495 macro avg 0.34 0.34 0.32 8495 weighted avg 0.36 0.35 0.33 8495
Результат на обучающих данных выглядит впечатляюще, но на тестовых — хуже. Это указывает на то, что модель не научилась распознавать паттерны вне обучающей выборки.
Это может быть связано с различными факторами, такими как недостаток признаков для улавливания значимых рыночных паттернов (одних только значений цен OHLC может быть недостаточно) или грубый способ определения тренда при создании целевой переменной, из-за чего модель пропускает промежуточные бары.
Поскольку наша цель была обучить модель прогнозировать пересечения уровня Фибоначчи, данный результат классификации может быть ошибочным, так как он неполный. Продолжим использовать его и проанализируем на тестовых данных в реальном торговом окружении.
Сохраним обученную модель в формате ONNX для внешнего использования в MQL5.
import skl2onnx from skl2onnx import convert_sklearn from skl2onnx.common.data_types import FloatTensorType
# Define the initial type of the model’s input initial_type = [('input', FloatTensorType([None, X_train.shape[1]]))] # Convert the pipeline to ONNX onnx_model = convert_sklearn(clf_pipeline, initial_types=initial_type, target_opset=13) # Save the ONNX model to a file with open(f"{symbol}.{timeframe}.Fibonnacitarg-RFC.onnx", "wb") as f: f.write(onnx_model.SerializeToString())
Обучение модели регрессора на основе целевой переменной по уровням Фибоначчи
Принципы для обучения модели регрессора остаются теми же, в данном случае меняются только тип модели и целевая переменная.
Импорт.
from sklearn.ensemble import RandomForestRegressor from sklearn.metrics import r2_score
Разделение на обучающую и тестовую выборки.
X = df.drop(columns=[ "Fibonacci Level" ]) y = df["Fibonacci Level"] X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42, shuffle=False)
Модель случайного леса.
model = RandomForestRegressor(n_estimators=100, min_samples_split=2, max_depth=10, random_state=42 ) reg_pipeline = Pipeline(steps=[ ("scaler", RobustScaler()), ("rfr", model) ]) reg_pipeline.fit(X_train, y_train)
Наконец, мы можем протестировать модель регрессора как на обучающей, так и на тестовой выборке.
y_train_pred = reg_pipeline.predict(X_train) print("Train accuracy score:",r2_score(y_train, y_train_pred)) y_test_pred = reg_pipeline.predict(X_test) print("Test accuracy score:",r2_score(y_test, y_test_pred))
Результат.
Train accuracy score: 0.9990321734526452 Test accuracy score: 0.9565827587164671
Мало что можно сказать об оценке R2 от регрессионной модели, но на тестовой выборке 0,9565 — неплохой результат для данных вне обучающей выборки.
Сохраняем эту обученную модель в формате ONNX для использования в MQL5.
# Define the initial type of the model’s input initial_type = [('input', FloatTensorType([None, X_train.shape[1]]))] # Convert the pipeline to ONNX onnx_model = convert_sklearn(reg_pipeline, initial_types=initial_type, target_opset=13) # Save the ONNX model to a file with open(f"{symbol}.{timeframe}.Fibonnacitarg-RFR.onnx", "wb") as f: f.write(onnx_model.SerializeToString())
Теперь протестируем прогнозную способность моделей в реальных торговых условиях.
Тестирование моделей машинного обучения с уровнями Фибоначчи в тестере стратегий
Загружаем модели случайного леса в формате ONNX как ресурсы для советника.
#resource "\\Files\\EURUSD.PERIOD_H4.Fibonnacitarg-RFC.onnx" as uchar rfc_onnx[] #resource "\\Files\\EURUSD.PERIOD_H4.Fibonnacitarg-RFR.onnx" as uchar rfr_onnx[]
Далее импортируем библиотеку для загрузки классификатора Random Forest и регрессора в формате ONNX.
#include <Random Forest.mqh>
CRandomForestClassifier rfc;
CRandomForestRegressor rfr; Используем те же значения окна lookahead и lookback, что и при обучении. Это позволит корректно определять продолжительность удержания позиций и время для закрытия.
input group "Models configs"; input target_var_type fib_target = CLASSIFIER; //Model type input int lookahead_window = 5; input int lookback_window = 10;
Переменная fib_target помогает выбрать тип модели для использования.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Setting the symbol and timeframe if (!MQLInfoInteger(MQL_TESTER) && !MQLInfoInteger(MQL_DEBUG)) if (!ChartSetSymbolPeriod(0, symbol_, timeframe_)) { printf("%s failed to set symbol %s and timeframe %s",__FUNCTION__,symbol_,EnumToString(timeframe_)); return INIT_FAILED; } //--- m_trade.SetExpertMagicNumber(magic_number); m_trade.SetDeviationInPoints(slippage); m_trade.SetMarginMode(); m_trade.SetTypeFillingBySymbol(Symbol()); //--- switch(fib_target) { case REGRESSOR: if (!rfr.Init(rfr_onnx)) { printf("%s failed to initialize the random forest regressor",__FUNCTION__); return INIT_FAILED; } break; case CLASSIFIER: if (!rfc.Init(rfc_onnx)) { printf("%s failed to initialize the random forest classifier",__FUNCTION__); return INIT_FAILED; } break; } //--- return(INIT_SUCCEEDED); }
В функции OnTick сигналы модели формируются на основе OHLC, как мы делали при обучении.
Эти сигналы используются для открытия сделок на покупку и продажу.
void OnTick() { //--- Getting signals from the model if (!isNewBar()) return; vector x = { iOpen(Symbol(), Period(), 1), iHigh(Symbol(), Period(), 1), iLow(Symbol(), Period(), 1), iClose(Symbol(), Period(), 1) }; long signal = 0; switch(fib_target) { case REGRESSOR: { double pred_fib = rfr.predict(x); signal = pred_fib>iClose(Symbol(), Period(), 0)?1:0; //If the predicted fibonacci is greater than the current close price, thats bullish otherwise thats bearish signal } break; case CLASSIFIER: signal = rfc.predict(x).cls; break; } //--- Trading based on the signals received from the model MqlTick ticks; if (!SymbolInfoTick(Symbol(), ticks)) { printf("Failed to obtain ticks information, Error = %d",GetLastError()); return; } double volume_ = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MIN); if (signal == 1) { if (!PosExists(POSITION_TYPE_BUY) && !PosExists(POSITION_TYPE_SELL)) m_trade.Buy(volume_, Symbol(), ticks.ask); } if (signal == 0) { if (!PosExists(POSITION_TYPE_SELL) && !PosExists(POSITION_TYPE_BUY)) m_trade.Sell(volume_, Symbol(), ticks.bid); } //--- Closing trades switch(fib_target) { case CLASSIFIER: CloseTradeAfterTime((Timeframe2Minutes(Period())*lookahead_window)*60); //Close the trade after a certain lookahead and according the the trained timeframe break; case REGRESSOR: CloseTradeAfterTime((Timeframe2Minutes(Period())*lookback_window)*60); //Close the trade after a certain lookahead and according the the trained timeframe break; } }
Закрытие сделок зависит от типа модели и параметров окон lookahead_window и lookback_window.
Для классификатора сделки закрываются после количества баров на текущем таймфрейме, равного окну lookahead_window.
Для моделей регрессора сделки будут закрываться после количества баров, равного lookback_window баров, тоже на текущем таймфрейме.
Это соответствует созданию целевых переменных в Python-скрипте.
Наконец, мы можем протестировать эти две модели на тестере стратегий.
Мы обучали модели на данных с 01.01.2005 to 01.01.2023, поэтому тестировать будем на данных вне выборки: с 01.01.2023 по 31.12.2023.

Тип модели: Классификатор


Тип модели: Регрессор

Модель регрессора показал отличные результаты, учитывая что это новые данные — 57,42% выигрышных сделок.
Для упрощения, в торговом советнике я преобразовал непрерывный результат регрессора Random Forest в бинарный сигнал.
signal = pred_fib>iClose(Symbol(), Period(), 0)?1:0; //If the predicted Fibonacci is greater than the current close price, that's bullish otherwise that's bearish signal
Это полностью меняет способ интерпретации прогнозируемого уровня Фибоначчи, поскольку, в отличие от ручной торговли, где мы обычно открываем сделку в конце тренда после получения сигнала его подтверждения, здесь подход иной. В ручной торговле мы, как правило, устанавливаем торговые цели на определенном уровне Фибоначчи (чаще всего 61,8%).
Используя данный подход, мы предполагаем, что наши модели машинного обучения уже выявили этот паттерн в пределах заданных окон lookback и lookahead, использованных на этапе обучения. Следовательно, нам остается лишь открывать сделки и удерживать их в течение заранее определенного количества баров.
Ключевым фактором здесь являются значения окон lookahead и lookback, главным образом потому, что при ручном использовании инструмента Фибоначчи мы обычно не учитываем количество баров, применяемых для расчета уровней (минимумов и максимумов). Как правило, мы просто размещаем инструмент там, где считаем нужным.
Хотя инструмент работает в ручной торговле, он может создавать иллюзию корректности его размещения, тогда как на практике мы просто устанавливаем его в удобной для нас точке, не опираясь на чtтко определtнные правила.
Именно эти два параметра (окна lookahead и lookback) необходимо оптимизировать, если мы хотим исследовать эффективность уровней Фибоначчи при создании целевой переменной и их использовании в машинном обучении в целом.
Заключительные мысли
Уровни коррекции Фибоначчи являются действенным инструментом для формирования целевой переменной в задачах машинного обучения, что подтверждается отчетом из тестера стратегий, полученным на регрессионной модели. Даже при использовании минимального набора признаков — Open, High, Low и Close — которые сами по себе не формируют большого количества устойчивых паттернов, модели смогли выявить определенные закономерности и показать результаты лучше случайного угадывания, опираясь на информацию, извлеченную из уровней Фибоначчи.
Как ни интерпретировать полученные результаты, на мой взгляд, они выглядят впечатляюще.
Тем не менее, на текущем этапе идея еще недостаточно проработана. Необходимо расширить набор признаков, добавив значения технических индикаторов и подтверждения торговых стратегий, чтобы помочь модели, основанной на уровнях Фибоначчи, улавливать более сложные рыночные паттерны. Также рекомендую проработать другие уровни Фибоначчи.
При дальнейшем развитии данной концепции она может оказаться особенно эффективной на рынках акций и фондовых индексов, где коррекции регулярно происходят в рамках долгосрочных бычьих трендов, а также на старших таймфреймах (например, дневном), где рыночные данные характеризуются меньшим уровнем шума.
Таблица вложений
| Имя файла и путь | Описание и назначение |
|---|---|
| Experts\Fibonacci AI based.mq5 | Главный советник для тестирования моделей машинного обучения. |
| Include\Random Forest.mqh | Содержит классы для загрузки и развертывания классификатора и регрессора Random Forest, представленных в формате .ONNX. |
| Files\*.onnx | Модели машинного обучения в формате ONNX. |
| Files\*.csv | CSV-файлы, содержащие наборы данных, которые будут использоваться для обучения моделей машинного обучения. |
| Python\fibbonanci-in-ml.ipynb | Скрипт на Python для обработки данных и обучения моделей случайного леса. |
Источники и ссылки
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/18078
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Особенности написания Пользовательских Индикаторов
Разработка торговых стратегий с использованием осцилляторов Parafrac и Parafrac V2: Оценка эффективности при одиночном входе
Преодоление ограничений машинного обучения (Часть 2): Отсутствие воспроизводимости
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
