Привет, Хабр!

Сегодня мы рассмотрим такую замечательную библиотеку как mlfinlab.

Если вы пытались применить методы машинного обучения к финансовым данным, то наверняка сталкивались с массой подводных камней: от шумных данных до проблем с автокорреляцией. mlfinlab — это библиотека, которая реализует передовые техники из книги Маркоса Лопеса де Прадо "Advances in Financial Machine Learning". Она позволяет не изобретать велосипед, а использовать проверенные временем методы для решения сложных задач финансового МЛ.

Начнем с установки. Ничего сложного:

pip install mlfinlab

Теперь импортируем необходимые модули:

import pandas as pd
import numpy as np
import mlfinlab

Добываем данные

Для примера будем использовать исторические данные по акциям компании Apple (тикер: AAPL). Воспользуемся библиотекой yfinance для загрузки данных.

import yfinance as yf

ticker = 'AAPL'
data = yf.download(ticker, start='2020-01-01', end='2021-01-01', interval='1d')
prices = data['Close']

Разметка баров

Обычные временные бары могут вводить в заблуждение из-за неравномерной активности рынка. mlfinlab предлагает альтернативу — создание баров на основе объема, долларов или количества тиков.

Создадим долларовые бары с порогом в 1 миллион долларов.

from mlfinlab.data_structures import StandardBars

db = StandardBars(bar_type='dollar', threshold=1e6)
dollar_bars = db.batch_run(data)

Теперь данные сгруппированы по реальной рыночной активности.

Разметка событий

Определение значимых изменений цены — важный момент в финансовом МЛ. Используем CUSUM фильтр для выявления точек смены тренда.

from mlfinlab.filters.filters import cusum_filter

threshold = 0.02  # 2% изменение цены
events = cusum_filter(prices, threshold=threshold)

Мы получили список дат, когда цена изменилась более чем на 2%. Это потенциальные точки входа или выхода.

Тройной барьер в помощь

Теперь нужно присвоить метки нашим событиям, чтобы модель могла учиться. Используем метод Triple Barrier Method.

from mlfinlab.labeling.labeling import get_events, get_bins

# Устанавливаем вертикальные барьеры через 5 дней
vertical_barriers = mlfinlab.labeling.add_vertical_barrier(t_events=events, close=prices, num_days=5)

# Получаем события с учетом тройного барьера
events = get_events(close=prices,
                    t_events=events,
                    pt_sl=[1, 1],  # Устанавливаем пороги прибыли и убытка
                    target=None,
                    min_ret=0.01,
                    vertical_barrier_times=vertical_barriers)

# Получаем метки
labels = get_bins(events=events, close=prices)

Теперь есть метки, которые учитывают не только изменение цены, но и временной фактор.

Применяем мета-лейблинг

Финансовые данные часто несбалансированы: количество успешных сделок может быть значительно меньше неудачных. Мета-лейблинг помогает решить эту проблему.

from mlfinlab.meta_labeling.meta_labeling import MetaLabeling

meta = MetaLabeling()
meta_labels = meta.get_meta_labels(events, prices)

Мета-лейблинг позволяет улучшить точность модели, обучая ее распознавать условия, при которых стоит доверять первоначальным прогнозам.

Учет автокорреляции

Автокорреляция может привести к переобучению модели. Используем метод Computation of the Effective Sample Size (ESS).

from mlfinlab.sample_weights import get_weights_by_time_decay

# Получаем веса с учетом времени
weights = get_weights_by_time_decay(meta_labels['t1'], decay=0.5)

Это позволяет корректировать веса выборки, уменьшая влияние автокорреляции на модель.

Теперь можно и обучить модельку

Настало время обучить нашу модель. Используем XGBoost, потому что почему бы и нет?

import xgboost as xgb
from sklearn.model_selection import train_test_split

# Подготавливаем данные
X = prices.loc[labels.index].to_frame()
y = labels['bin']

# Разбиваем на обучающую и тестовую выборки
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)

# Создаем DMatrix для XGBoost
dtrain = xgb.DMatrix(X_train, label=y_train)
dtest = xgb.DMatrix(X_test, label=y_test)

# Задаем параметры модели
params = {
    'objective': 'binary:logistic',
    'eval_metric': 'auc',
}

# Обучаем модель
bst = xgb.train(params, dtrain, num_boost_round=100)

Посмотрим на качество нашей модели.

from sklearn.metrics import classification_report

# Предсказываем
y_pred = bst.predict(dtest)
y_pred_binary = [1 if y > 0.5 else 0 for y in y_pred]

# Выводим отчет
print(classification_report(y_test, y_pred_binary))

Чтобы убедиться, что наша модель не переобучилась, используем метод Walk-forward validation.

from mlfinlab.cross_validation.cross_validation import ml_cross_val_score

scores = ml_cross_val_score(bst, X, y, cv=5, sample_weight=weights)
print('Средний AUC: ', np.mean(scores))

Заключение

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

Куда идти дальше?

  • Изучить Fractionally Differentiated Features для создания стационарных временных рядов.

  • Попробовать Bet Sizing для управления капиталом.

  • Исследовать Clustering Algorithms для выявления скрытых закономерностей.

Подробнее с библиотекой можно ознакомиться здесь.

28 октября пройдет открытый урок на тему «Построение торгового агента на базе алгоритмов обучения с подкреплением». Участники узнают, как построить модель финансового рынка, создать и обучить торгового агента с использованием специализированного фреймворка. Если интересно — записывайтесь на урок на странице курса «ML для финансового анализа».

Комментарии (4)


  1. bellerofonte
    22.10.2024 06:36

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

    Спойлер - они не оправдались. Чем именно полезна библиотека - не особо понятно.

    1. зачем делать преобразование баров, если потом dollar_bars нигде не используется, и все вычисляется на основе цен закрытия оригинальных баров?

    2. во вступлении заявлены реальные проблемы, но не показано, насколько именно библиотека помогла решить ту или иную проблему. например, каким был AUC до применения Computation of the Effective Sample Size (ESS) и каким стал после?


  1. Krasnoarmeec
    22.10.2024 06:36

    Что я делаю не так?


    1. bellerofonte
      22.10.2024 06:36

      денег не занесли


      1. Krasnoarmeec
        22.10.2024 06:36

        Вот оно как, оказывается...

        Не то чтобы печалька, но осадочек остался.