Ejemplo n.º 1
0
    def _get_best_bid_ask():
        """
        Determine and return best active bid and asks in the order book
        :return: best_bid: best buy price
                 best_ask: best sell price
                 best_ask_order: best bid order object
                 best_bid_order:  best ask order object

        """
        # initial bid and asks unrealistic / out of bound
        best_bid = 0
        best_ask = 999999
        best_ask_order = None
        best_bid_order = None

        # run through the order book, determine best bid and asks
        for fm_id, order in Order.current().items():
            if not order.is_consumed and not order.is_private:
                if order.order_side == OrderSide.BUY and order.price > best_bid:
                    best_bid = order.price
                    best_bid_order = order
                elif order.order_side == OrderSide.SELL and order.price < best_ask:
                    best_ask = order.price
                    best_ask_order = order

        return best_bid, best_ask, best_bid_order, best_ask_order
Ejemplo n.º 2
0
    def _make_market(self, priv_order: Order):
        """
        Implements market-maker functionality

        Public order price determination -
            private order price - Profit margin for buying
            private order price + Profit margin for selling
        """
        self._pending_order = False

        # ensure we don't have an already active/pending order
        for _, order in Order.current().items():
            if order.mine and not order.is_consumed and not order.is_private:
                self._pending_order = True

        # PUBLIC MARKET SIDE ======================================================

        market = self._public_market_id

        if self._role == Role.BUYER:
            price = priv_order.price - PROFIT_MARGIN
            order_side = OrderSide.BUY
        else:
            price = priv_order.price + PROFIT_MARGIN
            order_side = OrderSide.SELL

        # fixed attributes
        units = 1
        order_type = OrderType.LIMIT
        ref = f"Order: {self._sent_order_count} - SM"

        # submit order
        if not self._pending_order and not self._waiting_for_server:
            self._create_new_order(market, price, units, order_side,
                                   order_type, ref)
Ejemplo n.º 3
0
    def received_orders(self, orders: List[Order]):
        # Track best bids/asks for reactive strategy, this is tracked
        # throughout the session in case is_portfolio optimal is called
        current_orders = [o for o in Order.all().values() if o.is_pending]

        for market_id, market_info in sorted(self.markets.items()):
            orders_in_market = []
            security = market_info.item
            for order in current_orders:
                if order.market.fm_id == market_id:
                    orders_in_market.append(order)

            self._best_bid_dict[security] = self._get_best_bid(orders_in_market)
            self._best_ask_dict[security] = self._get_best_ask(orders_in_market)     

        my_orders = [o for o in Order.current().values() if o.mine and o.is_pending]

        # Clear stale orders (based on order depth) when running reative strategy
        if self._reactive_condition and len(my_orders) != 0:
            for o in my_orders:
                if self._find_order_depth(o, current_orders) > 2 and \
                    not self._waiting_for_order:
                        cancel_order = self._make_cancel_order(o)
                        self.send_order(cancel_order)
                        self._waiting_for_order = True

        # Clear order book if there are unmet orders only when the MM strategy is running
        if self._mm_condition() and len(my_orders) != 0:
                self._clear_orders()
Ejemplo n.º 4
0
    def received_orders(self, orders: List[Order]):
        """
        Subscribed to Order book updates
        :param orders: list of order objects
        """
        for order in orders:
            self.inform(order)

            # pending order in private market
            # even if order is partially filled out, it returns 3 entries
            # the buy for x units going through (consumed, not pending)
            # the sell (how many units were sold) (consumed not pending)
            # an order update, with outstanding quantity and price (pending)
            if order.is_private and order.is_pending:
                # if order.is_private and not order.mine: FOR ACTUAL SIMULATION TIMES
                # assign correct role to bot

                if order.order_side == OrderSide.BUY:
                    self._role = Role.BUYER

                elif order.order_side == OrderSide.SELL:
                    self._role = Role.SELLER

                # call strategy based on bot type
                if self._bot_type == BotType.MARKET_MAKER:
                    self._make_market(order)
                elif self._bot_type == BotType.REACTIVE:
                    self._react_to_market(order)

            # during actual simulation add a not order.mine to this
            # if the private order gets cancelled, delete our order from public market
            if order.is_private and order.order_type == OrderType.CANCEL:
                # for some reason, all the order attributes need to be present, so it's not
                # possible to keep track of your old order by reference
                # old order reference only contain the specific attributes we define, everything
                # else is None type
                orders = Order.current()
                for _, o in orders.items():

                    # future proofing, if multiple types of orders in priv and one type expires
                    # only delete the corresponding orders in public
                    if o.mine and not o.is_private and order.order_side == o.order_side\
                            and not self._waiting_for_server:
                        cancel_order = copy.copy(o)
                        cancel_order.ref = f"Cancel {o.ref}"
                        cancel_order.order_type = OrderType.CANCEL
                        self.send_order(cancel_order)
                        self._waiting_for_server = True
                        break

            # if our order gets consumed
            if order.mine and not order.is_private and order.is_consumed:
                self._pending_order = False
