######################################################################### # Not currently using this as the call to reqTickers takes > 10 seconds # ######################################################################### import datetime import pandas as pd from ib_insync import * from ibkr.exchange import SMART ib = IB() ib.connect('127.0.0.1', 7497, clientId=1) # Assuming TWS is running on the current machine. underlying = Index('SPX', 'CBOE') ib.qualifyContracts(underlying) underlying_ticker = ib.reqTickers(underlying)[0] atm = underlying_ticker.last print('Last Price:', atm) chains = ib.reqSecDefOptParams(underlying.symbol, '', underlying.secType, underlying.conId) chain = next(c for c in chains if c.tradingClass == 'SPXW' and c.exchange == SMART) today = datetime.datetime.now().strftime('%Y%m%d') expirations = [exp for exp in chain.expirations if exp == today] max_strike_distance = 100 call_strikes = sorted(strike for strike in chain.strikes if strike <= (atm + max_strike_distance) and strike >= atm) put_strikes = sorted(strike for strike in chain.strikes if strike <= atm and strike >= (atm - max_strike_distance)) put_contracts = [Option('SPX', expiration, strike, 'P', SMART) for expiration in expirations for strike in put_strikes] call_contracts = [Option('SPX', expiration, strike, 'C', SMART) for expiration in expirations for strike in call_strikes] contracts = put_contracts + call_contracts qualified_contracts = ib.qualifyContracts(*contracts) # Requesting market data (e.g., current bid / ask) for each contract. # This is what takes a long time. tickers = ib.reqTickers(*qualified_contracts) data = [] for ticker in tickers: symbol = ticker.contract.localSymbol strike = ticker.contract.strike right = 'CALL' if ticker.contract.right == 'C' else 'PUT' # TODO: Bid and Ask. price = iv = delta = gamma = vega = theta = underlying_price = None # TODO: The model greeks are not always available, wait for them. if ticker.modelGreeks is not None: price = ticker.modelGreeks.optPrice iv = ticker.modelGreeks.impliedVol delta = ticker.modelGreeks.delta gamma = ticker.modelGreeks.gamma vega = ticker.modelGreeks.vega theta = ticker.modelGreeks.theta underlying_price = ticker.modelGreeks.undPrice data.append([symbol, strike, right, price, iv, delta, gamma, vega, theta, underlying_price]) option_chain = pd.DataFrame(data, columns=['Symbol', 'Strike', 'Type', 'Price', 'IV', 'Delta', 'Gamma', 'Vega', 'Theta', 'Underlying Price']) print('Option Chain:') print(option_chain) target_delta = 0.10 # Separate calls and puts. calls = option_chain[option_chain['Type'] == 'CALL'].copy() puts = option_chain[option_chain['Type'] == 'PUT'].copy() # Find the difference between the target delta and actual delta for calls and puts. calls['Delta Delta'] = abs(calls['Delta'] - target_delta) puts['Delta Delta'] = abs(puts['Delta'] + target_delta) # Find the row where this difference is minimized for calls. closest_call_strike = calls.loc[calls['Delta Delta'].idxmin()] # Find the row where this difference is minimized for puts. closest_put_strike = puts.loc[puts['Delta Delta'].idxmin()] # Determine the target strikes. target_long_call_strike = closest_call_strike['Strike'] + 50 target_long_put_strike = closest_put_strike['Strike'] - 50 def find_closest_strike(target_strike, option_type, option_chain): options = option_chain[option_chain['Type'] == option_type].copy() options['Strike Distance'] = abs(options['Strike'] - target_strike) nearest_strike = options.loc[options['Strike Distance'].idxmin()] return nearest_strike # Find the closest call and put strikes to the desired targets closest_long_call_strike = find_closest_strike(target_long_call_strike, 'CALL', option_chain) closest_long_put_strike = find_closest_strike(target_long_put_strike, 'PUT', option_chain) # For entering an iron condor. print('Short Call Strike:', closest_call_strike['Strike']) print('Long Call Strike:', closest_long_call_strike['Strike']) print("Short Put Strike:", closest_put_strike['Strike']) print('Long Put Strike:', closest_long_put_strike['Strike']) ib.disconnect()