First of all, thanks for your work and your efforts to get asyncio to work with Pyqt5. I am missing more examples and a tutorial here, and that's probably my main issue. I am currently having trouble combining ib_insync with pyqt5. The former is an async library to connect to the API of Interactive brokers, which can be used without asyncio knowledge by nesting loops and applying a monkey-patch. Nevertheless, when combining with PyQt and my application gets more complex, things start to fall apart, so I'm trying to go to manual async control of ib_insync.
Hence, I wrote a small example script which runs a Pyqt5 application with 2 buttons. One will connect to the brokerage using ib_insync's connectAsync function. My first problem is located right here, as despite having wrote the example based on yours, Python is telling me the following error:
...\Python38-32\lib\site-packages\qasync\__init__.py:275: RuntimeWarning: coroutine 'MainWindow.connect_to_tws' was never awaited
My second problem is that ib_insync also contains blocking calls, such as qualifyContracts, which is to be tested with the second button once connected.
I am aware that this is a very specific appplication that would require you to have ib_insync and a brokerage account with IB, but it would really help me if you could have a look at my code in order to detect what am I doing wrong:
import asyncio
from ib_insync import IB, util, Stock
import functools
from PyQt5 import QtCore, QtGui, QtWidgets, uic
import qasync
from qasync import asyncSlot, asyncClose, QApplication, QThreadExecutor
import sys
import traceback
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
uic.loadUi('mainwindow.ui', self)
self.loop = asyncio.get_event_loop()
# Connect widgets signals
self.connect_button.pressed.connect(self.connect_button_action)
self.refresh_portfolio_button.pressed.connect(self.portfolio_button_action)
async def connect_to_tws(self):
self.ib_client = IB()
self.ib_client.client.setConnectOptions('+PACEAPI')
self.ib_client.client.MaxRequests = 0 # Disables throttling
self.ib_client.connectAsync('127.0.0.1', 7496, clientId=21)
self.connect_button.setEnabled(False)
self.refresh_portfolio_button.setEnabled(True)
@asyncClose
async def closeEvent(self, event):
await self.session.close()
@asyncSlot()
async def connect_button_action(self):
# Connect to IB
with QThreadExecutor(1) as exec:
await self.loop.run_in_executor(exec, self.connect_to_tws)
@asyncSlot()
async def portfolio_button_action(self):
print('button_action_event')
try:
self.portfolio_table.setEnabled(False)
self.portfolio_progress_bar.setVisible(True)
tasks = list()
tasks.append(self.loop.create_task(self.get_portfolio_data()))
self.loop.run_until_complete(asyncio.wait(tasks))
except Exception as e:
traceback.print_tb(e.__traceback__)
print(e)
async def get_portfolio_data(self):
futures = [self.loop.run_in_executor(None, self.blocking_call)]
results = await asyncio.gather(*futures)
return results
def blocking_call(self):
contract = Stock('ADBE', 'SMART', 'USD')
print('Thread: before qualifyContracts call')
self.ib_client.qualifyContracts(contract)
print('Thread: after qualifyContracts call')
return contract
def on_portfolio_update_completed(self):
self.portfolio_table.setEnabled(True) # TODO: data to be loaded to the table. Doesn't matter for the test purpose
self.portfolio_progress_bar.setVisible(False)
print('Finished thread task')
async def main():
def close_future(future, loop):
loop.call_later(10, future.cancel)
future.cancel("Close Application")
loop = asyncio.get_event_loop()
future = asyncio.Future()
window = None
try:
app = QApplication.instance()
app.setStyle('fusion')
if hasattr(app, 'aboutToQuit'):
getattr(app, 'aboutToQuit').connect(functools.partial(close_future, future, loop))
window = MainWindow()
window.show()
except Exception as e:
print(traceback.format_exc())
print(e)
if window is not None and window.ib is not None and window.ib.isConnected():
window.ib.disconnect()
print('Disconnected from IB')
sys.exit(0)
await future
return True
if __name__ == '__main__':
try:
qasync.run(main())
except asyncio.exceptions.CancelledError:
print(e)
sys.exit(0)
First of all, thanks for your work and your efforts to get asyncio to work with Pyqt5. I am missing more examples and a tutorial here, and that's probably my main issue. I am currently having trouble combining ib_insync with pyqt5. The former is an async library to connect to the API of Interactive brokers, which can be used without asyncio knowledge by nesting loops and applying a monkey-patch. Nevertheless, when combining with PyQt and my application gets more complex, things start to fall apart, so I'm trying to go to manual async control of ib_insync.
Hence, I wrote a small example script which runs a Pyqt5 application with 2 buttons. One will connect to the brokerage using ib_insync's connectAsync function. My first problem is located right here, as despite having wrote the example based on yours, Python is telling me the following error:
...\Python38-32\lib\site-packages\qasync\__init__.py:275: RuntimeWarning: coroutine 'MainWindow.connect_to_tws' was never awaited
My second problem is that ib_insync also contains blocking calls, such as qualifyContracts, which is to be tested with the second button once connected.
I am aware that this is a very specific appplication that would require you to have ib_insync and a brokerage account with IB, but it would really help me if you could have a look at my code in order to detect what am I doing wrong:
Thanks in advance