async def visual_inspection_test(self): UNDERLYINGS = self.BEAR + self.BULL SPREAD = self.RITC - self.USD * UNDERLYINGS # # Test Visual 1 # LMT_ORDER = self.RITC.to_order(qty=100, order_type='LMT', price_fn=improve_on_best_quote(1)) # MKT_ORDER = -1 * self.RITC.to_order(qty=100, order_type='MKT') # assert(all(await asyncio.gather(MKT_ORDER.execute_later(5), LMT_ORDER.execute()))) # # Test Visual 2 # LMT_ORDER = SPREAD.to_order(qty=100, order_type='MKT') # MKT_ORDER = -1 * SPREAD.to_order(qty=100, order_type='MKT') # assert(all(await asyncio.gather(MKT_ORDER.execute_later(5), LMT_ORDER.execute()))) # # Test 3 Present Single Limit Order # LMT_ORDER = self.RITC.to_order(qty=100, order_type='LMT', price_fn=improve_on_best_quote(1)) # await LMT_ORDER.execute() # Test 4 Table Scrolling # LMT_ORDER = self.RITC.to_order(qty=100, order_type='LMT', price_fn=improve_on_best_quote(1)) # LMT_ORDER_2 = -1*self.RITC.to_order(qty=100, order_type='LMT', price_fn=improve_on_best_quote(1)) # # Then check order fill qtys working visually # MKT_ORDER = self.RITC.to_order(qty=50, order_type='MKT') # await self.assert_order_execution(*([LMT_ORDER]*20 + [LMT_ORDER_2]*20), MKT_ORDER) # Test 5 Market Dashboard MKT_ORDER = SPREAD.to_order(qty=50, order_type='MKT') LMT_ORDER = self.RITC.to_order(qty=50, order_type='LMT', price_fn=improve_on_best_quote(1)) LMT_ORDER_2 = self.RITC.to_order(qty=50, order_type='LMT', price_fn=improve_on_best_quote(2)) LMT_ORDER_3 = -1 * self.RITC.to_order( qty=50, order_type='LMT', price_fn=improve_on_best_quote(1)) # # Then check order fill qtys working visually MKT_ORDER_2 = -1 * self.RITC.to_order(qty=50, order_type='MKT') MKT_ORDER_3 = -1 * self.RITC.to_order(qty=23, order_type='MKT') await self.assert_order_execution( *([LMT_ORDER] * 20 + [LMT_ORDER_2] * 20 + [MKT_ORDER] * 20 + [LMT_ORDER_3] * 25), MKT_ORDER_2, MKT_ORDER_3) print('[TEST] Visual Tests Complete!' ) # Obviously not going to get called :)
async def validate_pricing_functions(self): edge = 1 direction = 1 price_fn = improve_on_best_quote(edge) price_improved = price_fn(direction, self.RITC.evaluate) assert (price_improved == self.RITC.evaluate(direction) - 1) print("[TEST] Imporve on best quote: Success!")
async def validate_mkt_order_execution(self): print("[TEST SUITE] Starting market order execution tests...") UNDERLYINGS = self.BEAR + self.BULL SPREAD = self.RITC - self.USD * UNDERLYINGS # SPREAD_USD_EXPSOURE = RITC * USD # HEDGED_SPREAD = SPREAD - SPREAD_USD_EXPSOURE ORDER = SPREAD.to_order(qty=100, order_type='MKT', group_name='MKT') SIGNED_ORDER = ORDER.inv_sign() * ORDER SIGNED_ORDER.group_name = 'SIGNED' await self.assert_order_execution(ORDER, SIGNED_ORDER) print("[TEST] Market - Market Order Transaction: Success!") # Simple Limit vs Market LMT_ORDER = self.RITC.to_order(qty=100, order_type='LMT', price_fn=improve_on_best_quote(1)) MKT_ORDER = self.RITC.to_order(qty=100, order_type='MKT') SIGNED_MKT_ORDER = LMT_ORDER.inv_sign() * MKT_ORDER await self.assert_order_execution(LMT_ORDER, SIGNED_MKT_ORDER) print("[TEST] Limit - Market Order Transaction: Success!") # Complex vs Market # Note: A complex order is not added to the limit order book # Instead it is a Market Order with dispatch to server postponed until the limit price is within # some threshold of the best quote. # It is first of all clear that for both Complex MKT and Complex LMT orders they should not be executed # until there is SUFFICIENT LIQUIDITY for all orders to be executed (TODO) # The issue with Complex LMT Orders is that we can't place limit orders for multiple underlying products # As we have more unkowns than equations (1 aggregate price target). Thus we will create a new order # type called CMPLX to stress the point that it is a market order executable subject to a condition # rather than a limit order # TODO: Fix the contrived scenario to make it trigger the complex order. NOTE ADD Back in LMT_IMPROVE to execution # Contrived Orders to make the nex part of the test work # Imporve the best ask by 1 # TODO: Fix this! LMT_IMPROVE = -1 * self.RITC.to_order( qty=10, order_type='LMT', price_fn=improve_on_best_quote(-1), group_name='LMT_IMPROVE') # Buy the spread at 1 below the market price -> Which we've setup to happen in the previous line! CMPLX_ORDER = SPREAD.to_order( qty=100, order_type='CMPLX', price_fn=improve_on_best_quote(1), group_name='CMPLX_ORDER' ) # Place a buy limit order at current market best bid # CMPLX_ORDER = SPREAD.to_order(qty=100, order_type='CMPLX', price_fn=improve_on_best_quote(0)) # Place a buy limit order at current market best bid MKT_ORDER = SPREAD.to_order(qty=100, order_type='MKT', group_name='MKT_ORDER') SIGNED_MKT_ORDER = SPREAD.inv_sign() * MKT_ORDER # Mops up the LMT_Imporve which did not improve enough to cross # the spread and thus was not executed as a marketable limit order LMT_IMPROVE_MOPUP = self.RITC.to_order(qty=10, order_type='MKT', group_name='LMT_IMPROVE_MOPUP') await asyncio.gather( LMT_IMPROVE_MOPUP.execute_later(delay=1), self.assert_order_execution(CMPLX_ORDER, LMT_IMPROVE, SIGNED_MKT_ORDER)) print("[TEST] Complex Limit - Market Order Transaction: Success!") # Marketable Limit vs Limit LMT_IMPROVE = self.RITC.to_order(qty=10, order_type='LMT', price_fn=improve_on_best_quote(-3), group_name='LMT_IMPROVE') LMT = -1 * self.RITC.to_order(qty=10, order_type='LMT', price_fn=improve_on_best_quote(0), group_name='LMT') await self.assert_order_execution(LMT_IMPROVE, LMT) print("[TEST] Marketable Limit - Limit Order Transaction: Success!") # Marketable Limit vs Market LMT_IMPROVE = self.RITC.to_order(qty=10, order_type='LMT', price_fn=improve_on_best_quote(-3), group_name='LMT_IMPROVE') MKT = -1 * self.RITC.to_order( qty=10, order_type='MKT', group_name='MKT') await self.assert_order_execution(LMT_IMPROVE, MKT) print("[TEST] Marketable Limit - Limit Order Transaction: Success!") # Sequence Orders LMT = self.RITC.to_order(qty=10, order_type='LMT', price_fn=improve_on_best_quote(0), group_name='LMT') MKT = -1 * self.RITC.to_order( qty=20, order_type='MKT', group_name='MKT') MOPUP_LMT = self.RITC.to_order(qty=10, order_type='LMT', price_fn=improve_on_best_quote(0), group_name='MOPUP_LMT') SEQ = LMT.then(MOPUP_LMT) await self.assert_order_execution(SEQ, MKT) print("[TEST] Sequence Order Transaction: Success!") print("[TEST SUITE] Finished market order execution tests...")
async def validate_risk_monitor(self): print("[TEST SUITE] Starting Risk Monitor tests...") # ---- Simple Net Position offest check 1 - 1 ---- # Note this is an edge case that checks we arent printing money # MKT vs MKT should be impossible for any trader to realise a net profit / loss # as they will be settled back at the midprice MKT_BUY = self.RITC.to_order(qty=30, order_type='MKT') # Cast the security to the bot's exchange connection and create an order MKT_SELLS = [ -1 * self.RITC.assign_trader(bot).to_order(qty=10, order_type='MKT') for bot in self.bots ] # Make sure all orders are executed await self.assert_order_execution(MKT_BUY, *MKT_SELLS) # Check that sum of bot net positions = -1 trader net position net_bot_positions = sum([bot._risk.net_position for bot in self.bots]) bot_pnls = sum([bot._risk.pnl for bot in self.bots]) net_trader_position = self.trader._risk.net_position trader_pnl = self.trader._risk.pnl assert (net_trader_position == -1 * net_bot_positions) assert (trader_pnl == 0) assert (bot_pnls == 0) print("[TEST] Net Positions & PnL Basic Matching: Success") # ---- Simple Net Position offest check 1 - 1 in a MOVING market---- # If the previous test no one could make money or lose money as # they simply settled at the market midprice which hadn't changed # Now we will move the market by 1 point and the onls should be symmetric # The limit orders will shift the best bid best ask by 1 after the same transactions # as previous where completed LMT_BUY = self.RITC.assign_trader(self.mopup_bot).to_order( qty=30, order_type='LMT', price_fn=improve_on_best_quote(-1)) LMT_SELL = -1 * self.RITC.assign_trader(self.mopup_bot).to_order( qty=30, order_type='LMT', price_fn=improve_on_best_quote(1)) # Make sure all orders are executed async def check_pnls(): await asyncio.sleep(1) # Ensures the market moving orders # have been executed first # NOTE I did have an issue when i shortened this sleep # so this is a hack for sure # but its not something we normally would do in the course of trading # so it should be fine. # Check that sum of bot net positions = -1 trader net position net_bot_positions = sum( [bot._risk.net_position for bot in self.bots]) bot_pnls = sum([bot._risk.pnl for bot in self.bots]) net_trader_position = self.trader._risk.net_position trader_pnl = self.trader._risk.pnl assert (net_trader_position == -1 * net_bot_positions) assert (trader_pnl == -1 * bot_pnls) assert (trader_pnl != 0) assert (self.trader._risk.realised == 0) print("[TEST] Net Positions & PnL Basic Moving Market: Success") # ---- Realised PNL Check ---- # Now that we have non zero pnls we want to realise 1/2 of it # and check that realised pnl's are correct (50 50 split) # Since the market orders came earlier than the limit # which raised the bid the bot traders will take the hit to # there realised pnl # First we need to mopup those limits so they don't get in the way MKT_BUY = self.RITC.assign_trader(self.mopup_bot).to_order( qty=30, order_type='MKT') MKT_SELL = -1 * self.RITC.assign_trader(self.mopup_bot).to_order( qty=30, order_type='MKT') await self.assert_order_execution(MKT_BUY, MKT_SELL) # Now Lets sell half the traders stock MKT_SELL = -1 * self.RITC.to_order(qty=15, order_type='MKT') MKT_BUYS = [ self.RITC.assign_trader(bot).to_order(qty=5, order_type='MKT') for bot in self.bots ] await self.assert_order_execution(MKT_SELL, *MKT_BUYS) # Checks the realised risk and unrealised has been split correctly assert (self.trader._risk.realised == self.trader._risk.unrealised) assert (self.trader._risk.realised != 0) assert (self.trader._risk.pnl == trader_pnl) last_bots_pnl = bot_pnls bots_realised = sum([bot._risk.realised for bot in self.bots]) bots_unrealised = sum([bot._risk.unrealised for bot in self.bots]) bot_pnls = sum([bot._risk.pnl for bot in self.bots]) assert (bots_realised == bots_unrealised) assert (bot_pnls != 0) assert (bot_pnls == last_bots_pnl) print( "[TEST] Realised and unrealised pnl working as expected: Success" ) MKT_SELL = -1 * self.RITC.to_order(qty=15, order_type='MKT') MKT_BUY = self.RITC.assign_trader(self.mopup_bot).to_order( qty=15, order_type='MKT') await self.assert_order_execution( MKT_SELL, MKT_BUY ) # now get rid of the traders remaining stock and close out position await asyncio.gather(self.assert_order_execution(LMT_BUY, LMT_SELL), check_pnls()) print("[TEST SUITE] Finished Risk Monitor Tests...")