Многие расстроились😭, когда Yahoo.Finance закрыл🚫 все лазейки для получения бесплатных котировок. Но к всеобщему счастью🎉, уже есть альтернативы бесплатных данных. В этот раз мы скачаем бесплатную дневную историю с биржи IEX для ~8 тысяч американских активов примерно за ~2 минуты⏱️. Поможет нам в этом Python 2.7🐍. А рассказывать будет Роман Щеголихин.
Пытливые умы на сайте биржи могут найти бесплатную историю тиков за предыдущие 10 месяцев в формате pcap (tcpdump).
☝️На бирже IEX совершается примерно ~2.5% оборота акций, что необходимо учесть. Тики не дадут построить идеальную историю изменения цены из-за недостатка данных по остальным биржам.
В отличие от многих зарубежных поставщиков данных, IEX (https://iextrading.com/) предоставляет исторические данные бесплатно. Дневная история за 5 последних лет доступна для более чем 8 тысяч активов, среди которых такие рынки как:
- New York Stock Exchange
- Nasdaq Global Select
- NYSE Arca
- NYSE American
- NASDAQ Global Market
- NASDAQ Capital Market
- BATS Exchange
Кстати, дневная история учитывает торги на всех американских биржах, в отличии от тиков. RAA.
Этот брокер имеет простой API, и главное, бесплатный. Даже регистрироваться не надо. Правда, есть ограничение на 100 запросов в секунду.
Документация по API: https://iextrading.com/developer/docs/
Список доступных активов: https://api.iextrading.com/1.0/ref-data/symbols
Запрос по нужному активу выглядит так: https://api.iextrading.com/1.0/stock/aapl/chart/1m
Это запрос по Apple inc. дневной истории за последний месяц. Котировки отрегулированны на сплиты и дивиденды.
Ну что же, список котировок есть, API есть. Как всё это дело скачать и побыстрей? Ниже скрипт на Python 2.7 с использованием технологии MultiCurl и библиотеки pycurl.
И на загрузку более 8 тысяч активов за месяц у меня уходит всего ~110 секунд. 🤘 Здорово!
🎁Код в студию
Список тикеров получаем “на лету” из IEX и берем из них только работающие инструменты. Замеры скорости приведены для красоты. Основную работу выполняет функция [code]performMyMulti[/code]. В данном примере она пачками по [code]block[/code] тикеров параллельно выкачивает историю дневок за последние 30 дней. В качестве пачки на вход этой функции поступает список [code]tools_[/code], который содержит строковые коды инструментов. Второй параметр этой функции, [code]time_frame[/code] — задает глубину. Чтобы скачать котировки за 5 лет, задайте [code]’5y’[/code]. Результаты складываются в текстовые файлы в каталог data. Данные в них — это объекты json, которые дальше можно парсить и использовать по назначению.
[raaAdSenceArticle]
[code python]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# -*- coding: utf-8 -*- import pycurl import requests import json import time import os def performMyMulti(tools_, time_frame = '1m'): ''' Функция многопоточного скачивания. Принимает на вход список кодов инструментов для скачивания. Количество инструментов в этом списке не должно превышать 100шт. ''' m = pycurl.CurlMulti() m.handles = [] files = [] # список файлов для сохранения результатов start_ = time.time() # замер времени для расчета скорости, начальная точка # создание и настройка curl-объектов for tool_ in tools_: c = pycurl.Curl() # имя файла для сохранения результатов; файлы сохраняются в каталог data fileName = "data%s%s_%s.txt" % (os.sep, tool_, time_frame) fileName = fileName.replace('*', '_') f = open(fileName, "wb") files.append(f) # файл добавляется в список, чтобы потом закрыть его c.setopt(c.WRITEDATA, f) # кроме файла здесь можно указывать функцию, но файл нам наиболее удобен url = "https://api.iextrading.com/1.0/stock/%s/chart/%s" % (tool_, time_frame) c.setopt(pycurl.URL, url) m.add_handle(c) m.handles.append(c) num_handles = len(m.handles) while num_handles: while 1: # выполнить запросы ret, num_handles = m.perform() if ret != pycurl.E_CALL_MULTI_PERFORM: break m.select(1.0) # очистка for c in m.handles: c.close() m.remove_handle(c) for f in files: f.close() m.close() del m.handles end_ = time.time() # замер времени для расчета скорости, конечная точка return len(tools_) / (end_-start_) # скорость в секунду # скачиваем список инструментов r = requests.get('https://api.iextrading.com/1.0/ref-data/symbols') data = json.loads(r.text) tools = [] #список кодов инструментов # выбираем коды инструментов в отдельный массив for tool in data: try: if tool['isEnabled'] is True: tools.append(tool['symbol']) except: continue block = 80 #количество параллельных запросов (не более 100шт) tools_count = len(tools) print(u"Всего инструментов для скачивания: %d" % tools_count) loops = tools_count / block # количество полных циклов (циклов по block запросов) tail = tools_count % block # количество оставшихся запросов tools_ok = 0 # общее количество выполненных запросов start = time.time() # замер общего времени, начальная точка for i in range(loops): # в цикле по всем полным циклам srez = tools[i*block:i*block+block:1] # формируем выборку из следующих block инструментов speed = performMyMulti(srez) # выполняем параллельное скачивание tools_ok += block print(u"готово %d из %d, скорость %f в сек" % (tools_ok, tools_count, speed)) if tail > 0: # "докачиваем" оставшиеся инструменты i += 1 srez = tools[block*i:block*i+tail] speed = performMyMulti(srez) tools_ok += tail print(u"готово %d из %d, скорость %f в сек" % (tools_ok, tools_count, speed)) end = time.time() # замер общего времени, конечная точка print(u"Всё скачали! Ушло %f сек" % (end-start)) |
[/code]
🏁Заключение
Код можно адаптировать для скачивания минутной истории в реальном времени.
Также доступны тики в реальном времени через вебсокеты (websockets). Что делает данную биржу крайне ценной находкой.
Роман Щеголихин
roman.shchegolikhin@bk.ru
💬В комментариях напишите, где вы берёте данные или поблагодарите Романа. Порекомендуйте лучших поставщиков данных.