AuthorJing Wu2018-06-02

Introduction

QuantConnect provides US options trade and quotes price data for approximately 4000 symbols, each of which has roughly 10 strikes on average. Data is available starting January 1st, 2008. In this tutorial, we will discuss how to use QuantConnect to start your options trading algorithm.

Add Options

Before trading options, you need to add options for a given underlying equity and set the resolution in step Initialize with AddOption method. The commonly used parameters will be explained in the method table. Please refer to the link below for details of each method.

Method Parameters
AddOption(underlying, resolution, fillDataForward) underlying(string): The underlying equity symbol resolution: Tick, Second, Minute, Hour, or Daily. Default is minute fillDataForward(bool): If true, returns the last available data even if none in that time slice. The default value is true.
def Initialize(self):
    self.SetStartDate(2017, 1, 1)   # Set Start Date
    self.SetEndDate(2017, 6, 30)    # Set End Date
    self.SetCash(50000)             # Set Strategy Cash
    equity = self.AddEquity("GOOG") # Add the underlying stock: Google
    option = self.AddOption("GOOG") # Add the option corresponding to underlying stock
    self.symbol = option.Symbol

The return value of AddOption method is an option security object, please refer to the link for detailed properties and methods of option class.

Filter Contracts

After adding the options for specific underlying stock, you can set the filter criteria with SetFilter method to pull contracts using the specified min and max strike and expiration range values you need for a given symbol.

Method Parameters
SetFilter(minStrike,maxStrike,minExpiry,maxExpiry) minStrike, maxStrike: The minimum and maximum strike rank relative to market price min Expiry, max Expiry: The range of time to expiration to include, for example, 10 would exclude contracts expiring in less than 10 days

Here parameters minStrike and maxStrike are the relative multipliers with respect to the market price. We use Google(NASDAQ: GOOG) as an example to describe the filter criteria. If today is 01/03/2017, the market price of underlying stock is $776, the strike prices of GOOG options are spaced $2.5. Then SetFilter(-1, +2, 0, 90) will first look up at the money contracts with strike being K=$777.5 (Here K is 777.5 the next closest multiple to the underlying price of 775 since rarely will an option be ATM exactly). Then SetFilter will look for options with strikes between and including (777.5 - 2.5 * 1, 777.5 + 2.5 * 2). The time to expiration of these options are restricted within 90 days from now on. 

For the strike, the exchange normally chooses the strike prices at which options can be written so that they are spaced $2.50, $5, or $10 apart. Typically the spacing is $2.50 when the stock price is between $5 and $25, $5 when the stock price is between $25 and $200, and $10 for stock prices above $200. So you should carefully choose the parameters of minStrike and maxStrike in case there are no contracts that satisfy the filter criteria if the range is too small, less than the minimum units of strike prices change.

For the expiry, there are many expiration dates that apply to the different series of options. An option cycle is the pattern of months in which options contracts expire. There are three kinds of common option cycles. The options on the January cycle have contracts available in the first month of each quarter (January, April, July and October). Options assigned to the February cycle use the middle month of each quarter (February, May, August and November). And options in the March cycle have options available during the last month of each quarter (March, June, September and December). In addition, individual stock options typically expire in the current month and the subsequent month.

# filter the contracts with strikes between (market price - 10, market price + 10)
option.SetFilter(-10,10)
# filter the contracts which expires more than 30 days but no longer than 60 days
option.SetFilter(timedelta(30), timedelta(60))
# filter the contracts with strikes between(ATM Strike - 10 * strike space value, market price + 10 * strike space value) and with expiration days less than 180 days
option.SetFilter(-10, +10, 0, 180)

Select Contracts

For QuantConnect API, Slice class provides a data structure for all of an algorithm's data at a single time step. So you need use property Slice.OptionChains to request options data for this slice.

OptionChains is a collection of  OptionChain keyed by the option's underlying symbol. The elements in Slice.OptionChains have properties Key(the underlying symbol object) Value(the option chain).

OptionChain represents an entire chain of option contracts for a single underlying security. In other words, It is a list of option contracts.

OptionContract defines a single option contract at a specific expiration and strike price. For any contract x in option chain, you can use the following statements to check different options properties.