Ejemplo n.º 5
0
    def _cancel_my_orders(self):
        """
        Cancels all of my orders in the market
        """
        for _, order in Order.current().items():

            # if I have an active order, cancel it UNLESS
            if order.mine and not self._waiting:
                self._waiting = True
                cancel_order = copy.copy(order)
                cancel_order.order_type = OrderType.CANCEL
                cancel_order.ref = f"Cancel - {order.ref} - SM"
                self.send_order(cancel_order)
                self._waiting = False
Ejemplo n.º 6
0
    def _make_market(self):
        # if there is a private order, and no public order, CREATE NEW ORDER(S)
        self._active_public_orders_count = len(self._active_public_orders)
        self.inform(
            f"Private: {self._active_private_orders_count}, Public: {self._active_public_orders_count}"
        )
        self.inform(
            f"{self._active_private_orders}, {self._active_public_orders}")
        if self._active_private_orders_count > 0 and self._active_public_orders_count < 1\
                and not self._waiting_for_server:
            self.inform("Order required ====================================")
            # for each active order in private market (for task 1, just 1)
            for fm_id in self._active_private_orders:

                # PUBLIC ORDER CREATION ==================================================
                is_private = False
                priv_order = self._active_private_orders[fm_id]

                # if manager order is a bid
                if priv_order.order_side == OrderSide.BUY:
                    self._role = Role.BUYER
                    price = priv_order.price - PROFIT_MARGIN
                    order_side = OrderSide.BUY

                # if manager order is an ask
                else:
                    self._role = Role.SELLER
                    price = priv_order.price + PROFIT_MARGIN
                    order_side = OrderSide.SELL

                units = 1
                order_type = OrderType.LIMIT
                ref = f"Order: {self._order_tracking_number} - SM"
                # PRIVATE ORDER CREATION

                self._create_new_order(price, units, order_side, order_type,
                                       ref, is_private)

        # if there is a public order, but not private order (STALE PUBLIC ORDER)
        # walk through current orders, delete my orders
        if self._active_public_orders_count > 0 and self._active_private_orders_count < 1\
                and not self._waiting_for_server:
            current_orders = Order.current()
            for _, o in current_orders.items():
                if o.mine:
                    cancel_order = copy.copy(o)
                    cancel_order.order_type = OrderType.CANCEL
                    cancel_order.ref = f"Cancel {o.ref}"
                    self.send_order(cancel_order)
                    self._waiting_for_server = True
Ejemplo n.º 7
0
    def _reactive_condition(self):
        """
        Returns True when the reactive strategy is to be executed
        """
        self._order_count = len([o for o in Order.current().values() if o.mine])
        time = self._find_time_elapsed()

        # Do not run on the first instance as variables are yet to be initiated
        if time < 2/30:
            return False
        
        # Run reactive strategy in the latter 1 - MM_PROPORTION of the session time.
        if time > self._MM_PROPORTION * self._session_time and self._order_count == 0:
            return True
        elif self._order_count != 0:
            return False
        else:
            return False
Ejemplo n.º 8
0
    def _get_best_bid_ask():
        """
        Walks the order book and determines what the best bid and asks are
        for each market
        :return     : dictionaries of best bid and ask orders for each
                        market
        """
        VERY_HIGH_ASK = 999999
        VERY_LOW_BID = -1

        # track best bid_ask prices and orders
        # key - market, value - [best price, best price order]
        best_bids = {
            'a': [VERY_LOW_BID, None],
            'b': [VERY_LOW_BID, None],
            'c': [VERY_LOW_BID, None],
            'note': [VERY_LOW_BID, None]
        }
        best_asks = {
            'a': [VERY_HIGH_ASK, None],
            'b': [VERY_HIGH_ASK, None],
            'c': [VERY_HIGH_ASK, None],
            'note': [VERY_HIGH_ASK, None]
        }

        # track current best bids and asks
        for order_id, order in Order.current().items():

            dict_key = order.market.item.lower()

            if order.order_side == OrderSide.BUY:
                if order.price > best_bids[dict_key][0]:
                    best_bids[dict_key][0] = order.price
                    best_bids[dict_key][1] = order
            else:
                if order.price < best_asks[dict_key][0]:
                    best_asks[dict_key][0] = order.price
                    best_asks[dict_key][1] = order

        return best_bids, best_asks
