예제 #1
0
    def find_crit_order(self, market_id, side, holdings=None, units=1):
        """
        Returns a buy/sell order with score-increasing critical price, for the chosen market.
        """
        holdings = holdings if holdings else self._holdings
        # initialise test order and relevant variables
        test_o = Order(0, units, OrderType.LIMIT, side, market_id, ref=f"crit_{market_id}_{side.name}")
        buy = side==OrderSide.BUY
        sell = not buy
        x = 1 if sell else -1

        # if order exists, iterate on current price until critical price is reached
        current_crit_o = self._crit_orders.get(market_id, {}).get(side)
        if current_crit_o:
            test_o.price = copy.copy(current_crit_o.price)
            while self.get_performance_change([test_o]) <= 0:
                test_o.price += x
            while self.get_performance_change([test_o]) > 0:
                test_o.price -= x
            test_o.price += x
            return test_o
        
        # else, use binary search to find solution
        else:
            price_range = [self.markets[market_id]['minimum'], self.markets[market_id]['maximum']]
            # solve inequality: price @ min(pchange), s.t. pchange>0
            while price_range[1] - price_range[0] > 1:
                test_o.price = int(round(np.mean(price_range)))
                pchange = self.get_performance_change([test_o])
                if ((pchange>0) & buy) | ((pchange<0) & sell):
                    price_range = [test_o.price, price_range[1]]
                elif ((pchange>0) & sell) | ((pchange<0) & buy):
                    price_range = [price_range[0], test_o.price]
                # if performance change equals zero, score-increasing order can be immediately inferred
                else:
                    test_o.price = test_o.price + x
                    return test_o
            test_o.price = price_range[int(sell)]
            return test_o
예제 #2
0
    def received_order_book(self, order_book, market_id):
        try:
            # PUBLIC MARKET ACTIONS
            if self._public_market_id == market_id and len(order_book) > 0:
                self.order_housekeeping(order_book)

                # record and compute confint if market info is available
                ci = (0, self._MAX_MKT_PRICE)
                if len([o for o in order_book if not o.mine]) > 0:
                    self.record_ob_data(order_book)
                    ci = self.compute_confint()

                # MARKET MAKER STRATEGY
                if self.bot_type() == BotType.MARKET_MAKER:
                    # if no order exists in the market, create new order
                    if len(self._own_orders) < self._MAX_ACTIVE_ORDERS and len(
                            self._pending_orders) == 0:
                        # initialise order
                        new_order = Order(0,
                                          1,
                                          OrderType.LIMIT,
                                          OrderSide.BUY,
                                          self._public_market_id,
                                          ref='pub_order')

                        # sell if too many assets, buy if too few assets, choose based on market price if asset number is correct
                        is_sell = self._ob_data[-1][1] / self._MAX_MKT_PRICE
                        if self._holdings['markets'][market_id][
                                'units'] > self._ASSETS_REQ:
                            is_sell = 1
                        elif self._holdings['markets'][market_id][
                                'units'] < self._ASSETS_REQ:
                            is_sell = 0

                        # create order based on CI
                        self.inform(
                            f"[PUBLIC] w{int(round(self._CONFIDENCE*100))}CI: {tuple([round(v, 3) for v in ci])}"
                        )
                        if is_sell < 0.5:
                            new_order.price = int(round(max(0, ci[0])))
                        else:
                            new_order.side = OrderSide.SELL
                            new_order.price = int(
                                round(min(ci[1], self._MAX_MKT_PRICE)))

                        # check that order is valid before sending
                        if self.check_order_validity(new_order,
                                                     (ci[1] - ci[0]) / 2):
                            self.inform(
                                f"[{self.bot_type().name}] sending valid {new_order.side.name} order @ {new_order.price}."
                            )
                            self._pending_orders[new_order.ref] = new_order
                            self.send_order(new_order)

            # infer bot role from private market order
            ## THIS ASSUMES THERE IS ONLY 1 ORDER IN THE PRIVATE MARKET AND NO NEW ORDERS ARRIVE THROUGH THE SESSION
            if self.role(
            ) == None and market_id == self._private_market_id and len(
                    order_book) > 0:
                if order_book[0].side == OrderSide.BUY:
                    self._role = Role.BUYER
                else:
                    self._role = Role.SELLER
        except:
            traceback.print_exc()