Properties of Option Contract Description
x.Symbol.Value String representation of option contract's symbol
x.AskPrice, x.BidPrice Ask and bid prices
x.Expiry Expiration date
x.Strike Strike price
x.ImpliedVolatility Implied volatility
x.Greeks Greeks letter
x.Right Right being purchased x.Right = OptionRight.Call (0) [right to buy] x.Right = OptionRight.Put (1) [right to sell]
x.UnderlyingLastPrice Last price the underlying security traded at
x.UnderlyingSymbol Underlying security's symbol

We can print out the details of the contract after filtering with Python data frame to show these properties. Assume today is 01/03/2017. The stock price at 01/03/2017 09:31:00 is $776.01 per share. Here we use SetFilter(-1, +1, 0, 60) to filter the contracts.

def OnData(self, slice: Slice) -> None:
    chain = slice.OptionChains.get(self.symbol)
    if chain:
        self.Log(f"underlying price: {chain.Underlying.Price}")
        df = pd.DataFrame([[x.Right,x.Strike,x.Expiry,x.BidPrice,x.AskPrice] for x in chain],
                           index=[x.Symbol.Value for x in chain],
                           columns=['type(call 0, put 1)', 'strike', 'expiry', 'ask price', 'bid price'])
        self.Log(str(df))
Symbol type(call 0, put 1) Strike Expiry Ask Price Bid Price
GOOG 170217C00780000 0 780.0 2017-02-17 26.4 27.9
GOOG 170120P00782500 1 782.5 2017-01-20 14.7 16.3
GOOG 170120C00782500 0 782.5 2017-01-20 9.4 10.2
GOOG 170120P00780000 1 780.0 2017-01-20 13.4 15.0
GOOG 170120C00780000 0 780.0 2017-01-20 10.6 11.5
GOOG 170217P00780000 1 780.0 2017-02-17 28.9 30.8
GOOG 170120P00777500 1 777.5 2017-01-20 12.2 13.7
GOOG 170120C00777500 0 777.5 2017-01-20 11.8 12.9

Here we give an example of how to find ATM, ITM OTM contracts for trading. First, we need to extract the OptionChain from OptionChains according to symbols we added in Initialize step. Secondly, we extract ATM, ITM and OTM contracts by using UnderlyingLastPrice and Strike properties. Note here the strikes of ATM options are not exactly the same as the market price of underlying stocks, thus here we first sort the contracts by the absolute values of the difference between the UnderlyingLastPrice and the Strike. Then we choose the contract with the minimum absolute value as the ATM contract.

chain = slice.OptionChains.get(self.symbol)
if chain:
    # differentiate the call and put options
    call = [x for x in chain if x.Right == OptionRight.Call]
    put = [x for x in chain if x.Right == OptionRight.Put]
    # choose ITM call contracts
    contracts = [x for x in call if x.UnderlyingLastPrice - x.Strike > 0]
    # or choose ATM contracts
    contracts = sorted(chain, key = lambda x: abs(x.UnderlyingLastPrice - x.Strike))[0]
    # or choose OTM call contracts
    contracts = [x for x in call if x.UnderlyingLastPrice - x.Strike < 0]
    # sort the contracts by their expiration dates
    contracts = sorted(contracts, key = lambda x: x.Expiry, reverse = True)

Finally, we trade the options by using the contract's symbol.

if len(contracts) == 0: continue
# trade the contracts with the farthest expiration
symbol = contracts[0].Symbol
self.MarketOrder(symbol, 1)
self.MarketOnCloseOrder(symbol, -1)

Summary

After mastering the basic knowledge of options market, this tutorial we take a close at how to use Quantconnect to customize your own options trading. For example, how you can access an option chain, how to view the details of the contract as a Python data frame, and the most important how to trade the specific option contract.

Next chapter we will examine some important topics of options like the payoff, Put-Call parity, and the synthetic positions. By learning all those concepts, we will start some brief hedging strategies involving options.

Algorithm

This simple example demonstrates how you can inspect the option chain to pick a specific option contract to trade.




Previous: General Features of Options Next: Put-Call Parity and Arbitrage Strategies