Drop need for `ib_insync.IB.qualifyContractsAsync()' mod
As per https://github.com/erdewit/ib_insync/pull/454 the more correct way to do this is with `.reqContractDetailsAsync()` which we wrap with `Client.con_deats()` and which works just as well. Further drop all the `dict`-ifying that was being done in that method and instead always return `ContractDetails` object in an fqsn-like explicitly keyed `dict`.broker_bumpz
parent
8b1c521ae9
commit
4d23f6e4d7
|
@ -355,28 +355,34 @@ class Client:
|
||||||
# batch request all details
|
# batch request all details
|
||||||
results = await asyncio.gather(*futs)
|
results = await asyncio.gather(*futs)
|
||||||
|
|
||||||
# XXX: if there is more then one entry in the details list
|
# one set per future result
|
||||||
details = {}
|
details = {}
|
||||||
for details_set in results:
|
for details_set in results:
|
||||||
|
|
||||||
|
# XXX: if there is more then one entry in the details list
|
||||||
# then the contract is so called "ambiguous".
|
# then the contract is so called "ambiguous".
|
||||||
for d in details_set:
|
for d in details_set:
|
||||||
con = d.contract
|
con = d.contract
|
||||||
unique_sym = f'{con.symbol}.{con.primaryExchange}'
|
|
||||||
|
|
||||||
as_dict = asdict(d)
|
key = '.'.join([
|
||||||
|
con.symbol,
|
||||||
|
con.primaryExchange or con.exchange,
|
||||||
|
])
|
||||||
|
expiry = con.lastTradeDateOrContractMonth
|
||||||
|
if expiry:
|
||||||
|
key += f'.{expiry}'
|
||||||
|
|
||||||
# nested dataclass we probably don't need and that
|
# nested dataclass we probably don't need and that
|
||||||
# won't IPC serialize
|
# won't IPC serialize..
|
||||||
as_dict.pop('secIdList')
|
d.secIdList = ''
|
||||||
|
|
||||||
details[unique_sym] = as_dict
|
details[key] = d
|
||||||
|
|
||||||
return details
|
return details
|
||||||
|
|
||||||
async def search_stocks(
|
async def search_stocks(
|
||||||
self,
|
self,
|
||||||
pattern: str,
|
pattern: str,
|
||||||
get_details: bool = False,
|
|
||||||
upto: int = 3, # how many contracts to search "up to"
|
upto: int = 3, # how many contracts to search "up to"
|
||||||
|
|
||||||
) -> dict[str, ContractDetails]:
|
) -> dict[str, ContractDetails]:
|
||||||
|
@ -388,31 +394,13 @@ class Client:
|
||||||
'''
|
'''
|
||||||
descriptions = await self.ib.reqMatchingSymbolsAsync(pattern)
|
descriptions = await self.ib.reqMatchingSymbolsAsync(pattern)
|
||||||
|
|
||||||
if descriptions is not None:
|
if descriptions is None:
|
||||||
descrs = descriptions[:upto]
|
|
||||||
|
|
||||||
if get_details:
|
|
||||||
deats = await self.con_deats([d.contract for d in descrs])
|
|
||||||
return deats
|
|
||||||
|
|
||||||
else:
|
|
||||||
results = {}
|
|
||||||
for d in descrs:
|
|
||||||
con = d.contract
|
|
||||||
# sometimes there's a weird extra suffix returned
|
|
||||||
# from search?
|
|
||||||
exch = con.primaryExchange.rsplit('.')[0]
|
|
||||||
unique_sym = f'{con.symbol}.{exch}'
|
|
||||||
expiry = con.lastTradeDateOrContractMonth
|
|
||||||
if expiry:
|
|
||||||
unique_sym += f'{expiry}'
|
|
||||||
|
|
||||||
results[unique_sym] = {}
|
|
||||||
|
|
||||||
return results
|
|
||||||
else:
|
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
# limit
|
||||||
|
descrs = descriptions[:upto]
|
||||||
|
return await self.con_deats([d.contract for d in descrs])
|
||||||
|
|
||||||
async def search_symbols(
|
async def search_symbols(
|
||||||
self,
|
self,
|
||||||
pattern: str,
|
pattern: str,
|
||||||
|
@ -427,36 +415,30 @@ class Client:
|
||||||
results = await self.search_stocks(
|
results = await self.search_stocks(
|
||||||
pattern,
|
pattern,
|
||||||
upto=upto,
|
upto=upto,
|
||||||
get_details=True,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
for key, contracts in results.copy().items():
|
for key, deats in results.copy().items():
|
||||||
tract = contracts['contract']
|
|
||||||
sym = tract['symbol']
|
tract = deats.contract
|
||||||
|
sym = tract.symbol
|
||||||
|
sectype = tract.secType
|
||||||
|
|
||||||
sectype = tract['secType']
|
|
||||||
if sectype == 'IND':
|
if sectype == 'IND':
|
||||||
results[f'{sym}.IND'] = tract
|
results[f'{sym}.IND'] = tract
|
||||||
results.pop(key)
|
results.pop(key)
|
||||||
exch = tract['exchange']
|
exch = tract.exchange
|
||||||
|
|
||||||
if exch in _futes_venues:
|
if exch in _futes_venues:
|
||||||
# try get all possible contracts for symbol as per,
|
# try get all possible contracts for symbol as per,
|
||||||
# https://interactivebrokers.github.io/tws-api/basic_contracts.html#fut
|
# https://interactivebrokers.github.io/tws-api/basic_contracts.html#fut
|
||||||
con = Contract(
|
con = ibis.Future(
|
||||||
'FUT+CONTFUT',
|
|
||||||
symbol=sym,
|
symbol=sym,
|
||||||
exchange=exch,
|
exchange=exch,
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
possibles = await self.ib.qualifyContractsAsync(con)
|
all_deats = await self.con_deats([con])
|
||||||
for i, condict in enumerate(sorted(
|
results |= all_deats
|
||||||
map(asdict, possibles),
|
|
||||||
# sort by expiry
|
|
||||||
key=lambda con: con['lastTradeDateOrContractMonth'],
|
|
||||||
)):
|
|
||||||
expiry = condict['lastTradeDateOrContractMonth']
|
|
||||||
results[f'{sym}.{exch}.{expiry}'] = condict
|
|
||||||
except RequestError as err:
|
except RequestError as err:
|
||||||
log.warning(err.message)
|
log.warning(err.message)
|
||||||
|
|
||||||
|
@ -600,6 +582,12 @@ class Client:
|
||||||
raise ValueError(f"No contract could be found {con}")
|
raise ValueError(f"No contract could be found {con}")
|
||||||
|
|
||||||
self._contracts[pattern] = contract
|
self._contracts[pattern] = contract
|
||||||
|
|
||||||
|
# add an aditional entry with expiry suffix if available
|
||||||
|
conexp = contract.lastTradeDateOrContractMonth
|
||||||
|
if conexp:
|
||||||
|
self._contracts[pattern + f'.{conexp}'] = contract
|
||||||
|
|
||||||
return contract
|
return contract
|
||||||
|
|
||||||
async def get_head_time(
|
async def get_head_time(
|
||||||
|
@ -1640,7 +1628,7 @@ async def backfill_bars(
|
||||||
|
|
||||||
out, fails = await get_bars(proxy, fqsn, end_dt=first_dt)
|
out, fails = await get_bars(proxy, fqsn, end_dt=first_dt)
|
||||||
|
|
||||||
if out == None:
|
if out is None:
|
||||||
# could be trying to retreive bars over weekend
|
# could be trying to retreive bars over weekend
|
||||||
# TODO: add logic here to handle tradable hours and
|
# TODO: add logic here to handle tradable hours and
|
||||||
# only grab valid bars in the range
|
# only grab valid bars in the range
|
||||||
|
|
Loading…
Reference in New Issue