УДК 33
Газимов А.Ш.
студент
Уфимский университет науки и технологий (г. Уфа, Россия)
ПРИМЕНЕНИЕ МАТЕМАТИЧЕСКОГО АНАЛИЗА И ИСКУССТВЕННОГО ИНТЕЛЛЕКТА В ДНЕВНОМ ТРЕЙДИНГЕ
Аннотация: в статье представлена модель искусственного интеллекта, способная предвидеть рост стоимости ценной бумаги.
Ключевые слова: трейдинг, искусственный интеллект, ценные бумаги.
Цена ценной бумаги может зависеть от погоды, политики, конкурентов, новых игроков на рынке, инноваций и многих других факторов. И именно по этой причине самыми успешными трейдерами являются математики и физики. В то время как обычный народ пытается управлять хаосом, доктора наук подстраиваются под него. В конечном итоге скажем, что в течение одного дня цена может пойти либо вверх, либо вниз, варианта всего два - а посему, можно предположить, что она будто зависит от подбрасывания монеты. Такой гипотезой в свое время так или иначе воспользовались Луи Башелье, Майрон Шоулз и Фишер Блэк, и, наконец, Джеймс Саймонс. Каждый из них в своём стиле победил гипотезу эффективного рынка (гипотеза при которой считается, что паттернов в цене активов не существует), при этом заработав огромное количество денег. Пройдемся по их стопам и применим современный подход к оцениванию цены бумаг на рынке.
Шоулз и Блек составили революционную модель, которая определяет теоретическую цену на европейские опционы. Решив эту аналитическую формулу получаем ожидаемую стоимость покупки/продажи в указанный день,
таким образом открылась возможность безрискового хеджирования (Покупая акции и одновременно продавая опционы call на эти акции, инвестор может конструировать безрисковую позицию, где прибыли по акциям будут точно компенсировать убытки по опционам, и наоборот). Эта модель породила четыре новые отрасли и была настоящим прорывом в области экономики.
Более интересная для нас персона - Джеймс Саймонс, основал хедж-фонд (инвестиционная компания) "Ренессанс", в которой по большей части используется машинное обучение и анализ больших данных для предсказания роста/падения цен. Прибыль от вложенных 100$ в 1988 на сегодняшний день могла бы составить 8.400.000.000$, что безоговорочно делает это самым выгодным вкладом за всю историю.
С огромным ростом популярности машинного обучения в последние годы было бы глупо не заинтересоваться механизмом работы скрипта, осуществляющего обучение искусственного интеллекта. Будем пользоваться языком программирования Python, для обучающей модели я выбрал Случайный Лес (Random Forest Classifier) из библиотеки scikit-learn. Также нам понадобится модуль yfinance от YaHoo для загрузки исторических данных в модель. Ну и Pandas, конечно, для удобной работы с большими данными.
import yfinance as yf import pandas as pd
from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import precision_score import time
Рисунок 1.
Тикером в трейдинге называется краткое название ценной бумаги (в нашем случае это будет АОЗРС). Мы будем работать с американской биржей и предугадывать направление движения фондового индекса Б&Р500, а точнее, вырастет ли цена бумаги в течение всего дня.
ft Загрузка данных для тикера ЛЕ5РС [S&P 500) ticker„syiribo~l = ""GSPC" stack„data = yf,Ticker(ticker„5ymbol) stack_history ~ stock.data.history( ="max")
print(stock.histcry)
stock_history.index = pd.to_datetine(stock_history.index) del stock_histary["Dividends"] del stock„history["Stock Splits"]
stock_history["Next_C~lase"] == stock_.history["C~Lose"] .shiftC-l)
stock_history["Target"] = (stock_history ["Next_CLose" ] > stock_histary [ "Close1']) .a^tigeCint) stock.history = stock, .history Лос.1 "1998- 01- 01" j j. copy Q
Рисунок 2.
35 строка кода покажет нам такие данные:
Open High . Dividends Stock Splits
Date
1927-12-30 00 00:00-05 00 17 660000 17 660000 . 0 о 0.0
1928-01-03 00 00:00-05 00 17 760000 17 760000 3 о 0.0
1928-01-04 00 00:00-05 00 17 719999 17 719999 . 0 о 0.0
1928-01-05 00 00:00-05 00 17 549999 17 549999 0 0 0.0
1928-01-06 00 00:00-05 00 17 660000 17 660000 , 0 0 0.0
2024-06-14 00 00:00-04 00 5424 080078 5432 390137 . 0 0 0.0
2024-06-17 00 00:00-04 00 5431 109863 5488 500000 a 0 0.0
2024-06-18 00 00:00-04 00 54 76 149902 5490 379883 . о 0 0.0
2024-06-20 00 00:00-04 00 5499 990234 5505 529785 о 0 0.0
2024-06-21 00 00:00-04 00 54 66 770020 54 78 310059 . о 0 0.0
[24234 rows X 7 columns]
Рисунок 3.
Как вы видите, в нашем распоряжении 7 столбцов - дата, цены открытия, закрытия, наибольшей и наименьшей за день, а также дивиденды и дробление. Последние два столбца нам не нужны (они все равно по нулям), поэтому удалим их в 37 и 38 строке. В 36 мы настроили дату как индекс, чтобы в будущем программа все данные привязывала именно к дате. С 39 строки начинается самое интересное - мы добавляем к нашей таблице два новых столбец - цену закрытия на следующий день (Next_Close) и целевое значение (Target), представляющее из себя ответ на вопрос: "Будет ли цена завтра вечером больше чем сегодня вечером?" или "Вырастет ли завтра цена в течение
дня?". Этот столбец нам очень сильно пригодится в будущем, когда мы будем проверять нашу модель на точность. В 41 строке избавимся от "лишних" данных по цене до 1990 года, просто бумага стоила намного меньше в то время, чем сейчас и эти данные мы должны считать мусорными.
U Создание модели случайного леез
randot!i_f orest_model = RandomForestClassifierC mators=29B, min.samf >les_split=50, rand nm_sTate=l)
Рисунок 4.
Вот так просто создается сама модель Случайного Леса. Уже на этом моменте можно "скормить" ей наши данные о цене (цены открытия и закрытия, максимальная и минимальная за день) и получать какой-никакой результат, но гораздо большего мы достигнем, если дадим ей другие, более полные данные.
if Создание предикторов на основе различных горизонтов rolling_horizoris = [2, 5, 60, 250, 1800] new_features - []
47
for horizon in rolling_horizons:
rolling^averages - stook_fiistory.rolling(horizon) .meanO
ratio^col = f''Clcse_Ratio_{horizon}"
stock_history[ratio_col] = stock_fiistoryi" Close" ] / rolling_averages [" Close1 ] trend_col = f1 Trend_{horizon)-"
stockj^istcry[trend^col] - stock_history.shift(1).rolling(horizon],sun()["Targat"]
new^features +- [rationed, trend^col]
if Удаление строк с отсутствующими значениями в предикторах stock_f\istory = stock_fiisTory.dropna( =new_features)
Рисунок 5.
В 45 строке в списке лежат горизонты - количество дней которое мы будем брать за расчет скользящих средних и трендов. Последние 2 дня, неделя, 3 месяца (в торговом месяце ~20 дней), год (в торговом году ~250 дней), и, соответственно, 4 года. Таким образом у нас добавится целых 10 столбцов на анализ нашей модели. В 60 строке сотрем все строки в которых появились
(not a number, если считать тренд за, например, 5 дней первые 4 будут дня будут пустыми, так как данные по цене брать неоткуда).
Пришло время самой сложной части программы для понимания: бэктестинга (backtesting).
def backtest_model(datar model, predictors, start_index=25G0, step_size=25Q): all_predictions = []
for i in range(start_index, data.sfiape[8], step_size): train_data = data,iloc[EJ:i] .copyC) test_data = data. iloc[i:(i + step^size)].copyO
predictions = make_predictions(trainjjata, test^data, predictors, model) all^predictions.append(predict ions) return pd.concat(all_pre diet ions)
def niake„predictions(train_data, test^data, predictors, model): model.,fit(train_data[predictors], train_data["Target"]) predicted_probs = mode L.predict_profja (test_data[predictors]) [:, 1] predicted_labels = (predicted_probs G.63).astype(int)
predictions = pd.Series(predicted_labels =test_data.index, ■= PrpriLotions")
combined_resuits = pd.conoat([test_dataf"Target"], predictions], =1) return combined„results
Рисунок 6.
Данная функция обучается на первых 2500 днях из переменной data и строит прогноз на следующие 250 дней, затем добавляет последний год к предыдущим десяти и предсказывает двенадцатый год. То есть, по сути, начиная с 10 лет модель каждую итерацию цикла увеличивает обучаемый набор на год. В 27 строке все предсказания собираются в 1 панда-датасет, последним элементом этого набора как раз и будет нас интересующее число: предсказание на завтра. Функция make_predictions, используемая в 25 строке и описанная в 11 строке возвращает две колонки нулей и единиц, действительные и предполагаемые значения роста цены. В 14 строке есть настройка коэффициента уверенности: если модель на 63% и более уверенна что значение будет 1, то она выберет 1, в обратном случае будет выбран 0.
Ы # Тестирование модели на исторических данных
predicted_results - backtest_mQdel(stDck_fiistDry, random_fcrest_model, new_features)
Ik
¿5 ff Оценка результатов
precision_metric = precisian_score(predicted_re5ults [' target1 ], predicted^resuits ["Predictions' ]) last„predicted_vBlue = predicted_results['PrEriictions ].iloc[-1]
68
# Вывод результатов
priritif"Prerts^rffi joore:- iprecision_metric} ) printC'Tarqet Valu = Counti:")
print(predicted_results[ ' ] ,velue_countsO / predicted_results . shape [?])
print(' Predictions Value Courts:')
print[predicted_results [ Рг-'Ji' г ic7"1 ].value_counts()) printf Last Prediction: , lsst_pretiicteiJ_VBlue)
76
# Замер времени окончания работы скрипта и вывод общего времени работы end_tirae = time.time i)
print(1 Е:;емя . aD-зт-' скрипта: , end_time - start_time)
Рисунок 7.
Запустив программу получаем такие выводы:
Precision Score: 0.6011396011396012
Target Value Counts:
Target
1 0.544631 0 0.455369
Name: count, dtype: float64 Predictions Value Counts: Predictions
0 4836
1 351
Nane: count, dtype: int64 last Prediction: 0
Время работы скрипта: 55.96072769165039 Process finished with exit code 0
Рисунок 8.
Точность модели написана в самой первой строчке - это означает, что когда модель думала, что цена в течение дня вырастет, она действительно выросла в ~60% случаев. Ниже представлена статистика по реальному количеству дней, когда цена выросла - 54.4%. Из этих двух чисел можем
сделать вывод, что модель действительно прибыльная. Еще ниже есть статистика по точному количеству дней, когда модель угадала, что цена может вырасти: 351 день (то есть она действительно выросла в 351*0.6011=211 случаях). Наконец, строка Last Prediction: 0 - завтра цена по мнению модели не вырастет. Время работы скрипта в секундах. Послесловие.
Несмотря на то, что точность модели выше реального количества "прибыльных" дней, сама модель вполне возможно может проиграть наши деньги - просто напросто все "победы" могут нивелироваться одним большим проигрышем из дней неудачных.
Что же делать теперь? Все опытные трейдеры всегда опираются на множество факторов при принятии решения, точно так же и мы должны найти больше факторов, а не основывать все наши действия на одной только модели искусственного интеллекта. Возможно, стоит добавить еще больше столбцов в датасет stock_history, изменить коэффициент уверенности (в программе он был
0.63., работать с моделью в связке с индикаторами сухого мат. анализа, ну и наконец, следить за новостями.
СПИСОК ЛИТЕРАТУРЫ:
1. https://www.youtube.com/watch?v=A5w-dEgIU1M&list=LL&index=2&ab_channel=Veritasium
https://www.youtube.com/watch?v=10_BenficgE&list=LL&index=40&t=243s&ab_ channel=Dataquest;
2. https://scikit-learn.ru
Gazimov A.Sh.
Ufa University of Science and Technology (Ufa, Russia)
APPLICATION OF MATHEMATICAL ANALYSIS AND ARTIFICIAL INTELLIGENCE IN DAY TRADING
Abstract: the article presents an artificial intelligence model that can predict the increase in the value of a security.
Keywords: trading, artificial intelligence, AI, Python.