Example #1
0
 def test_cancel_order(self):
     book = OrderBook()
     limit_buy_order = Order(ID_GENERATOR, 1, 100, "LIMIT", 100)
     book.add_order(limit_buy_order)
     self.assertEqual(limit_buy_order.order_state, 'ACTIVE')
     book.cancel_order(limit_buy_order.id)
     self.assertEqual(limit_buy_order.order_state, 'CANCELLED')
Example #2
0
 def test_lazy_cleanup(self):
     book = OrderBook()
     limit_buy_order = Order(ID_GENERATOR, 1, 100, "LIMIT", 100)
     limit_sell_order = Order(ID_GENERATOR, 2, 105, "LIMIT", -100)
     book.add_order(limit_buy_order)
     book.add_order(limit_sell_order)
     book.cancel_order(limit_buy_order.id)
     book.cancel_order(limit_sell_order.id)
     self.assertEqual(limit_buy_order.order_state, 'CANCELLED')
     self.assertEqual(limit_sell_order.order_state, 'CANCELLED')
     self.assertEqual(len(book.bids), 1)
     self.assertEqual(len(book.asks), 1)
     book._OrderBook__lazy_remove_completed_orders()
     self.assertEqual(len(book.bids), 0)
     self.assertEqual(len(book.asks), 0)
Example #3
0
class test_order_book(unittest.TestCase):
    def setUp(self):
        self.completed_trades = []
        self.completed_orders = []
        self.orders = []
        self.order_book = OrderBook("KEQ")
        for i in range(1, 10):
            quote = test_quotes[str(i)]
            if "price" in quote:
                quote["price"] = Decimal(quote["price"])
            order = json.loads(self.order_book.process_order(quote))
            self.orders.append(order)
            for trades in self.order_book.completed_trades:
                self.completed_trades.append(trades)
            for orders in self.order_book.completed_orders:
                self.completed_orders.append(orders)

    def test_get_min_ask(self):
        self.assertEqual(self.order_book.get_min_ask(), 99.5)

    def test_get_max_bid(self):
        self.assertEqual(self.order_book.get_max_bid(), 99)

    def test_process_order(self):
        self.assertEqual(len(self.order_book.bids.keys()), 1)
        self.assertEqual(len(self.order_book.asks.keys()), 2)
        self.assertEqual(len(self.completed_trades), 6)
        self.assertEqual(len(self.order_book.ongoing_orders), 3)
        self.assertEqual(len(self.completed_orders), 6)

    def test_modify_order(self):
        quote = test_quotes[str(10)]
        if "price" in quote:
            quote["price"] = Decimal(quote["price"])
        new_order = json.loads(
            self.order_book.modify_order(self.orders[8]["order_id"], quote))
        self.assertEqual(new_order["price"], '75')

    def test_cancel_order(self):
        quote = test_quotes[str(10)]
        if "price" in quote:
            quote["price"] = Decimal(quote["price"])
        new_order = json.loads(self.order_book.process_order(quote))
        self.order_book.cancel_order(new_order["order_id"])
        self.assertEqual(len(self.order_book.bids.keys()), 1)
Example #4
0
class Engine:
    def __init__(self):
        self.orderbook = OrderBook()
        self.orderbook.on_event = self.on_event
        self.trades = []
        self._next_order_id = 0
        self.all_orders = {}

    def next_order_id(self):
        n = self._next_order_id
        self._next_order_id += 1
        return n

    def limit_order(self, side, price, amount):
        o = Order(self.next_order_id(), side, price, amount)
        self.all_orders[o.id] = o
        self.orderbook.limit_order(o)
        self.validate()
        return o

    def cancel_order(self, orderid):
        o = self.orderbook.cancel_order(self.all_orders[orderid].price,
                                        orderid)
        self.validate()
        return o

    def on_event(self, name, evt):
        if name == 'trade':
            self.trades.append(evt)

    def validate(self):
        book = self.orderbook
        assert not book.bids or not book.asks or book.bids.max() < book.asks.min(), \
            'bids asks shouldn\'t cross'
        assert all(price == self.all_orders[makerid].price
                   for _, makerid, _, price in self.trades), \
            'trade price equals to maker price'
        assert all(better_price(price,
                                self.all_orders[takerid].price,
                                self.all_orders[takerid].side)
                   for takerid, _, _, price in self.trades), \
            'trade price equal or better than taker price'
        assert all(order.price == price
                   for price, lvl in book.levels.items()
                   for order in lvl.orders), \
            'level price is correct'
        assert all(sum(o.size for o in lvl.orders) == lvl.volume
                   for price, lvl in book.levels.items()), \
            'level volume is correct'
