Downloading Historical Intraday US Equities From DTN IQFeed with Python

Downloading Historical Intraday US Equities From DTN IQFeed with Python

In this article we will be discussing how to obtain intraday historic US equities data from the DTN IQFeed market data vendor. It is possible to obtain the data through a socket connection to the local IQLink server that is provided when an account is created. In this article we will make use of a streaming socket connection with Python to buffer this data and create CSV files of intraday market data for US equities.

Note: I have no affiliation with DTN IQFeed beyond being a customer. I am simply writing this article to help those who have an IQFeed account (or are considering getting one) to download data without the need for GUI software.

Python Socket Connection to IQFeed

I will assume that you already have an account with IQFeed. If not then it is possible to obtain a two-week free trial upon sign-up. After signing up to the required exchanges and level of data granularity you will be asked to download the IQLink launcher. This tool only natively works on Windows but can be executed on a Mac or a Linux machine under WINE with a bit of work!

Firing up the IQLink launcher brings up the connection dialog:

DTN IQFeed IQLink Launcher
DTN IQFeed IQLink Launcher

Clicking 'Start IQLink' will launch the server. You'll be prompted for your username and password. Once the server is running it is necessary to create a stream socket connection to a local port (9100 is the default). You can then send messages across this socket and receive the data in a buffered fashion.

The first task is to create the iqfeed.py file and import both the system and socket libraries:

# iqfeed.py

import sys
import socket

The buffering of the data is handled by the read_historical_data_socket function. It requires a socket object and the number of bytes to buffer per read. The function simply appends the latest batch of buffered data to a string and returns it once the "!ENDMSG!" string is found within (i.e. the buffer has reached the end of the data!):

# iqfeed.py

def read_historical_data_socket(sock, recv_buffer=4096):
    """
    Read the information from the socket, in a buffered
    fashion, receiving only 4096 bytes at a time.

    Parameters:
    sock - The socket object
    recv_buffer - Amount in bytes to receive per read
    """
    buffer = ""
    data = ""
    while True:
        data = sock.recv(recv_buffer)
        buffer += data

        # Check if the end message string arrives
        if "!ENDMSG!" in buffer:
            break
   
    # Remove the end message string
    buffer = buffer[:-12]
    return buffer

The socket must connect to the local machine on port 9100. For this example we are going to download four stock symbols: SPY, AAPL, GOOG and AMZN from the start of 2014 to the present.

IQFeed accepts messages in the following format: CMD,SYM,[options]\n. Notice the newline character. This must be added otherwise the message will not work. The provided options are [bars in seconds],[beginning date: CCYYMMDD HHmmSS],[ending date: CCYYMMDD HHmmSS],[empty],[beginning time filter: HHmmSS],[ending time filter: HHmmSS],[old or new: 0 or 1],[empty],[queue data points per second].

We will be using the following example message: "HIT,GOOG,60,20140101 075000,,,093000,160000,1\n". This says to return historical data (HIT) for the GOOG ticker symbol, at a rate of once per 60 seconds (i.e. minutely bars), from 07:50:00 on the 1st January 2014 with no end (i.e. to "yesterday"). The data is filtered to only be present from 09:30:00 until 16:00:00, which is the NYSE market time opening hours, using new data.

The first task is to define the host, port and symbols for download. Each of the four symbols is looped over and the message for historical data is constructed. Then a socket is opened. AF_INET specifies that a tuple of (host, port) should be expected when connecting. SOCK_STREAM states that the socket should be a stream socket.

Once the socket is opened the message is sent and the historical data is buffered, after which the socket is closed. All of the line endings are removed and the data is written to a file called "sym.csv" in the same directory as the Python code, where "sym" is the ticker symbol:

# iqfeed.py

if __name__ == "__main__":
    # Define server host, port and symbols to download
    host = "127.0.0.1"  # Localhost
    port = 9100  # Historical data socket port
    syms = ["SPY", "AAPL", "GOOG", "AMZN"]

    # Download each symbol to disk
    for sym in syms:
        print "Downloading symbol: %s..." % sym

        # Construct the message needed by IQFeed to retrieve data
        message = "HIT,%s,60,20140101 075000,,,093000,160000,1\n" % sym

        # Open a streaming socket to the IQFeed server locally
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.connect((host, port))

        # Send the historical data request
        # message and buffer the data
        sock.sendall(message)
        data = read_historical_data_socket(sock)
        sock.close

        # Remove all the endlines and line-ending
        # comma delimiter from each record
        data = "".join(data.split("\r"))
        data = data.replace(",\n","\n")[:-1]

        # Write the data stream to disk
        f = open("%s.csv" % sym, "w")
        f.write(data)
        f.close()

The format of the data is given by:

[YYYY-MM-DD HH:mm:SS],[OPEN],[LOW],[HIGH],[CLOSE],[VOLUME],[OPEN INTEREST]

A typical set of lines within a file would be as follows:

2012-01-03 09:31:00,30.6400,30.5000,30.6400,30.5100,6128,6128
2012-01-03 09:32:00,30.5600,30.4900,30.4900,30.5600,6528,400
2012-01-03 09:33:00,30.5000,30.5000,30.5000,30.5000,6672,144
2012-01-03 09:34:00,30.3800,30.3400,30.3400,30.3500,8423,1751
2012-01-03 09:35:00,30.5300,30.5300,30.5300,30.5300,8623,200
2012-01-03 09:36:00,30.6400,30.5500,30.5500,30.6400,9423,800
2012-01-03 09:37:00,30.6500,30.6500,30.6500,30.6500,10329,906
2012-01-03 09:38:00,30.6900,30.6600,30.6900,30.6600,12329,2000
2012-01-03 09:39:00,30.7200,30.6400,30.6500,30.7200,13729,1400
2012-01-03 09:40:00,30.7500,30.6900,30.7200,30.7500,17029,3300

The data goes back quite a long way in terms of years of availability. However it can take some time to download once you start considering large quantities of symbols going back five years or more. If you wish to download data types other than equities then take a look at the IQFeed symbol guide. Obviously you will need to be subscribed to the appropriate exchange for the symbol download to work.

Be aware that the intraday data provided by IQFeed is non-adjusted. That is to say it does not account for corporate actions such as dividends or stock splits. You will need to carry out your own corporate action handling.