def _get_closest_valid_contract(self, theoretical_strike, expiration, ib, right='P'): """Return valid contract for expiration closest to theoretical_strike""" exchange = self.option_asset.chain.exchange symbol = self.option_asset.underlying_qc.symbol strikes_sorted = sorted(list(self.option_asset.chain.strikes), key=lambda x: abs(x - theoretical_strike)) ii = 0 contract = Option(symbol, expiration, strikes_sorted[ii], right, exchange, tradingClass=self.option_asset.trading_class) qualified_contract = ib.qualifyContracts(contract) while len(qualified_contract) == 0 or ii > 1000: ii = ii + 1 contract = Option(symbol, expiration, strikes_sorted[ii], right, exchange) qualified_contract = ib.qualifyContracts(contract) # Assertion to break when infinite loop exits after after ii > 1000 assert len(qualified_contract) > 0, "No valid contracts found" return qualified_contract
def find_eligible_contracts(self, symbol, right): EXCHANGE = 'SMART' MAX_STRIKE_OFFSET = 5 stock = Stock(symbol, EXCHANGE, currency="USD") self.ib.qualifyContracts(stock) [ticker] = self.ib.reqTickers(stock) ticker_value = ticker.marketPrice() chains = self.ib.reqSecDefOptParams(stock.symbol, "", stock.secType, stock.conId) chain = next(c for c in chains if c.exchange == EXCHANGE) def valid_strike(strike): if strike % 1 == 0: if right == 'C': max_ntm_call_strike = ticker_value + MAX_STRIKE_OFFSET return ticker_value <= strike <= max_ntm_call_strike elif right == 'P': min_ntm_put_strike = ticker_value - MAX_STRIKE_OFFSET return min_ntm_put_strike <= strike <= ticker_value return False strikes = [strike for strike in chain.strikes if valid_strike(strike)] # TODO: Remove slicing once contract selection algorithm implemented exp_offset = self.config["nope"]["expiry_offset"] expirations = sorted(exp for exp in chain.expirations)[exp_offset:exp_offset + 1] contracts = [Option(self.SYMBOL, expiration, strike, right, EXCHANGE, tradingClass=self.SYMBOL) for expiration in expirations for strike in strikes] return contracts
def _createOption(underlying, strike, right, expiration): option = FuturesOption() if _isFuture(underlying) else Option() option.symbol = underlying.symbol option.lastTradeDateOrContractMonth = toTWSDateFromDate(expiration) option.strike = strike option.right = right option.exchange = underlying.exchange return option
def get_closest_valid_twin_contract(qualified_contracts, ib): """ Returns call for put (and vice versa) qualified contract Will return an error if contract not found""" key = lambda x: 'C' if x == 'P' else 'P' contracts = [Option(list_elem[0], list_elem[1], list_elem[2], list_elem[3], list_elem[4]) for list_elem \ in [[contract.symbol, contract.lastTradeDateOrContractMonth, contract.strike, key(contract.right), contract.exchange] for contract in qualified_contracts]] qualified_contract_twins = ib.qualifyContracts(*contracts) return qualified_contract_twins
def fetch_possible_contract(self, right='C'): print('fetch_possible_contract------ 1') print(right, ' ', self.symbol) o = Option(symbol=self.symbol, right=right, exchange=self.exchange) # print('fetch_possible_contract 1: ', self.symbol, ' ', right) o_cd = self.ib_.reqContractDetails(o) # print('fetch_possible_contract 2: ', self.symbol, ' ', right) cs = [j.contract for j in o_cd] print('fetch_possible_contract------ 2') print('Done: ', right, ' ', self.symbol) print('fetch_possible_contract------ 3') return cs
def find_eligible_contracts(self, symbol, right): is_auto_select = self.config["nope"]["contract_auto_select"] EXCHANGE = "SMART" MAX_STRIKE_OFFSET = 6 if is_auto_select else 11 stock = Stock(symbol, EXCHANGE, currency="USD") self.ib.qualifyContracts(stock) [ticker] = self.ib.reqTickers(stock) ticker_value = ticker.marketPrice() chains = self.ib.reqSecDefOptParams(stock.symbol, "", stock.secType, stock.conId) chain = next(c for c in chains if c.exchange == EXCHANGE) def valid_strike(strike): if strike % 1 == 0: if right == "C": max_ntm_call_strike = ticker_value + MAX_STRIKE_OFFSET min_itm_call_strike = (ticker_value - MAX_STRIKE_OFFSET if is_auto_select else ticker_value) return min_itm_call_strike <= strike <= max_ntm_call_strike elif right == "P": min_ntm_put_strike = ticker_value - MAX_STRIKE_OFFSET max_itm_put_strike = (ticker_value + MAX_STRIKE_OFFSET if is_auto_select else ticker_value) return min_ntm_put_strike <= strike <= max_itm_put_strike return False strikes = [strike for strike in chain.strikes if valid_strike(strike)] if is_auto_select: min_dte = self.config["nope"]["auto_min_dte"] expirations = sorted( exp for exp in chain.expirations)[min_dte:min_dte + 5] else: exp_offset = self.config["nope"]["expiry_offset"] expirations = sorted( exp for exp in chain.expirations)[exp_offset:exp_offset + 1] contracts = [ Option( self.SYMBOL, expiration, strike, right, EXCHANGE, tradingClass=self.SYMBOL, ) for expiration in expirations for strike in strikes ] return contracts
def get_opt(ib, df): '''returns the valid options and pickles them Args: (ib) as the active ib object (df) datframe with columns und_contract, expiry, strike Returns: options dataframe''' df = df.reset_index(drop=True) # reset the index und_contract = df.iloc[0].und_contract # get the underlying df_und = snp_und(ib, und_contract) divrate = df_und.divrate.item() # extract the dividend rate # get the ohlc df_ohlc = get_ohlc(ib, und_contract, fspath) # symbol symbol = und_contract.symbol undPrice = df_und.undPrice[0] # build the puts and calls df['right'] = np.where(df.strike < undPrice, 'P', 'C') df['dte'] = [get_dte(e) for e in df.expiry] df_tgt = filter_kxdte(df, df_ohlc) # make the und_contracts und_contracts = [ Option(symbol, expiry, strike, right, exchange) for symbol, expiry, strike, right in zip( df_tgt.symbol, df_tgt.expiry, df_tgt.strike, df_tgt.right) ] qc = [ ib.qualifyContracts(*und_contracts[i:i + blks]) for i in range(0, len(und_contracts), blks) ] qc1 = [q for q1 in qc for q in q1] df_qc = util.df(qc1).iloc[:, [2, 3, 4, 5]] df_qc.columns = ['symbol', 'expiry', 'strike', 'right'] df_opt = df_qc.merge(df_tgt, on=list(df_qc), how='inner') df_opt['option'] = qc1 df_und1 = df_und[['symbol', 'undPrice', 'lot', 'margin']].set_index( 'symbol') # get respective columns from df_und df_opt = df_opt.set_index('symbol').join( df_und1) # join for lot and margin # get the standard deviation based on days to expiry df_opt = df_opt.assign(stdev=[df_ohlc.iloc[i].stdev for i in df_opt.dte]) # get the volatality based on days to expiry df_opt = df_opt.assign( volatility=[df_ohlc.iloc[i].volatility for i in df_opt.dte]) # high52 and low52 for the underlying df_opt = df_opt.assign(hi52=df_ohlc[:252].high.max()) df_opt = df_opt.assign(lo52=df_ohlc[:252].low.min()) df_opt.loc[df_opt.right == 'P', 'hi52'] = np.nan df_opt.loc[df_opt.right == 'C', 'lo52'] = np.nan df_opt.loc[ df_opt.dte <= 1, 'dte'] = 2 # Make the dte as 2 for 1 day-to-expiry to prevent bsm divide-by-zero error # get the black scholes delta, call and put prices bsms = [ get_bsm(undPrice, strike, dte, rate, volatility, divrate) for undPrice, strike, dte, rate, volatility, divrate in zip( repeat(undPrice), df_opt.strike, df_opt.dte, repeat(rate), df_opt.volatility, repeat(divrate)) ] df_bsm = pd.DataFrame(bsms) df_opt = df_opt.reset_index().join(df_bsm) # join with black-scholes df_opt['bsmPrice'] = np.where(df_opt.right == 'P', df_opt.bsmPut, df_opt.bsmCall) df_opt['pop'] = np.where(df_opt.right == 'C', 1 - df_opt.bsmDelta, df_opt.bsmDelta) df_opt = df_opt.drop(['bsmCall', 'bsmPut', 'bsmDelta'], axis=1) # get the option prices cs = list(df_opt.option) tickers = [ib.reqTickers(*cs[i:i + 100]) for i in range(0, len(cs), 100)] df_opt = df_opt.assign( price=[t.marketPrice() for ts in tickers for t in ts]) df_opt = df_opt.assign(rom=df_opt.price / df_opt.margin * tradingdays / df_opt.dte * df_opt.lot) df_opt.to_pickle(fspath + und_contract.symbol + '_opt.pkl') return None
# ..compute 1 stdev and mask chains within fence df_ch = df_ch.assign(sd1=df_ch.undPrice * df_ch.iv * (df_ch.dte / 365).apply(math.sqrt)) fence_mask = (df_ch.strike > df_ch.undPrice + df_ch.sd1 * CALLSTD) | \ (df_ch.strike < df_ch.undPrice - df_ch.sd1 * PUTSTD) df_ch = df_ch[fence_mask].reset_index(drop=True) # ..identify puts and calls df_ch.insert(3, 'right', np.where(df_ch.strike < df_ch.undPrice, 'P', 'C')) # .. make the opts raw contract list opts = [ Option(s, e, k, r, x) for s, e, k, r, x in zip(df_ch.symbol, df_ch.expiry, df_ch.strike, df_ch.right, ['NSE' if MARKET.upper() == 'NSE' else 'SMART'] * len(df_ch)) ] # Qualify the options BLK = 100 optblks = [opts[i:i + BLK] for i in range(0, len(opts), BLK)] blkdict = dict() todo = set() result = set() for optblk in optblks:
def get_option_chain( ib: IB, qualified_contract: Contract, expirations: str, use_delayed_data=False, strike_min=None, strike_max=None, strike_modulus=None, rights=["P", "C"], ) -> pd.DataFrame: """ TODO: Write documentation """ if use_delayed_data: ib.reqMarketDataType(3) [ticker] = ib.reqTickers(qualified_contract) current_price = ticker.marketPrice() strike_min = strike_min or current_price * 0.90 strike_max = strike_max or current_price * 1.10 chains = ib.reqSecDefOptParams(qualified_contract.symbol, '', qualified_contract.secType, qualified_contract.conId) chain = next(c for c in chains if c.tradingClass == qualified_contract.symbol and c.exchange == qualified_contract.exchange) if strike_modulus: strikes = [ strike for strike in chain.strikes if strike_min < strike < strike_max and strike % strike_modulus == 0 ] else: strikes = [ strike for strike in chain.strikes if strike_min < strike < strike_max ] contracts = [ Option(qualified_contract.symbol, expiration, strike, right, qualified_contract.exchange, tradingClass=qualified_contract.symbol) for right in rights for expiration in expirations for strike in strikes ] if use_delayed_data: ib.reqMarketDataType(3) ib.qualifyContracts(*contracts) contracts = [contract for contract in contracts if contract.multiplier] if use_delayed_data: ib.reqMarketDataType(3) tickers = ib.reqTickers(*contracts) d = { "Expiration": [ str(ticker.contract.lastTradeDateOrContractMonth) for ticker in tickers ], "Strike": [ticker.contract.strike for ticker in tickers], "Right": [str(ticker.contract.right) for ticker in tickers], "Ask": [ticker.ask for ticker in tickers], "Multiplier": [int(ticker.contract.multiplier) for ticker in tickers], } return pd.DataFrame(data=d)
def test_position_pnl(): qqq_put = PortfolioItem( contract=Option( conId=397556522, symbol="QQQ", lastTradeDateOrContractMonth="20201218", strike=300.0, right="P", multiplier="100", primaryExchange="AMEX", currency="USD", localSymbol="QQQ 201218P00300000", tradingClass="QQQ", ), position=-1.0, marketPrice=4.1194396, marketValue=-411.94, averageCost=222.4293, unrealizedPNL=-189.51, realizedPNL=0.0, account="DU2962946", ) assert round(position_pnl(qqq_put), 2) == -0.85 spy = PortfolioItem( contract=Stock( conId=756733, symbol="SPY", right="0", primaryExchange="ARCA", currency="USD", localSymbol="SPY", tradingClass="SPY", ), position=100.0, marketPrice=365.4960022, marketValue=36549.6, averageCost=368.42, unrealizedPNL=-292.4, realizedPNL=0.0, account="DU2962946", ) assert round(position_pnl(spy), 4) == -0.0079 spy_call = PortfolioItem( contract=Option( conId=454208258, symbol="SPY", lastTradeDateOrContractMonth="20201214", strike=373.0, right="C", multiplier="100", primaryExchange="AMEX", currency="USD", localSymbol="SPY 201214C00373000", tradingClass="SPY", ), position=-1.0, marketPrice=0.08, marketValue=-8.0, averageCost=96.422, unrealizedPNL=88.42, realizedPNL=0.0, account="DU2962946", ) assert round(position_pnl(spy_call), 2) == 0.92 spy_put = PortfolioItem( contract=Option( conId=458705534, symbol="SPY", lastTradeDateOrContractMonth="20210122", strike=352.5, right="P", multiplier="100", primaryExchange="AMEX", currency="USD", localSymbol="SPY 210122P00352500", tradingClass="SPY", ), position=-1.0, marketPrice=5.96710015, marketValue=-596.71, averageCost=528.9025, unrealizedPNL=-67.81, realizedPNL=0.0, account="DU2962946", ) assert round(position_pnl(spy_put), 2) == -0.13
['symbol', 'dte', 'strike'], ascending=[True, True, True]) df_calls = df_calls.groupby(['symbol', 'dte']).head(nBand) else: df_calls = pd.DataFrame([]) if 'P' in [k for k in gb.indices]: df_puts = gb.get_group('P').reset_index(drop=True).sort_values( ['symbol', 'dte', 'strike'], ascending=[True, True, False]) df_puts = df_puts.groupby(['symbol', 'dte']).head(nBand) else: df_puts = pd.DataFrame([]) dfc = pd.concat([df_puts, df_calls]).reset_index(drop=True) # qualify the options opts = [Option(i.symbol, i.expiry, i.strike, i.right, data[market]['exchange']) for i in dfc[['symbol', 'expiry', 'strike', 'right']].itertuples()] qual_opts = [ib.run(qual_contract(ib, opt)) for opt in opts] qual_opts = [q for q in qual_opts if q] qual_opts = [o for q in qual_opts for o in q] # get the qualified option prices optPrice = {q.conId: ib.run( get_tick(ib, q))[0].marketPrice() for q in qual_opts} # get the margins mgn_ord = Order(action='SELL', orderType='MKT', totalQuantity=1, whatIf=True) optwim = {q.conId: ib.run(get_margin( ib, q, mgn_ord)) for q in qual_opts}
# get SPY option chain symbol = "SPY" stock = Stock(symbol, "SMART", currency="USD") contracts = ib.qualifyContracts(stock) [ticker] = ib.reqTickers(stock) tickerValue = ticker.marketPrice() print(tickerValue) chains = ib.reqSecDefOptParams(stock.symbol, "", stock.secType, stock.conId) chain = next(c for c in chains if c.exchange == "SMART") print(chain) # get call options for all expirations and strikes within range strikes = [ strike for strike in chain.strikes if strike % 5 == 0 and tickerValue - 20 < strike < tickerValue + 20 ] contracts = [ Option(symbol, expiration, strike, "C", "SMART", tradingClass=chain.tradingClass) for expiration in chain.expirations for strike in strikes ] contracts = ib.qualifyContracts(*contracts) tickers = ib.reqTickers(*contracts) print(tickers[0])
def main(symbol): # util.logToConsole(logging.DEBUG) util.logToFile('log.txt') s = symbol.upper() click.echo("Options for {} Loading: ".format(s), nl=False) ib = IB() ib.connect('127.0.0.1', 7497, clientId=3, readonly=True) contract = Stock(s, 'SMART', 'USD') ib.qualifyContracts(contract) click.echo('Chains ', nl=False) chains = ib.reqSecDefOptParams(contract.symbol, '', contract.secType, contract.conId) chain = next(c for c in chains if c.exchange == 'SMART') click.echo('Price '.format(s), nl=False) ib.reqMarketDataType(1) [ticker] = ib.reqTickers(contract) value = ticker.marketPrice() strikes = [ strike for strike in chain.strikes if value * 0.90 < strike < value * 1.0 ] expirations = sorted(exp for exp in chain.expirations)[:2] rights = ['P', 'C'] click.echo("Option Contracts {}@{} ".format(s, value), nl=False) contracts = [ Option(s, expiration, strike, right, 'SMART', tradingClass=s) for right in rights for expiration in expirations for strike in strikes ] click.echo('Validate ', nl=False) contracts = ib.qualifyContracts(*contracts) click.echo(len(contracts), nl=False) ib.reqMarketDataType(4) click.echo(' Ticker') tickers = ib.reqTickers(*contracts) options = [] for t in tickers: # click.echo(t) # calc = ib.calculateOptionPrice( # t.contract, volatility=0.14, underPrice=value) # print(calc) options.append(OptionData(t)) df = util.df(options, [ 'symbol', 'lastTradeDateOrContractMonth', 'strike', 'right', 'marketPrice', 'optionYield', 'timeToExpiration', 'spread', 'bid', 'ask', 'impliedVol', 'delta', 'gamma', 'vega' ]) click.echo(df) currentWeekPut = df[(df['right'] == 'P') & (df['lastTradeDateOrContractMonth'] == expirations[0])] click.echo(currentWeekPut.loc[(abs(abs(currentWeekPut.delta) - 0.2)).sort_values().index].head(2)) ib.disconnect()
) chain = next(c for c in chains if c.tradingClass == "SPY" and c.exchange == "SMART") [ticker] = ib.reqTickers(x) xValue = ticker.marketPrice() strikes = [ strike for strike in chain.strikes if strike % 5 == 0 and xValue - 2 < strike < xValue + 2 ] expirations = sorted(exp for exp in chain.expirations)[:3] rights = ["P", "C"] contracts = [ Option("SPY", expiration, strike, right, "SMART", tradingClass="SPY") for right in rights for expiration in expirations for strike in strikes ] contracts = ib.qualifyContracts(*contracts) # 2) ricevi tickers # 3) calcola hedge basato su greeks start = datetime.datetime(2020, 4, 14, 13, 30).replace(tzinfo=pytz.utc) allticks: List = [] ticks = ib.reqHistoricalTicks( contracts[0], startDateTime=start, endDateTime=None,
class TestIBInstrumentProvider: def setup(self): self.ib = MagicMock() self.loop = asyncio.get_event_loop() self.clock = LiveClock() self.logger = LiveLogger( loop=self.loop, clock=self.clock, level_stdout=LogLevel.DEBUG, ) self.provider = InteractiveBrokersInstrumentProvider( client=self.ib, logger=self.logger, config=InstrumentProviderConfig()) @staticmethod def async_return_value(value: object) -> asyncio.Future: future: asyncio.Future = asyncio.Future() future.set_result(value) return future @pytest.mark.parametrize( "filters, expected", [ ( { "secType": "STK", "symbol": "AMD", "exchange": "SMART", "currency": "USD" }, Stock("AMD", "SMART", "USD"), ), ( { "secType": "STK", "symbol": "INTC", "exchange": "SMART", "primaryExchange": "NASDAQ", "currency": "USD", }, Stock("INTC", "SMART", "USD", primaryExchange="NASDAQ"), ), ( { "secType": "CASH", "symbol": "EUR", "currency": "USD", "exchange": "IDEALPRO" }, Forex(symbol="EUR", currency="USD"), ), # EUR/USD, ({ "secType": "CFD", "symbol": "IBUS30" }, CFD("IBUS30")), ( { "secType": "FUT", "symbol": "ES", "exchange": "GLOBEX", "lastTradeDateOrContractMonth": "20180921", }, Future("ES", "20180921", "GLOBEX"), ), ( { "secType": "OPT", "symbol": "SPY", "exchange": "SMART", "lastTradeDateOrContractMonth": "20170721", "strike": 240, "right": "C", }, Option("SPY", "20170721", 240, "C", "SMART"), ), ( { "secType": "BOND", "secIdType": "ISIN", "secId": "US03076KAA60" }, Bond(secIdType="ISIN", secId="US03076KAA60"), ), ( { "secType": "CRYPTO", "symbol": "BTC", "exchange": "PAXOS", "currency": "USD" }, Crypto("BTC", "PAXOS", "USD"), ), ], ) def test_parse_contract(self, filters, expected): result = self.provider._parse_contract(**filters) fields = [ f.name for f in expected.__dataclass_fields__.values() if getattr(expected, f.name) ] for f in fields: assert getattr(result, f) == getattr(expected, f) @pytest.mark.asyncio async def test_load_equity_contract_instrument(self, mocker): # Arrange instrument_id = InstrumentId.from_str("AAPL.NASDAQ") contract = IBTestStubs.contract(symbol="AAPL") contract_details = IBTestStubs.contract_details("AAPL") mocker.patch.object( self.provider._client, "reqContractDetailsAsync", return_value=self.async_return_value([contract_details]), ) mocker.patch.object( self.provider._client, "qualifyContractsAsync", return_value=self.async_return_value([contract]), ) # Act await self.provider.load(secType="STK", symbol="AAPL", exchange="NASDAQ") equity = self.provider.find(instrument_id) # Assert assert InstrumentId(symbol=Symbol("AAPL"), venue=Venue("NASDAQ")) == equity.id assert equity.asset_class == AssetClass.EQUITY assert equity.asset_type == AssetType.SPOT assert 100 == equity.multiplier assert Price.from_str("0.01") == equity.price_increment assert 2, equity.price_precision @pytest.mark.asyncio async def test_load_futures_contract_instrument(self, mocker): # Arrange instrument_id = InstrumentId.from_str("CLZ2.NYMEX") contract = IBTestStubs.contract(symbol="CLZ2", exchange="NYMEX") contract_details = IBTestStubs.contract_details("CLZ2") mocker.patch.object( self.provider._client, "reqContractDetailsAsync", return_value=self.async_return_value([contract_details]), ) mocker.patch.object( self.provider._client, "qualifyContractsAsync", return_value=self.async_return_value([contract]), ) # Act await self.provider.load(symbol="CLZ2", exchange="NYMEX") future = self.provider.find(instrument_id) # Assert assert future.id == instrument_id assert future.asset_class == AssetClass.INDEX assert future.multiplier == 1000 assert future.price_increment == Price.from_str("0.01") assert future.price_precision == 2 @pytest.mark.asyncio async def test_load_options_contract_instrument(self, mocker): # Arrange instrument_id = InstrumentId.from_str("AAPL211217C00160000.SMART") contract = IBTestStubs.contract(secType="OPT", symbol="AAPL211217C00160000", exchange="NASDAQ") contract_details = IBTestStubs.contract_details("AAPL211217C00160000") mocker.patch.object( self.provider._client, "reqContractDetailsAsync", return_value=self.async_return_value([contract_details]), ) mocker.patch.object( self.provider._client, "qualifyContractsAsync", return_value=self.async_return_value([contract]), ) # Act await self.provider.load(secType="OPT", symbol="AAPL211217C00160000", exchange="SMART") option = self.provider.find(instrument_id) # Assert assert option.id == instrument_id assert option.asset_class == AssetClass.EQUITY assert option.multiplier == 100 assert option.expiry_date == datetime.date(2021, 12, 17) assert option.strike_price == Price.from_str("160.0") assert option.kind == OptionKind.CALL assert option.price_increment == Price.from_str("0.01") assert option.price_precision == 2 @pytest.mark.asyncio async def test_load_forex_contract_instrument(self, mocker): # Arrange instrument_id = InstrumentId.from_str("EUR/USD.IDEALPRO") contract = IBTestStubs.contract(secType="CASH", symbol="EURUSD", exchange="IDEALPRO") contract_details = IBTestStubs.contract_details("EURUSD") mocker.patch.object( self.provider._client, "reqContractDetailsAsync", return_value=self.async_return_value([contract_details]), ) mocker.patch.object( self.provider._client, "qualifyContractsAsync", return_value=self.async_return_value([contract]), ) # Act await self.provider.load(secType="CASH", symbol="EURUSD", exchange="IDEALPRO") fx = self.provider.find(instrument_id) # Assert assert fx.id == instrument_id assert fx.asset_class == AssetClass.FX assert fx.multiplier == 1 assert fx.price_increment == Price.from_str("0.00005") assert fx.price_precision == 5 @pytest.mark.asyncio async def test_contract_id_to_instrument_id(self, mocker): # Arrange contract = IBTestStubs.contract(symbol="CLZ2", exchange="NYMEX") contract_details = IBTestStubs.contract_details("CLZ2") mocker.patch.object( self.provider._client, "qualifyContractsAsync", return_value=self.async_return_value([contract]), ) mocker.patch.object( self.provider._client, "reqContractDetailsAsync", return_value=self.async_return_value([contract_details]), ) # Act await self.provider.load(symbol="CLZ2", exchange="NYMEX") # Assert expected = {138979238: InstrumentId.from_str("CLZ2.NYMEX")} assert self.provider.contract_id_to_instrument_id == expected def test_filters(self): pass