Order filled but expired according to the socket messages

Using the futures API, I have a situation where an order gets filled and the socket message says it is expired.

Here is the sequence of events:

at ETH price at 474.83

Submitted LONG orders:

  • OPEN Take Profit Limit 474.68, Trigger lastPrice <= 474.69
  • CLOSE Stop Loss Limit 475.08, Trigger lastPrice <= 474.67

Exchange took the orders at 2020-11-19 21:45:51

At price 474.65, I received socket updates:

  • CLOSE order expired
  • OPEN order expired

The exchange shows the OPEN order as filled and the CLOSE as expired.
The socket sends me an expired message for both orders.

and here are the same orders on the web site:

what could cause that issue?

We discussed in TG group already and I quoted here:

As per your screenshot, your TP trigger price is 474.69, right after the price hit that(at this moment, TP expired and tried to place a limit order), it dropped fast enough to hit the SL price which is 474.67; So the SL order expired and at the same time tried to place a close order and found nothing to close (The TP order is still busy placing its limit order to get that 0.001 filled)
All because they almost happened at the same time

I do understand, however this means that stop orders are fundamentally unreliable.

In the old days of markets being computerized there was the same issue where brokers would handle the stops and then submit a new order once the stop was triggered. It made them completely unfit for a lot of strategies. This was a long time ago.
Now we have the ability to have the stop trigger + new order done in a single step, and that’s even done by brokers which are external to the market.

Since Binance IS the market we’re trading on, there is no reason why the process of handling the stop and placing the order wouldn’t happen at the same execution time (and therefore the same price) besides maybe the technological convenience of separating the processes.

I think this behavior should be well documented in the stop’s documentation. Not in some blog page, etc but in the API section, along with the reasons why orders can be expired, which is only vaguely explained on Reddit, but this should be in the main documentation.

That means that stop orders on Binance are completely unfit for large quantities as, all things equal, they can incur significantly more slippage than on platforms that handle the process in on step. This should be documented properly so people can make decisions based on how the process works. Right now they have to go with assumptions and guesses.

Let’s clarify your needs firstly. What you want are as below:

  1. Place a TP order that a trigger price TP_1, once the market price hits that, place a limit order with Price_1 to open a position
  2. In the mean time, place another SL order that has a trigger price TP_2 (very close to TP_1), place another order to close the position that’s filled from #1

Logically, you cannot make sure #2 can work as you cannot assure #1 can open an order successfully before #2 can be triggered and take actions

What’s logical should be like below:

  1. Place a TP order that a trigger price TP_1, once the market price hits that, place a limit order with Price_1 to open a position
  2. Wait for the order from #1 to be filled by listening to WS, then place an order to close the position filled from #1

Or:
2. (No wait) place an SL order that would place an order to open another position on the opposite direction with the same quantity as #1; This way you want have to worry about no position to be closed and can still hedge your risk (if that’s what your purpose is)

The first scenario is the right idea.

The reason I tried to implement it like this is specifically because the API is way too slow to place orders in reaction to a WS message if the prices are too close. If Binance offered co-location like Forex brokers where you can complain things are too slow it if takes 1ms roundtrip, it would be an option, but right now by the time you’re getting a WS message and send the REST resquest (even while keeping the rest connection alive so a socket doesn’t have to be allocated), it’s too slow to react on tiny price changes.

Keep in mind that I’m porting code that runs on another platform, so the model is valid. I’m actually pretty much on my own trying to prove that extending to Binance would make sense. So I need to find a way to pre-submit the open and close with very tight prices because relying on the a server roundtrip with the current performance is a non starter.

“you cannot assure #1 can open an order successfully before #2 can be triggered and take actions” this is specifically where the problem is. In the mid 90s, you had brokers that were handling stop orders and then passing an order on the market, on your behalf. To some extent, that practice still exists on some markets, but since Binance is the exchange itself and there is no 3rd party involved, I don’t understand why the process is separated into two steps that can’t be guaranteed to work in the execution step.

The issue here is that if the execution of the stop triggers another process which doesn’t have a guarantee in execution time, and where the exchange doesn’t really support many features on the orders themselves (like contingent / chained orders, OCOs, etc), the mechanism is quite dangerous and I think the exact workings of it should be very clearly documented.

Additionally having an order expire to generate another order… OR not ,is another reliability issue because we know from the WS that the stop has been hit but then we know nothing else; how long should I wait to decide if the new order will be placed… or not? there is no guaranteed execution time there either.

So, I am trying find how to make that scenario work on Binance. At the root, I need an order to trigger another one when it starts to fill, and they can be extremely close to each other.
The strategy we’re running, and I’m trying to port, is some market making hybrid where I need to satisfy the condition above in many scenarios.

You mean you can put TP/SL orders in parallel and make them work?
“Logically, you cannot make sure #2 can work as you cannot assure #1 can open an order successfully before #2 can be triggered and take actions” - Like I said, this is a logic problem - #1 & #2 should be chained actions rather than actions in parallel; How did you make them work in parallel? The limit order triggered from #2 should logically be placed right after the one is filled from #1 since it’s used to close the positions filled from #1

The only solution I can come up with is using one-way mode instead of hedge mode; Then in #1, generate a ‘buy’ limit order; meanwhile in #2, generate a ‘sell’ limit order (put the same quantity as it is in #1)and don’t set it as reduce-Only; Then even if #2 gets placed before the order gets filled from#1, it can still get placed successfully;