Python Binance Asyncio Maker Order/Trade With Web Socket Stream

This example will use

NOTE:

  • This sample will attemp to create marker order (usually with lower fee), thus need to handle complex scenario like order would immediately match (maker order becomes taker order), order would not match after certain duration (price too high or too low) and order partially match.
  • Binance REST API to query order status usually delay by 1 to 5 seconds, and could delay up to minutes during super peak session. Binance Websocket Stream is more reliable to get latest order status.

Setup

import asyncioimport binance_clientfrom unicorn_binance_websocket_api.unicorn_binance_websocket_api_manager import BinanceWebSocketApiManagerBINANCE_API_KEY = ...BINANCE_SECRET_KEY = ...running = Truefind_orders = {}

Helper functions

async def create_taker_order(binance, symbol, side):    # try to place marker order    order_id = None    while not order_id:        prices = await binance.get_price(symbol=symbol)        price = float(prices['price'])        # adjust price lower/higher to prevent immediate match        if side == 'buy':            price *= 0.9995        elif side == 'sell':            price *= 1.0005        # buy BUSD 12 worth of BTC        quantity = 12 / price        price = f"{price:.2f}"        quantity = f"{ quantity:.6f}"        print('price', price, 'quantity', quantity)        try:            data = await binance.order_limit_maker(symbol=symbol, side=side, quantity=quantity, price=price)            order_id = data['orderId']            print('order_id', order_id)        except binance_client.BinanceException as e:            if e.code == -2010 and e.msg == 'Order would immediately match and take.':                await asyncio.sleep(1)            else:                raise e    return order_id
async def check_order(binance, symbol, order_id):    loop_count = 0    while True:        # try to get order status        status = None        while not status:            try:                # check websocket order data                data = find_orders.get(order_id)                if data:                    print('order data from websocket')                    data = data[-1] # get the latest update                if not data:                    # check order data via api                    print('order data from api')                    data = await binance.query_order(symbol=symbol, order_id=order_id)                if data:                    status = data['status']                    print('status', status)                else:                    await asyncio.sleep(1)            except binance_client.BinanceException as e:                if e.code == -2013 and e.msg == 'Order does not exist.':                    await asyncio.sleep(1)                else:                    raise e        if status in ['FILLED', 'REJECTED', 'EXPIRED']: # 'CANCELED', 'PENDING_CANCEL',             print('success', status)            return True        loop_count += 1        if loop_count > 10:            if status in ['PARTIALLY_FILLED']:                print('partial', status)                return True            data = await binance.cancel_order(symbol=symbol, order_id=order_id)            status = data['status']            print('cancel', status)            return False        await asyncio.sleep(1)

Main

async def binance_websocket():    binance_websocket_api_manager = BinanceWebSocketApiManager()    binance_websocket_api_manager.create_stream('arr', '!userData', api_key=BINANCE_API_KEY, stream_label="UnicornFy", output="UnicornFy")    while running:        if binance_websocket_api_manager.is_manager_stopping():            break        oldest_stream_data_from_stream_buffer = binance_websocket_api_manager.pop_stream_data_from_stream_buffer()        if oldest_stream_data_from_stream_buffer:            stream = oldest_stream_data_from_stream_buffer            if 'event_type' in stream:                if stream['event_type'] == 'executionReport':                    order_id = stream['order_id']                    orders = find_orders.get(order_id)                    if not orders:                        orders = []                        find_orders[order_id] = orders                    # try to conver to query_order format                    orders.append({                        'clientOrderId': stream['client_order_id'],                        # 'cummulativeQuoteQty':                         'executedQty': stream['last_executed_quantity'],                        'icebergQty': stream['iceberg_quantity'],                        'orderId': order_id,                        'origQty': stream['order_quantity'],                        # 'origQuoteOrderQty':                        'price': stream['order_price'],                        'side': stream['side'],                        'status': stream['current_order_status'],                        'symbol': stream['symbol'],                        'time': stream['order_creation_time'],                        'updateTime': stream['transaction_time'],                        'eventTime': stream['event_time'],                        'source': 'userData'                    })                    print('find_orders', len(find_orders))                else:                    print('event_type', stream['event_type'])        else:            await asyncio.sleep(1)    binance_websocket_api_manager.stop_manager_with_all_streams()    print('binance_websocket END')async def binance_order():    global running    binance = binance_client.BinanceClientAsync(api_key=BINANCE_API_KEY, secret_key= BINANCE_SECRET_KEY)    # binance_helper = binance_client.BinanceHelper(client=binance)    symbol = 'BTCBUSD'    side = 'buy'    # wait binance_websocket start, else order data not received in time    print('wait ...')    await asyncio.sleep(5)    try:        result = False        while not result:            order_id = await create_taker_order(binance, symbol, side)            result = await check_order(binance, symbol, order_id)            print('result', result)            except binance_client.BinanceException as e:        print(e)    await binance.close()    running = False    print('binance_order END')async def main():    tasks = [binance_websocket(), binance_order()]    await asyncio.gather(*tasks)if __name__ == "__main__":    asyncio.run(main())

❤️ Is this article helpful?

Buy me a coffee ☕ or support my work via PayPal to keep this space 🖖 and ad-free.

Do send some 💖 to @d_luaz or share this article.

✨ By Desmond Lua

A dream boy who enjoys making apps, travelling and making youtube videos. Follow me on @d_luaz

👶 Apps I built

Travelopy - discover travel places in Malaysia, Singapore, Taiwan, Japan.