Ejemplo n.º 9
0
    def _get_order_book_state(self):
        """
        Ascertain how many active orders are mine, or from the manager to me,
            and if I have a stale order in the markets
        :return: num_private_orders : number of active private orders
                 num_my_public_orders : number of my non-trade public orders
                 my_stale_priv_order : which order of mine is stale
                 manager_order : order object created by the manager
        """
        num_private_orders = 0
        manager_order = None
        num_my_public_orders = 0
        my_stale_priv_order = None

        for fm_id, order in Order.current().items():
            # if there is a private order not created by me
            if order.is_private and not order.mine:
                num_private_orders += 1
                manager_order = order
                if manager_order.fm_id not in self._priv_orders and \
                        manager_order.original_id not in self._priv_orders:
                    self._units_to_trade = manager_order.units
                    self._priv_orders[order.fm_id] = order.units

                # figure out our role based on private order
                if manager_order.order_side == OrderSide.BUY:
                    self._role = Role.BUYER
                else:
                    self._role = Role.SELLER

            # if i created a public order that DID NOT EXECUTE IMMEDIATELY
            elif not order.is_private and order.mine:
                num_my_public_orders += 1
                my_stale_priv_order = order

        return num_private_orders, num_my_public_orders, my_stale_priv_order, manager_order
Ejemplo n.º 10
0
    def _make_market(self):

        # get order book state summary
        num_private_orders, num_my_public_orders, my_stale_priv_order, \
            manager_order = self._get_order_book_state()

        # reset order tracking when no private left - IDLE state
        if num_private_orders == 0:
            self._units_to_trade = 0
            self._priv_orders = {}

        # CANCELLING STALE ORDERS =========================================================
        if num_my_public_orders > 0 and self._units_to_trade < 1 and \
                not self._waiting_for_server:
            self._waiting_for_server = True
            self._cancel_order(my_stale_priv_order)
            self._last_accepted_public_order_id = 0
            self._priv_orders = {}  # reset private order tracking
            return

        # PRIVATE ORDER CREATION ==========================================================
        # need to confirm that the last sent order traded, and manager order > 0

        if (self._last_accepted_public_order_id not in Order.current()) \
                and (self._units_to_trade > 0) and (not self._last_accepted_public_order_id == 0) \
                and (num_my_public_orders == 0):

            # determine order attributes
            is_private = True
            price = manager_order.price
            units = 1
            order_side = None

            if self.role() == Role.BUYER:
                order_side = OrderSide.SELL
            elif self.role() == Role.SELLER:
                order_side = OrderSide.BUY

            order_type = OrderType.LIMIT
            ref = f"Private order - {self._tradeID}"

            if not self._waiting_for_server:
                self._last_accepted_public_order_id = 0
                self._units_to_trade -= 1
                self._create_new_order(price, units, order_side, order_type, ref, is_private)
                return
        # END PRIVATE ORDER CREATION ======================================================

        # PUBLIC ORDER CREATION ===========================================================
        # no order of mine in the public market, but there is a private request

        if self._units_to_trade > 0 and num_my_public_orders == 0 and \
                not self._waiting_for_server:
            # self._waiting_for_server = True
            # self.inform("Creating public order.")
            # determine order attributes
            is_private = False

            if self.role() == Role.BUYER:
                order_side = OrderSide.BUY
                price = manager_order.price - PROFIT_MARGIN
            else:
                order_side = OrderSide.SELL
                price = manager_order.price + PROFIT_MARGIN

            units = 1
            order_type = OrderType.LIMIT
            ref = f"Public order - {self._tradeID}"
            if self.role() == Role.BUYER:
                if self._cash_available >= price:
                    self._waiting_for_server = True
                    self._create_new_order(price, units, order_side, order_type, ref, is_private)
                else:
                    self.inform(f"Not enough cash to trade.")
            else:
                if self.role() == Role.SELLER:
                    if self._public_widgets_available > 0:
                        self._waiting_for_server = True
                        self._create_new_order(price, units, order_side, order_type, ref, is_private)
                    else:
                        self.inform(f"Not enough widgets to trade.")
            return
