From dc3ac8de01b57b552ca54b89889cb27f8e5e92b1 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Sun, 18 Jun 2023 19:51:13 -0400 Subject: [PATCH] binance: support order "modifies" B) Only a couple tweaks to make this work according to the docs: https://binance-docs.github.io/apidocs/futures/en/#modify-order-trade - use a PUT request. - provide the original user id in a `'origClientOrderId'` msg field. - don't expect the same oid in the PUT response. Other broker-mode related details: - don't call `OrderDialogs.add_msg()` until after the existing check since we want to check against the *last* msgs contents not the new request. - ensure we pass the `modify=True` flag in the edit case. --- piker/brokers/binance/api.py | 40 +++++++++++++++++++++++++++------ piker/brokers/binance/broker.py | 38 ++++++++++++++++++------------- piker/brokers/binance/venues.py | 5 +++-- 3 files changed, 59 insertions(+), 24 deletions(-) diff --git a/piker/brokers/binance/api.py b/piker/brokers/binance/api.py index 15fd92ae..1fbe89ba 100644 --- a/piker/brokers/binance/api.py +++ b/piker/brokers/binance/api.py @@ -628,13 +628,24 @@ class Client: oid: int | None = None, tif: str = 'GTC', - recv_window: int = 60000 + recv_window: int = 60000, + # iceberg_quantity: float | None = None, - # order_resp_type: str | None = None, + resp_type: str = 'ACK', + + # TODO: this is probably useful for doing stops, maybe we + # can set it only on dark-stops? + # close_all: bool = False, + + modify: bool = False, ) -> str: ''' - Submit a live limit order to ze binance. + Submit or modify a live limit order to ze binance. + + For modify see: + - spot: + - futes https://binance-docs.github.io/apidocs/futures/en/#modify-order-trade ''' # lookup the binance-native symbol from search table @@ -647,10 +658,22 @@ class Client: ('quantity', quantity), ('price', price), ('recvWindow', recv_window), - ('newOrderRespType', 'ACK'), + ('newOrderRespType', resp_type), ('timestamp', binance_timestamp(now())) + + # ('closeAll', close_all), ]) - if oid: + + action: str = 'post' + + # NOTE: modifies only require diff key for user oid: + # https://binance-docs.github.io/apidocs/futures/en/#modify-order-trade + if modify: + assert oid + params['origClientOrderId'] = oid + action: str = 'put' + + elif oid: params['newClientOrderId'] = oid log.info( @@ -661,11 +684,14 @@ class Client: 'order', params=params, signed=True, - action='post' + action=action, ) # ensure our id is tracked by them - if oid: + if ( + oid + and not modify + ): assert oid == resp['clientOrderId'] reqid: str = resp['orderId'] diff --git a/piker/brokers/binance/broker.py b/piker/brokers/binance/broker.py index 10248f9f..0145c7f5 100644 --- a/piker/brokers/binance/broker.py +++ b/piker/brokers/binance/broker.py @@ -164,6 +164,7 @@ async def handle_order_requests( # validate order = BrokerdOrder(**msg) oid: str = order.oid # emsd order id + modify: bool = False # NOTE: check and report edits if existing := dialogs.get(order.oid): @@ -171,25 +172,31 @@ async def handle_order_requests( f'Existing order for {oid} updated:\n' f'{pformat(existing.maps[-1])} -> {pformat(msg)}' ) - # TODO: figure out what special params we have to send? - # https://binance-docs.github.io/apidocs/futures/en/#modify-order-trade + modify = True - # track latest request state such that map - # lookups start at the most recent msg and then - # scan reverse-chronologically. - dialogs.add_msg(oid, msg) + # only add new msg AFTER the existing check + dialogs.add_msg(oid, msg) - # XXX: ACK the request **immediately** before sending - # the api side request to ensure the ems maps the oid -> - # reqid correctly! - resp = BrokerdOrderAck( - oid=oid, # ems order request id - reqid=oid, # our custom int mapping - account='binance', # piker account - ) - await ems_order_stream.send(resp) + else: + # XXX NOTE: update before the ack! + # track latest request state such that map + # lookups start at the most recent msg and then + # scan reverse-chronologically. + dialogs.add_msg(oid, msg) + + # XXX: ACK the request **immediately** before sending + # the api side request to ensure the ems maps the oid -> + # reqid correctly! + resp = BrokerdOrderAck( + oid=oid, # ems order request id + reqid=oid, # our custom int mapping + account='binance', # piker account + ) + await ems_order_stream.send(resp) # call our client api to submit the order + # NOTE: modifies only require diff key for user oid: + # https://binance-docs.github.io/apidocs/futures/en/#modify-order-trade try: reqid = await client.submit_limit( symbol=order.symbol, @@ -197,6 +204,7 @@ async def handle_order_requests( quantity=order.size, price=order.price, oid=oid, + modify=modify, ) # SMH they do gen their own order id: ints.. diff --git a/piker/brokers/binance/venues.py b/piker/brokers/binance/venues.py index 4b530122..2de73185 100644 --- a/piker/brokers/binance/venues.py +++ b/piker/brokers/binance/venues.py @@ -43,8 +43,6 @@ _futes_url = f'https://fapi.{_domain}' _spot_ws: str = 'wss://stream.binance.com/ws' # 'wss://ws-api.binance.com:443/ws-api/v3', -# NOTE: spot test network only allows certain ep sets: -# https://testnet.binance.vision/ _testnet_spot_ws: str = 'wss://testnet.binance.vision/ws-api/v3' # https://binance-docs.github.io/apidocs/futures/en/#websocket-market-streams @@ -52,6 +50,9 @@ _futes_ws: str = f'wss://fstream.{_domain}/ws/' _auth_futes_ws: str = 'wss://fstream-auth.{_domain}/ws/' # test nets +# NOTE: spot test network only allows certain ep sets: +# https://testnet.binance.vision/ +# https://www.binance.com/en/support/faq/how-to-test-my-functions-on-binance-testnet-ab78f9a1b8824cf0a106b4229c76496d _testnet_spot_url: str = 'https://testnet.binance.vision/api' _testnet_spot_ws: str = 'wss://testnet.binance.vision/ws'