Beispiel #1
0
 def getLastTrade(self, symbol):
     self.sendMessage(
         self.exchangeID,
         Message({
             "msg": "QUERY_LAST_TRADE",
             "sender": self.id,
             "symbol": symbol
         }))
Beispiel #2
0
    def wakeup(self, currentTime):
        # Allow the base Agent to do whatever it needs to.
        super().wakeup(currentTime)

        # This agent only needs one wakeup call at simulation start.  At this time,
        # each client agent will send a number to each agent in its peer list.
        # Each number will be sampled independently.  That is, client agent 1 will
        # send n2 to agent 2, n3 to agent 3, and so forth.

        # Once a client agent has received these initial random numbers from all
        # agents in the peer list, it will make its first request from the sum
        # service.  Afterwards, it will simply request new sums when answers are
        # delivered to previous queries.

        # At the first wakeup, initiate peer exchange.
        if not self.peer_exchange_complete:
            n = [self.random_state.randint(low=0, high=100) for i in range(len(self.peer_list))]
            log_print("agent {} peer list: {}", self.id, self.peer_list)
            log_print("agent {} numbers to exchange: {}", self.id, n)

            for idx, peer in enumerate(self.peer_list):
                self.sendMessage(peer, Message({"msg": "PEER_EXCHANGE", "sender": self.id, "n": n[idx]}))

        else:
            # For subsequent (self-induced) wakeups, place a sum query.
            n1, n2 = [self.random_state.randint(low=0, high=100) for i in range(2)]

            log_print("agent {} transmitting numbers {} and {} with peer sum {}", self.id, n1, n2, self.peer_sum)

            # Add the sum of the peer exchange values to both numbers.
            n1 += self.peer_sum
            n2 += self.peer_sum

            self.sendMessage(self.serviceAgentID, Message({"msg": "SUM_QUERY", "sender": self.id,
                                                           "n1": n1, "n2": n2}))

        return
Beispiel #3
0
    def processSum(self):

        current_sum = sum([x[0] + x[1] for x in self.numbers.values()])
        self.total += current_sum

        log_print("Agent {} computed sum: {}", self.id, current_sum)

        for sender in self.numbers.keys():
            self.sendMessage(
                sender,
                Message({
                    "msg": "SUM_QUERY_RESPONSE",
                    "sender": self.id,
                    "sum": current_sum
                }))
Beispiel #4
0
    def wakeup(self, currentTime):
        super().wakeup(currentTime)

        if self.mkt_close is None:
            # Ask our exchange when it opens and closes.
            self.sendMessage(
                self.exchangeID,
                Message({
                    "msg": "WHEN_MKT_CLOSE",
                    "sender": self.id
                }))

        else:
            # Get close price of ETF/nav
            self.getLastTrade(self.symbol)
    def wakeup(self, currentTime):
        # Parent class handles discovery of exchange times and market_open wakeup call.
        super().wakeup(currentTime)

        # Only if the superclass leaves the state as ACTIVE should we proceed with our
        # trading strategy.
        if self.state != 'ACTIVE': return

        if not self.prime_open:
            # Ask our primary when it opens and closes, exchange is handled in TradingAgent
            self.sendMessage(self.primeID, Message({"msg": "WHEN_PRIME_OPEN", "sender": self.id}))
            self.sendMessage(self.primeID, Message({"msg": "WHEN_PRIME_CLOSE", "sender": self.id}))

        # Steady state wakeup behavior starts here.
        if not self.mkt_closed and self.prime_closed:
            print('The prime closed before the exchange')
            sys.exit()

        elif self.mkt_closed and self.prime_closed:
            return

        # If we've been told the market has closed for the day, we will only request
        # final price information, then stop.
        # If the market has closed and we haven't obtained the daily close price yet,
        # do that before we cease activity for the day.  Don't do any other behavior
        # after market close.
        elif self.mkt_closed and not self.prime_closed:
            if self.switched_mkt and self.currentTime >= self.prime_open:
                self.getEtfNav()
                self.state = 'AWAITING_NAV'
            elif not self.switched_mkt:
                for i, s in enumerate(self.portfolio):
                    if s not in self.daily_close_price:
                        self.getLastTrade(s)
                        self.state = 'AWAITING_LAST_TRADE'
                if 'ETF' not in self.daily_close_price:
                    self.getLastTrade('ETF')
                    self.state = 'AWAITING_LAST_TRADE'

                print('holdings before primary: ' + str(self.holdings))

                self.setWakeup(self.prime_open)
                self.switched_mkt = True
            else:
                self.setWakeup(self.prime_open)
            return

        # Schedule a wakeup for the next time this agent should arrive at the market
        # (following the conclusion of its current activity cycle).
        # We do this early in case some of our expected message responses don't arrive.

        # Agents should arrive according to a Poisson process.  This is equivalent to
        # each agent independently sampling its next arrival time from an exponential
        # distribution in alternate Beta formation with Beta = 1 / lambda, where lambda
        # is the mean arrival rate of the Poisson process.
        else:
            delta_time = self.random_state.exponential(scale=1.0 / self.lambda_a)
            self.setWakeup(currentTime + pd.Timedelta('{}ns'.format(int(round(delta_time)))))

            # Issue cancel requests for any open orders.  Don't wait for confirmation, as presently
            # the only reason it could fail is that the order already executed.  (But requests won't
            # be generated for those, anyway, unless something strange has happened.)
            self.cancelOrders()

            # The ETF arb agent DOES try to maintain a zero position, so there IS need to exit positions
            # as some "active trading" agents might.  It might exit a position based on its order logic,
            # but this will be as a natural consequence of its beliefs... but it submits marketable orders so...

            # If the calling agent is a subclass, don't initiate the strategy section of wakeup(), as it
            # may want to do something different.
            # FIGURE OUT WHAT TO DO WITH MULTIPLE SPREADS...
            for i, s in enumerate(self.portfolio):
                self.getCurrentSpread(s)
            self.getCurrentSpread('ETF')
            self.state = 'AWAITING_SPREAD'
 def placeBasketOrder(self, quantity, is_create_order):
     order = BasketOrder(self.id, self.currentTime, 'ETF', quantity, is_create_order)
     print('BASKET ORDER PLACED: ' + str(order))
     self.sendMessage(self.primeID, Message({"msg": "BASKET_ORDER", "sender": self.id,
                                             "order": order}))
     self.state = 'AWAITING_BASKET'
 def getEtfNav(self):
     self.sendMessage(self.primeID, Message({"msg": "QUERY_NAV", "sender": self.id}))
