erdewit / ib_insync

Python sync/async framework for Interactive Brokers API
BSD 2-Clause "Simplified" License
2.76k stars 726 forks source link

QtWindow stops responding during IB.run() #282

Closed diogoseca closed 3 years ago

diogoseca commented 3 years ago

First of all, thank you for sharing this repository. It has saved me days of work and stress that would be put to making sense of the original IB Python API documentation and code.

I'm currently attempting and failing to run examples/qt_ticker_table.py The QtWindow completely freezes and stops responding while running the main loop IB.run()

image After about 5 minutes, the following message gets printed (spammed):

QEventDispatcherWin32::wakeUp: Failed to post a message (Not enough quota is available to process this command.)
QEventDispatcherWin32::wakeUp: Failed to post a message (Not enough quota is available to process this command.)
QEventDispatcherWin32::wakeUp: Failed to post a message (Not enough quota is available to process this command.)
QEventDispatcherWin32::wakeUp: Failed to post a message (Not enough quota is available to process this command.)
....
QEventDispatcherWin32::wakeUp: Failed to post a message (Not enough quota is available to process this command.)

I'm running Windows 10. I tried using both PyQt5 and PySide2 (including changing the respective imports and util.useQt('PySide2) to no avail.

Any advice on how to make this work?

noobymcnoob commented 3 years ago

I can't reproduce this. Looks like a setup problem. Try using a virtualenv.

diogoseca commented 3 years ago

@noobymcnoob thanks for testing this. I can't reproduce this on a fresh Linux install either, and it runs with no issues on both Python 3.6 and 3.7.

Perhaps it's an issue with Windows... I will experiment with a fresh windows environment to see if it's the case.

diogoseca commented 3 years ago

Tested the same conda environment, i.e.:

pip=20.1.1
python=3.7.7
ib-insync==0.9.61
numpy==1.19.1
pandas==1.1.0
pyqt5==5.15.0

On Ubuntu it runs with no problem, running smoothly. On Windows, the main window opens up but immediately gets stuck and "stops responding".

diogoseca commented 3 years ago

@noobymcnoob what was your environment or package versions?

erdewit commented 3 years ago

Try to get PyQt from conda instead of via pip.

diogoseca commented 3 years ago

I tried installing it with conda, and the result is the same.

romanrdgz commented 3 years ago

Observing the same problem with Windows 10 and Python 3.8.0

romanrdgz commented 3 years ago

Runs if modified like this, but data is not updated in the table:

if __name__ == '__main__':
    import sys
    app = qt.QApplication(sys.argv)
    app.setStyle('fusion')
    window = Window('127.0.0.1', 7497, 1)
    window.resize(600, 400)
    window.show()
    app.exec_()
erdewit commented 3 years ago

Runs if modified like this, but data is not updated in the table:

The data is not updated as the Qt event loop is running, but the asyncio event loop is not. The trick is to let them run both.

erdewit commented 3 years ago

I could reproduce the issue on Windows 10, Python 3.9 using the ProactorEventloop. A work-around for this specific loop has been added to util.useQt() to fix the issue.

romanrdgz commented 3 years ago

Thanks for the quick fix, Ewald. Could you please publish a new version, so I am able to update the module easily? I have plenty of poetry environments, and patching them all from Git source would be a mess. In fact, I just manually patched one of them (currently at 0.9.62, latest in pip), and the line numbers do not match (line 'stack.append((qloop, timer))' should be line 496, and it is 491 in my file). Thanks again

erdewit commented 3 years ago

This has just been released in v0.9.63.

photoszzt commented 2 years ago

@erdewit I'm using v0.9.70 on Windows with PySide6 (6.2.2.1). I'm still seeing the same problem.

I'm using python 3.7 installed from Windows store.

photoszzt commented 2 years ago

I try with PyQt5 and it works with v0.9.70 using the qt example but PySide6 hangs. With PyQt6, the qt example exits immediatly with the following error: QWidget: Must construct a QApplication before a QWidget

feelgood-interface commented 2 years ago

@photoszzt I have the same issue. Using qasync instead, seems to work.

photoszzt commented 2 years ago

@feelgood-interface I end up using another qthread and move most of computation to another thread like the traditional mvc way. async is too confusing especially when it doesn't work as expected.

NewEpoch2020 commented 1 year ago

WIN10 + PySide6 + Python3.10 + ib_insync 0.9.71 not work. The program gets stuck just after running.

zdytch commented 1 year ago

Same thing with Win10 + PySide6 + Python3.10 + ib_insync 0.9.81

@feelgood-interface could you share a working example of using ib_insync with qasync?

feelgood-interface commented 1 year ago

@zdytch

app = QApplication(sys.argv)
loop = qasync.QEventLoop(app)
asyncio.set_event_loop(loop)

Then I used asyncSlot from qasync.

zdytch commented 1 year ago

@feelgood-interface Yes, this piece of code is from qasync examples. But what I mean is a working example of qasync with ib_insync.

For example, I try to use qasync here: https://github.com/erdewit/ib_insync/blob/master/examples/qt_ticker_table.py

I'm thinking conceptually to replace:

util.patchAsyncio() 
util.useQt()

with:

loop = qasync.QEventLoop(app)
asyncio.set_event_loop(loop)

But I cannot get it working: RuntimeError: Event loop already running

milanster commented 1 year ago

For people still struggling with this, I was too, and felt helpless until I found out the real issue behind it (for my case at least). So I'm hoping this could help some of you with this issue.

In short, I found out that the reason this issue was happening was due to the fact that different parts of my application were trying to access/update the same UI field.

Example: I have a loop that runs async (loops every second) and updates a bunch of fields (positions, their sizes, etc) A specific field is being updated as such self.ui.myfield.setValue(x)

However, when a position size is changed (adding to a position or partialing, etc.) another piece of code detects this change and also tries to modify that same field (perhaps some kinda racing condition?). When that happens, and when two different pieces of code are trying to update the same field, I start getting that "Failed to post ... " message infinite number of times as shown in OP's post

Long story short, make sure you're not trying to "over" update specific UI fields or update them simultaneously from different parts of your code as this was the cause of the crash in my case.

FYI i'm on: Win 10 python 3.8.12 pyqt5 ib-insync==0.9.70 qtinter==0.11.0 (using it instead of qasync)

Good luck!

Henry-E commented 11 months ago

Even just running the default PyQt example on Windows is enough to trigger the error QEventDispatcherWin32::wakeUp: Failed to post a message (Not enough quota is available to process this command.)

Win 11 python 3.11.4 PyQt6 6.5.2 ib-insync 0.9.86

So unfortunately it doesn't seem like getting rid of conflicting calls to the thread would be enough to fix it, as is suggested in the @milanster 's message.

(And of course I modified the original example to use util.useQt('PyQt6'))