def buyer_strategy(order_book, open_orders, spreads): time.sleep(10) while True: time.sleep(0.001) if not open_orders.open_bid_order_id: open_bid_price = order_book.bids.price_tree.max_key() - spreads.bid_spread if 0.01 * float(open_bid_price) < float(open_orders.accounts['USD']['available']): order = {'size': '0.01', 'price': str(open_bid_price), 'side': 'buy', 'product_id': 'BTC-USD', 'post_only': True} response = requests.post(exchange_api_url + 'orders', json=order, auth=exchange_auth) try: response = response.json() except ValueError: file_logger.error('Unhandled response: {0}'.format(pformat(response))) if 'status' in response and response['status'] == 'pending': open_orders.open_bid_order_id = response['id'] open_orders.open_bid_price = open_bid_price open_orders.open_bid_rejections = Decimal('0.0') file_logger.info('new bid @ {0}'.format(open_bid_price)) elif 'status' in response and response['status'] == 'rejected': open_orders.open_bid_order_id = None open_orders.open_bid_price = None open_orders.open_bid_rejections += Decimal('0.04') file_logger.warn('rejected: new bid @ {0}'.format(open_bid_price)) elif 'message' in response and response['message'] == 'Insufficient funds': open_orders.open_bid_order_id = None open_orders.open_bid_price = None file_logger.warn('Insufficient USD') elif 'message' in response and response['message'] == 'request timestamp expired': open_orders.open_bid_order_id = None open_orders.open_bid_price = None file_logger.warn('Request timestamp expired') else: file_logger.error('Unhandled response: {0}'.format(pformat(response))) continue if open_orders.open_bid_order_id and not open_orders.open_bid_cancelled: bid_too_far_out = open_orders.open_bid_price < (order_book.bids.price_tree.max_key() - spreads.bid_too_far_adjustment_spread) bid_too_close = open_orders.open_bid_price > (order_book.bids.price_tree.max_key() - spreads.bid_too_close_adjustment_spread) cancel_bid = bid_too_far_out or bid_too_close if cancel_bid: if bid_too_far_out: file_logger.info('CANCEL: open bid {0} too far from best bid: {1} spread: {2}'.format( open_orders.open_bid_price, order_book.bids.price_tree.max_key(), order_book.bids.price_tree.max_key() - open_orders.open_bid_price)) if bid_too_close: file_logger.info('CANCEL: open bid {0} too close to best bid: {1} spread: {2}'.format( open_orders.open_bid_price, order_book.bids.price_tree.max_key(), order_book.bids.price_tree.max_key() - open_orders.open_bid_price)) open_orders.cancel('bid') continue
def market_maker_strategy(open_orders, order_book, spreads): time.sleep(10) open_orders.get_open_orders() open_orders.cancel_all() while True: time.sleep(0.005) if order_book.asks.price_tree.min_key() - order_book.bids.price_tree.max_key() < 0: file_logger.warn('Negative spread: {0}'.format( order_book.asks.price_tree.min_key() - order_book.bids.price_tree.max_key())) continue if not open_orders.open_bid_order_id: open_bid_price = order_book.asks.price_tree.min_key() - spreads.bid_spread - open_orders.open_bid_rejections if 0.01 * float(open_bid_price) < float(open_orders.accounts['USD']['available']): order = {'size': '0.01', 'price': str(open_bid_price), 'side': 'buy', 'product_id': 'BTC-USD', 'post_only': True} response = requests.post(exchange_api_url + 'orders', json=order, auth=exchange_auth) if 'status' in response.json() and response.json()['status'] == 'pending': open_orders.open_bid_order_id = response.json()['id'] open_orders.open_bid_price = open_bid_price open_orders.open_bid_rejections = Decimal('0.0') file_logger.info('new bid @ {0}'.format(open_bid_price)) elif 'status' in response.json() and response.json()['status'] == 'rejected': open_orders.open_bid_order_id = None open_orders.open_bid_price = None open_orders.open_bid_rejections += Decimal('0.04') file_logger.warn('rejected: new bid @ {0}'.format(open_bid_price)) elif 'message' in response.json() and response.json()['message'] == 'Insufficient funds': open_orders.open_bid_order_id = None open_orders.open_bid_price = None file_logger.warn('Insufficient USD') else: file_logger.error('Unhandled response: {0}'.format(pformat(response.json()))) continue if not open_orders.open_ask_order_id: open_ask_price = order_book.bids.price_tree.max_key() + spreads.ask_spread + open_orders.open_ask_rejections if 0.01 < float(open_orders.accounts['BTC']['available']): order = {'size': '0.01', 'price': str(open_ask_price), 'side': 'sell', 'product_id': 'BTC-USD', 'post_only': True} response = requests.post(exchange_api_url + 'orders', json=order, auth=exchange_auth) if 'status' in response.json() and response.json()['status'] == 'pending': open_orders.open_ask_order_id = response.json()['id'] open_orders.open_ask_price = open_ask_price file_logger.info('new ask @ {0}'.format(open_ask_price)) open_orders.open_ask_rejections = Decimal('0.0') elif 'status' in response.json() and response.json()['status'] == 'rejected': open_orders.open_ask_order_id = None open_orders.open_ask_price = None open_orders.open_ask_rejections += Decimal('0.04') file_logger.warn('rejected: new ask @ {0}'.format(open_ask_price)) elif 'message' in response.json() and response.json()['message'] == 'Insufficient funds': open_orders.open_ask_order_id = None open_orders.open_ask_price = None file_logger.warn('Insufficient BTC') else: file_logger.error('Unhandled response: {0}'.format(pformat(response.json()))) continue if open_orders.open_bid_order_id and not open_orders.open_bid_cancelled: bid_too_far_out = open_orders.open_bid_price < (order_book.asks.price_tree.min_key() - spreads.bid_too_far_adjustment_spread) bid_too_close = open_orders.open_bid_price > (order_book.bids.price_tree.max_key() - spreads.bid_too_close_adjustment_spread) cancel_bid = bid_too_far_out or bid_too_close if cancel_bid: if bid_too_far_out: file_logger.info('CANCEL: open bid {0} too far from best ask: {1} spread: {2}'.format( open_orders.open_bid_price, order_book.asks.price_tree.min_key(), open_orders.open_bid_price - order_book.asks.price_tree.min_key())) if bid_too_close: file_logger.info('CANCEL: open bid {0} too close to best bid: {1} spread: {2}'.format( open_orders.open_bid_price, order_book.bids.price_tree.max_key(), open_orders.open_bid_price - order_book.bids.price_tree.max_key())) open_orders.cancel('bid') continue if open_orders.open_ask_order_id and not open_orders.open_ask_cancelled: ask_too_far_out = open_orders.open_ask_price > (order_book.bids.price_tree.max_key() + spreads.ask_too_far_adjustment_spread) ask_too_close = open_orders.open_ask_price < (order_book.asks.price_tree.min_key() - spreads.ask_too_close_adjustment_spread) cancel_ask = ask_too_far_out or ask_too_close if cancel_ask: if ask_too_far_out: file_logger.info('CANCEL: open ask {0} too far from best bid: {1} spread: {2}'.format( open_orders.open_ask_price, order_book.bids.price_tree.max_key(), open_orders.open_ask_price - order_book.bids.price_tree.max_key())) if ask_too_close: file_logger.info('CANCEL: open ask {0} too close to best ask: {1} spread: {2}'.format( open_orders.open_ask_price, order_book.asks.price_tree.min_key(), open_orders.open_ask_price - order_book.asks.price_tree.min_key())) open_orders.cancel('ask') continue
def manage_orders(): max_bid = Decimal(order_book.bids.price_tree.max_key()) min_ask = Decimal(order_book.asks.price_tree.min_key()) if min_ask - max_bid < 0: file_logger.warn('Negative spread: {0}'.format(min_ask - max_bid)) return False if command_line: print('Latency: {0:.6f} secs, ' 'Min ask: {1:.2f}, Max bid: {2:.2f}, Spread: {3:.2f}, ' 'Your ask: {4:.2f}, Your bid: {5:.2f}, Your spread: {6:.2f}'.format( ((datetime.now(tzlocal()) - order_book.last_time).microseconds * 1e-6), min_ask, max_bid, min_ask - max_bid, open_orders.float_open_ask_price, open_orders.float_open_bid_price, open_orders.float_open_ask_price - open_orders.float_open_bid_price), end='\r') if not open_orders.open_bid_order_id and not open_orders.insufficient_usd: if open_orders.insufficient_btc: size = 0.1 open_bid_price = Decimal(round(max_bid + Decimal(open_orders.open_bid_rejections), 2)) else: size = 0.01 spreads.bid_spread = Decimal(round((random.randrange(15) + 6) / 100, 2)) open_bid_price = Decimal(round(min_ask - Decimal(spreads.bid_spread) - Decimal(open_orders.open_bid_rejections), 2)) order = {'size': size, 'price': str(open_bid_price), 'side': 'buy', 'product_id': 'BTC-USD', 'post_only': True} response = requests.post(exchange_api_url + 'orders', json=order, auth=exchange_auth) if 'status' in response.json() and response.json()['status'] == 'pending': open_orders.open_bid_order_id = response.json()['id'] open_orders.open_bid_price = open_bid_price open_orders.open_bid_rejections = 0.0 file_logger.info('new bid @ {0}'.format(open_bid_price)) elif 'status' in response.json() and response.json()['status'] == 'rejected': open_orders.open_bid_order_id = None open_orders.open_bid_price = None open_orders.open_bid_rejections += 0.04 file_logger.warn('rejected: new bid @ {0}'.format(open_bid_price)) elif 'message' in response.json() and response.json()['message'] == 'Insufficient funds': open_orders.insufficient_usd = True open_orders.open_bid_order_id = None open_orders.open_bid_price = None file_logger.warn('Insufficient USD') else: file_logger.error('Unhandled response: {0}'.format(pformat(response.json()))) return False return True if not open_orders.open_ask_order_id and not open_orders.insufficient_btc: if open_orders.insufficient_usd: size = 0.10 open_ask_price = Decimal(round(min_ask + Decimal(open_orders.open_ask_rejections), 2)) else: size = 0.01 spreads.ask_spread = Decimal(round((random.randrange(15) + 6) / 100, 2)) open_ask_price = Decimal(round(max_bid + Decimal(spreads.ask_spread) + Decimal(open_orders.open_ask_rejections), 2)) order = {'size': size, 'price': str(open_ask_price), 'side': 'sell', 'product_id': 'BTC-USD', 'post_only': True} response = requests.post(exchange_api_url + 'orders', json=order, auth=exchange_auth) if 'status' in response.json() and response.json()['status'] == 'pending': open_orders.open_ask_order_id = response.json()['id'] open_orders.open_ask_price = open_ask_price file_logger.info('new ask @ {0}'.format(open_ask_price)) open_orders.open_ask_rejections = 0 elif 'status' in response.json() and response.json()['status'] == 'rejected': open_orders.open_ask_order_id = None open_orders.open_ask_price = None open_orders.open_ask_rejections += 0.04 file_logger.warn('rejected: new ask @ {0}'.format(open_ask_price)) elif 'message' in response.json() and response.json()['message'] == 'Insufficient funds': open_orders.insufficient_btc = True open_orders.open_ask_order_id = None open_orders.open_ask_price = None file_logger.warn('Insufficient BTC') else: file_logger.error('Unhandled response: {0}'.format(pformat(response.json()))) return False return True if open_orders.open_bid_order_id and Decimal(open_orders.open_bid_price) < round( min_ask - Decimal(spreads.bid_adjustment_spread), 2): file_logger.info('CANCEL: open bid {0} threshold {1} diff {2}'.format( Decimal(open_orders.open_bid_price), round(min_ask - Decimal(spreads.bid_adjustment_spread), 2), Decimal(open_orders.open_bid_price) - round(min_ask - Decimal(spreads.bid_adjustment_spread), 2))) open_orders.cancel('bid') return True if open_orders.open_ask_order_id and Decimal(open_orders.open_ask_price) > round( max_bid + Decimal(spreads.ask_adjustment_spread), 2): file_logger.info('CANCEL: open ask {0} threshold {1} diff {2}'.format( Decimal(open_orders.open_ask_price), round(max_bid - Decimal(spreads.ask_adjustment_spread), 2), Decimal(open_orders.open_ask_price) - round(max_bid + Decimal(spreads.ask_adjustment_spread), 2))) open_orders.cancel('ask') return True return True