Ejemplo n.º 1
0
    def received_order_book(self, order_book, market_id):

        time_elapsed = int(round(((time.time() - self._start_time) /
                                  60)))  #rounds seconds to minutes

        # updates current unit holdings according to item name and in order with payoff data
        for items in self._payoffs:
            self._current_unit_holdings[items] = self.holdings["markets"][
                self._market_ids[items]]["available_units"]

        #print("[CURRENT HOLDING] ", self._current_unit_holdings)

        #changes bot type from mm to reactive once time left <= 5min
        if (self._session_time - time_elapsed) <= 5:
            self._role = BotType.MARKET_MAKER
        else:
            self._role = BotType.REACTIVE

        Orders = [
            Order(500, 1, OrderType.LIMIT, OrderSide.SELL, 713, ref="b1"),
            Order(100, 1, OrderType.LIMIT, OrderSide.BUY, 714, ref="b1")
        ]

        self.get_potential_performance(Orders)

        pass
Ejemplo n.º 2
0
    def _print_trade_opportunity(self, other_order):
        order_type = "Sell" if other_order.side == OrderSide.BUY else "Buy"
        self.inform("Opportunity: {} one unit at price of ${:<5.2f}".format(order_type, other_order.price/100))

        if self._role == Role.BUYER:
            #do we really need to define this again?
            # cash_avail =self.holdings["cash"]["available_cash"]
            can_buy = cash_avail >= other_order.price
            #why are there massive gaps here
            self.inform("           : Profit is ${:.2f} per unit".format(int(DS_REWARD_CHARGE - other_order.price) / 100))
            self.inform("           : With ${:.2f} of available cash I can buy at least {} units".format(cash_avail / 100, cash_avail // other_order.price))
            self.inform("           : There are {} units for sale at this price".format(other_order.units))
            #I feel some of the code here overlaps what we've previously done
            #is there a way to call the other method instead of repeating this code?
            #although this is only a suggestion
            if can_buy and self._bot_type == BotType.REACTIVE and not (self._have_an_order or self._waiting_for_server):
                self.inform("           : I will buy one unit of widget at the price of {}".format(other_order.price))
                order = Order(other_order.price, 1, OrderType.LIMIT, OrderSide.BUY, self._market_id, ref="o{}".format(self._orders_ref))
                self._orders_ref += 1
                self.send_order(order)
                self._waiting_for_server = True
                self.inform("The buy order reference is: o{}".format(self._orders_ref))
            else:
                reason = "I do not have enough cash"
                if self._bot_type != BotType.REACTIVE:
                    reason = "I am not a reactive trader"
                elif self._have_an_order:
                    reason = "I already have an order placed in the order book"
                elif self._waiting_for_server:
                    reason = "I am still waiting for the server"
                self.inform("           : I cannot buy any units because {}".format(reason))

        else:
            #you don't need this line because you've already defined it above, right?
            # widgets_avail = self.holdings["markets"][self._market_id]["available_units"]
            can_sell = widgets_avail > 0
            self.inform("           : Profit is {} per unit".format(other_order.price - DS_REWARD_CHARGE))
            self.inform("           : I have a total of {0} widgets, so I can sell up to {0} units".format(widgets_avail))
            self.inform("           : The buyer wishes to buy {} units at this price".format(other_order.units))
            if can_sell and self._bot_type == BotType.REACTIVE and not (self._have_an_order or self._waiting_for_server):
                self.inform("           : I will sell one unit of widget at the price of {}".format(other_order.price))
                order = Order(other_order.price, 1, OrderType.LIMIT, OrderSide.SELL, self._market_id, ref="o{}".format(self._orders_ref))
                self._orders_ref += 1
                self.send_order(order)
                self._waiting_for_server = True
                self.inform("The sell order reference is: o{}".format(self._orders_ref))
            else:
                #again, is there a way to pull this out into a new method so we can just call that method each time instead?
                reason = "I do not have enough widgets"
                if self._bot_type != BotType.REACTIVE:
                    reason = "I am not a reactive trader"
                elif self._have_an_order:
                    reason = "I already have an order in the order book"
                elif self._waiting_for_server:
                    reason = "I am still waiting for the server"
                self.inform("           : I cannot sell any units because {}".format(reason))
Ejemplo n.º 3
0
    def _make_order(self,
                    order_price,
                    order_side,
                    order_unit=ORDER_UNIT,
                    order_type=OrderType.LIMIT):
        """
        MAKES order and stores in active order
        :param order_price: price made after decision
        :param order_side: buyer or seller
        :param order_unit: (Optional, not available) Traded units
        :param order_type: (Optional, not available) Type of order
        :return: sends order
        """
        self._line_break_inform(inspect.stack()[0][3])

        # Use reference maker to make reference for current order
        ref = self._make_order_ref(self._market_id, order_price, order_side)

        # Updates the active order to store latest order to be made
        self.active_order = Order(order_price,
                                  order_unit,
                                  order_type,
                                  order_side,
                                  self._market_id,
                                  ref=ref)

        # Change order status to MADE
        self.order_status = OrderStatus["MADE"]
Ejemplo n.º 4
0
    def _marketmaker(self, other_order):

        #initial parameters and displays cash balance
        place_sell_order = False
        place_buy_order = False
        print("Current cash balance ", self.holdings['cash']['available_cash'])
        print("Current asset balance ",
              self.holdings['cash']['available_units'])

        #if we already have a sell/buy order, then we do not place another
        for order in other_order:
            if (order.mine and order.side == OrderSide.SELL):
                place_sell_order = True
            if (order.mine and order.side == OrderSide.BUY):
                place_buy_order = True

        #if we have positive asset, and can place a order, we place sell order for 5c more than our DS_REWARD_CHARGE
        if (not self._wait_sell_server_mm and not place_sell_order and
                self.holdings['markets'][self._market_id]['available_units'] >
                0):  #sell
            place_sell_order = Order(DS_REWARD_CHARGE + 5,
                                     1,
                                     OrderType.LIMIT,
                                     OrderSide.SELL,
                                     self._market_id,
                                     ref="b1")

            #Send order
            self.send_order(place_sell_order)
            self._wait_buy_server_mm = True
            print("[ORDER PLACED] ", place_sell_order)

        # if we have positive asset, and can place a order, we place buy order for 5c less than our DS_REWARD_CHARGE
        if (not self._wait_buy_server_mm and not place_buy_order
                and self.holdings['cash']['available_cash'] >=
            (DS_REWARD_CHARGE - 5)):  # buy
            place_buy_order = Order(DS_REWARD_CHARGE - 5,
                                    1,
                                    OrderType.LIMIT,
                                    OrderSide.BUY,
                                    self._market_id,
                                    ref="s1")
            self._wait_sell_server_mm = True
            self.send_order(place_buy_order)
            print("[ORDER PLACED] ", place_buy_order)
Ejemplo n.º 5
0
 def make_order(self, agent=None):
     if agent:
         agent.inform("Making Order with ref" + self.ref)
     return Order(self.price,
                  self.units,
                  self.order_type,
                  self.order_side,
                  self.market_id,
                  ref=self.ref)
Ejemplo n.º 6
0
    def enforce_liquidity(self, market_id, units=1, confidence=None):
        """
        If a sell @ bid in the current market leads to net improved performance, creates and sends the sell @ bid order.
        Creates confidence bounds for bids/asks based on market volatility, to ensure arbitrage execution.
        """
        confidence = confidence if confidence else self._ARBITRAGE_CONDFIDENCE
        # if volatility info is not available, end function
        ask_vol = self._timewvar.get(market_id,{}).get(OrderSide.SELL)
        if ask_vol==None: return

        # initialise buy order and cash needed for the order
        ask = self.t_confint_bound(self._asks[market_id], ask_vol**0.5, confidence, int(self.time_elapsed()), upper=True)
        if not (self.markets[market_id]['minimum'] <= ask <= self.markets[market_id]['maximum']): return
        current_buy = Order(ask, units, OrderType.LIMIT, OrderSide.BUY, market_id, ref="current_buy")
        cn = max(ask*units - self._holdings['cash']['available_cash'], 0)
        # if more than enough cash is available, end function
        if not cn: return
        # else, if another market can sell @ bid and improve net performance buying in current market @ ask, sell @ bid in that market
        highest_pchange = 0
        highest_sell = None
        for other_m_id, raw_bid in {k:v for k,v in self._bids.items() if (k!=market_id) & (v>self.markets[k]['minimum'])}.items():
            # if volatility info is not available, continue to next market
            bid_vol = self._timewvar.get(market_id,{}).get(OrderSide.BUY)
            if bid_vol==None: continue
            # if bid price would create an invalid order, continue to next market
            bid = self.t_confint_bound(raw_bid, bid_vol**0.5, confidence, int(self.time_elapsed()))
            if not (self.markets[other_m_id]['minimum'] <= bid <= self.markets[other_m_id]['maximum']): continue
            # initialise the sell @ bid order
            other_sell = Order(bid, int(cn/bid)+(cn%bid>0), OrderType.LIMIT, OrderSide.SELL, other_m_id, ref="other_sell")
            # records the (valid) order pair with the highest performance change
            if self.valid_order(other_sell, bypass_tracking=True):
                pchange = self.get_performance_change([current_buy, other_sell])
                if pchange > highest_pchange:
                    highest_sell = other_sell
                    highest_pchange = pchange
        
        # sell @ bid in the market that results in the highest performance increase
        if highest_sell:
            if self.valid_order(highest_sell, bypass_tracking=True):
                self.send_order(highest_sell)
                self._holdings['markets'][highest_sell.market_id]['available_units'] -= highest_sell.units
                self.inform(f"[LIQUIDITY MANAGEMENT] offloading {self.markets[highest_sell.market_id]['item']} @ {highest_sell.price}.")
Ejemplo n.º 7
0
    def received_order_book(self, order_book, market_id):
        print("hehrhrhe")
        print(self._market_id)
        orders_count = 0
        for order in order_book:
            if order.mine:
                orders_count += 1
        if orders_count < 2:
            my_buy_order = Order(100, 1, OrderType.LIMIT, OrderSide.BUY, 539, ref="b1")
            print("my buy order is ",my_buy_order)

            self.send_order(my_buy_order)
        pass
Ejemplo n.º 8
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
Ejemplo n.º 9
0
 def received_holdings(self, holdings):
     try:
         self._current_assets = sum(
             [m['units'] for m in holdings['markets'].values()])
         # if total assets do not match required assets
         if self._current_assets != self._ASSETS_REQ and self._private_units > 0:
             # trade from private market until required asset count is reached again
             private_order = Order(
                 self._private_price,
                 1,
                 OrderType.LIMIT,
                 (OrderSide.BUY if self._current_assets < self._ASSETS_REQ
                  else OrderSide.SELL),
                 self._private_market_id,
                 ref='priv_order')
             private_order.owner_or_target = self._DEALER_ID
             # decrement private units and disable role if private units have reached zero (no arbitrage opportunities left)
             self._private_units -= 1
             if self._private_units == 0:
                 self._role = None
             self.send_if_valid_order(private_order)
     # display tracebacks for main recurring loops to aid debugging
     except:
         traceback.print_exc()
Ejemplo n.º 10
0
 def cancel_sent_order(self, agent=None):
     self.order_type = OrderType.CANCEL
     self.sent_order = self.make_order(agent)
     agent.inform("Making cancel order for order with ref " + self.ref)
     return Order(self.price, self.units, self.order_type, self.order_side, self.market_id, ref=self.ref)
Ejemplo n.º 11
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()
Ejemplo n.º 12
0
    def _reactive(self, other_order):

        print("Current cash balance ", self.holdings['cash']['available_cash'])
        print("Current asset balance ",
              self.holdings['cash']['available_units'])
        min_order_price = self.MAXIMUM
        place_buy_order = False

        #need to check the order placed was of us and make sure it doesn't place another order.
        for order in other_order:
            if (order.mine and order.side == OrderSide.BUY):
                place_buy_order = True

        #if we are buyer and any person who is selling a sell order which is less than DS_UTIL,
        #we will buy from it.
        #calculated the minimum order of sell and placed a buy order if it is less than the given amount.
        #also checked that we placed one order till the server gives the confirmation.

        if (self._role == Role.BUYER):

            #find the lowest ask order price
            for (id, order) in self._trade_opportunity['sell'].items():
                if (order._price < min_order_price):
                    min_order_price = order._price

            #if a valid lowest ask price is present, no outstanding orders, and have enough money for profitable trade
            # then execute trade

            if (min_order_price != self.MAXIMUM
                    and not self._waiting_for_server and not place_buy_order
                    and
                    self.holdings['cash']['available_cash'] >= min_order_price
                    and DS_REWARD_CHARGE >= min_order_price):

                place_buy_order = Order(min_order_price,
                                        1,
                                        OrderType.LIMIT,
                                        OrderSide.BUY,
                                        self._market_id,
                                        ref="b1")

                self.send_order(place_buy_order)
                print("[ORDER PLACED] ", place_buy_order)
                self._waiting_for_server = True

        #reset parameters
        max_order_price = self.MINIMUM
        place_sell_order = False

        #check no existing sell orders
        for order in other_order:
            if (order.mine and order.side == OrderSide.SELL):
                place_sell_order = True

        #if seller, than
        if (self._role == Role.SELLER):

            #check all market orders and find highest bid price
            for (id, order) in self._trade_opportunity['buy'].items():
                if (order._price > max_order_price):
                    max_order_price = order._price
            #print("max order price to buy is ", max_order_price)

            #if profitable trade exists, and order able to be sent to server, and we have available assets,
            # then send order
            if (max_order_price != self.MINIMUM
                    and not self._waiting_for_server and not place_sell_order
                    and self.holdings['markets'][
                        self._market_id]['available_units'] > 0
                    and DS_REWARD_CHARGE <= max_order_price):

                #send sell order
                place_sell_order = Order(max_order_price,
                                         1,
                                         OrderType.LIMIT,
                                         OrderSide.SELL,
                                         self._market_id,
                                         ref="b1")

                self.send_order(place_sell_order)
                print("[ORDER PLACED] ", place_sell_order)
                self._waiting_for_server = True
Ejemplo n.º 13
0
    def received_order_book(self, order_book, market_id):
        """
        Most logic should reside in this function, and it should also
        cooperate with other classes
        :param order_book: The order book of specific market
        :param market_id:  Id of the corresponding market
        :return: No return. Only processes to be executed.
        """
        self.inform("Trying to send cancel order on non-existing orders")
        Order(500, 1, OrderType.CANCEL, OrderSide.SELL, )


        self.inform("received order book from %d" % market_id)

        # Task spec specify bot need to be either reactive or market maker,
        # not both depending on the type of bot, make orders when appropriate.
        # When the bid-ask spread is large, print can buy at Lowest sell price
        # or sell at highest buy price

        best_ask = None
        best_bid = None

        # Variable used to check whether our order was completed
        order_currently_pending = False

        self.inform("Printing order book")
        for order in order_book:
            self.inform("order is: %d, %d" % (order.price, order.units))
            if order.mine:
                self.inform("It's own order")
                order_currently_pending = True
                self.status = OrderStatus["PENDING"]

            price = order.price
            units = order.units

            if order.side == OrderSide.SELL:
                # determine which is lowest ASK price
                if best_ask is None:
                    best_ask = (price, units)
                else:
                    if price < best_ask[0]:
                        best_ask = (price, units)

            elif order.side == OrderSide.BUY:
                # determine which is highest BID price
                if best_bid is None:
                    best_bid = (price, units)
                else:
                    if price > best_bid[0]:
                        best_bid = (price, units)

        try:
            bid_ask_spread = best_ask[0] - best_bid[0]
            self.inform("Spread is: " + str(bid_ask_spread))
        except TypeError:
            self.inform("no bid ask spread available")

        # If our order was not in the order book, but it was on the last
        # iteration (therefore complete or cancelled)
        if not order_currently_pending:
            # TODO change the order status
            self.status = OrderStatus["COMPLETED"]
            self.inform("Order was completed in market "
                        + str(self._market_id))

        # Bot is a market maker
        if self._bot_type == BotType["MARKET_MAKER"]:
            # Check that no order is currently pending
            if (self.status is None) or self.status != OrderStatus["PENDING"]:
                self.status = OrderStatus["MAKING"]
                self.inform("We can make a market-making order")
                self._market_maker_orders_price(best_ask[0], best_bid[0])
                print(market_id)

        if self._bot_type == BotType["REACTIVE"]:
            if self.status != OrderStatus["PENDING"]:
                self.status = OrderStatus["MAKING"]
                self.inform("We can make a reactive order")
                self._reactive_orders_price(best_bid, best_ask)

        self.inform(self.status)
Ejemplo n.º 14
0
    def received_order_book(self, order_book, market_id):
        # should these variable names not be preluded with _?
        sell_orders = [order for order in order_book if order.side == OrderSide.SELL and not order.mine]
        buy_orders = [order for order in order_book if order.side == OrderSide.BUY and not order.mine]
        my_orders = [order for order in order_book if order.mine]


        sell_orders.sort(key=lambda x: x.price)
        buy_orders.sort(key=lambda x: x.price)
        # best_bid_order and best_ask_order contain the order with the best bid or ask
        # they are set to None if there is no buy or sell order in the order book
        best_bid_order = None if not buy_orders else buy_orders[-1]
        best_ask_order = None if not sell_orders else sell_orders[0]

        #what is this line of code meant to do?
        self._have_an_order = my_orders != []

        # CASE 1: reactive bot
        if self._bot_type == BotType.REACTIVE:
            # I am a buyer, and reward is higher than price to buy
            if best_ask_order is not None and self._role == Role.BUYER and \
                    best_ask_order.price < DS_REWARD_CHARGE and self._widgets_bought <5:
                self._print_trade_opportunity(best_ask_order)
            # I am a seller, and the price I can sell at is higher than the charge
            elif best_bid_order is not None and self._role == Role.SELLER and \
                    best_bid_order.price < DS_REWARD_CHARGE:
                self._print_trade_opportunity(best_bid_order)

        # CASE 2: the bot is a market maker
        else:
            widgets_avail = self.holdings["markets"][self._market_id]["available_units"]

            # if I am a buyer with non-zero balance
            if self._role == Role.BUYER and not (self._have_an_order \
                    or self._waiting_for_server) and cash_avail >= 5:
                if best_ask_order is None:
                    limit_price = min(cash_avail, DS_REWARD_CHARGE - self._required_profit)
                    order = Order(limit_price, 1, OrderType.LIMIT, OrderSide.BUY, \
                                  self._market_id, ref="o{}".format(self._orders_ref))
                    self._orders_ref += 1
                    self.send_order(order)
                    self._waiting_for_server = True
                    self.inform("I have sent a buy order with reference o{}".format(self._orders_ref))
                else:
                    limit_price = min(cash_avail, DS_REWARD_CHARGE - self._required_profit, best_ask_order.price - self._required_profit)
                    order = Order(limit_price, 1, OrderType.LIMIT, OrderSide.BUY, self._market_id, ref="o{}".format(self._orders_ref))
                    self._orders_ref += 1
                    self.send_order(order)
                    self._waiting_for_server = True
                    self.inform("I have sent a buy order with reference o{}".format(self._orders_ref))

            # if I am a seller with at least one widget
            elif self._role == Role.SELLER and not (self._have_an_order or self._waiting_for_server) and widgets_avail > 0:
                if best_bid_order is None:
                    limit_price = DS_REWARD_CHARGE + self._required_profit
                    order = Order(limit_price, 1, OrderType.LIMIT, OrderSide.SELL, self._market_id, ref="o{}".format(self._orders_ref))
                    self._orders_ref += 1
                    self.send_order(order)
                    self._waiting_for_server = True
                    self.inform("I have sent a sell order with reference o{}".format(self._orders_ref))
                else:
                    limit_price = max(DS_REWARD_CHARGE + self._required_profit,
                                      best_bid_order.price + self._required_profit)
                    order = Order(limit_price, 1, OrderType.LIMIT, OrderSide.SELL, self._market_id,
                                  ref="o{}".format(self._orders_ref))
                    self._orders_ref += 1
                    self.send_order(order)
                    self._waiting_for_server = True
                    self.inform("I have sent a sell order with reference o{}".format(self._orders_ref))
            else:
                if self._have_an_order:
                    reason = "I already have an order in the order book"
                elif self._waiting_for_server:
                    reason = "I am still waiting for the server"
                elif self._role == Role.BUYER and cash_avail < 5:
                    reason = "I do not have enough cash available"
                elif self._role == Role.SELLER and widgets_avail == 0:
                    reason = "I do not have any widgets"
                self.inform("I cannot trade any units because {}".format(reason))
Ejemplo n.º 15
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()
Ejemplo n.º 16
0
    def is_portfolio_optimal(self):
        """
        Returns true if the current holdings are optimal (as per the performance formula), false otherwise.
        :return:
        """
        # Order(self, price, units, type, side, market, date=None, id=None, ref=None):)

        Orders = []

        #for every market item, loop through i.e. StockA, StockB etc.

        for first_asset_range in range(-1, 1):
            Orders.append(
                Order(
                    self.get_trade_price(first_asset_range,
                                         self._market_ids.values()[0]), 1,
                    OrderType.LIMIT, self.get_buy_sell(first_asset_range),
                    self._market_ids[self._current_unit_holdings.key()[0],
                                     None, None, None]))
            if len(self._current_unit_holdings) > 1 and len(
                    self._current_unit_holdings) <= 4:
                for second_asset_range in range(-1, 1):
                    Orders.append(
                        Order(
                            self.get_trade_price(second_asset_range,
                                                 self._market_ids.values()[1]),
                            1, OrderType.LIMIT,
                            self.get_buy_sell(second_asset_range),
                            self._market_ids[
                                self._current_unit_holdings.key()[1], None,
                                None, None]))
                    if len(self._current_unit_holdings) > 2 and len(
                            self._current_unit_holdings) <= 4:
                        for third_asset_range in range(-1, 1):
                            Orders.append(
                                Order(
                                    self.get_trade_price(
                                        third_asset_range,
                                        self._market_ids.values()[2]), 1,
                                    OrderType.LIMIT,
                                    self.get_buy_sell(third_asset_range),
                                    self._market_ids[
                                        self._current_unit_holdings.key()[2],
                                        None, None, None]))
                            if len(self._current_unit_holdings) > 3 and len(
                                    self._current_unit_holdings) <= 4:
                                for fourth_asset_range in range(-1, 1):
                                    Orders.append(
                                        Order(
                                            self.get_trade_price(
                                                fourth_asset_range,
                                                self._market_ids.values()[3]),
                                            1, OrderType.LIMIT,
                                            self.get_buy_sell(
                                                fourth_asset_range),
                                            self._market_ids[
                                                self._current_unit_holdings.
                                                key()[3], None, None, None]))
                                    if self.get_potential_performance(
                                            Orders
                                    ) > self.get_potential_performance():
                                        return False
                            elif self.get_potential_performance(
                                    Orders) > self.get_potential_performance():
                                return False
                    elif self.get_potential_performance(
                            Orders) > self.get_potential_performance():
                        return False
            elif self.get_potential_performance(
                    Orders) > self.get_potential_performance():
                return False

        #return true if none of the orders tested for each asset yielded improvement in performance.
        return True