order execution during a fast price move

Hi,

I’ve had some issue recently with a setup similar to this one:

price is $1000
I set 2 open SHORT limit orders, one (A) at $1005 and the other one (B) at $1006

The price suddenly jumps to $1010.

I get a filled notification for B and THEN for A, even though A has been hit before.

Obviously both orders had to be executed but my question is about the order.

I would like to know if the sequence is deterministic, and also understand the logic:

  • Is it random? (if so, it’s obviously a big problem)
  • Is it by submission order? A sent before B or the opposite
  • Is it by order price closer to the instrument’s price? fill the closest first
  • Is it done by price order (A then B) but the notifications are somehow not sent in order?
  • or, anything else?

Also, can you have a situation where B fills, and A, despite being ‘on the way’ gets only a partial fill? or if B fills (partially or not), then there is always enough to fill A?

Hi there,

Taking the assumption the referred notification is the order update event through user data stream, the “payloads are not guaranteed to be in order during heavy periods; make sure to order your updates using E” (https://binance-docs.github.io/apidocs/futures/en/#user-data-streams)

Regarding your 2nd question, if both B and A are with timeInForce = IOC ( Immediate or Cancel), then both A and B can be filled totally or partially. This depends on the order set up and market movement.

Using the E fields doesn’t help: let’s say I get the message that B is filled, at this stage I have no idea if I will receive a message for A since I have a unique message for B. I can’t wait for a while ‘just to see’ if I will get another message and then sort them out.
So, in short, I guess we have to assume that message order is random.

But then, about the second part, that raises the question: is the execution random too?

If the price is higher than both A and B, what is the logic that determines which one gets filled first? There is some data to go by such as the order timestamp, or the order price delta with the last price; and of course, there is also doing it randomly.

But then, if the execution can be random and the reporting of the execution can also be in a random order that’s a little bit clown-ish.

Now the orders in my case are ‘good until cancelled’, so I would expect some kind of logic about how they get filled if the price allows both to get filled. Do we know for sure that this process is random? it doesn’t make sense to end up with 2 partial fills for example.

No. You can check your historical trades and you’d find the tradeID is smaller for the one with lower ask price

1 Like

We ran a test on BNB, let’s take it as an example:

The highlighted orders are the ones that matter.

line 10, the short open order was at 43.012 (OS-AnazVoxpiXA)
line 17, the short open order was at 42.962 (OS-YCOzVqA21X0)
line 24, the short close order was at 42.914 (CS-AnazVoxpiXA)

and the execution order was:

open limit short OS-AnazVoxpiXA -> 27885423744. at 43.012
open limit short OS-YCOzVqA21X0 -> 27885423749 at 42.962
close limit short CS-AnazVoxpiXA -> 27885423791 at 42.914

The order OS-YCOzVqA21X0 was further from the price, and also it was submitted earlier to the exchange, so that’s two reasons it should have been executed earlier than OS-AnazVoxpiXA
The price was at 43.03 for BOTH orders.
Filling OS-YCOzVqA21X0 first would have given an advantage, filling at a higher price than expected.
However, OS-YCOzVqA21X0 was a larger order, does it play a role in the execution order?

So my question is back: what are the execution rules precisely?

Your description and your table are very confusing and full of conflicts
Tell me this way:

place time, filled time, limit price, filled price, trade ID (/fapi/v1/userTrades) of each order

Is “CS-AnazVoxpiXA” cancelled or not?

I wish the Binance CSVs would be exported in execution order. They can’t even be sorted because of the layout :frowning:
I removed the close because it’s not really relevant to the issue.

Here is the info:

orderid type order price fill price open time fill time binance id submission order execution order order sent socket open time socket fill time
OS-YCOzVqA21X0 Open 42.962 43.03 09:07:44 09:07:44 27885423749 1 2 09:07:44.094 09:07:44.155 09:07:44.176
OS-AnazVoxpiXA Open 43.012 43.03 09:07:44 09:07:44 27885423744 2 1 09:07:44.113 09:07:44.175 09:07:44.176

On the right side are the times recorded by our server: when we sent the orders and when the socket message for open and filled arrived.
We can see that the submission order and the execution order are not the same, which leaves these few options:

  • Orders are filled by closest price to the market price
  • Orders are filled by quantity (the second order was larger)
  • Orders are filled by newest first (which would be opposite to what’s typical)
  • Orders are processed randomly
  • Or, some other scenario I didn’t think about
  1. Those two orders were placed with price lower than highest bid so they’re both filled right way
  2. What’s binance id? They’re obviously not the valid trade ids for bnbusdt
  3. Based on the behavior they should be filled almost at the same time. (again they were placed at the same time with price lower than highest bid)
    Don’t see why this is an example to make you suspect of the trading rule
  1. this is not a problem; the price moved while the orders were processed and it’s ok that they’re both executed instantly.
  2. what I called ‘Binance id’ is the column B of the excel, it’s the numerical value that shows the execution order (as opposite to my ClientId)
  3. I’m not ‘suspicious’, but I need to understand fill rules to have some deterministic process.

Currently:

  • We can’t trust the insertion order when submitting several orders at once, so we have to submit them separately if we want them to be filled in order (assuming Binance gives priority to age, like brokers commonly do, but it’s again not documented anywhere).
  • We can’t trust the reporting mechanism with sockets because notifications can arrive out of order when the system is ‘busy’, with ‘busy’ not defined anywhere.
  • We can’t trust the reporting through the rest interface, because not only it’s slow, it’s not accurate in many cases as discussed daily on Telegram (and this is not documented properly as well).
  • We can’t rely on a steady insertion speed because it seems to vary a lot and there is no guarantee there.

So, hopefully, we can trust the order fill system to be deterministic so we can at least rely on one thing.

Here is a bit of background: I’ve been trying for a few month to initiate a move to Binance, porting tech that was built for another platform.
The trades normally have very low price deltas with fairly high volumes, which means speed is pretty much everything.

I understand that Binance doesn’t charge for access and therefore doesn’t offer any guarantees when it comes to things like insertion speed, notification latency, etc which means that everything has to be organized in a semi-blind way to be able to mitigate issues.

Now, here is why this matters to me:

Let’s say I send short open orders A and B, where A’s price is lower than B. The price moves quickly and both orders get filled.

  • If I receive A’s filled notification first, I can assume that A was filled and I don’t know anything about B, so I can set the close order for A. Now I have a close order which is far from the last price (which passed B), and will only have the quantity of A (unless I let the exchange set the quantity for me).
  • If I receive B’s filled notification first, I can assume that both A and B were filled, and I can set the close based on this.

So just by having notifications out of order, there is already an issue, but there are workarounds.
Now, what if we have the same scenario, but there are not filled in the same order:

B gets filled first and then there is not enough volume available to fill A? Now I can’t assume that B being filled means that A got filled. I can’t assume that A will not somehow get filled while I’m sending the close order, so I have to rely on the socket’s messages. But now, I may get a B filled then later an A partially filled notification, OR I may get an A partially filled and later a B filled notification. How I have to react to these is different.

Since we can’t rely on any kind of reporting, I would like to know that I can trust that the fill rules are deterministic, and, for example:

  • When several orders have to be filled, the get filled oldest first, or
  • When several orders have to be filled, the furthest to the price gets filled first, or
  • When several orders have to be filled, the one with the smallest quantity gets filled first

Something, anything really, that is 100% reliable and I can use to base a reaction on because I can’t trust the time of the reporting, nor the contents.

In most cases, it would be irrelevant, but in a case where you do tiny deltas with large quantities, this is essential. Right now I’ve been running tests with tiny amounts and I already see these problems pop up again and again, day after day.

This is why understanding the exact rule about how orders are filled is very important here. It’s not suspicion :smiley:

If A price is lower than B’s and A is placed before B, A will always be filled firstly.
Let me know if you see otherwise by providing orders’ limit price, place time, filled time and trade ID

In practice that’s exactly the opposite that happened. A was placed before B and B was filled before A.
I put the times, prices and IDs in my previous post.

I don’t see anything “exactly the opposite”. A & B were filled right way at the same way. Invalid trade IDs.
Like I said, show some typical example using that format
order Id, limit price, place time, filled time and trade ID

but it is exactly what I posted above (I just called the Trade ID “Binance ID”, so let me rename it):

clientorderid type order price fill price open time fill time trade id submission order execution order order sent socket open time socket fill time
OS-YCOzVqA21X0 Open 42.962 43.03 09:07:44 09:07:44 27885423749 1 2 09:07:44.094 09:07:44.155 09:07:44.176
OS-AnazVoxpiXA Open 43.012 43.03 09:07:44 09:07:44 27885423744 2 1 09:07:44.113 09:07:44.175 09:07:44.176

and the same is shown in the excel screenshot which is taken directly from binance’s web site, I just added the yellow highlighting.

I don’t understand what more info is needed? I have the binance output in the first message and I have the same data extracted from it, with extra info when it comes to time that I posted again in this reply. It has exactly the fields you’re asking, and some more.

  1. “27885423749” and “27885423749” are not valid trades ids (use /fapi/v1/userTrades to get the ‘id’)
  2. This is a bad example. Both orders hit the highest bid were filled right away

ok, I see what you mean now, so not the OrderId but the TradeId. I’ve to find again on which account this was though, so I don’t have it at hand right now, just the excel export, with the ClientOrderId, and the extra data we captured. I’ll check this week.

But this is not a bad example, this is very specifically the example of the situation I want to handle. I think I can narrow it down to a specific question:

If orders A and B will be filled at the same time, which one gets filled first and which one has then a chance to be a partial fill.

And I need to know it because the fill notification may arrive whenever, it’s not precise and may be out of order as well, so I can’t rely on the idea that the first one I receives is the first one that got executed. So if I know the fill rule and I get a notification, in some cases I can infer what happened to the second order before waiting for a notification that may arrive whenever it feels like.

For example, with 2 orders filled simultaneously, if prices are A < B and for this scenario (open short) we have the rule “lower price fills first”: if I get the notification that B was filled, I can automatically infer that A was fully filled and make a close order that will match A and B’s quantities. With orders that are very close, this matters a lot.

So in the end, the question can be reduced to : what is the exact fill rule.
Support told me that when selling it’s lowest price, when buying it’s the higher price. In practice I have recorded that this is not always the case when prices are very close during high volatility, so I’m still looking for a super precise breakdown of how the orders will be processed.

I do not understand the ‘going in circle’ situation with this question:

there is an excel spreadsheet exported from Binance which show all the orders and when they got filled.

I added to that data from the server log that has the time these orders were submitted and when they were reported to be filled to give some context.

With the server log we see which order was submitted first and on the binance excel sheet we see which order got filled first.

And we see that the price moved to fill “at the same time” (= both orders have to be filled now by this last move, this is just semantics) the two orders and the fill order, as reported by binance’s excel sheet, doesn’t match the expectation, nor what the support has described.

I don’t understand how getting the “BinanceId” instead of the “ClientId” would change anything. Or, should we assume that the excel exported by binance is not reliable? because if we assume it is reliable, then all useful data is here, in this thread, and it shows the execution order.

Posted in the wrong position. Let me do it again:

Nothing could be placed at exactly the same time.
Next time:

Share the information from query of /fapi/v1/order
Info from /fapi/v1/userTrades

Nothing could be placed at exactly the same time.
Next time:

  1. Share the information from query of /fapi/v1/order
  2. Info from /fapi/v1/userTrades