Комплексный проект: получить данные, обучить модель, оформить заказ, получить уведомление
Пару недель назад я случайно болтал с другом, в масках, на социальной дистанции, как обычно. Он рассказывал мне, как пытался - я цитирую - детоксикацию из брокерского приложения, которое он использовал. Я спросил его о значении слова «детокс» в данном конкретном контексте, опасаясь, что он может разориться, но нет: он сказал мне, что постоянно торгует. «Если определенная акция росла более часа или около того, и я уже превысил порог прибыли в 1%, то я продаю, - сказал он, - среди других личных правил, которым я следовал». Оставив в стороне небольшой псевдонаучный аспект этих правил, я понял, что он имел в виду под детоксом: следование им означало астрономически большое количество проверок телефона.
Поэтому я задумался: можно ли автоматизировать набор правил, которые задумал этот парень? И на самом деле - можно ли автоматизировать более разумный набор правил, чтобы я позволил системе делать торговлю за меня? Поскольку вы читаете это, я предполагаю, что вас зацепило название, так что вы, вероятно, уже догадались, что ответ положительный. Давайте подробнее остановимся на этом, но прежде всего: время - золото, и я не хочу никого кликать. Вот что мы собираемся сделать:
- Получайте подробные данные о ценах на акции в режиме реального времени: в идеале, с интервалом в одну минуту. Чем богаче, тем лучше - мы будем использовать Yahoo! Финансирование для этого, подробности будут позже.
- Вместо личного набора правил мы собираемся добавить в систему немного искусственного интеллекта. Полное раскрытие информации: я ни в коем случае не эксперт в анализе временных рядов, там уже есть много руководств о том, как обучить нейронные сети торговле, и я действительно не хочу чрезмерно разрабатывать такую игрушечную систему, так что давайте будьте проще: на данный момент подойдет очень простая модель ARIMA.
- На этом этапе у нас будут данные и прогноз, полученные от алгоритма, поэтому мы сможем решить, продавать, покупать или держать; нам нужно связаться с нашим брокером, чтобы действительно выполнить действие. Мы собираемся использовать Робин Гуд и Альпаку.
- Вот и все - система закончена. Последнее, что нам нужно, - это развернуть его где-нибудь, в нашем случае AWS, и отслеживать активность. Я решил отправлять сообщение Telegram группе каждый раз, когда моя система выполняет какое-либо действие.
А что нам понадобится?
- Python 3.6 с некоторыми библиотеками.
- Учетная запись AWS с правами администратора для хранения и развертывания.
- Node.js, просто чтобы настроить бессерверную структуру для развертывания.
- Учетная запись Telegram для мониторинга.
Все, что я закодировал, доступно здесь. Хорошо! Итак, без лишних слов, приступим к первой части: получению данных.
Получение данных
Получить данные непросто. Несколько лет назад был официальный Yahoo! Finance API, а также альтернативы, такие как Google Finance - к сожалению, оба были прекращены уже много лет. Но не волнуйтесь, на рынке по-прежнему есть множество альтернатив. Мои личные требования были:
- Бесплатно: для производственной системы я определенно поменяю этот пункт на дешевые альтернативы, но для игрушечной системы или подтверждения концепции, как бы вы это ни называли, я хочу, чтобы это было бесплатно.
- Высокий лимит скорости: в идеале без лимита, но все, что выше 500 ударов в минуту, более чем достаточно.
- Данные в реальном времени: некоторые API предоставляют данные с небольшой задержкой, скажем, 15 минут. Я хочу реальную сделку - максимально приближенную к текущей цене акций.
- Простота использования: Опять же - это просто POC. Я хочу самый простой.
Имея в виду этот список, я выбрал yfinance
- неофициальную альтернативу старому Yahoo Finance API. Имейте в виду, что для реальной системы и на основе потрясающего списка, предоставленного Патриком Коллинзом, я определенно выбрал бы Alpha Vantage API, но пока давайте не будем усложнять.
Библиотека yfinance
была разработана Раном Арусси для доступа к Yahoo! Финансовые данные после закрытия официального API. Цитата из репозитория GitHub,
С тех пор, как Yahoo! финансы прекратили работу API исторических данных, многие программы, которые полагались на него, перестали работать.
yfinance стремится решить эту проблему, предлагая надежный, многопоточный и питонический способ загрузки исторических рыночных данных с Yahoo! финансы.
Сладкий, достаточно для меня. Как это работает? Для начала нам нужно его установить:
$ pip install yfinance --user
И тогда мы можем получить доступ ко всему с помощью объекта Ticker:
import yfinance as yf google = yf.Ticker(“GOOG”)
Этот метод довольно быстрый, в среднем чуть более 0,005 секунды, и возвращает МНОГО информации об акции; например, google.info
содержит 123 поля, включая следующие:
52WeekChange: 0.3531152 SandP52WeekChange: 0.17859101 address1: 1600 Amphitheatre Parkway algorithm: None annualHoldingsTurnover: None annualReportExpenseRatio: None ask: 1815 askSize: 1100 ... twoHundredDayAverage: 1553.0764 volume: 1320946 volume24Hr: None volumeAllCurrencies: None website: http://www.abc.xyz yield: None ytdReturn: None zip: 94043
Дополнительная информация доступна несколькими способами: dividends
, splits
, balance_sheet
или earnings
среди других. Большинство этих методов возвращают данные в объекте pandas
DataFrame, поэтому нам нужно немного поиграть с ним, чтобы получить то, что мы хотим. На данный момент мне просто нужна информация о цене акций во времени; history
метод лучше всего подходит для этой цели. Мы можем выбрать как период, так и даты интервалов, а также частоту данных с точностью до одной минуты - обратите внимание, что внутридневная информация доступна только в том случае, если период меньше 60 дней, и что данные с детализацией в 1 миллион разрешены только за 7 дней. получать по запросу. Транспонированные данные последней записи с интервалом в 1 м выглядят следующим образом:
df = google.history(period='1d', interval="1m") print(df.head())
Мы можем видеть, как он индексируется по дате и времени, и каждая запись имеет семь функций: четыре фиксированных точки цены акции в течение этой минуты (открытие, максимум, минимум и закрытие) плюс объем, дивиденды и дробление акций. Я собираюсь использовать только низкий уровень, поэтому давайте сохраним эти данные:
df = google.history(period='1d', interval="1m") df = df[['Low']] df.head()
Наконец, поскольку мы собираемся использовать данные только за последний день, давайте переиндексируем фрейм данных, чтобы удалить компоненты даты и часового пояса и оставить только время:
df['date'] = pd.to_datetime(df.index).time df.set_index('date', inplace=True) df.head()
Хорошо выглядеть! Мы уже знаем, как получить самую свежую информацию из yfinance
- позже мы накормим этим наш алгоритм. Но для этого нам нужен алгоритм, который нужно кормить: перейдем к следующей части.
Добавление ИИ
Я уже говорил это раньше, но повторю еще раз: не пытайтесь повторить это дома. Что я собираюсь сделать здесь, так это подобрать ОЧЕНЬ простую модель ARIMA для прогнозирования следующего значения цены акции; думайте об этом как о фиктивной модели. Если вы хотите использовать это для реальной торговли, я бы порекомендовал искать лучшие и более сильные модели, но имейте в виду: если бы это было легко, все бы это сделали.
Сначала давайте разделим фрейм данных на обучение и тестирование, чтобы мы могли использовать тестовый набор для проверки результатов фиктивной модели - я собираюсь сохранить последние 10% данных в качестве тестового набора:
X = df.index.values y = df['Low'].values # The split point is the 10% of the dataframe length offset = int(0.10*len(df)) X_train = X[:-offset] y_train = y[:-offset] X_test = X[-offset:] y_test = y[-offset:]
Если построить график, то получим:
plt.plot(range(0,len(y_train)),y_train, label='Train') plt.plot(range(len(y_train),len(y)),y_test,label='Test') plt.legend() plt.show()
Теперь давайте сопоставим модель с данными обучения и получим прогноз. Обратите внимание, что гиперпараметры модели являются фиксированными, тогда как в реальном мире вы должны использовать перекрестную проверку, чтобы получить оптимальные - ознакомьтесь с этим замечательным руководством о Как искать в сетке гиперпараметры ARIMA с помощью Python. Я использую конфигурацию 5, 0, 1 и получаю прогноз на данный момент сразу после завершения данных обучения:
from statsmodels.tsa.arima.model import ARIMA model = ARIMA(y_train, order=(5,0,1)).fit() forecast = model.forecast(steps=1)[0]
Посмотрим, насколько хорошо работает наша фиктивная модель:
print(f'Real data for time 0: {y_train[len(y_train)-1]}') print(f'Real data for time 1: {y_test[0]}') print(f'Pred data for time 1: {forecast}') --- Real data for time 0: 1776.3199462890625 Real data for time 1: 1776.4000244140625 Pred data for time 1: 1776.392609828666
Это неплохо - с этим можно поработать. С помощью этой информации мы можем определить набор правил на основе того, что мы хотим сделать, например, удерживать, если цена растет, или продавать, если она падает. Я не буду вдаваться в подробности по этой части, потому что я не хочу, чтобы вы подали на меня в суд, говоря, что вы потеряли все свои деньги, поэтому, пожалуйста, определите свой собственный набор правил :) А пока я собираюсь чтобы объяснить следующую часть: подключение к брокеру.
Подключение к брокеру
Как вы, наверное, догадались, эта часть сильно зависит от брокера, которого вы используете. Я говорю о двух брокерах, Робин Гуде и Альпаке; причина в том, что они оба:
- Иметь общедоступный API (официальный или нет).
- Не взимайте комиссию за торговлю.
В зависимости от типа вашей учетной записи у вас могут быть некоторые ограничения: например, RobinHood разрешает всего 3 сделки в течение 5-дневного периода, если баланс вашего счета ниже 25000 $; Альпака разрешает гораздо больше запросов, но по-прежнему имеет ограничение в 200 запросов в минуту на ключ API.
Робин Гуд
Есть несколько библиотек, в которые входит RobinHood API, но, к сожалению, насколько мне известно, ни одна из них не является официальной. Библиотека Санко была самой большой, с 1,5 тыс. Звезд на GitHub, но ее поддержка прекращена; LichAmnesia’s продолжила путь Санко, но пока у нее всего 99 звезд. Я собираюсь использовать библиотеку robin_stocks, у которой на момент написания этой статьи чуть более 670 звезд. Установим:
$ pip install robin_stocks
Не все действия требуют входа в систему, но большинство из них требует входа в систему, поэтому полезно войти в систему, прежде чем делать что-либо еще. RobinHood требует MFA, поэтому необходимо его настроить: перейдите в свою учетную запись, включите двухфакторную аутентификацию и выберите «другое», когда вас спросят о приложении, которое вы хотите использовать. Вам будет представлен буквенно-цифровой код, который вы будете использовать в приведенном ниже коде:
import pyotp import robin_stocks as robinhood RH_USER_EMAIL = <<<YOUR EMAIL GOES HERE>>> RH_PASSWORD = <<<YOUR PASSWORD GOES HERE>>> RH_MFA_CODE = <<<THE ALPHANUMERIC CODE GOES HERE>>> timed_otp = pyotp.TOTP(RH_MFA_CODE).now() login = rh.login(RH_USER_EMAIL, RH_PASSWORD, mfa_code=totp)
Купить или продать довольно просто:
# Buying 5 shares of Google
rh.order_buy_market('GOOG', 5)
# Selling 5 shares of Google
rh.order_sell_market('GOOG', 5)
Ознакомьтесь с документацией для расширенного использования и примеров.
Альпака
Для Альпаки мы будем использовать alpaca-trade-api
библиотеку, у которой более 700 звезд в GitHub. Установить:
$ pip install alpaca-trade-api
После входа в учетную запись вы получите идентификатор ключа API и секретный ключ; оба необходимы для входа в систему:
import alpaca_trade_api as alpaca ALPACA_KEY_ID = <<<YOUR KEY ID GOES HERE>>> ALPACA_SECRET_KEY = <<<YOUR SECRET KEY GOES HERE>>> # Change to https://api.alpaca.markets for live BASE_URL = 'https://paper-api.alpaca.markets' api = alpaca.REST( ALPACA_KEY_ID, ALPACA_SECRET_KEY, base_url=BASE_URL)
Отправка заказов немного сложнее, чем с РобинГудом:
# Buying 5 shares of Google api.submit_order( symbol='GOOG', qty='5', side='buy', type='market', time_in_force='day' ) # Selling 5 shares of Google api.submit_order( symbol='GOOG', qty='5', side='sell', type='market', time_in_force='day' )
Вот и все! Обратите внимание, что оставлять учетные данные в виде обычного текста - это очень, ОЧЕНЬ плохой поступок, но не волнуйтесь, на следующем шаге мы переключимся на переменные среды, что намного безопаснее. Теперь давайте развернем все в облаке и будем следить за ним.
Развертывание и мониторинг
Мы собираемся развернуть все в AWS Lambda. Очевидно, это не лучший вариант для производственной системы, поскольку у Lambda нет хранилища, и мы хотели бы хранить обученную модель где-нибудь, например, в S3. Однако на данный момент этого достаточно - мы запланируем ежедневное выполнение лямбды, обучая модель каждый раз с данными за текущий день. Для мониторинга мы настроим бота Telegram, который будет отправлять сообщение с указанием действия, которое необходимо предпринять, и его результатов. Обратите внимание, что AWS Lambda предоставляется бесплатно до определенного предела, но помните о квотах, если вы хотите отправлять много сообщений.
Первое, что нужно сделать - это создать бота. Я выполнил официальную инструкцию Telegram:
- Найдите пользователя @BotFather в Telegram.
- Используйте команду
\newbot
и выберите имя и логин для вашего бота. - Возьмите токен и храните его в надежном месте, он вам скоро понадобится.
Следующий шаг: развертывание. Есть несколько способов развертывания в Lambda. Я собираюсь использовать бессерверный фреймворк, поэтому давайте установим его и создадим шаблон:
$ npm install serverless --global $ serverless create --template aws-python3 --path ai_trading_system
Это создаст папку scheduled_tg_bot
с тремя файлами: .gitignore
, serverless.yml
и handler.py
. Бессерверный файл определяет развертывание: что, когда и как оно будет запускаться. Файл обработчика будет содержать код для запуска:
import telegram import sys import os CHAT_ID = XXXXXXXX TOKEN = os.environ['TELEGRAM_TOKEN'] # The global variables should follow the structure: # VARIABLE = os.environ['VARIABLE'] # for instance: # RH_USER_EMAIL = os.environ['RH_USER_EMAIL] def do_everything(): # The previous code to get the data, train the model # and send the order to the broker goes here. return 'The action performed' def send_message(event, context): bot = telegram.Bot(token=TOKEN) action_performed = do_everything() bot.sendMessage(chat_id=CHAT_ID, text=action_performed)
Вам нужно изменить CHAT_ID
на идентификатор группы, канала или беседы, с которой должен взаимодействовать бот. Здесь вы можете найти как получить идентификатор из канала и как получить идентификатор из группы.
Теперь мы собираемся определить, как запускать код. Откройте serverless.yml
и напишите:
org: your-organization-name app: your-app-name service: ai_trading_system frameworkVersion: “>=1.2.0 <2.0.0” provider: name: aws runtime: python3.6 environment: TELEGRAM_TOKEN: ${env:TELEGRAM_TOKEN} # If using RobinHood RH_USER_EMAIL: ${env:RH_USER_EMAIL} RH_PASSWORD: ${env:RH_PASSWORD} RH_MFA_CODE: ${env:RH_MFA_CODE} # If using Alpaca ALPACA_KEY_ID: ${env:ALPACA_KEY_ID} ALPACA_SECRET_KEY: ${env:ALPACA_SECRET_KEY} functions: cron: handler: handler.send_message events: # Invoke Lambda function at 21:00 UTC every day - schedule: cron(00 21 * * ? *)
Этот код сообщает AWS, какую среду выполнения мы хотим, и распространяет токен Telegram из нашей собственной среды, поэтому нам не нужно его развертывать. После этого мы определяем, что cron будет запускать функцию ежедневно в 21:00 по всемирному координированному времени.
Осталось только получить учетные данные AWS и установить их вместе с токеном и остальными переменными в качестве переменных среды перед развертыванием. Получить учетные данные довольно просто:
На консоли AWS:
- Перейдите в Мои учетные данные безопасности - Пользователи - Добавить пользователя.
- Выберите имя пользователя и выберите Программный доступ.
- Следующая страница: выберите Присоединить существующие политики напрямую - Доступ администратора.
- Скопируйте идентификатор ключа доступа и секретный ключ доступа и сохраните их.
Вот и все. Теперь давайте экспортируем учетные данные AWS и токен Telegram. Откройте терминал и напишите:
$ export AWS_ACCESS_KEY_ID=[your key goes here] $ export AWS_SECRET_ACCESS_KEY=[your key goes here] $ export TELEGRAM_TOKEN=[your token goes here] # If using RobinHood $ export RH_USER_EMAIL=[your mail goes here] $ export RH_PASSWORD=[your password goes here] $ export RH_MFA_CODE=[your mfa code goes here] # If using Alpaca $ export ALPACA_KEY_ID=[your key goes here] $ export ALPACA_SECRET_KEY=[your key goes here]
Установите необходимые пакеты локально и, наконец, разверните все на AWS:
$ pip3 install -r requirements.txt -t . --system $ serverless deploy
Были сделаны! Бот будет торговать за нас каждый день в 21:00 по всемирному координированному времени и сообщит нам о выполненном действии. Неплохо для проверки концепции - теперь я могу сказать своему другу, что он может перестать лихорадочно проверять свой телефон, чтобы торговать :)
Обратите внимание, что все ресурсы, которые мы использовали в этом руководстве, имеют собственную документацию: я призываю вас углубиться в то, что вы считаете интересным - помните, что это всего лишь игрушечная система! Однако, как игрушечная система, я считаю, что это хорошая отправная точка для более богатого и сложного продукта. Удачного кодирования!
Вы можете проверить код в GitHub.
Примечание редакторам Data Science. Хотя мы разрешаем независимым авторам публиковать статьи в соответствии с нашими правилами и рекомендациями, мы не поддерживаем вклад каждого автора. В этом случае, как указывает сам автор: не пытайтесь торговать, не посоветовавшись с профессионалами. См. Подробности в наших Условиях для читателей.
Использованная литература:
[1] П. Коллинз, Лучшие биржевые API и отраслевой ландшафт в 2020 году (2020), средний
[2] Р. Арусси, Надежно загружайте исторические рыночные данные с Yahoo! Финансы с Python (2019), Aroussy.com
[3] Дж. Браунли, Как искать в сетке гиперпараметры модели ARIMA с помощью Python (2017 г.), Machine Learning Mastery
[4] Дж. Браунли, Как делать вневыборочные прогнозы с ARIMA в Python (2017 г.), Machine Learning Mastery
[5] Бессерверная команда, Пример расписания Cron AWS Python, GitHub