Skip to content

Commit e457696

Browse files
committed
Workaroud TWS API bug for bad FOP contract matches
When IBKR started offering "Event Contracts" for some reason the contract matcher started returning Event Contracts _and_ FOP contracts just for FOP requests, which is clearly wrong. Now we do an extra level of checking to _only_ return the input security type requested to prevent cross-instrument contract retrieval. e.g. if you're requesting an NQ call contract, you don't want IBKR to suggest "did you mean Event Contract for NQ closing over 21,000 instead?" Now we just ignore any returned contracts not matching the input security type (if an input security type was provided).
1 parent 2d08c0c commit e457696

File tree

1 file changed

+27
-1
lines changed

1 file changed

+27
-1
lines changed

ib_async/ib.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2133,10 +2133,36 @@ async def qualifyContractsAsync(
21332133
self._logger.warning(f"Unknown contract: {contract}")
21342134
result.append(None)
21352135
elif len(detailsList) > 1:
2136-
possibles = [details.contract for details in detailsList]
2136+
# BUG FIX:
2137+
# - IBKR is returning EC _and_ FOP contracts for only FOP requests,
2138+
# which is clearly incorrect, so now if an input request has `secType`
2139+
# defined, we only return matching `secType` contracts.
2140+
if contract.secType:
2141+
possibles = [
2142+
details.contract
2143+
for details in detailsList
2144+
if contract.secType == details.contract.secType # type: ignore
2145+
]
2146+
2147+
# if our match instrument type filter resolved to only _one_ matching
2148+
# contract, then we found a single usable result to add.
2149+
if len(possibles) == 1:
2150+
c = possibles[0]
2151+
if contract.exchange == "SMART":
2152+
# Allow contracts to become more generic if SMART requested as input
2153+
c.exchange = contract.exchange # type: ignore
2154+
2155+
util.dataclassUpdate(contract, c)
2156+
result.append(contract)
2157+
continue
2158+
else:
2159+
# else, return all matches if no specific secType requested
2160+
possibles = [details.contract for details in detailsList]
2161+
21372162
self._logger.warning(
21382163
f"Ambiguous contract: {contract}, " f"possibles are {possibles}"
21392164
)
2165+
21402166
if returnAll:
21412167
result.append(possibles)
21422168
else:

0 commit comments

Comments
 (0)