import random import numpy as np import unittest from pyziabm.trader2017_r3 import Provider, Provider5, Taker, MarketMaker, MarketMaker5, PennyJumper, InformedTrader class TestTrader(unittest.TestCase): ''' Five classes: 1. ZITrader is a base class with make_add_quote() 2. Taker inherits from ZITrader with process_signal() 3. Provider inherits from ZITrader with make_cancel_quote(), confirm_cancel_local(), confirm_trade_local(), process_signal(), choose_price_from_exp() and bulk_cancel(). 4. MarketMaker inherits from Provider with confirm_trade_local(), cumulate_cashflow() and process_signal(). 5. PennyJumper inherits from ZITrader with make_cancel_quote(), confirm_trade_local() and process_signal(). PennyJumper has an ask_quote dictionary and bid_quote dictionary which can be None. ''' def setUp(self): self.p1 = Provider('p1', 1, 1, 0.05) self.p5 = Provider5('p5', 1, 5, 0.05) self.t1 = Taker('t1', 1) self.i1 = InformedTrader('i1', 1, 'buy') self.i2 = InformedTrader('i2', 2, 'sell') self.m1 = MarketMaker('m1', 1, 1, 0.05, 12, 60) self.m5 = MarketMaker5('m5', 1, 5, 0.05, 12, 60) self.j1 = PennyJumper('j1', 1, 5) self.q1 = {'order_id': 'p1_1', 'timestamp': 1, 'type': 'add', 'quantity': 1, 'side': 'buy', 'price': 125} self.q2 = {'order_id': 'p1_2', 'timestamp': 2, 'type': 'add', 'quantity': 5, 'side': 'buy', 'price': 125} self.q3 = {'order_id': 'p1_3', 'timestamp': 3, 'type': 'add', 'quantity': 1, 'side': 'buy', 'price': 124} self.q4 = {'order_id': 'p1_4', 'timestamp': 4, 'type': 'add', 'quantity': 1, 'side': 'buy', 'price': 123} self.q5 = {'order_id': 'p1_5', 'timestamp': 5, 'type': 'add', 'quantity': 1, 'side': 'buy', 'price': 122} self.q6 = {'order_id': 'p1_6', 'timestamp': 6, 'type': 'add', 'quantity': 1, 'side': 'sell', 'price': 126} self.q7 = {'order_id': 'p1_7', 'timestamp': 7, 'type': 'add', 'quantity': 5, 'side': 'sell', 'price': 127} self.q8 = {'order_id': 'p1_8', 'timestamp': 8, 'type': 'add', 'quantity': 1, 'side': 'sell', 'price': 128} self.q9 = {'order_id': 'p1_9', 'timestamp': 9, 'type': 'add', 'quantity': 1, 'side': 'sell', 'price': 129} self.q10 = {'order_id': 'p1_10', 'timestamp': 10, 'type': 'add', 'quantity': 1, 'side': 'sell', 'price': 130} # ZITrader tests def test_make_add_quote(self): time = 1 quantity = 1 side = 'sell' price = 125 q = self.p1._make_add_quote(time, quantity, side, price) expected = {'order_id': 'p1_1', 'timestamp': 1, 'type': 'add', 'quantity': 1, 'side': 'sell', 'price': 125} self.assertDictEqual(q, expected) # Taker tests def test_repr_Taker(self): #print('Provider: {0}, Taker: {1}'.format(self.p1, self.t1)) self.assertEqual('Taker: Trader(t1, 1, Taker)', 'Taker: {0}'.format(self.t1)) def test_process_signal_Taker(self): ''' Generates a quote object (dict) and appends to quote_collector ''' time = 1 q_taker = 0.5 low_ru_seed = 1 hi_ru_seed = 10 self.assertFalse(self.t1.quote_collector) random.seed(low_ru_seed) self.t1.process_signal(time, q_taker) self.assertEqual(len(self.t1.quote_collector), 1) self.assertEqual(self.t1.quote_collector[0]['side'], 'buy') self.assertEqual(self.t1.quote_collector[0]['price'], 2000000) random.seed(hi_ru_seed) self.t1.process_signal(time, q_taker) self.assertEqual(len(self.t1.quote_collector), 1) self.assertEqual(self.t1.quote_collector[0]['side'], 'sell') self.assertEqual(self.t1.quote_collector[0]['price'], 0) # InformedTrader tests def test_repr_InformedTrader(self): #print('Provider: {0}, Taker: {1}'.format(self.p1, self.t1)) self.assertEqual('Taker: Trader(i1, 1, InformedTrader)', 'Taker: {0}'.format(self.i1)) self.assertEqual('Taker: Trader(i2, 2, InformedTrader)', 'Taker: {0}'.format(self.i2)) def test_process_signal_InformedTrader(self): ''' Generates a quote object (dict) and appends to quote_collector ''' time1 = 1 self.assertFalse(self.t1.quote_collector) self.i1.process_signal(time1) self.assertEqual(len(self.i1.quote_collector), 1) self.assertEqual(self.i1.quote_collector[0]['side'], 'buy') self.assertEqual(self.i1.quote_collector[0]['price'], 2000000) self.assertEqual(self.i1.quote_collector[0]['quantity'], 1) time2 = 2 self.i2.process_signal(time2) self.assertEqual(len(self.i2.quote_collector), 1) self.assertEqual(self.i2.quote_collector[0]['side'], 'sell') self.assertEqual(self.i2.quote_collector[0]['price'], 0) self.assertEqual(self.i2.quote_collector[0]['quantity'], 2) # Provider tests def test_repr_Provider(self): #print('Provider: {0}, Taker: {1}'.format(self.p1, self.t1)) self.assertEqual('Provider: Trader(p1, 1, Provider)', 'Provider: {0}'.format(self.p1)) self.assertEqual('Provider: Trader(p5, 1, Provider)', 'Provider: {0}'.format(self.p5)) def test_make_cancel_quote_Provider(self): q = self.p1._make_cancel_quote(self.q1, 2) expected = {'order_id': 'p1_1', 'timestamp': 2, 'type': 'cancel', 'quantity': 1, 'side': 'buy', 'price': 125} self.assertDictEqual(q, expected) def test_confirm_cancel_local_Provider(self): self.p1.local_book[self.q1['order_id']] = self.q1 self.p1.local_book[self.q2['order_id']] = self.q2 self.assertEqual(len(self.p1.local_book), 2) q = self.p1._make_cancel_quote(self.q1, 2) self.p1.confirm_cancel_local(q) self.assertEqual(len(self.p1.local_book), 1) expected = {self.q2['order_id']: self.q2} self.assertDictEqual(self.p1.local_book, expected) def test_confirm_trade_local_Provider(self): ''' Test Provider for full and partial trade ''' # Provider self.p1.local_book[self.q1['order_id']] = self.q1 self.p1.local_book[self.q2['order_id']] = self.q2 # trade full quantity of q1 trade1 = {'timestamp': 2, 'trader': 'p1', 'order_id': 'p1_1', 'quantity': 1, 'side': 'buy', 'price': 2000000} self.assertEqual(len(self.p1.local_book), 2) self.p1.confirm_trade_local(trade1) self.assertEqual(len(self.p1.local_book), 1) expected = {self.q2['order_id']: self.q2} self.assertDictEqual(self.p1.local_book, expected) # trade partial quantity of q2 trade2 = {'timestamp': 3, 'trader': 'p1', 'order_id': 'p1_2', 'quantity': 2, 'side': 'buy', 'price': 2000000} self.p1.confirm_trade_local(trade2) self.assertEqual(len(self.p1.local_book), 1) expected = {'order_id': 'p1_2', 'timestamp': 2, 'type': 'add', 'quantity': 3, 'side': 'buy', 'price': 125} self.assertDictEqual(self.p1.local_book.get(trade2['order_id']), expected) def test_choose_price_from_exp(self): # mpi == 1 sell_price = self.p1._choose_price_from_exp('bid', 75000, -100) self.assertLess(sell_price, 75000) buy_price = self.p1._choose_price_from_exp('ask', 25000, -100) self.assertGreater(buy_price, 25000) self.assertEqual(np.remainder(buy_price,self.p1._mpi),0) self.assertEqual(np.remainder(sell_price,self.p1._mpi),0) # mpi == 5 sell_price = self.p5._choose_price_from_exp('bid', 75000, -100) self.assertLess(sell_price, 75000) buy_price = self.p5._choose_price_from_exp('ask', 25000, -100) self.assertGreater(buy_price, 25000) self.assertEqual(np.remainder(buy_price,self.p5._mpi),0) self.assertEqual(np.remainder(sell_price,self.p5._mpi),0) def test_process_signal_Provider(self): time = 1 q_provider = 0.5 low_ru_seed = 1 hi_ru_seed = 10 tob_price = {'best_bid': 25000, 'best_ask': 75000} self.assertFalse(self.p1.quote_collector) self.assertFalse(self.p1.local_book) np.random.seed(low_ru_seed) self.p1.process_signal(time, tob_price, q_provider, -100) self.assertEqual(len(self.p1.quote_collector), 1) self.assertEqual(self.p1.quote_collector[0]['side'], 'buy') self.assertEqual(len(self.p1.local_book), 1) np.random.seed(hi_ru_seed) self.p1.process_signal(time, tob_price, q_provider, -100) self.assertEqual(len(self.p1.quote_collector), 1) self.assertEqual(self.p1.quote_collector[0]['side'], 'sell') self.assertEqual(len(self.p1.local_book), 2) def test_bulk_cancel_Provider(self): ''' Put 10 orders in the book, use random seed to determine which orders are cancelled, test for cancelled orders in the queue ''' self.assertFalse(self.p1.local_book) self.assertFalse(self.p1.cancel_collector) self.p1.local_book[self.q1['order_id']] = self.q1 self.p1.local_book[self.q2['order_id']] = self.q2 self.p1.local_book[self.q3['order_id']] = self.q3 self.p1.local_book[self.q4['order_id']] = self.q4 self.p1.local_book[self.q5['order_id']] = self.q5 self.p1.local_book[self.q6['order_id']] = self.q6 self.p1.local_book[self.q7['order_id']] = self.q7 self.p1.local_book[self.q8['order_id']] = self.q8 self.p1.local_book[self.q9['order_id']] = self.q9 self.p1.local_book[self.q10['order_id']] = self.q10 self.assertEqual(len(self.p1.local_book), 10) self.assertFalse(self.p1.cancel_collector) # np.random seed = 8 generates 1 position less than 0.025 from np.random.ranf: 5 np.random.seed(8) self.p1._delta = 0.025 self.p1.bulk_cancel(11) self.assertEqual(len(self.p1.cancel_collector), 1) # np.random seed = 7 generates 2 positions less than 0.1 from np.random.ranf: 0, 7 np.random.seed(7) self.p1._delta = 0.1 self.p1.bulk_cancel(12) self.assertEqual(len(self.p1.cancel_collector), 2) # np.random seed = 6 generates 0 position less than 0.025 from np.random.ranf np.random.seed(6) self.p1._delta = 0.025 self.p1.bulk_cancel(12) self.assertFalse(self.p1.cancel_collector) # MarketMaker tests def test_repr_MM(self): self.assertEqual('MarketMaker: Trader(m1, 1, MarketMaker, 12)', 'MarketMaker: {0}'.format(self.m1)) self.assertEqual('MarketMaker: Trader(m5, 1, MarketMaker, 12)', 'MarketMaker: {0}'.format(self.m5)) def test_confirm_trade_local_MM(self): ''' Test Market Maker for full and partial trade ''' # MarketMaker buys self.m1.local_book[self.q1['order_id']] = self.q1 self.m1.local_book[self.q2['order_id']] = self.q2 # trade full quantity of q1 trade1 = {'timestamp': 2, 'trader': 'p1', 'order_id': 'p1_1', 'quantity': 1, 'side': 'buy', 'price': 2000000} self.assertEqual(len(self.m1.local_book), 2) self.m1.confirm_trade_local(trade1) self.assertEqual(len(self.m1.local_book), 1) self.assertEqual(self.m1._position, 1) expected = {self.q2['order_id']: self.q2} self.assertDictEqual(self.m1.local_book, expected) # trade partial quantity of q2 trade2 = {'timestamp': 3, 'trader': 'p1', 'order_id': 'p1_2', 'quantity': 2, 'side': 'buy', 'price': 2000000} self.m1.confirm_trade_local(trade2) self.assertEqual(len(self.m1.local_book), 1) self.assertEqual(self.m1._position, 3) expected = {'order_id': 'p1_2', 'timestamp': 2, 'type': 'add', 'quantity': 3, 'side': 'buy', 'price': 125} self.assertDictEqual(self.m1.local_book.get(trade2['order_id']), expected) # MarketMaker sells self.setUp() self.m1.local_book[self.q6['order_id']] = self.q6 self.m1.local_book[self.q7['order_id']] = self.q7 # trade full quantity of q6 trade1 = {'timestamp': 6, 'trader': 'p1', 'order_id': 'p1_6', 'quantity': 1, 'side': 'sell', 'price': 0} self.assertEqual(len(self.m1.local_book), 2) self.m1.confirm_trade_local(trade1) self.assertEqual(len(self.m1.local_book), 1) self.assertEqual(self.m1._position, -1) expected = {self.q7['order_id']: self.q7} self.assertDictEqual(self.m1.local_book, expected) # trade partial quantity of q7 trade2 = {'timestamp': 7, 'trader': 'p1', 'order_id': 'p1_7', 'quantity': 2, 'side': 'sell', 'price': 0} self.m1.confirm_trade_local(trade2) self.assertEqual(len(self.m1.local_book), 1) self.assertEqual(self.m1._position, -3) expected = {'order_id': 'p1_7', 'timestamp': 7, 'type': 'add', 'quantity': 3, 'side': 'sell', 'price': 127} self.assertDictEqual(self.m1.local_book.get(trade2['order_id']), expected) def test_cumulate_cashflow_MM(self): self.assertFalse(self.m1.cash_flow_collector) expected = {'mmid': 'm1', 'timestamp': 10, 'cash_flow': 0, 'position': 0} self.m1._cumulate_cashflow(10) self.assertDictEqual(self.m1.cash_flow_collector[0], expected) def test_process_signal_MM5_12(self): time = 1 q_provider = 0.5 low_ru_seed = 1 hi_ru_seed = 10 # size > 1: market maker matches best price tob1 = {'best_bid': 25000, 'best_ask': 75000, 'bid_size': 10, 'ask_size': 10} self.assertFalse(self.m5.quote_collector) self.assertFalse(self.m5.local_book) random.seed(low_ru_seed) self.m5.process_signal(time, tob1, q_provider) self.assertEqual(len(self.m5.quote_collector), 12) self.assertEqual(self.m5.quote_collector[0]['side'], 'buy') for i in range(len(self.m5.quote_collector)): with self.subTest(i=i): self.assertLessEqual(self.m5.quote_collector[i]['price'], 25000) self.assertGreaterEqual(self.m5.quote_collector[i]['price'], 24935) self.assertTrue(self.m5.quote_collector[i]['price'] in range(24935, 25001, 5)) self.assertEqual(len(self.m5.local_book), 12) random.seed(hi_ru_seed) self.m5.process_signal(time, tob1, q_provider) self.assertEqual(len(self.m5.quote_collector), 12) self.assertEqual(self.m5.quote_collector[0]['side'], 'sell') for i in range(len(self.m5.quote_collector)): with self.subTest(i=i): self.assertLessEqual(self.m5.quote_collector[i]['price'], 75065) self.assertGreaterEqual(self.m5.quote_collector[i]['price'], 75000) self.assertTrue(self.m5.quote_collector[i]['price'] in range(75000, 75066, 5)) self.assertEqual(len(self.m5.local_book), 24) # size == 1: market maker adds liquidity one point behind self.setUp() tob2 = {'best_bid': 25000, 'best_ask': 75000, 'bid_size': 1, 'ask_size': 1} self.assertFalse(self.m5.quote_collector) self.assertFalse(self.m5.local_book) np.random.seed(low_ru_seed) self.m5.process_signal(time, tob2, q_provider) self.assertEqual(len(self.m5.quote_collector), 12) self.assertEqual(self.m5.quote_collector[0]['side'], 'buy') for i in range(len(self.m5.quote_collector)): with self.subTest(i=i): self.assertLessEqual(self.m5.quote_collector[i]['price'], 24995) self.assertGreaterEqual(self.m5.quote_collector[i]['price'], 24930) self.assertTrue(self.m5.quote_collector[i]['price'] in range(24930, 24995)) self.assertEqual(len(self.m5.local_book), 12) np.random.seed(hi_ru_seed) self.m5.process_signal(time, tob2, q_provider) self.assertEqual(len(self.m5.quote_collector), 12) self.assertEqual(self.m5.quote_collector[0]['side'], 'sell') for i in range(len(self.m5.quote_collector)): with self.subTest(i=i): self.assertLessEqual(self.m5.quote_collector[i]['price'], 75065) self.assertGreaterEqual(self.m5.quote_collector[i]['price'], 75005) self.assertTrue(self.m5.quote_collector[i]['price'] in range(75005, 75065, 5)) self.assertEqual(len(self.m5.local_book), 24) def test_process_signal_MM1_12(self): time = 1 q_provider = 0.5 low_ru_seed = 1 hi_ru_seed = 10 # size > 1: market maker matches best price tob1 = {'best_bid': 25000, 'best_ask': 75000, 'bid_size': 10, 'ask_size': 10} self.assertFalse(self.m1.quote_collector) self.assertFalse(self.m1.local_book) random.seed(low_ru_seed) self.m1.process_signal(time, tob1, q_provider) self.assertEqual(len(self.m1.quote_collector), 12) self.assertEqual(self.m1.quote_collector[0]['side'], 'buy') for i in range(len(self.m1.quote_collector)): with self.subTest(i=i): self.assertLessEqual(self.m1.quote_collector[i]['price'], 25000) self.assertGreaterEqual(self.m1.quote_collector[i]['price'], 24941) self.assertTrue(self.m1.quote_collector[i]['price'] in range(24941, 25001)) self.assertEqual(len(self.m1.local_book), 12) random.seed(hi_ru_seed) self.m1.process_signal(time, tob1, q_provider) self.assertEqual(len(self.m1.quote_collector), 12) self.assertEqual(self.m1.quote_collector[0]['side'], 'sell') for i in range(len(self.m1.quote_collector)): with self.subTest(i=i): self.assertLessEqual(self.m1.quote_collector[i]['price'], 75060) self.assertGreaterEqual(self.m1.quote_collector[i]['price'], 75000) self.assertTrue(self.m1.quote_collector[i]['price'] in range(75000, 75061)) self.assertEqual(len(self.m1.local_book), 24) # size == 1: market maker adds liquidity one point behind self.setUp() tob2 = {'best_bid': 25000, 'best_ask': 75000, 'bid_size': 1, 'ask_size': 1} self.assertFalse(self.m1.quote_collector) self.assertFalse(self.m1.local_book) np.random.seed(low_ru_seed) self.m1.process_signal(time, tob2, q_provider) self.assertEqual(len(self.m1.quote_collector), 12) self.assertEqual(self.m1.quote_collector[0]['side'], 'buy') for i in range(len(self.m1.quote_collector)): with self.subTest(i=i): self.assertLessEqual(self.m1.quote_collector[i]['price'], 24999) self.assertGreaterEqual(self.m1.quote_collector[i]['price'], 24940) self.assertTrue(self.m1.quote_collector[i]['price'] in range(24940, 25000)) self.assertEqual(len(self.m1.local_book), 12) np.random.seed(hi_ru_seed) self.m1.process_signal(time, tob2, q_provider) self.assertEqual(len(self.m1.quote_collector), 12) self.assertEqual(self.m1.quote_collector[0]['side'], 'sell') for i in range(len(self.m1.quote_collector)): with self.subTest(i=i): self.assertLessEqual(self.m1.quote_collector[i]['price'], 75060) self.assertGreaterEqual(self.m1.quote_collector[i]['price'], 75001) self.assertTrue(self.m1.quote_collector[i]['price'] in range(75001, 75061)) self.assertEqual(len(self.m1.local_book), 24) # PennyJumper tests def test_repr_PJ(self): self.assertEqual('PennyJumper: Trader(j1, 1, 5, PennyJumper)', 'PennyJumper: {0}'.format(self.j1)) def test_confirm_trade_local_PJ(self): # PennyJumper book self.j1._bid_quote = {'order_id': 'j1_1', 'timestamp': 1, 'type': 'add', 'quantity': 1, 'side': 'buy', 'price': 125} self.j1._ask_quote = {'order_id': 'j1_6', 'timestamp': 6, 'type': 'add', 'quantity': 1, 'side': 'sell', 'price': 126} # trade at the bid trade1 = {'timestamp': 2, 'trader': 'j1', 'order_id': 'j1_1', 'quantity': 1, 'side': 'buy', 'price': 0} self.assertTrue(self.j1._bid_quote) self.j1.confirm_trade_local(trade1) self.assertFalse(self.j1._bid_quote) # trade at the ask trade2 = {'timestamp': 12, 'trader': 'j1', 'order_id': 'j1_6', 'quantity': 1, 'side': 'sell', 'price': 2000000} self.assertTrue(self.j1._ask_quote) self.j1.confirm_trade_local(trade2) self.assertFalse(self.j1._ask_quote) def test_process_signal_PJ(self): # spread > mpi tob = {'bid_size': 5, 'best_bid': 999990, 'best_ask': 1000005, 'ask_size': 5} # PJ book empty self.j1._bid_quote = None self.j1._ask_quote = None # random.seed = 1 generates random.uniform(0,1) = 0.13 then .85 # jump the bid by 1, then jump the ask by 1 random.seed(1) self.j1.process_signal(5, tob, 0.5) self.assertDictEqual(self.j1._bid_quote, {'order_id': 'j1_1', 'timestamp': 5, 'type': 'add', 'quantity': 1, 'side': 'buy', 'price': 999995}) tob = {'bid_size': 1, 'best_bid': 999995, 'best_ask': 1000005, 'ask_size': 5} self.j1.process_signal(6, tob, 0.5) self.assertDictEqual(self.j1._ask_quote, {'order_id': 'j1_2', 'timestamp': 6, 'type': 'add', 'quantity': 1, 'side': 'sell', 'price': 1000000}) # PJ alone at tob tob = {'bid_size': 1, 'best_bid': 999995, 'best_ask': 1000000, 'ask_size': 1} # nothing happens self.j1.process_signal(7, tob, 0.5) self.assertDictEqual(self.j1._bid_quote, {'order_id': 'j1_1', 'timestamp': 5, 'type': 'add', 'quantity': 1, 'side': 'buy', 'price': 999995}) self.assertDictEqual(self.j1._ask_quote, {'order_id': 'j1_2', 'timestamp': 6, 'type': 'add', 'quantity': 1, 'side': 'sell', 'price': 1000000}) # PJ bid and ask behind the book tob = {'bid_size': 1, 'best_bid': 999990, 'best_ask': 1000005, 'ask_size': 1} self.j1._bid_quote = {'order_id': 'j1_1', 'timestamp': 5, 'type': 'add', 'quantity': 1, 'side': 'buy', 'price': 999985} self.j1._ask_quote = {'order_id': 'j1_2', 'timestamp': 6, 'type': 'add', 'quantity': 1, 'side': 'sell', 'price': 1000010} # random.seed = 1 generates random.uniform(0,1) = 0.13 then .85 # jump the bid by 1, then jump the ask by 1; cancel old quotes random.seed(1) self.j1.process_signal(10, tob, 0.5) self.assertDictEqual(self.j1._bid_quote, {'order_id': 'j1_3', 'timestamp': 10, 'type': 'add', 'quantity': 1, 'side': 'buy', 'price': 999995}) self.assertDictEqual(self.j1.cancel_collector[0], {'order_id': 'j1_1', 'timestamp': 10, 'type': 'cancel', 'quantity': 1, 'side': 'buy', 'price': 999985}) self.assertDictEqual(self.j1.quote_collector[0], self.j1._bid_quote) self.j1.process_signal(11, tob, 0.5) self.assertDictEqual(self.j1._ask_quote, {'order_id': 'j1_4', 'timestamp': 11, 'type': 'add', 'quantity': 1, 'side': 'sell', 'price': 1000000}) self.assertDictEqual(self.j1.cancel_collector[0], {'order_id': 'j1_2', 'timestamp': 11, 'type': 'cancel', 'quantity': 1, 'side': 'sell', 'price': 1000010}) self.assertDictEqual(self.j1.quote_collector[0],self.j1._ask_quote) # PJ not alone at the inside tob = {'bid_size': 5, 'best_bid': 999990, 'best_ask': 1000010, 'ask_size': 5} self.j1._bid_quote = {'order_id': 'j1_1', 'timestamp': 5, 'type': 'add', 'quantity': 1, 'side': 'buy', 'price': 999990} self.j1._ask_quote = {'order_id': 'j1_2', 'timestamp': 6, 'type': 'add', 'quantity': 1, 'side': 'sell', 'price': 1000010} # random.seed = 1 generates random.uniform(0,1) = 0.13 then .85 # jump the bid by 1, then jump the ask by 1; cancel old quotes random.seed(1) self.j1.process_signal(12, tob, 0.5) self.assertDictEqual(self.j1._bid_quote, {'order_id': 'j1_5', 'timestamp': 12, 'type': 'add', 'quantity': 1, 'side': 'buy', 'price': 999995}) self.assertDictEqual(self.j1.cancel_collector[0], {'order_id': 'j1_1', 'timestamp': 12, 'type': 'cancel', 'quantity': 1, 'side': 'buy', 'price': 999990}) self.assertDictEqual(self.j1.quote_collector[0], self.j1._bid_quote) self.j1.process_signal(13, tob, 0.5) self.assertDictEqual(self.j1._ask_quote, {'order_id': 'j1_6', 'timestamp': 13, 'type': 'add', 'quantity': 1, 'side': 'sell', 'price': 1000005}) self.assertDictEqual(self.j1.cancel_collector[0], {'order_id': 'j1_2', 'timestamp': 13, 'type': 'cancel', 'quantity': 1, 'side': 'sell', 'price': 1000010}) self.assertDictEqual(self.j1.quote_collector[0],self.j1._ask_quote) # spread at mpi, PJ alone at nbbo tob = {'bid_size': 1, 'best_bid': 999995, 'best_ask': 1000000, 'ask_size': 1} self.j1._bid_quote = {'order_id': 'j1_1', 'timestamp': 5, 'type': 'add', 'quantity': 1, 'side': 'buy', 'price': 999995} self.j1._ask_quote = {'order_id': 'j1_2', 'timestamp': 6, 'type': 'add', 'quantity': 1, 'side': 'sell', 'price': 1000000} random.seed(1) self.j1.process_signal(14, tob, 0.5) self.assertDictEqual(self.j1._bid_quote, {'order_id': 'j1_1', 'timestamp': 5, 'type': 'add', 'quantity': 1, 'side': 'buy', 'price': 999995}) self.assertFalse(self.j1.cancel_collector) self.assertFalse(self.j1.quote_collector) self.j1.process_signal(15, tob, 0.5) self.assertDictEqual(self.j1._ask_quote, {'order_id': 'j1_2', 'timestamp': 6, 'type': 'add', 'quantity': 1, 'side': 'sell', 'price': 1000000}) self.assertFalse(self.j1.cancel_collector) self.assertFalse(self.j1.quote_collector) # PJ bid and ask behind the book self.j1._bid_quote = {'order_id': 'j1_1', 'timestamp': 5, 'type': 'add', 'quantity': 1, 'side': 'buy', 'price': 999990} self.j1._ask_quote = {'order_id': 'j1_2', 'timestamp': 6, 'type': 'add', 'quantity': 1, 'side': 'sell', 'price': 1000010} # random.seed = 1 generates random.uniform(0,1) = 0.13 then .85 # cancel bid and ask random.seed(1) self.assertTrue(self.j1._bid_quote) self.assertTrue(self.j1._ask_quote) self.j1.process_signal(16, tob, 0.5) self.assertFalse(self.j1._bid_quote) self.assertFalse(self.j1._ask_quote) self.assertDictEqual(self.j1.cancel_collector[0], {'order_id': 'j1_1', 'timestamp': 16, 'type': 'cancel', 'quantity': 1, 'side': 'buy', 'price': 999990}) self.assertDictEqual(self.j1.cancel_collector[1], {'order_id': 'j1_2', 'timestamp': 16, 'type': 'cancel', 'quantity': 1, 'side': 'sell', 'price': 1000010}) self.assertFalse(self.j1.quote_collector)