from ib_insync import *
util.startLoop()
ib = IB()
ib.connect('127.0.0.1', 7497, clientId=12)
<IB connected to 127.0.0.1:7497 clientId=12>
Suppose we want to find the options on the SPX, with the following conditions:
To get the current market value, first create a contract for the underlyer (the S&P 500 index):
spx = Index('SPX', 'CBOE')
ib.qualifyContracts(spx)
[Index(conId=416904, symbol='SPX', exchange='CBOE', currency='USD', localSymbol='SPX')]
To avoid issues with market data permissions, we'll use delayed data:
ib.reqMarketDataType(4)
Then get the ticker. Requesting a ticker can take up to 11 seconds.
[ticker] = ib.reqTickers(spx)
ticker
Ticker(contract=Index(conId=416904, symbol='SPX', exchange='CBOE', currency='USD', localSymbol='SPX'), time=datetime.datetime(2019, 12, 31, 16, 58, 32, 252008, tzinfo=datetime.timezone.utc), last=3216.19, lastSize=0, high=3225.1, low=3212.03, close=3221.29, ticks=[TickData(time=datetime.datetime(2019, 12, 31, 16, 58, 32, 252008, tzinfo=datetime.timezone.utc), tickType=4, price=3216.19, size=0), TickData(time=datetime.datetime(2019, 12, 31, 16, 58, 32, 252008, tzinfo=datetime.timezone.utc), tickType=6, price=3225.1, size=0), TickData(time=datetime.datetime(2019, 12, 31, 16, 58, 32, 252008, tzinfo=datetime.timezone.utc), tickType=7, price=3212.03, size=0), TickData(time=datetime.datetime(2019, 12, 31, 16, 58, 32, 252008, tzinfo=datetime.timezone.utc), tickType=9, price=3221.29, size=0)])
Take the current market value of the ticker:
spxValue = ticker.marketPrice()
spxValue
3221.29
The following request fetches a list of option chains:
chains = ib.reqSecDefOptParams(spx.symbol, '', spx.secType, spx.conId)
util.df(chains)
exchange | underlyingConId | tradingClass | multiplier | expirations | strikes | |
---|---|---|---|---|---|---|
0 | SMART | 416904 | SPX | 100 | [20200116, 20200220, 20200319, 20200416, 20200... | [100.0, 200.0, 300.0, 400.0, 500.0, 600.0, 650... |
1 | CBOE | 416904 | SPXW | 100 | [20191231, 20200103, 20200106, 20200108, 20200... | [1000.0, 1100.0, 1150.0, 1200.0, 1225.0, 1250.... |
2 | SMART | 416904 | SPXW | 100 | [20191231, 20200103, 20200106, 20200108, 20200... | [1000.0, 1100.0, 1150.0, 1200.0, 1225.0, 1250.... |
3 | CBOE | 416904 | SPX | 100 | [20200116, 20200220, 20200319, 20200416, 20200... | [100.0, 200.0, 300.0, 400.0, 500.0, 600.0, 650... |
These are four option chains that differ in exchange
and tradingClass
. The latter is 'SPX' for the monthly and 'SPXW' for the weekly options. Note that the weekly expiries are disjoint from the monthly ones, so when interested in the weekly options the monthly options can be added as well.
In this case we're only interested in the monthly options trading on SMART:
chain = next(c for c in chains if c.tradingClass == 'SPX' and c.exchange == 'SMART')
chain
OptionChain(exchange='SMART', underlyingConId='416904', tradingClass='SPX', multiplier='100', expirations=['20200116', '20200220', '20200319', '20200416', '20200514', '20200618', '20200917', '20201015', '20201119', '20201217', '20210114', '20210318', '20210617', '20211216', '20221215'], strikes=[100.0, 200.0, 300.0, 400.0, 500.0, 600.0, 650.0, 700.0, 750.0, 800.0, 850.0, 900.0, 950.0, 1000.0, 1050.0, 1100.0, 1150.0, 1200.0, 1225.0, 1250.0, 1275.0, 1300.0, 1325.0, 1350.0, 1375.0, 1400.0, 1425.0, 1450.0, 1475.0, 1500.0, 1525.0, 1550.0, 1575.0, 1600.0, 1625.0, 1650.0, 1675.0, 1700.0, 1725.0, 1750.0, 1775.0, 1800.0, 1825.0, 1850.0, 1875.0, 1900.0, 1925.0, 1950.0, 1975.0, 2000.0, 2025.0, 2050.0, 2075.0, 2090.0, 2100.0, 2110.0, 2120.0, 2125.0, 2130.0, 2140.0, 2150.0, 2160.0, 2170.0, 2175.0, 2180.0, 2190.0, 2200.0, 2210.0, 2220.0, 2225.0, 2230.0, 2240.0, 2250.0, 2260.0, 2270.0, 2275.0, 2280.0, 2290.0, 2300.0, 2310.0, 2320.0, 2325.0, 2330.0, 2340.0, 2350.0, 2360.0, 2370.0, 2375.0, 2380.0, 2390.0, 2395.0, 2400.0, 2405.0, 2410.0, 2415.0, 2420.0, 2425.0, 2430.0, 2435.0, 2440.0, 2445.0, 2450.0, 2455.0, 2460.0, 2465.0, 2470.0, 2475.0, 2480.0, 2485.0, 2490.0, 2495.0, 2500.0, 2505.0, 2510.0, 2515.0, 2520.0, 2525.0, 2530.0, 2535.0, 2540.0, 2545.0, 2550.0, 2555.0, 2560.0, 2565.0, 2570.0, 2575.0, 2580.0, 2585.0, 2590.0, 2595.0, 2600.0, 2605.0, 2610.0, 2615.0, 2620.0, 2625.0, 2630.0, 2635.0, 2640.0, 2645.0, 2650.0, 2655.0, 2660.0, 2665.0, 2670.0, 2675.0, 2680.0, 2685.0, 2690.0, 2695.0, 2700.0, 2705.0, 2710.0, 2715.0, 2720.0, 2725.0, 2730.0, 2735.0, 2740.0, 2745.0, 2750.0, 2755.0, 2760.0, 2765.0, 2770.0, 2775.0, 2780.0, 2785.0, 2790.0, 2795.0, 2800.0, 2805.0, 2810.0, 2815.0, 2820.0, 2825.0, 2830.0, 2835.0, 2840.0, 2845.0, 2850.0, 2855.0, 2860.0, 2865.0, 2870.0, 2875.0, 2880.0, 2885.0, 2890.0, 2895.0, 2900.0, 2905.0, 2910.0, 2915.0, 2920.0, 2925.0, 2930.0, 2935.0, 2940.0, 2945.0, 2950.0, 2955.0, 2960.0, 2965.0, 2970.0, 2975.0, 2980.0, 2985.0, 2990.0, 2995.0, 3000.0, 3005.0, 3010.0, 3015.0, 3020.0, 3025.0, 3030.0, 3035.0, 3040.0, 3045.0, 3050.0, 3055.0, 3060.0, 3065.0, 3070.0, 3075.0, 3080.0, 3085.0, 3090.0, 3095.0, 3100.0, 3105.0, 3110.0, 3115.0, 3120.0, 3125.0, 3130.0, 3135.0, 3140.0, 3145.0, 3150.0, 3155.0, 3160.0, 3165.0, 3170.0, 3175.0, 3180.0, 3185.0, 3190.0, 3195.0, 3200.0, 3205.0, 3210.0, 3215.0, 3220.0, 3225.0, 3230.0, 3235.0, 3240.0, 3245.0, 3250.0, 3255.0, 3260.0, 3265.0, 3270.0, 3275.0, 3280.0, 3285.0, 3290.0, 3295.0, 3300.0, 3305.0, 3310.0, 3315.0, 3320.0, 3325.0, 3330.0, 3335.0, 3340.0, 3345.0, 3350.0, 3355.0, 3360.0, 3365.0, 3370.0, 3375.0, 3380.0, 3385.0, 3390.0, 3395.0, 3400.0, 3405.0, 3410.0, 3415.0, 3420.0, 3425.0, 3430.0, 3435.0, 3440.0, 3445.0, 3450.0, 3455.0, 3460.0, 3465.0, 3470.0, 3475.0, 3480.0, 3490.0, 3500.0, 3510.0, 3520.0, 3525.0, 3530.0, 3540.0, 3550.0, 3560.0, 3575.0, 3600.0, 3625.0, 3650.0, 3700.0, 3750.0, 3800.0, 3850.0, 3900.0, 3950.0, 4000.0, 4050.0, 4100.0, 4200.0, 4300.0, 4400.0, 4500.0, 4600.0])
What we have here is the full matrix of expirations x strikes. From this we can build all the option contracts that meet our conditions:
strikes = [strike for strike in chain.strikes
if strike % 5 == 0
and spxValue - 20 < strike < spxValue + 20]
expirations = sorted(exp for exp in chain.expirations)[:3]
rights = ['P', 'C']
contracts = [Option('SPX', expiration, strike, right, 'SMART', tradingClass='SPX')
for right in rights
for expiration in expirations
for strike in strikes]
contracts = ib.qualifyContracts(*contracts)
len(contracts)
48
contracts[0]
Option(conId=384688665, symbol='SPX', lastTradeDateOrContractMonth='20200116', strike=3205.0, right='P', multiplier='100', exchange='SMART', currency='USD', localSymbol='SPX 200117P03205000', tradingClass='SPX')
Now to get the market data for all options in one go:
tickers = ib.reqTickers(*contracts)
tickers[0]
Ticker(contract=Option(conId=384688665, symbol='SPX', lastTradeDateOrContractMonth='20200116', strike=3205.0, right='P', multiplier='100', exchange='SMART', currency='USD', localSymbol='SPX 200117P03205000', tradingClass='SPX'), time=datetime.datetime(2019, 12, 31, 16, 58, 41, 258764, tzinfo=datetime.timezone.utc), bid=28.1, bidSize=260, ask=28.5, askSize=75, last=26.2, lastSize=1, volume=17, high=29.15, low=26.2, close=26.65, bidGreeks=OptionComputation(impliedVol=0.12479434613887233, delta=-0.4467205699460659, optPrice=28.100000381469727, pvDividend=3.171605793435112, gamma=0.004541203481480199, vega=2.7584286390644355, theta=-0.9351184483257037, undPrice=3216.19), askGreeks=OptionComputation(impliedVol=0.1273924345982469, delta=-0.44758003325183715, optPrice=28.5, pvDividend=3.171605793435112, gamma=0.004449873325559049, vega=2.759225320523277, theta=-0.956080972911877, undPrice=3216.19), lastGreeks=OptionComputation(impliedVol=0.1121163044425008, delta=-0.441885782487882, optPrice=26.200000762939453, pvDividend=3.171605793435112, gamma=0.005046062232473765, vega=2.7537040141291262, theta=-0.8328175501618498, undPrice=3216.19), modelGreeks=OptionComputation(impliedVol=0.12597515955300287, delta=-0.44711612427890945, optPrice=30.020053965440823, pvDividend=3.171605793435112, gamma=0.004499237656712854, vega=2.7587969178159018, theta=-0.9446458451581966, undPrice=3216.19))
The option greeks are available from the modelGreeks
attribute, and if there is a bid, ask resp. last price available also from bidGreeks
, askGreeks
and lastGreeks
. For streaming ticks the greek values will be kept up to date to the current market situation.
ib.disconnect()