-
Notifications
You must be signed in to change notification settings - Fork 0
/
market_making_strat.py
182 lines (161 loc) · 6.14 KB
/
market_making_strat.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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
import os
from dotenv import load_dotenv
from interface_book import VenueOrderBook
from interface_order import OrderEvent, Side, OrderStatus
from binance_gateway import BinanceFutureGateway
import logging
logging.basicConfig(
format="%(asctime)s [%(threadName)-12.12s] [%(levelname)-5.5s] %(message)s",
level=logging.INFO,
)
# An order class with status information
class Order:
def __init__(self, symbol: str, side: Side, price, quantity, tif="IOC"):
self.symbol = symbol
self.side = side
self.price = price
self.quantity = quantity
self.tif = tif
self.last_order_event = None
self.cancelling = False
# Pricing strategy class
class PricingStrategy:
def __init__(
self,
symbol: str,
order_size,
sensitivity,
binance_gateway: BinanceFutureGateway,
):
self._symbol = symbol
self._order_size = order_size
self._sensitivity = sensitivity
self._binance_gateway = binance_gateway
self._live_buy_order = None
self._live_sell_order = None
def start(self):
logging.info(f"Start strategy for {self._symbol}..")
# callback on order book update
def on_orderbook(self, order_book: VenueOrderBook):
# raise a buy order if there is currently none
if self._live_buy_order is None:
_limit_price = order_book.get_book().get_best_bid()
_order = Order(
self._symbol,
Side.BUY,
_limit_price,
self._order_size,
)
self._post_only_order(_order)
else:
# should we refresh our price?
if (
abs(order_book.get_book().get_best_bid() - self._live_buy_order.price)
> self._sensitivity
):
# cancel live order
self._cancel_order(self._live_buy_order)
# raise a sell order if there is currently none
if self._live_sell_order is None:
_limit_price = order_book.get_book().get_best_ask()
_order = Order(
self._symbol,
Side.SELL,
_limit_price,
self._order_size,
)
self._post_only_order(_order)
else:
# should we refresh our price?
if (
abs(order_book.get_book().get_best_ask() - self._live_sell_order.price)
> self._sensitivity
):
# cancel live order
self._cancel_order(self._live_sell_order)
# callback on execution update
def on_execution(self, order_event: OrderEvent):
logging.info("Receive execution: {}".format(order_event))
if order_event.side == Side.BUY:
if self._live_buy_order:
self._live_buy_order.last_order_event = order_event
if self._is_complete(order_event):
# buy order is done, we can create new one
self._live_buy_order = None
else:
if self._live_sell_order:
self._live_sell_order.last_order_event = order_event
if self._is_complete(order_event):
# sell order is done, we can create new one
self._live_sell_order = None
def _post_only_order(self, order: Order):
if order.side == Side.BUY:
# ensure there's no existing buy order
if self._live_buy_order is None:
success = self._binance_gateway.place_limit_order(
order.side,
order.price,
order.quantity,
"GTX",
)
if success:
self._live_buy_order = order
else:
raise Exception(
"Logic error - attempt to raise buy order when there is already one"
)
else:
# ensure there's no existing sell order
if self._live_sell_order is None:
success = self._binance_gateway.place_limit_order(
order.side,
order.price,
order.quantity,
"GTX",
)
if success:
self._live_sell_order = order
# cancel the given order if not cancel request not previously sent
def _cancel_order(self, order: Order):
if not self._ready_to_cancel(order):
# not ready to cancel yet, wait
return
if not order.cancelling:
_order_id = order.last_order_event.order_id
logging.info("Sending cancel request for order id: {}".format(_order_id))
order.cancelling = self._binance_gateway.cancel_order(
order.symbol,
order.last_order_event.order_id,
)
# check if order has completed
def _is_complete(self, order_event: OrderEvent):
return (
order_event.status == OrderStatus.FILLED
or order_event.status == OrderStatus.PARTIALLY_FILLED
or order_event.status == OrderStatus.CANCELED
or order_event.status == OrderStatus.FAILED
)
# check if order is ready to cancel
def _ready_to_cancel(self, order: Order):
return order.last_order_event is not None and not self._is_complete(
order.last_order_event
)
if __name__ == "__main__":
# get api key and secret
dotenv_path = r"Z:\vault\.my_secret"
load_dotenv(dotenv_path=dotenv_path)
api_key = os.getenv("BINANCE_KEY")
api_secret = os.getenv("BINANCE_SECRET")
# strategy parameters
symbol = "BTCUSDT"
order_size = 0.01
sensitivity = 0.1
# create a binance gateway object
binance_gateway = BinanceFutureGateway(symbol, api_key, api_secret)
# create a strategy a register callbacks with gateway
strategy = PricingStrategy(symbol, order_size, sensitivity, binance_gateway)
binance_gateway.register_execution_callback(strategy.on_execution)
binance_gateway.register_depth_callback(strategy.on_orderbook)
# start
strategy.start()
binance_gateway.connect()