{"schemaVersion":"1.0","type":"TechArticle","types":["Article","TechArticle"],"slug":"create-and-cancel-orders-via-websocket-on-binance-gw4uk","url":"https://zyvop.com/create-and-cancel-orders-via-websocket-on-binance-gw4uk","title":"Create and Cancel Orders via WebSocket on Binance","subtitle":"How to access the Binance API via WebSocket in Python","tldr":"Until now it was only possible to receive data from Binance via WebSocket. To send requests to the Binance API, for example to create or cancel orders, you always had to use the slower REST API. This","keywords":["binance","Python","WebSockets","api","cryptocurrency","Software Engineering","trading,","Tutorial","UNICORN Binance Suite"],"entities":["Oliver Zehentleitner","Senior DevSecOps & AI Engineer","binance","Python","WebSockets","api","cryptocurrency","Software Engineering","trading,","Tutorial","UNICORN Binance Suite","ZyVOP"],"keyTakeaways":["Until now it was only possible to receive data from Binance via WebSocket.","To send requests to the Binance API, for example to create or cancel orders, you always had to use the slower REST API.","🚀 Recently, the Binance Spot Testnet and Binance Spot have added the ability to place orders, cancel orders, and handle other API requests via a WebSocket connection: Binance WebSocket API Documentation In Python, UNICORN Binance WebSocket API (part of the UNICORN Binance Suite) already supports the new features to send API requests to Binance via WebSocket."],"headings":["1. Binance","Account","API key and API secret","2. Installation of requirements","With PIP:","Or with Conda:","3. Create a Python script and establish a WebSocket API connection to Binance","4. Send requests and handle the responses","Global async function","Global callback function","Stream specific callback function","Request specific callback function","Save answer in variable","Using the stream_buffer","Multiple API streams","5. Available methods for API requests","Cancel open orders","Cancel an order","Create an order","6. Further information"],"outboundLinks":["https://testnet.binance.vision/","https://www.binance.com/","https://binance-docs.github.io/apidocs/websocket_api/en/#change-log","https://github.com/oliver-zehentleitner/unicorn-binance-websocket-api","https://blog.technopathy.club/page/unicorn-binance-suite","https://www.binance.com/en/activity/referral-entry/CPA?fromActivityPage=true&amp;ref=CPA_008DXU7CWB","https://blog.technopathy.club/how-to-create-a-binance-api-key-and-api-secret","https://www.python.org/","https://pypi.org/project/unicorn-binance-websocket-api/","https://cython.org/","https://www.pypy.org/","https://anaconda.org/conda-forge/unicorn-binance-websocket-api","https://www.anaconda.com/","https://oliver-zehentleitner.github.io/unicorn-binance-websocket-api/unicorn_binance_websocket_api.html#unicorn_binance_websocket_api.manager.BinanceWebSocketApiManager","https://gist.github.com/oliver-zehentleitner/5a5d739710400c8fbd9f04833c4bf1dc","https://gist.github.com/oliver-zehentleitner/b31adc37450a7a45752adb459c6b71d6","https://gist.github.com/oliver-zehentleitner/576ab4518ecbca583c3eec209533def1","https://oliver-zehentleitner.github.io/unicorn-binance-websocket-api/unicorn_binance_websocket_api.html#unicorn_binance_websocket_api.manager.BinanceWebSocketApiManager.create_stream","https://gist.github.com/oliver-zehentleitner/461a06fef1d809dd104e241599ab0f20","https://gist.github.com/oliver-zehentleitner/863f346969bbbe315ab808ca6e658013","https://gist.github.com/oliver-zehentleitner/57e1a32959b2019c62e0254f2ad19726","https://github.com/oliver-zehentleitner/unicorn-binance-websocket-api/wiki/%60stream_buffer%60","https://docs.python.org/3/library/collections.html#collections.deque","https://oliver-zehentleitner.github.io/unicorn-binance-websocket-api/unicorn_binance_websocket_api.html#unicorn_binance_websocket_api.manager.BinanceWebSocketApiManager.add_to_stream_buffer","https://gist.github.com/oliver-zehentleitner/96d5789f65761f08069b25229ec83af9","https://oliver-zehentleitner.github.io/unicorn-binance-websocket-api/unicorn_binance_websocket_api.html#unicorn_binance_websocket_api.manager.BinanceWebSocketApiManager.pop_stream_data_from_stream_buffer","https://gist.github.com/oliver-zehentleitner/241061d809c76ac1b08013a9ee40386c","https://gist.github.com/oliver-zehentleitner/7fc0c1ed65fa96bd9e65f3173143c17d","https://gist.github.com/oliver-zehentleitner/b2634fd6c45574b460c3fde8414f278c","https://developers.binance.com/docs/binance-trading-api/websocket_api#general-information-on-rate-limits","https://oliver-zehentleitner.github.io/unicorn-binance-websocket-api/","https://developers.binance.com/docs/binance-trading-api/websocket_api","https://developers.binance.com/docs/binance-trading-api/websocket_api#cancel-open-orders-trade","https://gist.github.com/oliver-zehentleitner/1ca32c20ff397e91f3466f788a718a6e","https://developers.binance.com/docs/binance-trading-api/websocket_api#cancel-order-trade","https://developers.binance.com/docs/binance-trading-api/websocket_api#place-new-order-trade","https://gist.github.com/oliver-zehentleitner/adf377f0c26740e7195d45d5f6bf93b3"],"contentText":"Until now it was only possible to receive data from Binance via WebSocket. To send requests to the Binance API, for example to create or cancel orders, you always had to use the slower REST API. This has changed now! 🚀 Recently, the Binance Spot Testnet and Binance Spot have added the ability to place orders, cancel orders, and handle other API requests via a WebSocket connection: Binance WebSocket API Documentation In Python, UNICORN Binance WebSocket API (part of the UNICORN Binance Suite) already supports the new features to send API requests to Binance via WebSocket. To do this, we will go through the following steps: Binance — Account — API key and API secret Installation of requirements — PIP — Conda Create a Python script and establish a WebSocket API connection to Binance Send requests and handle the responses — Global async function — Global callback function — Stream specific async function — Stream specific callback function — Request specific callback function — Save answer in variable — Using the stream_buffer — Multiple API Streams Available methods for API requests — ubwa.api.spot.cancel_order() — ubwa.api.spot.create_order() Further information 1. Binance Account To be able to trade on Binance you need a user account. If you don't have one yet, you can sign up via my referral link. With this we both get 100 USDT cashback vouchers for a 50 USD deposit. API key and API secret How to create an API Key/Secret pair you can read in detail here. 2. Installation of requirements Minimum requirement is a working Python 3.9+ installation. To use the UNICORN Binance WebSocket API in your Python script, you need to install it on the command line using one of the two commands: With PIP: This is the default way and should always work. It contains the plain source code and optimized Cython and PyPy Wheels: pip install unicorn-binance-websocket-api Or with Conda: This is only possible within an Anaconda environment: conda install -c conda-forge unicorn-binance-websocket-api 3. Create a Python script and establish a WebSocket API connection to Binance First we import unicorn_binance_websocket_api, define the callback function handle_socket_message() to print the received data and then store an instance of BinanceWebSocketApiManager() in the variable ubwa. If you want to connect BinanceWebSocketApiManager() to the testnet, you need to pass the string 'binance.com-testnet' to the exchange parameter. With process_stream_data=handle_socket_message we pass BinanceWebSocketApiManager() a global callback function, to this function all received responses of the API are passed by default. By default, all API requests return a string with a JSON structure. To automatically convert the JSON structure to a Python dictionary, we configure output_default=\"dict\". View GitHub Gist: oliver-zehentleitner/5a5d739710400c8fbd9f04833c4bf1dc Next we create the API stream, for this it is important to set the parameter api to True, otherwise a connection to another WebSocket endpoint would be established, where the API requests would not work. Please make sure that you use a valid API key/secret pair and consider the IP whitelist restrictions when testing! View GitHub Gist: oliver-zehentleitner/b31adc37450a7a45752adb459c6b71d6 Now all the prerequisites are met for us to send and process requests to the Binance API. 4. Send requests and handle the responses Note: According to this scheme all methods of ubwa.api can be called and executed. Using the ubwa.api object we can now send requests to the Binance API, e.g. a connection test with the ubwa.api.spot.ping() method. There are several ways to handle the API requests: Global async function Global callback function Stream specific async function Stream specific callback function Request specific callback function Save answer in variable Using the stream_buffer Multiple API Streams Global async function When receiving the response from Binance, the function handle_socket_message() is executed which we passed when initiating BinanceWebSocketApiManager(), and this is where you can hook your code. In our example, we simply output the received data: View GitHub Gist: oliver-zehentleitner/576ab4518ecbca583c3eec209533def1 Output: Received data: {\"id\":\"1cc8812a0c6b-08aa-6098-2742-ac0cedc8\",\"status\":200,\"result\":{},\"rateLimits\":[{\"rateLimitType\":\"REQUEST_WEIGHT\",\"interval\":\"MINUTE\",\"intervalNum\":1,\"limit\":1200,\"count\":2}]} I will use the example with ubwa.api.spot.ping() to introduce the other methods how you can receive and process the received data. Global callback function When receiving the response from Binance, the function handle_socket_message() is executed which we passed when initiating BinanceWebSocketApiManager(), and this is where you can hook your code. In our example, we simply output the received data: View GitHub Gist: oliver-zehentleitner/576ab4518ecbca583c3eec209533def1 Output: Received data: {\"id\":\"1cc8812a0c6b-08aa-6098-2742-ac0cedc8\",\"status\":200,\"result\":{},\"rateLimits\":[{\"rateLimitType\":\"REQUEST_WEIGHT\",\"interval\":\"MINUTE\",\"intervalNum\":1,\"limit\":1200,\"count\":2}]} Stream specific callback function It is possible to pass a callback function to ubwa.create_stream() as well. Then, for receiving responses from this stream, the stream specific callback function is used instead of the global callback function we passed to BinanceWebSocketApiManager(). View GitHub Gist: oliver-zehentleitner/461a06fef1d809dd104e241599ab0f20 Now we can run ping again and this time we would use the callback function handle_stream_message() instead of handle_socket_message(). View GitHub Gist: oliver-zehentleitner/576ab4518ecbca583c3eec209533def1 Output: Received stream data: {\"id\":\"1cc8812a0c6b-08aa-6098-2742-ac0cedc8\",\"status\":200,\"result\":{},\"rateLimits\":[{\"rateLimitType\":\"REQUEST_WEIGHT\",\"interval\":\"MINUTE\",\"intervalNum\":1,\"limit\":1200,\"count\":2}]} Request specific callback function Since not all types of data are treated the same way, there is also the possibility to process responses of a specific request with a specific callback function. View GitHub Gist: oliver-zehentleitner/863f346969bbbe315ab808ca6e658013 Output: Received ping response: {\"id\":\"1cc8812a0c6b-08aa-6098-2742-ac0cedc8\",\"status\":200,\"result\":{},\"rateLimits\":[{\"rateLimitType\":\"REQUEST_WEIGHT\",\"interval\":\"MINUTE\",\"intervalNum\":1,\"limit\":1200,\"count\":2}]} Save answer in variable There is also the possibility to let the called function wait until the response to the request has arrived and then store it directly into a variable. The disadvantage of this method is that the function becomes blocking, whereby several requests can only be processed sequentially. View GitHub Gist: oliver-zehentleitner/57e1a32959b2019c62e0254f2ad19726 Output: Awaited ping response: {\"id\":\"1cc8812a0c6b-08aa-6098-2742-ac0cedc8\",\"status\":200,\"result\":{},\"rateLimits\":[{\"rateLimitType\":\"REQUEST_WEIGHT\",\"interval\":\"MINUTE\",\"intervalNum\":1,\"limit\":1200,\"count\":2}]} Using the stream_buffer A completely different approach than the callback functions is the stream_buffer. This is the standard way of BinanceWebSocketApiManager() to process received data, here all received data is stored in a deque() stack and can be used as FIFO as well as LIFO stack to read the received data in a loop. The main advantage of this solution is the desynchronization between receiving and processing the new data. What does this mean? UBWA receives the new data in an AsyncIO event loop and processes them asynchronously. This means that the data is not received and processed sequentially, but that the callback functions within the event loop are started in parallel for each data record received, which can easily push your system to its limits during peak load times, e.g. if you receive more data faster than you can store in your database over a longer period for speed reasons. Because each received record is simply stored in the stream_buffer, the processing is immediately finished for UBWA. You can easily access the new data in the stream_buffer in another thread or better another process and adjust the processing time to your circumstances. Additionally the stream_buffer can be monitored by you and offers further options. As already mentioned the stream_buffer is the standard method of UBWA and is simply overwritten by setting the callback functions. So if you want to use it, do not pass a callback function in the class initialization of BinanceWebSocketApiManager() or anywhere else. One way to use callback functions everywhere and still use the stream_buffer in a special situation is to explicitly pass ubwa.add_to_stream_buffer as callback function. Of course it is also possible to use different stream_buffer, how to do that is described in the wiki. I now choose a simple example with only one global stream_buffer. If you have now simply omitted passing the callback functions, the global stream_buffer is activated by default and your stream will write its data there. Hereby you get access to the oldest record in the stack: View GitHub Gist: oliver-zehentleitner/96d5789f65761f08069b25229ec83af9 Note: If the stream_buffer is empty, ubwa.pop_stream_data_from_stream_buffer() returns the boolean value False! For example, if you have problems with your database, you can catch the exception of the database connection in a try block and use ubwa.add_to_stream_buffer() in the except block to save the record back into the stream_buffer and simply retrieve it later. Unfortunately, this messes up the chronological sorting! 🤨 View GitHub Gist: oliver-zehentleitner/241061d809c76ac1b08013a9ee40386c Multiple API streams If there is more than one API stream (with api=True), the methods must be told which stream to use. The stream_id is used to uniquely identify the streams and is returned by ubwa.create_stream(), alternatively you can also work with a stream_label. For this to work, a stream_label must also be defined when creating the stream with ubwa.create_stream(). Example with stream_id: View GitHub Gist: oliver-zehentleitner/7fc0c1ed65fa96bd9e65f3173143c17d Example with stream_label: View GitHub Gist: oliver-zehentleitner/b2634fd6c45574b460c3fde8414f278c 5. Available methods for API requests Note: Actions executed via WebSocket are subject to the same filters and rate restrictions as when executed via the REST API, and are also functionally equivalent: they provide the same functionality, accept the same parameters, and return the same status and error codes. Each API request has its own list of accepted and mandatory parameters, gives different responses, and is subject to different request limits. To understand what is happening in the background, it is always advisable to also study the official documentation of Unicorn Binance WebSocket API and the Binance WebSocket API. ubwa.api.spot.cancel_order() ubwa.api.spot.create_order() Cancel open orders Cancel all open orders on a symbol, including OCO orders. Docs: UBWA, Binance If you cancel an order that is a part of an OCO pair, the entire OCO is canceled. View GitHub Gist: oliver-zehentleitner/1ca32c20ff397e91f3466f788a718a6e Output: {\"id\":\"d37149a608c4-7951-fbbb-33f6-93d68e2d\",\"status\":200,\"result\":{\"symbol\":\"BUSDUSDT\",\"origClientOrderId\":\"1\",\"orderId\":942396461,\"orderListId\":-1,\"clientOrderId\":\"rkAnxL9oEZr7wzKaCMiAuQ\",\"price\":\"1.00000000\",\"origQty\":\"15.00000000\",\"executedQty\":\"0.00000000\",\"cummulativeQuoteQty\":\"0.00000000\",\"status\":\"CANCELED\",\"timeInForce\":\"GTC\",\"type\":\"LIMIT\",\"side\":\"SELL\",\"selfTradePreventionMode\":\"NONE\"},\"rateLimits\":[{\"rateLimitType\":\"REQUEST_WEIGHT\",\"interval\":\"MINUTE\",\"intervalNum\":1,\"limit\":1200,\"count\":3}]} Cancel an order Cancel an active order. Docs: UBWA, Binance If you cancel an order that is a part of an OCO pair, the entire OCO is canceled. View GitHub Gist: oliver-zehentleitner/1ca32c20ff397e91f3466f788a718a6e Output: {\"id\":\"d37149a608c4-7951-fbbb-33f6-93d68e2d\",\"status\":200,\"result\":{\"symbol\":\"BUSDUSDT\",\"origClientOrderId\":\"1\",\"orderId\":942396461,\"orderListId\":-1,\"clientOrderId\":\"rkAnxL9oEZr7wzKaCMiAuQ\",\"price\":\"1.00000000\",\"origQty\":\"15.00000000\",\"executedQty\":\"0.00000000\",\"cummulativeQuoteQty\":\"0.00000000\",\"status\":\"CANCELED\",\"timeInForce\":\"GTC\",\"type\":\"LIMIT\",\"side\":\"SELL\",\"selfTradePreventionMode\":\"NONE\"},\"rateLimits\":[{\"rateLimitType\":\"REQUEST_WEIGHT\",\"interval\":\"MINUTE\",\"intervalNum\":1,\"limit\":1200,\"count\":3}]} Create an order Create a new order. Docs: UBWA, Binance ubwa.api.spot.create_order() automatically creates a client_order_id and returns it. This way you can always uniquely identify the order in further steps. View GitHub Gist: oliver-zehentleitner/adf377f0c26740e7195d45d5f6bf93b3 Output: {\"id\":\"4db8f58ee69e-d597-fb26-8551-786707fa\",\"status\":200,\"result\":{\"symbol\":\"BUSDUSDT\",\"orderId\":942394911,\"orderListId\":-1,\"clientOrderId\":\"1\",\"transactTime\":1680911574690,\"price\":\"1.00000000\",\"origQty\":\"15.00000000\",\"executedQty\":\"0.00000000\",\"cummulativeQuoteQty\":\"0.00000000\",\"status\":\"NEW\",\"timeInForce\":\"GTC\",\"type\":\"LIMIT\",\"side\":\"SELL\",\"workingTime\":1680911574690,\"fills\":[],\"selfTradePreventionMode\":\"NONE\"},\"rateLimits\":[{\"rateLimitType\":\"ORDERS\",\"interval\":\"SECOND\",\"intervalNum\":10,\"limit\":50,\"count\":1},{\"rateLimitType\":\"ORDERS\",\"interval\":\"DAY\",\"intervalNum\":1,\"limit\":160000,\"count\":20},{\"rateLimitType\":\"REQUEST_WEIGHT\",\"interval\":\"MINUTE\",\"intervalNum\":1,\"limit\":1200,\"count\":4}]} 6. Further information There are many other functions to send requests to the Binance API. If you find bugs or have suggestions for improving the API implementation, you can open an issue via GitHub. For more information please read the documentation for unicorn-binance-websocket-api. I hope you found this informative and useful. Follow me on Binance Square, GitHub, Mastodon, X, and LinkedIn, or join Telegram for updates on my latest publications. Constructive feedback is always appreciated. Thank you for reading, and happy coding! ¯\\_(ツ)_/¯","contentHash":"sha256:306fbc8b92248652b7c759b6a58405972e4bf4b0ddfdbed17167e365acee8926","authorName":"Oliver Zehentleitner","authorUrl":"https://zyvop.com/author/oliverzehentleitner","authorSameAs":["https://blog.technopathy.club","https://github.com/oliver-zehentleitner/","https://x.com/unicorn_oz","https://www.linkedin.com/in/oliver-zehentleitner"],"category":"Tutorial","tags":["binance","Python","WebSockets","api","cryptocurrency","Software Engineering","trading,"],"audience":"Software engineers and developers building applications with Tutorial","tone":"Instructional, practical, code-first","readingTimeMinutes":9,"wordCount":1878,"faqs":null,"primaryTopic":"Tutorial","publishedAt":"2026-09-24T14:15:05.843Z","updatedAt":"2026-09-24T14:15:05.843Z","canonicalUrl":"https://blog.technopathy.club/create-and-cancel-orders-via-websocket-on-binance"}