def __init__(self, product_id='BTC-USD'): print("Initializing order Book websocket for " + product_id) self.product = product_id super(GDaxBook, self).__init__(products=[self.product]) super(GDaxBook, self).start() self._asks = RBTree() self._bids = RBTree() self._client = PublicClient() self._sequence = -1 self._current_ticker = None
def __init__(self, product_id='BTC-USD', log_to=None): super(OrderBook, self).__init__(products=product_id) self._asks = RBTree() self._bids = RBTree() self._client = PublicClient() self._sequence = -1 self._log_to = log_to if self._log_to: assert hasattr(self._log_to, 'write') self._current_ticker = None
def __init__(self, product_id='BTC-USD', windowSize=30): super(AutoBot, self).__init__(products=product_id, channels=['ticker']) self._client = PublicClient() self._sequence = -1 self._current_ticker = None self._queue = deque([], windowSize) self._window_size = windowSize self._last_average = 0 self._ownedCoins = 0
def __init__(self, product_id='BTC-USD', log_to=None, autoreconnect=True, max_retries=3): super(OrderBook, self).__init__(products=[product_id]) self.channels = ['full'] self._asks = RBTree() self._bids = RBTree() self._client = PublicClient() self._sequence = -1 self._log_to = log_to self._retries = 0 self._max_retries = max_retries self._autoreconnect = autoreconnect self._is_ready = False if self._log_to: assert hasattr(self._log_to, 'write') self._current_ticker = None
def __init__(self, key, secret, passphrase, product): self.key = key self.secret = secret self.passphrase = passphrase self.product = product self.websocket_client = WebsocketClient() self.order_book = OrderBook(product_id=product) self.auth_client = AuthenticatedClient(key, secret, passphrase) self.public_client = PublicClient() self.sells = [] self.buys = [] self.sell_tracker = 0 self.buy_tracker = 0 self.sell_fees = 0 self.buy_fees = 0 self.num_buys = 0 self.num_sells = 0 self.av_sell = 0 self.av_buy = 0 self.last_buy = 0 self.last_sell = 0 self.current_balance = 0 self.ticker_tracker = []
def __init__(self, url="wss://ws-feed.gdax.com", product_id='BTC-USD', auth=False, api_key="", api_secret="", api_passphrase="", log_to=None): super(OrderBook, self).__init__(url=url, products=product_id, auth=auth, api_key=api_key, api_secret=api_secret, api_passphrase=api_passphrase) print("------------------------------orderbook url:", url) self._asks = RBTree() self._bids = RBTree() self._client = PublicClient() self._sequence = -1 self._log_to = log_to if self._log_to: assert hasattr(self._log_to, 'write') self._current_ticker = None
def __init__(self, saveMessage=0, product_id='BTC-USD'): self.url = "wss://ws-feed.gdax.com/" self.ws = create_connection(self.url) self.product_id = product_id self.sequence = -1 self.stop = False self._sequence = -1 self._client = PublicClient() self._asks = RBTree() self._bids = RBTree() self._current_ticker = None self.saveMessage = saveMessage self.t1 = None self.t2 = None self.t3 = None
def __init__(self): self.binanceClient = BinanceClient(BinanceSettings.api_key, BinanceSettings.api_secret) self.gdax_public_client = GdaxPublicClient() self.gdax_authenticated_client = GdaxAuthenticatedClient( key=GdaxSettings.api_key, b64secret=GdaxSettings.api_secret, passphrase=GdaxSettings.api_passphrase) self.sandbox_gdax_authenticated_client = GdaxAuthenticatedClient( key=GdaxSettings.sandbox_key, b64secret=GdaxSettings.sandbox_secret, passphrase=GdaxSettings.sandbox_passphrase, api_url='https://api-public.sandbox.gdax.com') self.kraken_public_client = KrakenAPI() self.MARKET_BINANCE = 'binance' self.MARKET_GDAX = 'gdax' self.MARKET_KRAKEN = 'kraken'
def __init__(self, product_id='BTC-USD'): super(OrderBook, self).__init__(products=product_id) self._asks = RBTree() self._bids = RBTree() self._client = PublicClient(product_id=product_id) self._sequence = -1
class OrderBook(WebsocketClient): def __init__(self, product_id='BTC-USD', log_to=None): super(OrderBook, self).__init__(products=product_id) self._asks = RBTree() self._bids = RBTree() self._client = PublicClient() self._sequence = -1 self._log_to = log_to if self._log_to: assert hasattr(self._log_to, 'write') self._current_ticker = None @property def product_id(self): ''' Currently OrderBook only supports a single product even though it is stored as a list of products. ''' return self.products[0] def on_message(self, message): if self._log_to: pickle.dump(message, self._log_to) sequence = message['sequence'] if self._sequence == -1: self._asks = RBTree() self._bids = RBTree() res = self._client.get_product_order_book(product_id=self.product_id, level=3) for bid in res['bids']: self.add({ 'id': bid[2], 'side': 'buy', 'price': Decimal(bid[0]), 'size': Decimal(bid[1]) }) for ask in res['asks']: self.add({ 'id': ask[2], 'side': 'sell', 'price': Decimal(ask[0]), 'size': Decimal(ask[1]) }) self._sequence = res['sequence'] if sequence <= self._sequence: # ignore older messages (e.g. before order book initialization from getProductOrderBook) return elif sequence > self._sequence + 1: print('Error: messages missing ({} - {}). Re-initializing websocket.'.format(sequence, self._sequence)) self.close() self.start() return msg_type = message['type'] if msg_type == 'open': self.add(message) elif msg_type == 'done' and 'price' in message: self.remove(message) elif msg_type == 'match': self.match(message) self._current_ticker = message elif msg_type == 'change': self.change(message) self._sequence = sequence # bid = self.get_bid() # bids = self.get_bids(bid) # bid_depth = sum([b['size'] for b in bids]) # ask = self.get_ask() # asks = self.get_asks(ask) # ask_depth = sum([a['size'] for a in asks]) # print('bid: %f @ %f - ask: %f @ %f' % (bid_depth, bid, ask_depth, ask)) def on_error(self, e): self._sequence = -1 self.close() self.start() def add(self, order): order = { 'id': order.get('order_id') or order['id'], 'side': order['side'], 'price': Decimal(order['price']), 'size': Decimal(order.get('size') or order['remaining_size']) } if order['side'] == 'buy': bids = self.get_bids(order['price']) if bids is None: bids = [order] else: bids.append(order) self.set_bids(order['price'], bids) else: asks = self.get_asks(order['price']) if asks is None: asks = [order] else: asks.append(order) self.set_asks(order['price'], asks) def remove(self, order): price = Decimal(order['price']) if order['side'] == 'buy': bids = self.get_bids(price) if bids is not None: bids = [o for o in bids if o['id'] != order['order_id']] if len(bids) > 0: self.set_bids(price, bids) else: self.remove_bids(price) else: asks = self.get_asks(price) if asks is not None: asks = [o for o in asks if o['id'] != order['order_id']] if len(asks) > 0: self.set_asks(price, asks) else: self.remove_asks(price) def match(self, order): size = Decimal(order['size']) price = Decimal(order['price']) if order['side'] == 'buy': bids = self.get_bids(price) if not bids: return assert bids[0]['id'] == order['maker_order_id'] if bids[0]['size'] == size: self.set_bids(price, bids[1:]) else: bids[0]['size'] -= size self.set_bids(price, bids) else: asks = self.get_asks(price) if not asks: return assert asks[0]['id'] == order['maker_order_id'] if asks[0]['size'] == size: self.set_asks(price, asks[1:]) else: asks[0]['size'] -= size self.set_asks(price, asks) def change(self, order): try: new_size = Decimal(order['new_size']) except KeyError: return price = Decimal(order['price']) if order['side'] == 'buy': bids = self.get_bids(price) if bids is None or not any(o['id'] == order['order_id'] for o in bids): return index = [b['id'] for b in bids].index(order['order_id']) bids[index]['size'] = new_size self.set_bids(price, bids) else: asks = self.get_asks(price) if asks is None or not any(o['id'] == order['order_id'] for o in asks): return index = [a['id'] for a in asks].index(order['order_id']) asks[index]['size'] = new_size self.set_asks(price, asks) tree = self._asks if order['side'] == 'sell' else self._bids node = tree.get(price) if node is None or not any(o['id'] == order['order_id'] for o in node): return def get_current_ticker(self): return self._current_ticker def get_current_book(self): result = { 'sequence': self._sequence, 'asks': [], 'bids': [], } for ask in self._asks: try: # There can be a race condition here, where a price point is removed # between these two ops this_ask = self._asks[ask] except KeyError: continue for order in this_ask: result['asks'].append([order['price'], order['size'], order['id']]) for bid in self._bids: try: # There can be a race condition here, where a price point is removed # between these two ops this_bid = self._bids[bid] except KeyError: continue for order in this_bid: result['bids'].append([order['price'], order['size'], order['id']]) return result def get_ask(self): return self._asks.min_key() def get_asks(self, price): return self._asks.get(price) def remove_asks(self, price): self._asks.remove(price) def set_asks(self, price, asks): self._asks.insert(price, asks) def get_bid(self): return self._bids.max_key() def get_bids(self, price): return self._bids.get(price) def remove_bids(self, price): self._bids.remove(price) def set_bids(self, price, bids): self._bids.insert(price, bids)
class Interface: def __init__(self): self.binanceClient = BinanceClient(BinanceSettings.api_key, BinanceSettings.api_secret) self.gdax_public_client = GdaxPublicClient() self.gdax_authenticated_client = GdaxAuthenticatedClient( key=GdaxSettings.api_key, b64secret=GdaxSettings.api_secret, passphrase=GdaxSettings.api_passphrase) self.sandbox_gdax_authenticated_client = GdaxAuthenticatedClient( key=GdaxSettings.sandbox_key, b64secret=GdaxSettings.sandbox_secret, passphrase=GdaxSettings.sandbox_passphrase, api_url='https://api-public.sandbox.gdax.com') self.kraken_public_client = KrakenAPI() self.MARKET_BINANCE = 'binance' self.MARKET_GDAX = 'gdax' self.MARKET_KRAKEN = 'kraken' def get_prices(self, exchange): if exchange == self.MARKET_BINANCE: market_books = self.binanceClient.get_products_and_prices() elif exchange == self.MARKET_GDAX: market_books = self.gdax_public_client.get_products_with_prices() elif exchange == self.MARKET_KRAKEN: market_books = self.kraken_public_client.get_market_tickers() else: print("No exchange found with name: " + exchange) # TODO throw exception return market_books def create_test_order(self, exchange, symbol, side, limit_market, quantity, price=0.0): if exchange == self.MARKET_BINANCE: response = self.binanceClient.create_test_order(symbol=symbol, side=side, type=limit_market, quantity=quantity, price=price, timeInForce="GTC") print("order is filled") # The binance test order does not actually get passed to the matching engine, so we're unable to test this. if exchange == self.MARKET_GDAX: symbol_reformatted = symbol[:3] + "-" + symbol[ 3:] # TODO is this correct? response = self.sandbox_gdax_authenticated_client.create_order( symbol=symbol_reformatted, side=side, limit_market=limit_market, quantity=quantity, price=price) order_id = response["id"] order_filled = False while not order_filled: order = self.sandbox_gdax_authenticated_client.get_order( order_id) if order["status"] == "done": print("order is filled!") order_filled = True else: print("order not yet filled") time.sleep(5) def create_order(self, exchange, symbol, side, limit_market, quantity, price=0.0): if exchange == self.MARKET_BINANCE: order = self.binanceClient.create_order(symbol, side, quantity, price, type=limit_market) elif exchange == self.MARKET_GDAX: order = self.gdax_authenticated_client.create_order( symbol, side, limit_market, quantity, price) else: print("No exchange found with name: " + exchange) # TODO throw exception print(order) def order_filled(self, exchange, order_id): if exchange == self.MARKET_BINANCE: return self.binanceClient.get_order(order_id)['status'] == 'done' elif exchange == self.MARKET_GDAX: return self.gdax_authenticated_client.get_order( order_id)['status'] == 'done' else: return ''
class Bot(object): def __init__(self, key, secret, passphrase, product): self.key = key self.secret = secret self.passphrase = passphrase self.product = product self.websocket_client = WebsocketClient() self.order_book = OrderBook(product_id=product) self.auth_client = AuthenticatedClient(key, secret, passphrase) self.public_client = PublicClient() self.sells = [] self.buys = [] self.sell_tracker = 0 self.buy_tracker = 0 self.sell_fees = 0 self.buy_fees = 0 self.num_buys = 0 self.num_sells = 0 self.av_sell = 0 self.av_buy = 0 self.last_buy = 0 self.last_sell = 0 self.current_balance = 0 self.ticker_tracker = [] def get_order_info(self, ticker, number_measures, length_measures, order_book_skim): bid_intervals = [] bid_depths_intervals = [] ask_intervals = [] ask_depths_intervals = [] count = 1 while count <= number_measures: print('Volume check %s' % count) time.sleep(length_measures) current_order_book = self.order_book.get_current_book() bids, bid_depths, asks, ask_depths = sort_messages( ticker, current_order_book, order_book_skim) bid_intervals.append(bids) ask_intervals.append(asks) bid_depths_intervals.append(bid_depths) ask_depths_intervals.append(ask_depths) count += 1 return bid_intervals, bid_depths_intervals, ask_intervals, ask_depths_intervals def check_volatility(self, volatility_interval, num_volatility_measures): if len(self.ticker_tracker) > num_volatility_measures + 1: delta_price = np.diff(self.ticker_tracker) vol_measure = np.average(delta_price[-num_volatility_measures:]) else: vol_measure = 0 return abs(vol_measure) def start_order_book(self): self.order_book.start() def order_book_repeat_sample(self, duration, order_book_skim): with open('crypto_data.csv', 'w') as csv_file: writer = csv.writer( csv_file, delimiter='\t', lineterminator='\n', ) header = [ 'datetime', 'ticker price', 'average bid', 'average ask', 'bid volume', 'ask volume' ] writer.writerow(header) while True: ticker = float( self.public_client.get_product_ticker( self.product)['price']) current_order_book = self.order_book.get_current_book() bids, bid_depths, asks, ask_depths = sort_messages( ticker, current_order_book, order_book_skim) if len(bids) != 0 and len(asks) != 0 and len( bid_depths) != 0 and len(ask_depths) != 0: print(bids[1]) print(bids[2]) av_bid = np.average(bids) av_ask = np.average(asks) total_bids = np.sum(bid_depths) total_asks = np.sum(ask_depths) else: av_bid = 'N/A' av_ask = 'N/A' total_bids = 'N/A' total_asks = 'N/A' print('Average bid', av_bid) print('Average ask', av_ask) print('total bid volume', total_bids) print('total ask volume', total_asks) data = [ datetime.datetime.now(), ticker, av_bid, av_ask, total_bids, total_asks ] writer.writerow(data) time.sleep(duration) def track_performance(self, string_id, transaction): if 'side' in transaction.keys(): if transaction['side'] == 'sell': self.sells.append(transaction['id']) if transaction['side'] == 'buy': self.buys.append(transaction['id']) def evaluate_performance(self): print('Current sell orders:') for sell in self.sells: order = self.auth_client.get_order(sell) if 'message' in order.keys(): self.sells.remove(sell) else: print('price:', order['price'], 'size:', order['size']) if order['settled'] == True: self.sell_tracker += float(order['size']) * float( order['price']) self.sell_fees += float(order['fill_fees']) self.num_sells += float(order['size']) self.sells.remove(sell) print('Current buy orders:') for buy in self.buys: order = self.auth_client.get_order(buy) if 'message' in order.keys(): self.buys.remove(buy) else: print('price:', order['price'], 'size:', order['size']) if order['settled'] == True: self.buy_tracker += float(order['size']) * float( order['price']) self.buy_fees += float(order['fill_fees']) self.num_buys += float(order['size']) self.buys.remove(buy) if self.num_buys > 0: self.av_buy = self.buy_tracker / self.num_buys if self.num_sells > 0: self.av_sell = self.sell_tracker / self.num_sells print('Number of buys:', self.num_buys) print('Buy USD volume:', self.buy_tracker) print('Number of sells:', self.num_sells) print('Sell USD volume:', self.sell_tracker) print('Net fees:', self.sell_fees + self.buy_fees) print( 'Net USD profit:', self.sell_tracker - self.buy_tracker - self.sell_fees - self.buy_fees) print('Av sell:', self.av_sell) print('Av buy:', self.av_buy) def check_existing_sells(self, current_order_price, current_order_size, vol_measure): new_average = (self.sell_tracker + current_order_price * current_order_size) / ( self.num_sells + current_order_size) print('new av', new_average) if len(self.sells) > 0: if new_average > self.av_buy: if self.num_buys > 0: for sell in self.sells: order = self.auth_client.get_order(sell) order_price = float(order['price']) if 'message' in order.keys(): self.buys.remove(sell) return 'keep' else: if self.av_buy < current_order_price: if order_price < current_order_price - vol_measure: self.buys.remove(sell) self.auth_client.cancel_order(order['id']) return 'keep' else: return 'abandon' else: return 'abandon' else: if current_order_price > self.last_buy: return 'keep' else: return 'abandon' else: return 'abandon' else: return 'keep' def check_existing_buys(self, current_order_price, current_order_size, vol_measure): fees = 0.0025 * (current_order_price * current_order_size) current_plus_fees = current_order_price + fees new_average = (self.buy_tracker + current_order_price * current_order_size + fees) / (self.num_buys + current_order_size) if len(self.buys) > 0: if new_average < self.av_sell: if self.num_sells > 0: for buy in self.buys: order = self.auth_client.get_order(buy) order_plus_fees = float( order['price']) + 0.0025 * float( order['price']) * float(order['size']) if 'message' in order.keys(): self.buys.remove(buy) return 'keep' else: if self.av_sell > order_plus_fees: if order_plus_fees > current_plus_fees + vol_measure: self.buys.remove(buy) self.auth_client.cancel_order(order['id']) return 'keep' else: return 'abandon' else: return 'abandon' else: if current_order_price < self.last_sell: return 'keep' else: return 'abandon' else: return 'abandon' else: return 'keep' def execute_volume_strategy(self, number_measures, length_measures, order_book_skim, base_size, volatility_interval, num_volatility_measures, vol_confidence, run_minutes): t_end = time.time() + 60 * run_minutes while time.time() < t_end: print('time remaining', t_end - time.time()) # # while True: vol_measure = self.check_volatility(volatility_interval, num_volatility_measures) # accounts = self.auth_client.get_accounts() # balance = 0 # for account in accounts: # if account['currency'] == self.product: # balance = account['balance'] # print('balance', balance) ticker = float( self.public_client.get_product_ticker(self.product)['price']) bid_intervals, bid_depths_intervals, ask_intervals, ask_depths_intervals = self.get_order_info( ticker, number_measures, length_measures, order_book_skim) while check_order_info(bid_intervals, bid_depths_intervals, ask_intervals, ask_depths_intervals) == False: time.sleep(10) bid_intervals, bid_depths_intervals, ask_intervals, ask_depths_intervals = self.get_order_info( ticker, number_measures, length_measures, order_book_skim) ticker = float( self.public_client.get_product_ticker(self.product)['price']) self.ticker_tracker.append(ticker) self.check_volatility(volatility_interval, num_volatility_measures) decision = make_trade_decision(ticker, bid_intervals, bid_depths_intervals, ask_intervals, ask_depths_intervals, vol_measure, vol_confidence, base_size, self.num_buys, self.num_sells, self.av_buy, self.av_sell) if decision[0] == 'buy': place_decision = self.check_existing_buys( float(decision[1]), float(decision[2]), vol_measure) if place_decision == 'keep': print('Placing buy order...') print('price', decision[1], 'size', decision[2]) buy = self.auth_client.buy(price=decision[1], size=decision[2], product_id=self.product) self.last_buy = float(decision[1]) self.track_performance('buy', buy) time.sleep(10) if place_decision == 'abandon': 'Waiting on existing trades' elif decision[0] == 'sell': place_decision = self.check_existing_sells( float(decision[1]), float(decision[2]), vol_measure) if place_decision == 'keep': print('Placing sell order...') print('price', decision[1], 'size', decision[2]) sell = self.auth_client.sell(price=decision[1], size=decision[2], product_id=self.product) self.last_sell = float(decision[1]) self.track_performance('sell', sell) time.sleep(10) if place_decision == 'abandon': 'Waiting on existing trades' elif decision[0] == 'hold': print('Holding...') else: print('Problem...') self.evaluate_performance() print('test complete') print()
class OrderBook(WebsocketClient): def __init__(self, product_id='BTC-USD', log_to=None, autoreconnect=True, max_retries=3): super(OrderBook, self).__init__(products=[product_id]) self.channels = ['full'] self._asks = RBTree() self._bids = RBTree() self._client = PublicClient() self._sequence = -1 self._log_to = log_to self._retries = 0 self._max_retries = max_retries self._autoreconnect = autoreconnect self._is_ready = False if self._log_to: assert hasattr(self._log_to, 'write') self._current_ticker = None @property def product_id(self): ''' Currently OrderBook only supports a single product even though it is stored as a list of products. ''' return self.products[0] def is_ready(self): return self._is_ready def on_open(self): self._sequence = -1 self._retries = 0 print("-- Subscribed to OrderBook! --\n") def on_close(self): print("\n-- OrderBook Socket Closed! --") self._is_ready = False if not self.ws.sock or not self.ws.sock.connected and self._autoreconnect: self._sequence = -1 if self._retries < self._max_retries: print('-- OrderBook Reconnecting... --') self._retries += 1 self.start() else: print('-- Could not reconnect, stopping... --') def reset_book(self): self._is_ready = False self._asks = RBTree() self._bids = RBTree() res = self._client.get_product_order_book(product_id=self.product_id, level=3) for bid in res['bids']: self.add({ 'id': bid[2], 'side': 'buy', 'price': Decimal(bid[0]), 'size': Decimal(bid[1]) }) for ask in res['asks']: self.add({ 'id': ask[2], 'side': 'sell', 'price': Decimal(ask[0]), 'size': Decimal(ask[1]) }) print("\n-- OrderBook Data Initialized --") self._is_ready = True self._sequence = res['sequence'] def on_message(self, message): if self._log_to: pickle.dump(message, self._log_to) if 'sequence' not in message: return sequence = message['sequence'] if self._sequence == -1: print("\n-- Initializing OrderBook --") self.reset_book() return if sequence <= self._sequence: # ignore older messages (e.g. before order book initialization from getProductOrderBook) return elif sequence > self._sequence + 1: self.on_sequence_gap(self._sequence, sequence) return msg_type = message['type'] if msg_type == 'open': self.add(message) elif msg_type == 'done' and 'price' in message: self.remove(message) elif msg_type == 'match': self.match(message) self._current_ticker = message elif msg_type == 'change': self.change(message) self._sequence = sequence def on_error(self, ws, e): super(OrderBook, self).on_error(ws, e) if not ws.sock or not ws.sock.connected: self._sequence = -1 self._is_ready = False if self._retries < self._max_retries: print('-- OrderBook Disconnected, reconnecting... --') self._retries += 1 self.start() else: print('-- Could not reconnect, stopping... --') def on_sequence_gap(self, gap_start, gap_end): self._sequence = -1 self.reset_book() print('-- Error: messages missing, re-initializing book. --'.format( gap_start, gap_end, self._sequence)) def add(self, order): order = { 'id': order.get('order_id') or order['id'], 'side': order['side'], 'price': Decimal(order['price']), 'size': Decimal(order.get('size') or order['remaining_size']) } if order['side'] == 'buy': bids = self.get_bids(order['price']) if bids is None: bids = [order] else: bids.append(order) self.set_bids(order['price'], bids) else: asks = self.get_asks(order['price']) if asks is None: asks = [order] else: asks.append(order) self.set_asks(order['price'], asks) def remove(self, order): price = Decimal(order['price']) if order['side'] == 'buy': bids = self.get_bids(price) if bids is not None: bids = [o for o in bids if o['id'] != order['order_id']] if len(bids) > 0: self.set_bids(price, bids) else: self.remove_bids(price) else: asks = self.get_asks(price) if asks is not None: asks = [o for o in asks if o['id'] != order['order_id']] if len(asks) > 0: self.set_asks(price, asks) else: self.remove_asks(price) def match(self, order): size = Decimal(order['size']) price = Decimal(order['price']) if order['side'] == 'buy': bids = self.get_bids(price) if not bids: return assert bids[0]['id'] == order['maker_order_id'] if bids[0]['size'] == size: self.set_bids(price, bids[1:]) else: bids[0]['size'] -= size self.set_bids(price, bids) else: asks = self.get_asks(price) if not asks: return assert asks[0]['id'] == order['maker_order_id'] if asks[0]['size'] == size: self.set_asks(price, asks[1:]) else: asks[0]['size'] -= size self.set_asks(price, asks) def change(self, order): try: new_size = Decimal(order['new_size']) except KeyError: return try: price = Decimal(order['price']) except KeyError: return if order['side'] == 'buy': bids = self.get_bids(price) if bids is None or not any(o['id'] == order['order_id'] for o in bids): return index = [b['id'] for b in bids].index(order['order_id']) bids[index]['size'] = new_size self.set_bids(price, bids) else: asks = self.get_asks(price) if asks is None or not any(o['id'] == order['order_id'] for o in asks): return index = [a['id'] for a in asks].index(order['order_id']) asks[index]['size'] = new_size self.set_asks(price, asks) tree = self._asks if order['side'] == 'sell' else self._bids node = tree.get(price) if node is None or not any(o['id'] == order['order_id'] for o in node): return def get_current_ticker(self): return self._current_ticker def get_current_book(self): result = { 'sequence': self._sequence, 'asks': [], 'bids': [], } for ask in self._asks: try: # There can be a race condition here, where a price point is removed # between these two ops this_ask = self._asks[ask] except KeyError: continue for order in this_ask: result['asks'].append( [order['price'], order['size'], order['id']]) for bid in self._bids: try: # There can be a race condition here, where a price point is removed # between these two ops this_bid = self._bids[bid] except KeyError: continue for order in this_bid: result['bids'].append( [order['price'], order['size'], order['id']]) return result def get_ask(self): return self._asks.min_key() def get_asks(self, price): return self._asks.get(price) def remove_asks(self, price): self._asks.remove(price) def set_asks(self, price, asks): self._asks.insert(price, asks) def get_bid(self): return self._bids.max_key() def get_bids(self, price): return self._bids.get(price) def remove_bids(self, price): self._bids.remove(price) def set_bids(self, price, bids): self._bids.insert(price, bids)
class OrderBook(WebsocketClient): def __init__(self, product_id='BTC-USD', log_to=None): super(OrderBook, self).__init__(products=product_id) self._asks = RBTree() self._bids = RBTree() self._client = PublicClient() self._sequence = -1 self._log_to = log_to if self._log_to: assert hasattr(self._log_to, 'write') self._current_ticker = None @property def product_id(self): ''' Currently OrderBook only supports a single product even though it is stored as a list of products. ''' return self.products[0] def on_open(self): self._sequence = -1 print("-- Subscribed to OrderBook! --\n") def on_close(self): print("\n-- OrderBook Socket Closed! --") def reset_book(self): self._asks = RBTree() self._bids = RBTree() res = self._client.get_product_order_book( product_id=self.product_id, level=3) for bid in res['bids']: self.add({ 'id': bid[2], 'side': 'buy', 'price': Decimal(bid[0]), 'size': Decimal(bid[1]) }) for ask in res['asks']: self.add({ 'id': ask[2], 'side': 'sell', 'price': Decimal(ask[0]), 'size': Decimal(ask[1]) }) self._sequence = res['sequence'] def on_message(self, message): if self._log_to: pickle.dump(message, self._log_to) sequence = message['sequence'] if self._sequence == -1: self.reset_book() return if sequence <= self._sequence: # ignore older messages (e.g. before order book initialization from getProductOrderBook) return elif sequence > self._sequence + 1: self.on_sequence_gap(self._sequence, sequence) return msg_type = message['type'] if msg_type == 'open': self.add(message) elif msg_type == 'done' and 'price' in message: self.remove(message) elif msg_type == 'match': self.match(message) self._current_ticker = message elif msg_type == 'change': self.change(message) self._sequence = sequence def on_sequence_gap(self, gap_start, gap_end): self.reset_book() print('Error: messages missing ({} - {}). Re-initializing book at sequence.'.format( gap_start, gap_end, self._sequence)) def add(self, order): order = { 'id': order.get('order_id') or order['id'], 'side': order['side'], 'price': Decimal(order['price']), 'size': Decimal(order.get('size') or order['remaining_size']) } if order['side'] == 'buy': bids = self.get_bids(order['price']) if bids is None: bids = collections.OrderedDict() bids[order['id']] = order self.set_bids(order['price'], bids) else: asks = self.get_asks(order['price']) if asks is None: asks = collections.OrderedDict() asks[order['id']] = order self.set_asks(order['price'], asks) def remove(self, order): price = Decimal(order['price']) if order['side'] == 'buy': bids = self.get_bids(price) if bids is not None: if order['order_id'] in bids: del bids[order['order_id']] if len(bids) > 0: self.set_bids(price, bids) else: self.remove_bids(price) else: asks = self.get_asks(price) if asks is not None: if order['order_id'] in asks: del asks[order['order_id']] if len(asks) > 0: self.set_asks(price, asks) else: self.remove_asks(price) def match(self, order): size = Decimal(order['size']) price = Decimal(order['price']) if order['side'] == 'buy': bids = self.get_bids(price) if not bids: return top_order = bids.items()[0] assert top_order[1]['id'] == order['maker_order_id'] if top_order[1]['size'] == size: del bids[order['maker_order_id']] self.set_bids(price, bids) else: top_order[1]['size'] -= size self.set_bids(price, bids) else: asks = self.get_asks(price) if not asks: return top_order = asks.items()[0] assert top_order[1]['id'] == order['maker_order_id'] if top_order[1]['size'] == size: del asks[order['maker_order_id']] self.set_asks(price, asks) else: top_order[1]['size'] -= size self.set_asks(price, asks) def change(self, order): try: new_size = Decimal(order['new_size']) except KeyError: return try: price = Decimal(order['price']) except KeyError: return if order['side'] == 'buy': bids = self.get_bids(price) if bids is None or order['order_id'] not in bids: return bids[order['order_id']]['size'] = new_size self.set_bids(price, bids) else: asks = self.get_asks(price) if asks is None or order['order_id'] not in asks: return asks[order['order_id']]['size'] = new_size self.set_asks(price, asks) def get_current_ticker(self): return self._current_ticker def get_current_book(self): result = { 'sequence': self._sequence, 'asks': [], 'bids': [], } for ask in self._asks: try: # There can be a race condition here, where a price point is removed # between these two ops this_ask = self._asks[ask] except KeyError: continue for order in this_ask: result['asks'].append( [order['price'], order['size'], order['id']]) for bid in self._bids: try: # There can be a race condition here, where a price point is removed # between these two ops this_bid = self._bids[bid] except KeyError: continue for order in this_bid: result['bids'].append( [order['price'], order['size'], order['id']]) return result def get_ask(self): return self._asks.min_key() def get_asks(self, price): return self._asks.get(price) def remove_asks(self, price): self._asks.remove(price) def set_asks(self, price, asks): self._asks.insert(price, asks) def get_bid(self): return self._bids.max_key() def get_bids(self, price): return self._bids.get(price) def remove_bids(self, price): self._bids.remove(price) def set_bids(self, price, bids): self._bids.insert(price, bids)
from gdax.public_client import PublicClient client = PublicClient() def get_quotes(ticker): result = (client.get_product_ticker(ticker)) return result if __name__ == "__main__": get_quotes('BTC-USD')
class OrderBook(WebsocketClient): def __init__(self, product_id='BTC-USD'): super(OrderBook, self).__init__(products=product_id) self._asks = RBTree() self._bids = RBTree() self._client = PublicClient(product_id=product_id) self._sequence = -1 def on_message(self, message): sequence = message['sequence'] if self._sequence == -1: self._asks = RBTree() self._bids = RBTree() res = self._client.get_product_order_book(level=3) for bid in res['bids']: self.add({ 'id': bid[2], 'side': 'buy', 'price': Decimal(bid[0]), 'size': Decimal(bid[1]) }) for ask in res['asks']: self.add({ 'id': ask[2], 'side': 'sell', 'price': Decimal(ask[0]), 'size': Decimal(ask[1]) }) self._sequence = res['sequence'] if sequence <= self._sequence: # ignore older messages (e.g. before order book initialization from getProductOrderBook) return elif sequence > self._sequence + 1: print('Error: messages missing ({} - {}). Re-initializing websocket.'.format(sequence, self._sequence)) self.close() self.start() return # print(message) msg_type = message['type'] if msg_type == 'open': self.add(message) elif msg_type == 'done' and 'price' in message: self.remove(message) elif msg_type == 'match': self.match(message) elif msg_type == 'change': self.change(message) self._sequence = sequence # bid = self.get_bid() # bids = self.get_bids(bid) # bid_depth = sum([b['size'] for b in bids]) # ask = self.get_ask() # asks = self.get_asks(ask) # ask_depth = sum([a['size'] for a in asks]) # print('bid: %f @ %f - ask: %f @ %f' % (bid_depth, bid, ask_depth, ask)) def add(self, order): order = { 'id': order.get('order_id') or order['id'], 'side': order['side'], 'price': Decimal(order['price']), 'size': Decimal(order.get('size') or order['remaining_size']) } if order['side'] == 'buy': bids = self.get_bids(order['price']) if bids is None: bids = [order] else: bids.append(order) self.set_bids(order['price'], bids) else: asks = self.get_asks(order['price']) if asks is None: asks = [order] else: asks.append(order) self.set_asks(order['price'], asks) def remove(self, order): price = Decimal(order['price']) if order['side'] == 'buy': bids = self.get_bids(price) if bids is not None: bids = [o for o in bids if o['id'] != order['order_id']] if len(bids) > 0: self.set_bids(price, bids) else: self.remove_bids(price) else: asks = self.get_asks(price) if asks is not None: asks = [o for o in asks if o['id'] != order['order_id']] if len(asks) > 0: self.set_asks(price, asks) else: self.remove_asks(price) def match(self, order): size = Decimal(order['size']) price = Decimal(order['price']) if order['side'] == 'buy': bids = self.get_bids(price) if not bids: return assert bids[0]['id'] == order['maker_order_id'] if bids[0]['size'] == size: self.set_bids(price, bids[1:]) else: bids[0]['size'] -= size self.set_bids(price, bids) else: asks = self.get_asks(price) if not asks: return assert asks[0]['id'] == order['maker_order_id'] if asks[0]['size'] == size: self.set_asks(price, asks[1:]) else: asks[0]['size'] -= size self.set_asks(price, asks) def change(self, order): new_size = Decimal(order['new_size']) price = Decimal(order['price']) if order['side'] == 'buy': bids = self.get_bids(price) if bids is None or not any(o['id'] == order['order_id'] for o in bids): return index = map(itemgetter('id'), bids).index(order['order_id']) bids[index]['size'] = new_size self.set_bids(price, bids) else: asks = self.get_asks(price) if asks is None or not any(o['id'] == order['order_id'] for o in asks): return index = map(itemgetter('id'), asks).index(order['order_id']) asks[index]['size'] = new_size self.set_asks(price, asks) tree = self._asks if order['side'] == 'sell' else self._bids node = tree.get(price) if node is None or not any(o['id'] == order['order_id'] for o in node): return def get_current_book(self): result = { 'sequence': self._sequence, 'asks': [], 'bids': [], } for ask in self._asks: try: # There can be a race condition here, where a price point is removed # between these two ops this_ask = self._asks[ask] except KeyError: continue for order in this_ask: result['asks'].append([order['price'], order['size'], order['id']]) for bid in self._bids: try: # There can be a race condition here, where a price point is removed # between these two ops this_bid = self._bids[bid] except KeyError: continue for order in this_bid: result['bids'].append([order['price'], order['size'], order['id']]) return result def get_ask(self): return self._asks.min_key() def get_asks(self, price): return self._asks.get(price) def remove_asks(self, price): self._asks.remove(price) def set_asks(self, price, asks): self._asks.insert(price, asks) def get_bid(self): return self._bids.max_key() def get_bids(self, price): return self._bids.get(price) def remove_bids(self, price): self._bids.remove(price) def set_bids(self, price, bids): self._bids.insert(price, bids)