Ромирес
Ромирес личный блог
18 декабря 2017, 13:14

Как качать историю котировок (пример на Python, IQFeed)

   IQFeed -  это не самый дешёвый (но и не самый дорогой) провайдер исторических (и real-time) данных финансовых бирж и разнообразных trading venues. Со своими плюсами и минусами.

   В этой короткой статье расскажу, как закачать исторические данные из IQFeed при минимальном знании языка Python.

   Disclosure: я заинтересованное лицо, хоть и не в коммерческом смысле, т.к. ищу тех с кем можно расшарить сервис IQFeed вскладчину. См. подробнее: smart-lab.ru/blog/439522.php

   Из плюсов IQFeed – вполне сносное API для доступа к данным (уступающее по простоте RESTful сервисам, но минус REST – крайне низкая производительность, тяжело качать более или менее объёмные данные). Огромный выбор (акции, фьючерсы, опционы...). Минусы -тики только 180 дней (по SPY, кстати, это примерно 2.5GB). Adjusted данных по акциям нет.

   Скачивание сводится к формированию запроса -“хочу такие-то данные с такой-то по такую-то дату”. Запрос — это текстовая строка, отправленная в канал коммуникации (сокет).

   Вот примеры строки запроса на интрадей (минутки): «HIT,SPY,60,20160226 093000,20170226 160000,,093000,160000,1,,»

   Расшифровка: дайте интрадей (HIT), по SPY, с барами в 60 секунд (т.е. минутки), с 20160226 093000 (YYYYMMDD HHMMSS), по 20170226 160000, без ограничения кол-ва выдаваемых строк, в торговую сессию с 093000 по 160000 (т.е. без extra-hours), с “прямой” (от старого к новому) сортировкой по датам (1),  без RequestID, без DATAPOINTSPERSEND.

   Формально запрос выглядит так:

HTT,SYMBOL,BEGINDATE BEGINTIME,ENDDATE ENDTIME,MAXDATAPOINTS,BEGINFILTERTIME,ENDFILTERTIME,DIRECTION,REQUESTID,DATAPOINTSPERSEND<CR><LF>

 

   <CR><LF> это перевод строки “по-windowsовски” (\r\n). Говорю специально для тех, кто работает на Linux.

   Запрос нужно послать на предварительно открытый сокет localhost:9100 или 127.0.0.1:9100 (под Linux может иметь значение), на котором “висит” работающий клиент IQFeed (в Windows запустить вручную через IQLink Launcher), а дальше вычитывать с него порции (блоки) данных (формат текстовый, кстати там не OHLC, а HLOC) соединяя вместе. Чтение производить до появления слова “!ENDMSG!” к конце очередного блока.

Грубо говоря – всё. Это минимально достаточный набор действий.

Попробуем сделать это на Python:

import sys
import socket

def read_historical_data_socket(sock, fname, recv_buffer=4096):

    buffer = ""
    data = ""
    cont=True
    while cont:
        buffer = sock.recv(recv_buffer).decode('ascii')
        data += buffer
        if "!ENDMSG!" in data[-12:]:
            data = data[:-12]
            cont=False

        firstlines=buffer.split("\n",2)
        if len(firstlines)>1:
            sys.stdout.write("Download progress(%s): %s   \r" % (fname,firstlines[1][0:19]) )
            sys.stdout.flush()
        
    data = "".join(data.split("\r"))
    data = data.replace(",\n","\n")[:-1]
    
    f = open(fname, "w")
    f.write(data)
    f.close()
    return

if __name__ == "__main__":

    host = "127.0.0.1"
    port = 9100
    syms = ["SPY", "AAPL", "GOOG", "AMZN"]
    for sym in syms:
        message = "HIT,%s,60,20140101 000000,20160101 000000,,,,1\n" % sym
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.connect((host, port))

        sock.sendall(message.encode())
        read_historical_data_socket(sock,"%s.csv" % sym)
        sock.close

        sys.stdout.write("Downloaded symbol: %s                          " % sym)
        sys.stdout.flush()

    print

Собственно – всё. Пример  проверен и на Linux (Python 2.7.12) и на Windows (Python 3.5.4).
Примечания:
   Из недостатков скрипта — всё сначала закачивается в память. Тому есть причины: логика работы с сокетом — в получении равномерно нарезанных порций данных (4096 байт по умолчанию). Но сообщение !ENDMSG! может прийтись на границу двух блоков, потому быть «разрезанным» и при последовательном чтении с записью в файл (write-append block by block) просто неотдетектироваться. Для сохранения в файл on-the-fly без больших затрат памяти, нужна слегка усложнённая логика с хранением предыдущего считанного блока и детектом !ENDMSG! в них обоих сразу (в их конкатенации). Это усложняет скрипт. Для минуток особо морочиться не нужно (в худшем случае сотни мегабайт). Кроме того, нужно удалять запятые с конца строк (сделано) и реформатировать сами строки под конкретную программу ТА (не сделано).
   На Linux скрипт работает хорошо.
   И ещё. Не забывайте, что клиент IQFeed вылетает по timeout inactivity. Т.е. запустив клиент IQConnect, через IQLink, и потом поигравшись с скриптом вы долго можете мучиться с «неработающим сокетом», а причина банальна — iqfeed клиент закрылся по timeout inactivity (не пользовались долго).  

0 Комментариев

Активные форумы
Что сейчас обсуждают

Старый дизайн
Старый
дизайн