예제 #3
0
    def received_order_book(self, order_book, market_id):
        try:
            # order housekeeping
            try:
                # increment order age
                updated_ao = [o for o in order_book if o.mine][0]
                if self._active_orders.get(market_id) == updated_ao:
                    self._active_order_age[
                        market_id] = self._active_order_age.get(market_id,
                                                                0) + 1
                # unless the order is new, then make its age 1
                else:
                    self._active_orders[market_id] = updated_ao
                    self._active_order_age[market_id] = 1
                # purge order if it has stayed in the market for too long
                refresh_interval = (self._MM_REFRESH_INTERVAL
                                    if self.bot_type() == BotType.MARKET_MAKER
                                    else self._REACTIVE_REFRESH_INTERVAL)
                if self._active_order_age.get(market_id, 0) > refresh_interval:
                    self.cancel_order(self._active_orders[market_id])
                    self.inform("[ORDER REFRESH] purging stagnant order.")
            # clear active order info if no active order is found
            except IndexError:
                self._active_orders[market_id] = None
                self._active_order_age[market_id] = 0

            # public market actions
            if market_id == self._public_market_id:
                # stop processing if orderbook doesn't contain orders or role is not defined
                if len([o for o in order_book if not o.mine
                        ]) == 0 or self.role() == None:
                    return

                # if orderbook contains orders, initialise relevant variables (profit/critical prices)
                self.update_aggression()
                # the price at which profit will be made according to the minimum profit margin
                buy_profit = self._private_price - PROFIT_MARGIN
                sell_profit = self._private_price + PROFIT_MARGIN
                # the critical price at which desired profit (scaled using aggression) will be made
                buy_crit = self._private_price - self._target_profit
                sell_crit = self._private_price + self._target_profit
                # inform bot's desired market price
                if self.role() != None:
                    self.inform(
                        f"[{self.role().name}] target price: {buy_crit if self.role() == Role.BUYER else sell_crit}."
                    )
                # intialise order
                new_order = Order(self._private_price,
                                  1,
                                  OrderType.LIMIT,
                                  (OrderSide.BUY if self.role() == Role.BUYER
                                   else OrderSide.SELL),
                                  self._public_market_id,
                                  ref='pub_order')

                # implementation for market maker and reactive bot types
                # set appropriate buyer price, capture arbitrage if reactive
                if self.role() == Role.BUYER:
                    # find ask and assign order price so that profit will be made
                    ask = min([
                        o.price for o in order_book
                        if o.side == OrderSide.SELL and not o.mine
                    ] + [self._MAX_MKT_PRICE])
                    new_order.price = buy_crit
                    # identify all profitable trade opportunities
                    if ask <= buy_profit:
                        self._print_trade_opportunity(f'BUY @ {ask}.')
                        # reactive bot: capture desirable arbitrage opportunity at market price
                        if self.bot_type(
                        ) == BotType.REACTIVE and ask <= buy_crit:
                            new_order.price = ask
                            self.send_if_valid_order(new_order)
                        if ask >= buy_crit:
                            self.inform(
                                f"[{self.bot_type().name}] order is profitable but not profitable enough."
                            )

                # set appropriate seller price, capture arbitrage if reactive
                elif self.role() == Role.SELLER:
                    # find bid and assign order price so that profit will be made
                    bid = max([
                        o.price for o in order_book
                        if o.side == OrderSide.BUY and not o.mine
                    ] + [0])
                    new_order.price = sell_crit
                    # identify all profitable trade opportunities
                    if bid >= sell_profit:
                        self._print_trade_opportunity(f'SELL @ {bid}.')
                        # reactive bot: capture desirable arbitrage opportunity at market price
                        if self.bot_type(
                        ) == BotType.REACTIVE and bid >= sell_crit:
                            new_order.price = bid
                            self.send_if_valid_order(new_order)
                        if bid <= sell_crit:
                            self.inform(
                                f"[{self.bot_type().name}] order is profitable but not profitable enough."
                            )

                # market maker bot: send order if the order is valid, regardless if arbitrage opportunity is present
                if self.bot_type() == BotType.MARKET_MAKER:
                    self.send_if_valid_order(new_order)

            # private market actions
            elif market_id == self._private_market_id:
                try:
                    # infer bot role from private market order
                    po = [o for o in order_book if not o.mine][0]
                    if po.side == OrderSide.BUY:
                        self._role = Role.BUYER
                    elif po.side == OrderSide.SELL:
                        self._role = Role.SELLER
                    # store private market price and units info
                    self._private_price = int(po.price)
                    self._private_units = po.units
                except IndexError:
                    # on role detection failure, clear role, private price and private units
                    self._role = None
                    self._private_price = self._MAX_MKT_PRICE / 2
                    self._private_units = 0
        # display tracebacks for main recurring loops to aid debugging
        except:
            traceback.print_exc()