March cohort is now open: How to secure your spot:

1.4 million options contracts: Stream it all real-time with ThetaData

1.4 million options contracts: Stream it all real-time with ThetaData. I’ve been trading options contracts for more than 23 years.

I’ve been trading options contracts for more than 23 years.

When I started out, I had to rely on expensive broker data feeds for real-time data for trading and low-quality free data I scraped from websites for analysis.

I spent countless hours reverse engineering the CBOE website for live data, only to have my IP address blocked.

I spent $1,125 on 5 years of historic options data for one symbol (RUT) from iVolatility but that’s only a snapshot (and super expensive).

I even took 20-minute delayed snapshots from Yahoo and treated it as real-time, only to consistently lose money.

Things have improved for people like us, but not by much.

Free data is still delayed, filtered, and low quality.

Real-time streaming data is generally available on broker platforms for trading, but unavailable for analysis.

Until now.

1.4 million active options contracts: Real-time, streaming with ThetaData

The Options Price Reporting Authority (OPRA) is a securities information processor that consolidates options quotes and trade data from major US exchanges.

There are 1.4 million active options contracts trading at any time which generate over 3 terabytes of data each day.

OPRA consolidates and publishes these data in real-time.

Disseminating these data, unfiltered, to non-professionals has been made available through ThetaData, which has a connection to OPRA.

The ThetaData Python API streams quotes and trades in milliseconds because it’s compressed to 1/30th of the actual size.

And the best part? A ThetaData subscription is dirt cheap.

Let’s see how it works.

Imports and set up

Start by importing the ThetaData client classes. (You’ll need Java installed, instructions here.)

from datetime import date

import thetadata.client
from thetadata import (
    Quote,
    StreamMsg,
    ThetaClient,
    OptionRight,
    StreamMsgType
)
from thetadata import StreamResponseType as ResponseType

Then create a few variables you will use to grab the data.

last_call_quote = Quote()
last_put_quote = Quote()
price = 0

Create a callback

A callback is a function that is called as a result of an event. ThetaData uses callbacks to do something in response to a quote or trade.

def callback_straddle(msg):
    
    if (msg.type != StreamMsgType.QUOTE):
        return
    
    global price

    if msg.contract.isCall:
        last_call_quote.copy_from(msg.quote)
    else:
        last_put_quote.copy_from(msg.quote)

    straddle_bid = round(last_call_quote.bid_price + last_put_quote.bid_price, 2)
    straddle_ask = round(last_call_quote.ask_price + last_put_quote.ask_price, 2)
    straddle_mid = round((straddle_bid + straddle_ask) / 2, 2)
    
    time_stamp = thetadata.client.ms_to_time(
        msg.quote.ms_of_day
    )

    if price != straddle_mid:
        print(
            f"time: {time_stamp} bid: {straddle_bid} mid: {straddle_mid} ask: {straddle_ask}"
        )
        price = straddle_mid

In this function, you’ll first make sure the message type is a quote. If it’s not, return and do nothing. Otherwise, set the quotes for the call and put options you use to create your straddle. Then, calculate the bid and ask prices of the straddle and divide by two to get the midpoint. Finally, record the quote timestamp and print the result.

Connect and stream the data

Next, connect to ThetaData’s servers, start the stream for the call an put, and check the subscription status.

def streaming_straddle():

    client = ThetaClient(
        username="",
        passwd=""
    )

    client.connect_stream(
        callback_straddle
    )
    
    req_id_call = client.req_quote_stream_opt(
        "SPY", date(2023, 5, 5), 410, OptionRight.CALL
    )  # Request quote updates
    
    req_id_put = client.req_quote_stream_opt(
        "SPY", date(2023, 5, 5), 410, OptionRight.PUT
    )

    if (
        client.verify(req_id_call) != ResponseType.SUBSCRIBED
        or client.verify(req_id_put) != ResponseType.SUBSCRIBED
    ):
        raise Exception(
            "Unable to stream contract. A standard/PRO subscription required."
        )

This code sets the callback to respond to every quote update for the 5 May 2023 SPY options. You can use any symbol and expiration you want.

To start the stream, just call the function you just created.

streaming_straddle()

You’ll start to see data print to the screen as new quotes are received.

1.4 million options contracts: Stream it all real-time with ThetaData. I’ve been trading options contracts for more than 23 years.

ThetaData’s API provides first, second, and third-order Greeks, implied volatility, volume, open interest, and more.

With ThetaData, you have the same tools the professionals have.