Ejemplo n.º 11
0
    def _react_to_market(self):
        """
        Ascertains state of the market, best bid and asks
        Creates orders in public and private market
        Cancel public order if none left in private
        """
        # track best bid and asks
        best_bid, best_ask, best_bid_order, best_ask_order = self._get_best_bid_ask()

        # track state of order book
        num_private_orders, num_my_public_orders, my_stale_priv_order, \
            manager_order = self._get_order_book_state()

        # reset order tracking when no private left - IDLE state
        if num_private_orders == 0:
            self._units_to_trade = 0
            self._priv_orders = {}
            self._cant_respond_orders = {}

        # CANCELLING STALE ORDERS =========================================================
        if num_my_public_orders > 0 and self._units_to_trade < 1 and \
                not self._waiting_for_server:

            self._waiting_for_server = True
            self._cancel_order(my_stale_priv_order)
            self._last_accepted_public_order_id = 0

        # PRIVATE ORDER CREATION ==============================================================
        # only create private order if public order traded successfully, and there exists
        # a corresponding manager order
        if (self._last_accepted_public_order_id not in Order.current()) \
                and (self._units_to_trade > 0) and (not self._last_accepted_public_order_id == 0) \
                and (num_my_public_orders == 0):

            self._last_accepted_public_order_id = 0
            self.inform("Last public order traded, creating private order.")

            # determine order attributes
            is_private = True
            price = manager_order.price
            units = 1
            if self.role() == Role.BUYER:
                order_side = OrderSide.SELL
            else:
                order_side = OrderSide.BUY
            order_type = OrderType.LIMIT
            ref = f"Private order - {self._tradeID}"

            # if we are a buyer, we sell in private market. Ensure have enough priv widgets
            # if we are a seller, we buy in private market. Ensure have enough cash
            if (self.role() == Role.BUYER and self._private_widgets_available > 0) or \
                    (self.role() == Role.SELLER and self._cash_available >= price):

                # self.inform(f"Units left to trade = {self._units_to_trade}")
                if not self._waiting_for_server:
                    self._units_to_trade -= 1
                    self._create_new_order(price, units, order_side, order_type, ref, is_private)
            else:
                self.inform("Not enough assets to trade. Please check widget and cash balance.")

        # END PRIVATE ORDER CREATION ==========================================================

        # self.inform(f"{num_my_public_orders}, {num_private_orders}, remaining trades => {self._units_to_trade}")

        # PUBLIC ORDER CREATION ===============================================================
        # stale orders should be cleared at this stage; there exists a private order
        # create an order based on best bid / ask

        if self._units_to_trade > 0 and num_my_public_orders == 0 and \
                not self._waiting_for_server:

            is_private = False
            self._create_profitable_order(best_ask, best_bid, manager_order, is_private,
                                          best_bid_order, best_ask_order)
Ejemplo n.º 12
0
    def _make_market(self):

        num_pending_orders = 0
        num_manager_orders = 0
        manager_order = None

        for _, order in Order.current().items():
            # if previous private order sent is consumed
            if order.fm_id == self._last_order_sent and order.is_consumed:
                self._last_order_sent = None
            if order.mine and not order.is_consumed and not order.is_private:
                num_pending_orders += 1
            if order.mine and order.is_consumed and not order.is_private:
                num_pending_orders -= 1
            elif order.is_private and not order.mine:
                if not order.is_consumed:
                    num_manager_orders += 1
                    manager_order = order
                else:
                    num_manager_orders -= 1


        self.inform(f"{num_pending_orders}, {num_manager_orders}")

        # if there is a manager order present, decide role
        if num_manager_orders > 0:
            if manager_order.order_side == OrderSide.BUY:
                self._role = Role.BUYER
            elif manager_order.order_side == OrderSide.SELL:
                self._role = Role.SELLER

        # if there is a private order from manager, but no public order
        if num_pending_orders == 0 and not self._waiting_for_server \
                and num_manager_orders > 0:
            # create new public order ==============================================
            if self._role == Role.BUYER:
                price = manager_order.price - PROFIT_MARGIN
                order_side = OrderSide.BUY
            elif self._role == Role.SELLER:
                price = manager_order.price + PROFIT_MARGIN
                order_side = OrderSide.SELL

            is_private = False
            units = 1
            order_type = OrderType.LIMIT
            ref = f"Order: {self._total_orders_sent} - SM"

            self._create_new_order(price, units, order_side, order_type, ref, is_private)

        # if the previous public order has traded, then create private order
        if num_pending_orders == 0 and self._last_order_sent is not None \
                and num_manager_orders > 0:
            # create corresponding private order ===================================
            is_private = True
            price = manager_order.price
            if manager_order.order_side == OrderSide.BUY:
                order_side = OrderSide.SELL
            elif manager_order.order_side == OrderSide.SELL:
                order_side = OrderSide.BUY
            ref = f"Order: {self._total_orders_sent} - SM"

            self._create_new_order(price, units, order_side, order_type, ref, is_private)