class MarketSim(object):
    def __init__(self, order_arrival_lambda=2, initial_price=100., price_sigma=.2, quantity_mu=2, quantity_sigma=1,
                 periods=None, traders=50, tick_size=.0001, purge_after_vol=100,
                 open_time=dt.datetime(2017, 1, 1, 8, 0, 0), close_time=dt.datetime(2017, 1, 1, 15, 0, 0)):
        self.p0 = initial_price
        self.p = initial_price
        self.tick_size = tick_size
        self.purge_after_vol = purge_after_vol
        self.order_arrival_lambda = order_arrival_lambda
        self.price_sigma = price_sigma
        self.quantity_mu = quantity_mu
        self.quantity_sigma = quantity_sigma
        if periods:
            self.periods = periods
        else:
            self.periods = (close_time-open_time).total_seconds()
        if type(traders) == int:
            traders = range(traders)
        self.traders = traders

        self.orderbook = OrderBook()
        self.total_orders_submitted = 0
        self.sides = np.array(['ask', 'bid'])
        self.sign = np.array([1., -1.])
        self.time = 0
        self.orders_by_vol = deque(maxlen=None)

    def simulate_batch(self, size=10000, verbose=False):
        # number of orders that arrive
        inter_arrival_times = np.random.exponential(self.order_arrival_lambda, size=size)
        timestamps = inter_arrival_times.cumsum() + self.time
        self.process_orders(timestamps, verbose)
        self.purge_stale_orders()
        self.time = timestamps[-1]

    def simulate_periods(self, periods=None, verbose=False):
        if not periods:
            periods = self.periods
        while self.time < periods:
            self.simulate_batch(size=min(10000, periods/10), verbose=verbose)

    def process_orders(self, timestamps, verbose=False):
        # if new orders arrived--add them to the book
        n_orders = len(timestamps)
        # draw side (buy/sell) distribution is binomial, p=.5
        order_side = np.random.choice([0, 1], size=n_orders, replace=True)
        # randomly assign traders to each slot
        order_trader = np.random.choice(self.traders, size=n_orders, replace=True)
        order_price_shocks = np.random.lognormal(0, self.price_sigma, size=n_orders)
        order_quantity = np.ceil(np.random.lognormal(self.quantity_mu, self.quantity_sigma, size=n_orders))

        for i in xrange(n_orders):
            if timestamps[i] > self.periods:
                break
            side = self.sides[order_side][i]
            order_price = self.p * order_price_shocks[i] + self.sign[order_side][i] * self.tick_size * self.p
            quote = {
               "type": "limit",
               "side": side,
               "timestamp": timestamps[i],
               "trade_id": order_trader[i],
               "order_id": self.total_orders_submitted,
               "price": order_price,
               'quantity': int(order_quantity[i])
            }
            self.orderbook.process_order(quote, from_data=True, verbose=verbose)
            self.log_order_type(side)
            self.total_orders_submitted += 1
            self.sync_book_price()

    def purge_stale_orders(self):
        if len(self.orders_by_vol) > 0 & len(self.orderbook.tape) >= 100:
            current_vol = len(self.orderbook.tape)
            while current_vol-self.purge_after_vol >= self.orders_by_vol[0][0]:
                _, side, order_id = self.orders_by_vol.popleft()
                self.orderbook.cancel_order(side=side, order_id=order_id)
                if len(self.orders_by_vol) == 0:
                    break

    def sync_book_price(self):
        if len(self.orderbook.tape) > 0:
            self.p = float(self.orderbook.tape[-1]['price'])

    def plot_prices(self, time_scale=1.,plot_params={}):
        interval_trades = self.get_transactions(time_scale=time_scale)
        interval_trades.set_index('time')['price'].apply(lambda x: float(x)).plot(**plot_params)

    def get_tape_dataframe(self):
        return pd.DataFrame(list(self.orderbook.tape))

    def show_stats(self):
        n_trades = len(self.orderbook.tape)
        mean_quantity = self.get_tape_dataframe()['quantity'].apply(lambda x: float(x)).mean()
        print("trades per second: %3.3f" % (n_trades / self.time))
        print("quantity per 600: %3.3f" % (mean_quantity * 600))

    def log_order_type(self, side):
        order_id = self.total_orders_submitted
        current_vol = len(self.orderbook.tape)
        self.orders_by_vol.append((current_vol, str(side), int(order_id)))

    @staticmethod
    def get_side_id(side, party1, party2):
        if party1[1] == side:
            return party1[0]
        else:
            return party2[0]

    def get_transactions(self, time_scale=1):
        tape = self.get_tape_dataframe()
        tape['price'] = tape['price'].apply(float)
        tape['quantity'] = tape['quantity'].apply(int)
        tape['time'] = tape['timestamp'].apply(lambda x: np.floor(x/time_scale))
        tape['quantity'] = (tape.groupby('time')['quantity'].transform('sum'))
        agg = tape.groupby('time').last().reset_index()
        agg['ask_id'] = agg.apply(lambda row: MarketSim.get_side_id('ask', row['party1'], row['party2']), axis=1)
        agg['bid_id'] = agg.apply(lambda row: MarketSim.get_side_id('bid', row['party1'], row['party2']), axis=1)
        return agg[['time', 'ask_id', 'bid_id', 'quantity', 'price']]

    def export_transactions(self, filename):
        self.get_transactions().to_csv(filename, index=False)
