Exemple #1
0
    def on_message(self, message):
        super(OrderBookConsole, self).on_message(message)

        self.message_count += 1

        # Calculate newest bid-ask spread
        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])

        # Update Best Bid and Ask if there is a change
        if self._bid == bid and self._ask == ask and bid > self.bid_theo and ask < self.ask_theo:  # and self._bid_depth == bid_depth and self._ask_depth == ask_depth:
            # If there are no changes to the bid-ask spread since the last update, no need to print
            pass
        else:
            # If there are differences, update the cache
            self._bid = float(bid)
            self._ask = float(ask)
            self._bid_depth = bid_depth
            self._ask_depth = ask_depth
            self._spread = float(ask - bid)
            #logger.debug('Bid/Ask Updated - Bid: {:.3f} @ {:.2f}\tAsk: {:.3f} @ {:.2f}\tSpread: {:.2f}'.format(bid_depth, bid, ask_depth, ask, self._spread))

            # See if we need to place a trade
            self.on_bidask_update()

        # See if there is a trade in websocket data
        if message['type'] == 'match':
            self.trade_price = message['price']
            self.trade_size = message['size']
            self.trade_side = message['side']
            logger.debug('Trade: {}: {:.3f} @ {:.2f}'.format(
                self.trade_side.title(), float(self.trade_size),
                float(self.trade_price)))

        # See if something private came in the message (authenticated data)
        if 'user_id' in message:
            # We received a private message. Please log it.
            logger.debug(
                "***Private Message Received from Websocket***: user_id - " +
                message['user_id'] + " found in message.")
            message = self.auth_client.clean_message(message)
            logger.debug(message)

            if message['type'] == 'received':
                # A valid order has been received and is now active. This message is emitted for every single valid order as soon as the matching engine receives it whether it fills immediately or not.
                # The received message does not indicate a resting order on the order book. It simply indicates a new incoming order which as been accepted by the matching engine for processing.
                # Received orders may cause match message to follow if they are able to begin being filled (taker behavior).
                # Self-trade prevention may also trigger change messages to follow if the order size needs to be adjusted.
                # Orders which are not fully filled or canceled due to self-trade prevention result in an open message and become resting orders on the order book.
                # Market orders (indicated by the order_type field) may have an optional funds field which indicates how much quote currency will be used to buy or sell.
                # For example, a funds field of 100.00 for the BTC-USD product would indicate a purchase of up to 100.00 USD worth of bitcoin.

                # {
                #     "type": "received",
                #     "time": "2014-11-07T08:19:27.028459Z",
                #     "product_id": "BTC-USD",
                #     "sequence": 10,
                #     "order_id": "d50ec984-77a8-460a-b958-66f114b0de9b",
                #     "size": "1.34",
                #     "price": "502.1",
                #     "side": "buy",
                #     "order_type": "limit"
                # }

                if message['order_type'] == 'limit':
                    logger.debug("***Limit Order Place was Acknowledged***")
                    # Send the order to the orderbook
                    self.auth_client.add_my_order_ack(message)
                else:
                    logger.critical(
                        "We had a message type 'received' with an order_type other than limit: "
                        + message['order_type'])

            elif message['type'] == 'open':
                # The order is now open on the order book. This message will only be sent for orders which are not fully filled immediately.
                # remaining_size will indicate how much of the order is unfilled and going on the book.

                # {
                #     "type": "open",
                #     "time": "2014-11-07T08:19:27.028459Z",
                #     "product_id": "BTC-USD",
                #     "sequence": 10,
                #     "order_id": "d50ec984-77a8-460a-b958-66f114b0de9b",
                #     "price": "200.2",
                #     "remaining_size": "1.00",
                #     "side": "sell"
                # }

                logger.debug("***Limit Order " + message['order_id'] +
                             " is now open on the order book. ")
                logger.debug("Remaining Size: " + message['remaining_size'])

            elif message['type'] == 'done':
                # The order is no longer on the order book.
                # Sent for all orders for which there was a received message.
                # This message can result from an order being canceled or filled.
                # There will be no more messages for this order_id after a done message.
                # remaining_size indicates how much of the order went unfilled; this will be 0 for filled orders.
                # market orders will not have a remaining_size or price field as they are never on the open order book at a given price.

                # {
                #     "type": "done",
                #     "time": "2014-11-07T08:19:27.028459Z",
                #     "product_id": "BTC-USD",
                #     "sequence": 10,
                #     "price": "200.2",
                #     "order_id": "d50ec984-77a8-460a-b958-66f114b0de9b",
                #     "reason": "filled", // or "canceled"
                #     "side": "sell",
                #     "remaining_size": "0"
                # }

                if message['reason'] == 'canceled':
                    # Order canceled  received
                    logger.debug("***Cancel Order Message Acknowledged.***")
                    self.auth_client.process_cancel_message(message)

                elif message['reason'] == 'filled':
                    # Fill Message done
                    # Match message comes in first.
                    logger.debug(
                        "Message Type == 'done' with a reason of 'filled'")

                else:
                    logger.critical(
                        "Message Type == 'done' with a new message reason.")

            elif message['type'] == 'match':
                # We received a fill message
                if message['side'] == 'buy':
                    if len(self.auth_client.my_buy_orders) > 0:
                        if message[
                                'maker_order_id'] == self.auth_client.my_buy_orders[
                                    0]['id']:
                            logger.warning("***Received a Buy Fill Message***")
                            self.auth_client.process_fill_message(message)
                            if self.fill_notifications:
                                logger.debug("Sending Slack Notification:")
                                slack.send_message_to_slack(
                                    "{}: {} {:.4f} @ {:.2f} {}. NP: {:.0f} PnL: {:.2f}"
                                    .format(self.strategy_name,
                                            message['side'].title(),
                                            float(message['size']),
                                            float(message['price']),
                                            str(datetime.now().time()),
                                            self.auth_client.net_position,
                                            self.get_pnl()))
                elif message['side'] == 'sell':
                    if len(self.auth_client.my_sell_orders) > 0:
                        if message[
                                'maker_order_id'] == self.auth_client.my_sell_orders[
                                    0]['id']:
                            logger.warning(
                                "****Received a Sell Fill Message***")
                            self.auth_client.process_fill_message(message)
                            if self.fill_notifications:
                                logger.debug("Sending Slack Notification:")
                                slack.send_message_to_slack(
                                    "{}: {} {:.4f} @ {:.2f} {}. NP: {:.0f} PnL: {:.2f}"
                                    .format(self.strategy_name,
                                            message['side'].title(),
                                            float(message['size']),
                                            float(message['price']),
                                            str(datetime.now().time()),
                                            self.auth_client.net_position,
                                            self.get_pnl()))
                else:
                    logger.critical(
                        "We received a message that had something other than a buy or sell for the side..."
                    )

            elif message['type'] == 'change':
                # we received a change messages
                logger.critical(
                    "Received a Change Message... We currently aren't doing anything with these, but logging them."
                )
            else:
                logger.critical(
                    "Received a Message Type that we have not yet coded for. Message Type: "
                    + message['type'])
