I'm having a problem getting options data with IB's API. The data seems not to be correct. In my code I'm getting some 0DTE call options for the Mini SP500 March Futures contract and printing their bid, ask and delta. For this I'm using the ib_sync which simplifies development greatly. This is the code:
from datetime import datetime
from ib_insync import *
import pandas as pd
import math
from datetime import datetime, time
def week_of_month(dt):
""" Returns the week of the month for the specified date.
"""
first_day = dt.replace(day=1)
dom = dt.day
adjusted_dom = dom + first_day.weekday()
return int(math.ceil(adjusted_dom/7.0))
def get_trading_class(dt: datetime):
week = week_of_month(dt)
day = dt.weekday()
res = 'E' + str(week)
if day == 4:
return 'EW' + str(week)
else:
return 'E' + str(week) + chr(60+day)
ib = IB().connect('winhost', 7496, clientId=123, timeout=15)
es = Future('ES', '202303', 'CME')
print(ib.qualifyContracts(es))
ib.reqMarketDataType(1)
[ticker] = ib.reqTickers(es)
# spx current price
spxValue = ticker.marketPrice()
print('es futue value: ', spxValue)
chains = ib.reqSecDefOptParams(es.symbol, 'CME', es.secType, es.conId)
# chainsDf = util.df(chains)
# print(chainsDf.to_string(max_colwidth=10))
# chainsDf = chainsDf[(chains.exchange == 'SMART') & (chains.tradingClass == 'SPXW')]
print('week of the month:', week_of_month(datetime.now()))
trading_cls = get_trading_class(datetime.now())
print('trading class:', trading_cls)
chain = next(c for c in chains if c.tradingClass == trading_cls and c.exchange == 'CME')
expiration = chain.expirations[0]
print('expiration:',expiration)
call_strikes = [strike for strike in chain.strikes
if strike % 5 == 0
and spxValue - 10 < strike < spxValue + 30]
put_strikes = [strike for strike in chain.strikes
if strike % 5 == 0
and spxValue - 30 < strike < spxValue]
rights = ['P', 'C']
contracts = [Option('SPX', expiration, strike, 'C', 'SMART', tradingClass='SPXW') for strike in call_strikes]
contracts = ib.qualifyContracts(*contracts)
tickers = ib.reqTickers(*contracts)
for ticker in tickers:
print('call strike', ticker.contract.strike, 'bid:', ticker.bid, 'ask:', ticker.ask, 'delta:', ticker.lastGreeks.delta)
ib.disconnect()
And this is the output:
[Future(conId=495512572, symbol='ES', lastTradeDateOrContractMonth='20230317', multiplier='50', exchange='CME', currency='USD', localSymbol='ESH3', tradingClass='ES')]
es futue value: 4061.75
week of the month: 3
trading class: EW3
expiration: 20230217
call strike 4055.0 bid: 10.1 ask: 10.3 delta: 0.472330335007325
call strike 4060.0 bid: 7.9 ask: 8.1 delta: 0.3769870767527141
call strike 4065.0 bid: 6.1 ask: 6.3 delta: 0.29022751622672416
call strike 4070.0 bid: 4.6 ask: 4.8 delta: 0.212861073049887
call strike 4075.0 bid: 3.4 ask: 3.6 delta: 0.1491749774504159
call strike 4080.0 bid: 2.55 ask: 2.6 delta: 0.09797399088652259
call strike 4085.0 bid: 1.85 ask: 1.95 delta: 0.06485900831271653
call strike 4090.0 bid: 1.35 ask: 1.4 delta: 0.04255032736417017
I've double checked the price of the contract, and it's correct: 4061.75.
Now, looking at the TWS at the time I make this request, the bid asks and deltas of the options are incorrect. Look at the attached image.
I think I'm getting delayed data, because if the price of the futures contract is 4061.75, the first ITM call option with a delta over 50 should be the 4060, but in my output, the delta for that option is 0.37. Not even the 4055 call is ITM.
So my question is. How is it possible that I'm seeing real time data on the TWS but I'm getting delayed data through the API? Am I missing a Real Time data subscription for the API? In that case, which one?
These are my Market Data Subscriptions:
Thanks
ib_insync
: groups.io/g/insync $\endgroup$