Example #6
0
            printme ("\n")
            print_orderbook(order_book, old_orderbook)
            stats=myalgo.stats()
            printme ("total volume=", stats[0])
            printme ("my volume=", stats[1])
            printme ("participation=", stats[3])

            if myalgo != None:
                (algo_orders, mode) = myalgo.process_order(line, order)
                printme('')
                printme("RUNNING ALGO WITH MODE=", mode)
                old_orderbook = copy.deepcopy(order_book)
                for line in algo_orders:
                    printme(pprint.pformat(line))
                    if line['type'] == 'cancel':
                        order_book.cancel_order(line['side'],
                                                line['order_id'])
                    elif line['type'] == 'cancel_all':
                        if line['side'] == "bid":
                            q = order_book.bids
                        elif line['size'] == 'ask':
                            q = order_book.asks
                        else:
                            sys.exit('not given bid or ask')
                        for order in q.price_tree.get(Decimal(line['price']),
                                                      []):
                            if order.trade_id == line['trade_id']:
                                order_book.cancel_order(line['side'],
                                                        order.order_id)
                    elif line['type'] == 'modify':
                        order_book.modify_order(line['order_id'], {
                            'side': line['side'],
Example #7
0
            print_orderbook(order_book, old_orderbook)
            stats=myalgo.stats()
            printme ("total volume=", stats[0])
            printme ("my volume=", stats[1])
            printme ("participation=", stats[3])

            if myalgo != None:
                (algo_orders, mode) = myalgo.process_order(line,
                                                           trade, order)
                printme('')
                printme("RUNNING ALGO WITH MODE=", mode)
                old_orderbook = copy.deepcopy(order_book)
                for line in algo_orders:
                    printme(pprint.pformat(line))
                    if line['type'] == 'cancel':
                        order_book.cancel_order(line['side'],
                                                line['order_id'])
                    elif line['type'] == 'modify':
                        order_book.modify_order(line['order_id'], {
                            'side': line['side'],
                            'price': line['price'],
                            'quantity': line['quantity']})
                    else:
                        (trade, order) = order_book.process_order(line,
                                                                  False,
                                                                  False)
                        myalgo.process_trade(trade, mode)
                if len(algo_orders) > 0:
                    printme("\n")
                    printme("After algo")
                    print_orderbook(order_book, old_orderbook)
                    stats=myalgo.stats()