Beispiel #8
0
    def receiveMessage(self, currentTime, msg):
        super().receiveMessage(currentTime, msg)

        # Unless the intent of an experiment is to examine computational issues within an Exchange,
        # it will typically have either 1 ns delay (near instant but cannot process multiple orders
        # in the same atomic time unit) or 0 ns delay (can process any number of orders, always in
        # the atomic time unit in which they are received).  This is separate from, and additional
        # to, any parallel pipeline delay imposed for order book activity.

        # Note that computation delay MUST be updated before any calls to sendMessage.
        self.setComputationDelay(self.computation_delay)

        # Is the exchange closed?  (This block only affects post-close, not pre-open.)
        if currentTime > self.prime_close:
            # Most messages after close will receive a 'PRIME_CLOSED' message in response.
            log_print("{} received {}, discarded: prime is closed.", self.name,
                      msg.body['msg'])
            self.sendMessage(msg.body['sender'],
                             Message({"msg": "PRIME_CLOSED"}))
            # Don't do any further processing on these messages!
            return

        if msg.body['msg'] == "WHEN_MKT_CLOSE":
            self.mkt_close = msg.body['data']
            log_print("Recorded market close: {}",
                      self.kernel.fmtTime(self.mkt_close))
            self.setWakeup(self.mkt_close)
            return

        elif msg.body['msg'] == 'QUERY_LAST_TRADE':
            # Call the processQueryLastTrade method.
            self.queryLastTrade(msg.body['symbol'], msg.body['data'])
            return

        self.logEvent(msg.body['msg'], msg.body['sender'])

        # Handle all message types understood by this exchange.
        if msg.body['msg'] == "WHEN_PRIME_OPEN":
            log_print("{} received WHEN_PRIME_OPEN request from agent {}",
                      self.name, msg.body['sender'])

            # The exchange is permitted to respond to requests for simple immutable data (like "what are your
            # hours?") instantly.  This does NOT include anything that queries mutable data, like equity
            # quotes or trades.
            self.setComputationDelay(0)

            self.sendMessage(
                msg.body['sender'],
                Message({
                    "msg": "WHEN_PRIME_OPEN",
                    "data": self.prime_open
                }))

        elif msg.body['msg'] == "WHEN_PRIME_CLOSE":
            log_print("{} received WHEN_PRIME_CLOSE request from agent {}",
                      self.name, msg.body['sender'])

            # The exchange is permitted to respond to requests for simple immutable data (like "what are your
            # hours?") instantly.  This does NOT include anything that queries mutable data, like equity
            # quotes or trades.
            self.setComputationDelay(0)

            self.sendMessage(
                msg.body['sender'],
                Message({
                    "msg": "WHEN_PRIME_CLOSE",
                    "data": self.prime_close
                }))

        elif msg.body['msg'] == "QUERY_NAV":
            log_print("{} received QUERY_NAV ({}) request from agent {}",
                      self.name, msg.body['sender'])

            # Return the NAV for the requested symbol.
            self.sendMessage(
                msg.body['sender'],
                Message({
                    "msg":
                    "QUERY_NAV",
                    "nav":
                    self.nav,
                    "prime_closed":
                    True if currentTime > self.prime_close else False
                }))

        elif msg.body['msg'] == "BASKET_ORDER":
            order = msg.body['order']
            log_print("{} received BASKET_ORDER: {}", self.name, order)
            if order.is_buy_order:
                self.create += 1
            else:
                self.redeem += 1
            order.fill_price = self.nav
            self.sendMessage(
                msg.body['sender'],
                Message({
                    "msg": "BASKET_EXECUTED",
                    "order": order
                }))