def set_initial_holdings(self, user_holdings): """ Initialize each bot with the same base endowment + additional endowment in U[0, 5]. All bots have the same cash holding. :param user_holdings: :return: """ try: markets = [] for item in self.market_items: markets.append(Market.get_by_item(item)) for email, holdings in user_holdings.items(): for market in markets: if email not in self.endow: holdings.assets[market].units_initial = 0 else: holdings.assets[market].units_initial = int( self.endow[email][market.item][0]) holdings.cash_initial = self.base_cash except Exception as e: self.error(e) try: self.update_holdings(user_holdings, self.initial_holdings_updated_callback) except Exception as e: self.error(e)
def set_initial_holdings(self, user_holdings): """ Initialize each bot with the same base endowment + additional endowment in U[0, 5]. All bots have the same cash holding. :param user_holdings: :return: """ self.inform( "I have received old holdings. I will now calculate the initial holdings." ) markets = [] for item in self.market_items: markets.append(Market.get_by_item(item)) # Calculate the base endowment for the next round round_endow = random.randint(0, self.upper_endow) self.inform("Base endowment for round 1 is: {}".format(round_endow)) for email, holdings in user_holdings.items(): for market in markets: holdings.assets[ market].units_initial = round_endow + random.randint( 0, self.upper_endow) holdings.cash_initial = self.base_cash try: self.update_holdings(user_holdings, self.initial_holdings_updated_callback) except Exception as e: self.error(e)
def _send_valid_mm_orders(self): """ Executes list of valid market maker orders :return: List[Order] of valid orders """ for key in self._mm_orders: order = Order.create_new() order.market = Market(self._market_ids[key[0]]) price_tick = order.market.price_tick price = self._mm_orders[key] - \ (self._mm_orders[key] % price_tick) if price <= order.market.min_price: price = order.market.min_price elif price >= order.market.max_price: price = order.market.max_price order.price = price order.order_side = key[-1] order.order_type = OrderType.LIMIT order.units = 1 if order.market.min_price <= order.price <= order.market.max_price: self._order_id += 1 self._num_orders_sent += 1 self._num_active_mm_orders += 1 self.send_order(order) return
def _create_new_order(self, price: int, units: int, order_side: OrderSide, order_type: OrderType, ref: str, is_private: bool): """ :param price: determined price :param units: # of units to be submitted, fixed to 1 :param order_side: buy or sell :param order_type: limit or market, fixed to limit :param ref: customer string of format "Order: {self._sent_order_count} - SM" :return: """ new_order = Order.create_new() if is_private: market = self._private_market_id new_order.owner_or_target = "M000" else: market = self._public_market_id new_order.market = Market(market) new_order.price = price new_order.units = units new_order.order_side = order_side new_order.order_type = order_type new_order.ref = ref self.send_order(new_order) self._waiting_for_server = True
def set_initial_holdings(self, user_holdings): """ Initialize each bot with the same base endowment + additional endowment in U[0, 5]. All bots have the same cash holding. :param user_holdings: :return: """ self.inform("Starting run " + str(self.label) + " of simulations.") try: market = Market.get_by_item(MARKET_1) for email, holdings in user_holdings.items(): print(email) if email not in self.endow: holdings.assets[market].units_initial = 0 else: holdings.assets[market].units_initial = int( self.endow[email][0]) holdings.cash_initial = self.base_cash except Exception as e: self.inform(e) try: self.update_holdings(user_holdings, self.initial_holdings_updated_callback) except Exception as e: self.inform(e)
def received_holdings(self, holdings): """ Updates to necessary information whenever a trade is executed """ # Informs of initial details if self._find_time_elapsed() < 1/30: # Trader ID self.inform(holdings.name) # Initial allocation of holdings self.inform('---') self.inform(f'Total cash: {holdings.cash}, Available cash: {holdings.cash_available}') for market, assets in (sorted(holdings.assets.items(), key = lambda x: x[0].item)): self.inform(f'{market.name} - Total units: {assets.units}, Available units: {assets.units_available}') #Update fair prices whenever holdings change for market_id, market_info in sorted(self.markets.items()): security = market_info.item self._fair_buy_prices[security] = self._find_fair_price(market_id, holdings, OrderSide.BUY) self._fair_sell_prices[security] = self._find_fair_price(market_id, holdings, OrderSide.SELL) # Trade notes for cash if cash is below $10.00 and there are # sufficient notes. Taking a small decrease in performance. # Assumes the note market is the one with the highest market id note_id = sorted(self._market_ids.values())[-1] if holdings.cash < 1000 and holdings.assets[Market(note_id)].units \ > 2 and self._order_count == 0: order = self._make_order(note_id, OrderSide.SELL, 495, units = 2) if self._check_holdings(order, holdings, True): self.send_order(order) self._order_count += 2
def received_orders(self, orders: List[Order]): orders_avail = orders for o in orders_avail: # inform method just logs the messages self.inform(o) if o.mine: self.inform(o.owner, o.owner_or_target) # cancelling an order, make sure to check all orders sent are accepted # if o.mine: # cancel_order = copy.copy(o) # cancel_order.order_type = OrderType.CANCEL # self.send_order(cancel_order) # order has attribute mine (bool) to know if our order or not # order.all() fetches all previous orders, and we don't need to physically track all changes, # we can query this order.all() data to find the status of the order # all_orders = Order.all() if not self._order_sent: order = Order.create_new() order.market = Market(1573) order.order_side = OrderSide.BUY order.order_type = OrderType.LIMIT order.price = 100 order.ref = "rip" order.units = 1 # we will know this owner/target from the private orders we receive # Manager is always M000 order.owner_or_target = "T002" # sending private orders, the market code should be changed to 1573 self.send_order(order) self._order_sent = True
def order_rejected(self, info, order: Order): price = order.price units = order.units if order.is_private: market = Market(self._private_market_id) else: market = Market(self._public_market_id) #possible reasons for a rejected order if price > market.max_price or price < market.min_price: self.inform("Order rejected, price out of range") elif units > market.max_units or price < market.min_units: self.inform("Order rejected, units out of range") elif price % market.price_tick != 0: self.inform("Order rejected, price not divisible by price tick") elif units % market.unit_tick != 0: self.inform("Order rejected, units not divisible by unit tick") self._waiting_for_order = False
def _make_order(self, market_id, oside, price, otype = OrderType.LIMIT, \ units = 1): """ Makes and returns Order object with the defined parameters """ new_order = Order.create_new() new_order.mine = True new_order.market = Market(market_id) new_order.order_side = oside new_order.order_type = otype new_order.price = price new_order.units = units new_order.ref = f'{otype} Order in {new_order.market.fm_id} \ for {new_order.units}@{new_order.price}' return new_order
def Go_create_new_order(self, price: int, units: int, order_side: OrderSide, order_type: OrderType, ref: str, is_private: bool): """ Creates a new order given the parameters :param price: determined price :param units: # of units to be submitted, fixed to 1 :param order_side: buy or sell :param order_type: limit or market, fixed to limit :param ref: customer string of format "Order: {self._sent_order_count} - SM" :return: """ new_order = Order.create_new() # derive order attributes if is_private: market = self._private_market_id new_order.owner_or_target = MANAGER_ID else: market = self._public_market_id # make sure price is rounded in the public market price -= price % self._price_tick # in case price goes less than the tick, or more than ten # set prices to the bounds if price < self._price_tick: price = self._price_tick elif price > MAX_PRICE: price = MAX_PRICE new_order.market = Market(market) new_order.price = price new_order.units = units new_order.order_side = order_side new_order.order_type = order_type new_order.ref = ref # send order through self._waiting_for_server = True self.send_order(new_order) self._tradeID += 1
def _market_making_strategy(self): """ MARKET MAKER STRATEGY ===================== Simulate acquiring/disposing off one unit of each security to calculate the change in performance because of this balancing. This change in performance is determined to be the price the security should by bought/sold for (accounts for changing variance and changing expected return) That price is then adjusted by a PROFIT MARGIN, and submitted to the market """ # do nothing if sending through orders if self._waiting or (len(self._asset_units.keys()) == 0): return self._mm_orders = {} # acquire list of all securities securities = list(self._payoffs.keys()) # for each security, determine the prices of valid buys and sells that # can be created in the market order = Order.create_new() order.price = 0 for security in securities: order.market = Market(self._market_ids[security]) # create quasi buy order order.order_side = OrderSide.BUY self.is_portfolio_optimal([order]) # create quasi sell order order.order_side = OrderSide.SELL self.is_portfolio_optimal([order]) # filter out orders from potential orders that can't be executed # due to not enough cash / units self._remove_invalid_mm_orders() # # send valid market maker orders in the market if not self._waiting: self._waiting = True self._send_valid_mm_orders()
def make_order(self, market_id, oside, price, otype = OrderType.LIMIT, \ units = 1): """ Makes and returns Order object with the defined parameters """ new_order = Order.create_new() new_order.market = Market(market_id) new_order.order_side = oside new_order.order_type = otype new_order.price = price new_order.units = units new_order.ref = f'{otype} Order in {new_order.market} \ for {new_order.units}@{new_order.price}' if market_id == self._private_market_id: new_order.owner_or_target = "M000" return new_order
def initialised(self): """ Initialises bot Stores the market id parameters for Order Management """ # dict to track market attributes markets_to_trade = self.markets for key in markets_to_trade: self.inform(markets_to_trade[key]) # initialise public and private market IDs if markets_to_trade[key].private_market: self._private_market_id = key else: self._public_market_id = key # track public market price tick self._price_tick = Market(self._public_market_id).price_tick
def _sell_notes(self): """ Determines if current cash level is below arbitrary threshold, if it yes, sells notes at a small loss :return: """ # stop if initialising OR if have enough cash if len(self._asset_units.keys()) == 0 or \ self._cash_available > MIN_CASH_THRESHOLD: return # find the note key note_key = "" for asset in self._asset_units: if asset.lower() == "note": note_key = asset # check if have notes available to short if self._asset_units[note_key] > self._short_units_allowed[note_key]: self.inform(f"Cash avail: {self._cash_available}") self.inform(f"Selling notes+++++++++++++++++++++++++++") # create note sell orders for some price to obtain quick cash market = Market(self._market_ids[note_key]) price_tick = market.price_tick new_order = Order.create_new() new_order.price = NOTE_SELLING_PRICE - \ (NOTE_SELLING_PRICE % price_tick) new_order.market = market new_order.units = 1 new_order.order_side = OrderSide.SELL new_order.order_type = OrderType.LIMIT new_order.ref = "Order need_cash - SM" self._waiting = True self._order_id += 1 self._num_orders_sent += 1 self.send_order(new_order)
def _create_new_order(self, market: int, price: int, units: int, order_side: OrderSide, order_type: OrderType, ref: str): """ :param market: market ID for the order :param price: determined price :param units: # of units to be submitted, fixed to 1 :param order_side: buy or sell :param order_type: limit or market, fixed to limit :param ref: customer string of format "Order: {self._sent_order_count} - SM" :return: """ new_order = Order.create_new() new_order.market = Market(market) new_order.price = price new_order.units = units new_order.order_side = order_side new_order.order_type = order_type new_order.ref = ref self.send_order(new_order) self._waiting_for_server = True self._sent_order_count += 1