Open disaster123 opened 2 weeks ago
Hi @disaster123 ,
I do not see any obvious problems with the script you shared and my experience says it should work fine. A few steps you could use to debug are
errorEvent
and connect it to your local function that can be used to print the errors/messages from IBKR. This might show details of what might be going wrong in the order.Would be helpful if you can share more relevant code and even more detailed logs.
Happy to help.
Thx. 1.) implemented and will see what happens. 2.) not possible - exact same trade - gets executed fine just seconds before
I would suggest to use events rather than a blocking loop right after placing your orders.
the reason you need to sleep(0)
is to trigger the event loop, but AFAIK there is no warranty that it will pick up what you want. by using an even you are notified when it happens. what you are doing now is blocking and not allowing the event loop to run
Something like this should work
def on_fill(trade,fill):
orderok = True
print("IBKR: orderstatus.status: %s" % (trade.orderStatus.status))
orderok = False
trade = Ibkr2.myib.placeOrder(contract, order)
trade.fillEvent.connect(on_fill)
notice that the ordering notebook is using
trade = ib.placeOrder(contract, order)
while not trade.isDone():
ib.waitOnUpdate()
which does not block the event loop
Always follow The One Rule
@gnzsnz thanks for your suggestions and help. Some questions.
trade = Ibkr2.myib.placeOrder(contract, order) trade.fillEvent.connect(on_fill)
isn't a race possible in this case? - so the order is filled before the event is attached? Also Submitted is OK to me as well.
I had waitOnUpdate used in the past but there were problems with it - for example that if there i no event the loop neber proceed. For example trade goes to Submitted and than nothing happens - your loop blocks.
A couple things can happen:
I've seen orders go directly from PreSubmitted
to Filled
with nothing else in the middle.
You can subscribe to also just trade.statusEvent
and receive all status updates (including Submitted/Modified/Cancelled/Filled).
There is currently a bug where if you submit an order modification which is rejected (update has a bad price or rejected algo settings), the trade gets deleted from your client and won't show up until a restart even though it's still live (ValidationError
status updates). This has a fix coming eventually.
After you place your trade, the trade status and event handlers can't run again until you wait with a proper sleep or another await
entry point. So it's fine to run trade = placeOrder(); trade.statusEvent += eventHandler
because only your code is running between those two statements and no other updates can happen.
Also, it all depends on your own system design and program logic. You should also subscribe your entire ib client to status and error events (also documented at the usual place. If your trade fails to work the first time, it won't exist for any status updates. You probably want ib = IB(); ib.orderStatusEvent += globalOrderStatusEventHandler
to receive updates for any order changes.
None of this is simple or easy to get right without a lot of testing in various live situations, so just keep trying on maybe a test/sandbox account or low value trades until it starts working as expected.
it's possible that the order is filled before, but I have never seen it to actually happen. on my code i use transmit=False, then i attach the event, then submit again with transmit=True, but because my trade logic depends on this and i want to be 300% sure. But i never use it on my "quick tests" because it just never happens.
not sure what could be your problem with waitOnUpdate, personally I never use it. take into account that if you code is blocking, is possible that you are blocking waitOnUpdate as well, that's why i suggested The One Rule.
the original name of this project was great, because it's "insync". from the surface it looks synchronous, but it's just an appearance.
i attach the event, then submit again with transmit=True,
That's actually an interesting use case. Maybe we could allow the order API to also take an empty Trade
object it populates itself, so you could set event handlers on a Trade
object before the trade is submitted. You can also always listen to the global ib.*
events instead of per-task events too if per-task events can't be caught directly.
Given the way the event loop works, between placeOrder()
and the trade value being returned, nothing else happens, so it's impossible for events to trigger between those two cases (unless you yield to another await
in the middle).
Another issue with the event system is it doesn't queue events. Events are either fired against active listeners or dropped forever. We may want to eventually explore allowing certain events to "queue up" until consumed by an event handler (I currently get around this by having my event handlers set their own asyncio.Event()
update signals the event loop can wait on too, and this also allows me to pre-filter event notifications like when an update triggers Submitted->Submitted and I don't care to check the status because nothing about the execution changed).
we could add a parameter
async def trade_fill_event_handler():
your code here
trade = ib.placeOrder(contract,oder,fillEvent=trade_fill_event_handler)
but to be honest, they way it is right now is fine with me.
Hello,
i'm using the following code to place an order:
While the output is:
This order does not show up in ibkr client and was never executed nor is it in pending orders. This happens frequently...
Greets,