Как быстро скачать котировки с IEX

Многие расстроились😭, когда 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 и берем из них только работающие инструменты. Замеры скорости приведены для красоты. Основную работу выполняет функция performMyMulti. В данном примере она пачками по block тикеров параллельно выкачивает историю дневок за последние 30 дней. В качестве пачки на вход этой функции поступает список tools_, который содержит строковые коды инструментов. Второй параметр этой функции, time_frame — задает глубину. Чтобы скачать котировки за 5 лет, задайте ’5y’. Результаты складываются в текстовые файлы в каталог data. Данные в них — это объекты json, которые дальше можно парсить и использовать по назначению.

# -*- 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))

🏁Заключение

Код можно адаптировать для скачивания минутной истории в реальном времени.

Также доступны тики в реальном времени через вебсокеты (websockets). Что делает данную биржу крайне ценной находкой.

Роман Щеголихин
roman.shchegolikhin@bk.ru

💬В комментариях напишите, где вы берёте данные или поблагодарите Романа. Порекомендуйте лучших поставщиков данных.

☝Рынок вас манит? Подготовьтесь🎓 у профи в трейдинговой компании👍.