Exemple #2
0
                        order_book.short_std, order_book.long_std, long_sma,
                        short_sma))

        else:
            logger.info("Still Initializing. MA Count: " + str(my_MA.count) +
                        "")
            logger.info(
                'SMA: {:.2f}\tBid Theo: {:.2f}\tAsk Theo: {:.2f}'.format(
                    long_sma, order_book.bid_theo, order_book.ask_theo))

    time.sleep(1)

    if order_book.stop and reset_not_triggered:
        reset_not_triggered = False
        if strategy_settings.get('connection_notifications'):
            slack.send_message_to_slack(
                "Connection has stopped. Restarting. Stop = True!")
            logger.error("Connection has stopped. Restarting. Stop = True!")

        # Copy Critical Info from dead order book
        buy_levels = order_book.auth_client.buy_levels
        sell_levels = order_book.auth_client.sell_levels
        real_position = order_book.auth_client.real_position
        net_position = order_book.auth_client.net_position
        current_pnl = order_book.auth_client.pnl
        current_bids = order_book.auth_client.my_buy_orders
        current_asks = order_book.auth_client.my_sell_orders
        order_book.close()

        # Populate New Order book with previously saved critical info.
        order_book = OrderBookConsole(
            product_id=strategy_settings.get('product_id'),
Exemple #3
0
    def on_message(self, message):
        super(OrderBookConsole, self).on_message(message)

        self.message_count += 1
        logger.debug("Message Count: " + str(self.message_count))

        # Calculate newest bid-ask spread
        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])

        # Update Best Bid and Ask if there is a change
        if self._bid == bid and self._ask == ask and self._bid_depth == bid_depth and self._ask_depth == ask_depth:
            # If there are no changes to the bid-ask spread since the last update, no need to print
            pass
        else:
            # If there are differences, update the cache
            self._bid = bid
            self._ask = ask
            self._bid_depth = bid_depth
            self._ask_depth = ask_depth
            self._spread = ask - bid
            logger.debug(
                'bid: {:.3f} @ {:.2f}\task: {:.3f} @ {:.2f}\tspread: {:.2f}'.
                format(bid_depth, bid, ask_depth, ask, self._spread))

            # Since the bid/ask changed. Let's see if we need to place a trade.
            if self.valid_sma:
                # Update Theos
                self.net_position = self.buy_levels - self.sell_levels

                if self.net_position == 0:
                    # We are flat
                    self.bid_theo = self.sma - self.buy_initial_offset
                    self.ask_theo = self.sma + self.sell_initial_offset

                elif self.net_position > 0:
                    # We are long
                    if self.net_position > 2:
                        self.bid_theo = self.sma - (
                            self.buy_initial_offset *
                            abs(self.net_position + 1)) - (
                                self.buy_additional_offset *
                                ((self.net_position + 1) *
                                 (self.net_position + 1)))
                        self.ask_theo = self.sma - (
                            self.buy_initial_offset *
                            abs(self.net_position + 1) *
                            0.75) - (self.buy_additional_offset *
                                     ((self.net_position + 1 - 2) *
                                      (self.net_position + 1 - 2)))

                    else:
                        self.bid_theo = self.sma - self.buy_initial_offset * abs(
                            self.net_position + 1) - (
                                self.buy_additional_offset *
                                ((self.net_position + 1) *
                                 (self.net_position + 1)))
                        self.ask_theo = self.sma

                else:
                    # We are short
                    if self.net_position < -2:
                        self.ask_theo = self.sma + (
                            self.sell_initial_offset *
                            abs(self.net_position - 1)) + (
                                self.sell_additional_offset *
                                ((self.net_position - 1) *
                                 (self.net_position - 1)))
                        self.bid_theo = self.sma + (
                            self.sell_initial_offset *
                            abs(self.net_position - 1) *
                            0.75) + (self.sell_additional_offset *
                                     ((self.net_position - 1 + 2) *
                                      (self.net_position - 1 + 2)))

                    else:
                        self.ask_theo = self.sma + self.sell_initial_offset * abs(
                            self.net_position - 1) + (
                                self.sell_additional_offset *
                                ((self.net_position - 1) *
                                 (self.net_position - 1)))
                        self.bid_theo = self.sma

                logger.debug(
                    'Net Position: {}\tBid Theo: {:.2f}\tAsk Theo: {:.2f}'.
                    format(self.net_position, self.bid_theo, self.ask_theo))

                if ask < self.bid_theo:
                    # We want to place a Buy Order
                    logger.info(
                        "Ask is lower than Bid Theo, we are placing a Buy Order at:"
                        + str(bid) + "\t" + "Ask: " + str(ask) +
                        "\tBid Theo: " + str(self.bid_theo) + "\tSpread: " +
                        str(self._spread))

                    if round(Decimal(self._spread), 2) == self.min_tick:
                        logger.info("Spread: " + str(self._spread))
                        clean_bid = '{:.2f}'.format(bid, 2)
                        logger.info("Order Price: " + clean_bid)
                        order_successful = self.auth_client.place_my_limit_order(
                            side='buy',
                            price=clean_bid,
                            size='{:.3f}'.format(self.order_size))
                        if order_successful:
                            self.buy_levels += 1
                            logger.warning("Buy Levels: " +
                                           str(self.buy_levels))
                            slack.send_message_to_slack(
                                "Placing - Buy {:.3f} @ {}\tSpread: {:.2f}\t{}"
                                .format(self.order_size, clean_bid,
                                        self._spread, str(datetime.now())))
                            self.pnl -= Decimal(bid) * Decimal(self.order_size)

                        else:
                            # Order did not go through... Try again.
                            logger.critical("Order Rejected... Trying again")
                            logger.critical("Market Bid/Ask: " + str(bid) +
                                            " / " + str(ask))

                    else:
                        logger.info("Spread > 0.01: " + str(self._spread))
                        #clean_bid = '{:.2f}'.format(bid + self.min_tick, 2)
                        clean_bid = '{:.2f}'.format(bid, 2)
                        logger.info("Order Price: " + clean_bid)
                        order_successful = self.auth_client.place_my_limit_order(
                            side='buy',
                            price=clean_bid,
                            size='{:.3f}'.format(self.order_size))
                        if order_successful:
                            self.buy_levels += 1
                            logger.warning("Buy Levels: " +
                                           str(self.buy_levels))
                            slack.send_message_to_slack(
                                "Placing - Buy {:.3f} @ {}\tSpread: {:.2f}\t{}"
                                .format(self.order_size, clean_bid,
                                        self._spread, str(datetime.now())))
                            self.pnl -= Decimal(bid) * Decimal(self.order_size)

                        else:
                            # Order did not go through... Try again.
                            logger.critical("Order Rejected... Trying again")
                            logger.critical("Market Bid/Ask: " + str(bid) +
                                            " / " + str(ask))

                if bid > self.ask_theo:
                    # We want to place a Sell Order
                    logger.info(
                        "Bid is Higher than Ask Theo, we are placing a Sell order at:"
                        + str(ask) + "\t" + "Bid: " + str(bid) +
                        "\tAsk Theo: " + str(self.ask_theo) + "\tSpread: " +
                        str(self._spread))

                    if round(Decimal(self._spread), 2) == self.min_tick:
                        logger.info("Spread: " + str(self._spread))
                        clean_ask = '{:.2f}'.format(ask, 2)
                        logger.info("Order Price: " + clean_ask)
                        order_successful = self.auth_client.place_my_limit_order(
                            side='sell',
                            price=clean_ask,
                            size='{:.3f}'.format(self.order_size))
                        if order_successful:
                            self.sell_levels += 1
                            logger.warning("Sell Levels: " +
                                           str(self.sell_levels))
                            slack.send_message_to_slack(
                                "Placing - Sell {:.3f} @ {}\tSpread: {:.2f}\t{}"
                                .format(self.order_size, clean_ask,
                                        self._spread, str(datetime.now())))
                            self.pnl += Decimal(ask) * Decimal(self.order_size)

                        else:
                            # Order did not go through... Try again.
                            logger.critical("Order Rejected... Trying again")
                            logger.critical("Market Bid/Ask: " + str(bid) +
                                            " / " + str(ask))

                    else:
                        logger.info("Spread > 0.01: " + str(self._spread))
                        #clean_ask = '{:.2f}'.format(ask - self.min_tick, 2)
                        clean_ask = '{:.2f}'.format(ask, 2)
                        logger.info("Order Price: " + clean_ask)
                        order_successful = self.auth_client.place_my_limit_order(
                            side='sell',
                            price=(clean_ask),
                            size='{:.3f}'.format(self.order_size))
                        if order_successful:
                            self.sell_levels += 1
                            logger.warning("Sell Levels: " +
                                           str(self.sell_levels))
                            slack.send_message_to_slack(
                                "Placing - Sell {:.3f} @ {}\tSpread: {:.2f}\t{}"
                                .format(self.order_size, clean_ask,
                                        self._spread, str(datetime.now())))
                            self.pnl += Decimal(ask) * Decimal(self.order_size)

                        else:
                            # Order did not go through... Try again
                            logger.critical("Order Rejected... Trying again")
                            logger.critical("Market Bid/Ask: " + str(bid) +
                                            " / " + str(ask))

        # See if there is a trade
        if message['type'] == 'match':
            self.trade_price = message['price']
            self.trade_size = message['size']
            self.trade_side = message['side']
            logger.info('Trade: {}: {:.3f} @ {:.2f}'.format(
                self.trade_side.title(), Decimal(self.trade_size),
                Decimal(self.trade_price)))

        # See if there is something from me
        if 'user_id' in message:
            logger.warning("user_id - " + message['user_id'] +
                           " found in message.")
            for key, value in message.items():
                logger.debug(key + ": " + str(value) + "\n")

            if message['type'] == 'received':
                logger.warning("message_type - " + message['type'] +
                               " found in message.")
                if message['order_type'] == 'limit':
                    # We entered a limit order
                    logger.warning("We've entered a limit order")
                    for key, value in message.items():
                        logger.warning(key + ": " + str(value) + "\n")

                    # Send the order to the orderbook
                    self.auth_client.add_my_order(message)
                else:
                    logger.critical(
                        "We had a message type 'received' with an order_type other than limit: "
                        + message['order_type'])

            if message['type'] == 'match':
                self.auth_client.add_my_fill(message)
                logger.warning("Got a trade. trade_id: " +
                               str(message['trade_id']))
                logger.warning("Sending Slack Notification:")
                logger.warning(message)
                slack.send_message_to_slack(
                    "Filled - {} {:.3f} @ {:.2f} {}".format(
                        message['side'].title(), Decimal(message['size']),
                        Decimal(message['price']), str(datetime.now())))