-
Notifications
You must be signed in to change notification settings - Fork 18
/
manage_local_order_book.py
144 lines (108 loc) · 4.09 KB
/
manage_local_order_book.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
"""
Manages a local order book and prints out its best prices.
Based on https://developers.binance.com/docs/binance-spot-api-docs/web-socket-streams#diff-depth-stream
Instructions:
1. Have binance-connector installed
2. Define symbol in this file and adjust other fields if needed
3. python manage_local_order_book.py
"""
from binance.spot import Spot as Client
from binance.websocket.spot.websocket_stream import SpotWebsocketStreamClient
from binance.lib.utils import config_logging
import os
import logging
import json
import asyncio
config_logging(logging, logging.INFO)
symbol = 'BNBUSDT' # Example: BNBUSDT
base_url = 'https://testnet.binance.vision'
stream_url = 'wss://testnet.binance.vision/ws'
client = Client(base_url=base_url)
order_book = {
"lastUpdateId": 0,
"bids": [],
"asks": []
}
def get_snapshot():
"""
Retrieve order book
"""
return client.depth(symbol, limit=1000)
def manage_order_book(side, update):
"""
Updates local order book's bid or ask lists based on the received update ([price, quantity])
"""
price, quantity = update
# price exists: remove or update local order
for i in range(0, len(order_book[side])):
if price == order_book[side][i][0]:
# quantity is 0: remove
if float(quantity) == 0:
order_book[side].pop(i)
return
else:
# quantity is not 0: update the order with new quantity
order_book[side][i] = update
return
# price not found: add new order
if float(quantity) != 0:
order_book[side].append(update)
if side == 'asks':
order_book[side] = sorted(order_book[side], key=lambda order: float(order[0])) # asks prices in ascendant order
else:
order_book[side] = sorted(order_book[side], key=lambda order: float(order[0]), reverse=True) # bids prices in descendant order
# maintain side depth <= 1000
if len(order_book[side]) > 1000:
order_book[side].pop(len(order_book[side]) - 1)
def process_updates(message):
"""
Updates bid and ask orders in the local order book.
"""
for update in message['b']:
manage_order_book('bids', update)
for update in message['a']:
manage_order_book('asks', update)
# logging.info("Condition 'U' <= last_update_id + 1 <= 'u' matched! Process diff update")
def message_handler(_, message):
"""
Syncs local order book with depthUpdate message's u (Final update ID in event) and U (First update ID in event).
If synced, then the message will be processed.
"""
global order_book
json_data = json.loads(message)
depth_update_event = json_data.get('e')
if depth_update_event == "depthUpdate":
last_update_id = order_book['lastUpdateId']
# logging.info('LastUpdateId:' + str(last_update_id))
# logging.info('Message U:' + str(message['U']) + ' u:' + str(message['u']))
if json_data['u'] <= last_update_id:
return # Not an update, wait for next message
if json_data['U'] <= last_update_id + 1 <= json_data['u']: # U <= lastUpdateId+1 AND u >= lastUpdateId+1.
order_book['lastUpdateId'] = json_data['u']
process_updates(json_data)
else:
logging.info('Out of sync, re-syncing...')
order_book = get_snapshot()
async def listen_ws():
"""
Listens to the ws to get the updates messages.
"""
ws_client = SpotWebsocketStreamClient(stream_url=stream_url, on_message=message_handler)
ws_client.diff_book_depth(
symbol=symbol.lower(),
id=1,
speed=1000
)
async def get_best_price():
"""
Gets best available prices (for bid and ask) every second
"""
while True:
if order_book.get('lastUpdateId') > 0:
print(f'Best prices -> bid:{order_book["bids"][0][0]} , ask:{order_book["asks"][0][0]}')
await asyncio.sleep(1)
def main():
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.gather(listen_ws(), get_best_price()))
loop.close()
main()