roq-trading / roq-issues

Issue tracker for Roq's software solutions.
https://roq-trading.com/
1 stars 0 forks source link

[roq-binance-futures] OrderUpdate.client_order_id was not populated during download #435

Closed thraneh closed 10 months ago

thraneh commented 10 months ago

Using the FIX Bridge, it was noticed that it was not possible to properly issue an order cancel request. This would only happen after gateway restart.

These are the gateway event following restart:

The order was downloaded (update_type=SNAPSHOT)

order_update={stream_id=0, account="T1", order_id=1327747935573, exchange="binance-futures-fapi", symbol="ETHUSDT", side=BUY, position_effect=UNDEFINED, max_show_quantity=nan, order_type=LIMIT, time_in_force=GTC, execution_instructions=, create_time_utc=1704560847804000000ns, update_time_utc=1704560847804000000ns, external_account="", external_order_id="1257003957", client_order_id="", status=WORKING, quantity=0.010000000000000002, price=2000, stop_price=0, risk_exposure=nan, risk_exposure_change=nan, remaining_quantity=nan, traded_quantity=0, average_traded_price=0, last_traded_quantity=0, last_traded_price=0, last_liquidity=UNDEFINED, routing_id="clordi100867", max_request_version=1, max_response_version=1, max_accepted_version=1, update_type=SNAPSHOT, sending_time_utc=0ns, user="fix-bridge", strategy_id=0}

In particular, notice

The next update for this order comes from the drop-copy stream

order_trade_update={event_type=ORDER_TRADE_UPDATE, event_time=1704560892025ms, transaction_time=1704560892015ms, account_alias="", execution_report={symbol="ETHUSDT", client_order_id="WwIBVa3xIzUBAQAAAAAA", side=BUY, order_type=LIMIT, time_in_force=GTC, original_quantity=0.010000000000000002, original_price=2000, average_price=0, stop_price=0, execution_type=CANCELED, order_status=CANCELED, order_id=1257003957, last_filled_quantity=0, order_filled_accumulated_quantity=0, last_filled_price=0, margin_asset="", commission_asset="USDT", commission=0, order_trade_time=1704560892015ms, trade_id=0, bids_notional=0, asks_notional=0, is_trade_maker=false, is_reduce_only=false, stop_price_working_type=CONTRACT_PRICE, original_order_type=LIMIT, position_side=BOTH, if_close_all=false, activation_price=nan, callback_rate=nan, realized_profit=0, unknown_1=false, unknown_2=0, unknown_3=0, unknown_4="", self_trade_prevention_mode="NONE", price_match_mode="NONE", good_till_date=0ms}}

Notice

Which results in this order update

order_update={stream_id=3, account="T1", order_id=1327747935573, exchange="binance-futures-fapi", symbol="ETHUSDT", side=BUY, position_effect=UNDEFINED, max_show_quantity=nan, order_type=LIMIT, time_in_force=GTC, execution_instructions=, create_time_utc=1704560847804000000ns, update_time_utc=1704560892015000000ns, external_account="", external_order_id="1257003957", client_order_id="", status=CANCELED, quantity=0.010000000000000002, price=2000, stop_price=0, risk_exposure=0, risk_exposure_change=nan, remaining_quantity=nan, traded_quantity=0, average_traded_price=0, last_traded_quantity=0, last_traded_price=0, last_liquidity=TAKER, routing_id="clordi100867", max_request_version=1, max_response_version=1, max_accepted_version=1, update_type=INCREMENTAL, sending_time_utc=1704560892025000000ns, user="fix-bridge", strategy_id=0}

Notice

This is a secondary bug, we will get back to this towards the end

Then we get the request (from the FIX Bridge) to cancel the order

cancel_order={account="T1", order_id=1327747935573, request_template="", routing_id="clordi100868", version=2, conditional_on_version=1}

This looks correct.

However, this is the REST request that is being forwarded to Binance

symbol=ETHUSDT&origClientOrderId=&recvWindow=5000

Notice

We then get an exchange reject

{"code":-1102,"msg":"Param 'orderid' or 'origclientorderid' must be sent, but both were empty/null!"}

This is the bug that was observed.

There are therefore 2 issues

The latter must be fixed for both order modify and cancel requests.

This leaves the question why the order got canceled.

Looking at the FIX Bridge log

It is unclear how the order got canceled. Two options exist:

The user has confirmed that the order was not manually canceled.

The gateway has the option to instruct the exchange to auto-cancel orders following disconnect

The default should therefore be to not auto-cancel.

However, we find this in the gateway log (signature intentionally removed)

POST /fapi/v1/countdownCancelAll?timestamp=1704560894174&signature=

Inspecting the code, it appears that only --rest_order_countdown is being tested against non-empty.

This is a secondary bug: the --rest_cancel_on_disconnect flag should guide whether auto-cancel is enabled or not.

This has also been fixed.