def __init__(self): self._stock_levels = {} self._sides = item.initialise_sides(self._stock_levels) self._drinks = item.initialise_drinks(self._stock_levels) self._ingredients = item.initialise_ingredients(self._stock_levels) self._buns = item.initialise_buns(self._stock_levels) self._order_manager = OrderManager() self._lookup = {} obj_list = (*self._sides, *self._drinks, *self._ingredients, *self._buns) for obj in obj_list: self._lookup[obj.name] = obj standard_burger_buns = [self.get_object_by_name("Sesame bun")] * 2 standard_burger_fillings = [ self.get_object_by_name(name) for name in ("Beef Patty", "Cheddar Cheese", "Tomato Sauce") ] standard_wrap_fillings = [ self.get_object_by_name(name) for name in ("Chicken Patty", "Tomato", "Lettuce") ] self._standard_burger = Burger(standard_burger_fillings, standard_burger_buns) self._standard_wrap = Wrap(standard_wrap_fillings)
class TestOrderBook(unittest.TestCase): def setUp(self): self.order_manager = OrderManager() def test_receive_order_from_trading_strategy(self): order1 = { 'id': 10, 'price': 219, 'quantity': 10, 'side': 'bid', } self.order_manager.handle_order_from_trading_strategy(order1) self.assertEqual(len(self.order_manager.orders),1) self.order_manager.handle_order_from_trading_strategy(order1) self.assertEqual(len(self.order_manager.orders),2) self.assertEqual(self.order_manager.orders[0]['id'],1) self.assertEqual(self.order_manager.orders[1]['id'],2) def test_receive_order_from_trading_strategy_error(self): order1 = { 'id': 10, 'price': -219, 'quantity': 10, 'side': 'bid', } self.order_manager.handle_order_from_trading_strategy(order1) self.assertEqual(len(self.order_manager.orders),0) def display_orders(self): for o in self.order_manager.orders: print(o) def test_receive_from_gateway_filled(self): self.test_receive_order_from_trading_strategy() orderexecution1 = { 'id': 2, 'price': 13, 'quantity': 10, 'side': 'bid', 'status' : 'filled' } # self.display_orders() self.order_manager.handle_order_from_gateway(orderexecution1) self.assertEqual(len(self.order_manager.orders), 1) def test_receive_from_gateway_acked(self): self.test_receive_order_from_trading_strategy() orderexecution1 = { 'id': 2, 'price': 13, 'quantity': 10, 'side': 'bid', 'status' : 'acked' } # self.display_orders() self.order_manager.handle_order_from_gateway(orderexecution1) self.assertEqual(len(self.order_manager.orders), 2) self.assertEqual(self.order_manager.orders[1]['status'], 'acked')
def setUp(self): self.order_manager = OrderManager() self.person_1 = new_person( {'username': '******', 'name': 'Name1', 'surname': 'Surname1', 'password': '******', 'passwordRetype': 'test123', 'email': '*****@*****.**'}) self.person_1.number_of_stocks = 5 self.person_1.save() self.person_2 = new_person( {'username': '******', 'name': 'Name2', 'surname': 'Surname2', 'password': '******', 'passwordRetype': 'test123', 'email': '*****@*****.**'}) self.person_3 = new_person( {'username': '******', 'name': 'Name3', 'surname': 'Surname3', 'password': '******', 'passwordRetype': 'test123', 'email': '*****@*****.**'}) self.bidding_round = BiddingRound.objects.create(is_active=True) stock_order_1 = StockOrder() stock_order_1.owner = self.person_1 stock_order_1.order_type = BUY stock_order_1.order_price_per_share = 8.5 stock_order_1.order_amount_of_shares = 10 stock_order_1.bidding_round = self.bidding_round stock_order_2 = StockOrder() stock_order_2.owner = self.person_1 stock_order_2.order_type = BUY stock_order_2.order_price_per_share = 7.5 stock_order_2.order_amount_of_shares = 5 stock_order_2.bidding_round = self.bidding_round stock_order_3 = StockOrder() stock_order_3.owner = self.person_1 stock_order_3.order_type = BUY stock_order_3.order_price_per_share = 6.5 stock_order_3.order_amount_of_shares = 15 stock_order_3.bidding_round = self.bidding_round stock_order_arch = StockOrder() stock_order_arch.owner = self.person_1 stock_order_arch.order_type = SELL stock_order_arch.order_price_per_share = 5 stock_order_arch.order_amount_of_shares = 100 stock_order_arch.bidding_round = self.bidding_round stock_order_arch.is_archived = True self.order_1_person_1 = self.order_manager.place_order(stock_order_1) self.order_2_person_1 = self.order_manager.place_order(stock_order_2) self.order_3_person_1 = self.order_manager.place_order(stock_order_3) self.order_archived_person_1 = create_stock_order(stock_order_arch) self.order_1_person_2 = StockOrder.objects.create(owner=self.person_2) self.order_2_person_2 = StockOrder.objects.create(owner=self.person_2) self.order_1_person_3 = StockOrder.objects.create(owner=self.person_2)
def test_checker(self): #we expect the first order created to have an id of 0 self.x = OrderManager() assert self.x.id_exists('0') == False self.x.create_new_order() assert self.x.id_exists('0') == True
def __init__(self): # 股票 -> 策略 self.strategy_instance = StrategyFactory().create() # 股票 -> 仓位 self.stock_position_dic = {} # 订单管理 self.order_manager = OrderManager(self.stock_position_dic) self.quote_manager = QuoteManager() self.cumPNL = 0
def test_setters(self): self.x = OrderManager() id1 = self.x.create_new_order() assert len(self.x.orders) == 1 assert type(self.x.orders[0]) == Order assert type(self.x.get_order_by_id(id1)) == Order id2 = self.x.create_new_order() assert len(self.x.orders) == 2
def test_invalid_cases(self): self.x = OrderManager() with pytest.raises(TypeError): self.x.get_order_by_id('1.1') with pytest.raises(TypeError): self.x.get_order_by_id(1.1) with pytest.raises(KeyError): self.x.get_order_by_id('1') assert self.x.id_exists('a') == False
def process_order(self, order, delay=0): order_manager = OrderManager(self) is_acknowledged = order_manager.acknowledge_order(order) time.sleep(delay) if is_acknowledged: print("order is acknowledged") print(order.acknowledged) print(order.rejected) print(order_manager.warehouses) order_manager.ship_order(order=order) else: print("There is no inventory for this order") print(order.acknowledged) print(order.rejected) print(order_manager.warehouses)
def setUp(self): self.lp_2_gateway = deque() self.ob_2_ts = deque() self.ts_2_om = deque() self.ms_2_om = deque() self.om_2_ts = deque() self.gw_2_om = deque() self.om_2_gw = deque() self.liquidityProvider = LiquidityProvider(self.lp_2_gateway) self.bookBuilder = OrderBook(self.lp_2_gateway, self.ob_2_ts) self.tradingStrategy = TradingStrategy(self.ob_2_ts, self.ts_2_om, self.om_2_ts) self.marketSimulator = MarketSimulator(self.om_2_gw, self.gw_2_om) self.orderManager = OrderManager(self.ts_2_om, self.om_2_ts, self.om_2_gw, self.gw_2_om)
def main(): try: market = sys.argv[1] except IndexError: market = 'not a currency pair' if market not in constants.MARKETS: while True: market = str( input( "Please specify which currency pair to use (btcusd, ltcusd, etc)." )) if market in constants.MARKETS: break running = True md = MarketDataInterface(market) ts = TradingStrategy(market) om = OrderManager(market) while running: action = ts.get_final_strategy() price = (md.get_ticker_data(False))['value'] order_details = om.get_order_status(id) if action['action'] == "buy": result = om.buy(pair=market, risk=action['risk'], price=price) order_details = om.get_order_status(result) if result[0]: logging.info('Successfully bought {0}{1} at {2}{3}'.format( order_details['actual_amount'], market[:3], order_details['actual_end_price'], market[-3:])) else: logging.info('Buy failed') elif action['action'] == "sell": result = om.sell(pair=market, risk=action['risk'], price=price) order_details = om.get_order_status(result) if result: logging.info('Successfully sold {0}{1} at {2}{3}'.format( order_details['amount'], market[:3], order_details['price'], market[-3:])) else: logging.info('Sell failed') elif action['action'] == "wait": logging.info('Waited {}s, did not trade'.format( settings.MAIN_TIMER)) else: running = False logging.error('Unsupported action') time.sleep(settings.MAIN_TIMER) if not running: print('order error')
class StrategyManager: def __init__(self): # 股票 -> 策略 self.strategy_instance = StrategyFactory().create() # 股票 -> 仓位 self.stock_position_dic = {} # 订单管理 self.order_manager = OrderManager(self.stock_position_dic) self.quote_manager = QuoteManager() self.cumPNL = 0 def recv_market(self, market_data): # print("recv_market callback:", market_data.symbol, # market_data.market_time, market_data.high_price, # market_data.pre_close_price, self.market_count) # 股票的策略不存在,初始化 if market_data.symbol not in self.stock_position_dic: self.stock_position_dic[market_data.symbol] = Position() # 这只股票的仓位信息 stock_position = self.stock_position_dic[market_data.symbol] # update market quotes self.quote_manager.update_table(market_data.symbol, market_data) # 运算策略 self.strategy_instance.do_strategy(stock_position, self.order_manager, market_data, self.quote_manager) def recv_order_deal(self, deal_info): self.order_manager.recv_order_deal(deal_info) def reset(self): # 股票 -> 仓位 self.stock_position_dic.clear() def addPNL(self, pnl): self.cumPNL + pnl
def __init__(self, exchange): self.exchange = exchange self.orderManager = OrderManager() self.logger.info("Initiate Price Arbitrage Algo") self._buildFxTree() # build fx tree for all possible conversions # build list of leaves root = self.tree.root # get root w = Walker() # tree walker # unwrap nested tuple returned by Walker to a flat list of FXPair def unwrapWalkerToFlatList(x): if isinstance(x, tuple): if len(x) == 0: return [] s = [] for t in x: s.extend(unwrapWalkerToFlatList(t)) return s else: if x.getFXPair() is None: return [] # skip root element else: return [x.getFXPair()] self.conversion_paths = {} # all conversion paths for the pair <pair: [pair1, pair2...]> # build list of all conversion paths for k in FXNode.treeNodesWithSamePair.keys(): # iterate all pairs alternative_list = FXNode.treeNodesWithSamePair[k] # get list of leaves representing same pair but with different conversion path paths = [] for c in alternative_list: # iterate all leaves (same pair but different paths) if not c.is_leaf: continue # iterate only leaves path = unwrapWalkerToFlatList(w.walk(root, c)) # get path from root to this leaf paths.append(path) # list of lists if not k in self.conversion_paths.keys(): self.conversion_paths[k] = list(paths) else: self.conversion_paths[k].append(list(paths)) # set event triggers self.exchange.setEventHandler(tradeHandler=self.updateTradeHandler, orderHandler=self.updateOrderHandler)
def __init__(self, *args, **kwargs): super(TestOrderManager, self).__init__(*args, **kwargs) self.server = app.test_client() self.order_manager = OrderManager(self.server) self.test_data_key = "1" self.test_data = {"Toppings": "beef", "Sizes": "Large"} self.test_data_key2 = "2" self.test_data2 = {"Toppings": "Chicken", "Sizes": "Small"} self.test_data_key3 = "3" self.test_data3 = {"Toppings": "Fish", "Sizes": "Medium"} #reset what is on the test_client first due to other test r = self.server.get(self.order_manager._URL).get_json() for k in r.keys(): self.server.delete(self.order_manager._URL, json=k) #initialize the server and push the test_data first #use dumps because it is more consistent with the ordermanager adding method self.server.post(self.order_manager._URL, json={self.test_data_key: json.dumps(self.test_data)}) self.server.post( self.order_manager._URL, json={self.test_data_key2: json.dumps(self.test_data2)})
def main(): lp_2_gateway = deque() ob_2_ts = deque() ts_2_om = deque() om_2_ts = deque() gw_2_om = deque() om_2_gw = deque() lp = LiquidityProvider(lp_2_gateway) ob = OrderBook(lp_2_gateway, ob_2_ts) ts = TradingStrategy(ob_2_ts, ts_2_om, om_2_ts) ms = MarketSimulator(om_2_gw, gw_2_om) om = OrderManager(ts_2_om, om_2_ts, om_2_gw, gw_2_om) lp.read_tick_data_from_data_source() while len(lp_2_gateway) > 0: ob.handle_order_from_gateway() ts.handle_input_from_bb() om.handle_input_from_ts() ms.handle_order_from_gw() om.handle_input_from_market() ts.handle_response_from_om() lp.read_tick_data_from_data_source()
#COMMISSION = .0 # Cost in dollars per share traded #COMMISSION_MIN = .0 # Minimum cost in dollars per stock traded #COMMISSION_MAX = .0 # Maximum cost in percent of trade value #SLIPPAGE = .0 # Average slippage in price due to market volatility # Create QuoteManager object quote_manager = QuoteManager(DB_FILEPATH) # Create AccountManager object my_account = AccountManager(START_BALANCE, MARGIN_PERCENT, quote_manager) # Create OrderManager object order_manager = OrderManager(quote_manager, my_account, slippage=SLIPPAGE, commission_min=COMMISSION_MIN, commission=COMMISSION, commission_max=COMMISSION_MAX) # Create an order_history DataFrame order_history = {} # Load signals data signals = pd.read_csv(SIGNALS_PATH, index_col=0) signal_dates = [date.replace('-', '_') for date in signals.index] # Load GDX component symbols gdx_symbols = pd.read_csv(GDX_CSV_PATH).symbol gdx_symbols = gdx_symbols[gdx_symbols.isin(signals.columns)] # Skip days until START_DAY is found
class OrderManagerTest(TestCase): def setUp(self): self.order_manager = OrderManager() self.person_1 = new_person( {'username': '******', 'name': 'Name1', 'surname': 'Surname1', 'password': '******', 'passwordRetype': 'test123', 'email': '*****@*****.**'}) self.person_1.number_of_stocks = 5 self.person_1.save() self.person_2 = new_person( {'username': '******', 'name': 'Name2', 'surname': 'Surname2', 'password': '******', 'passwordRetype': 'test123', 'email': '*****@*****.**'}) self.person_3 = new_person( {'username': '******', 'name': 'Name3', 'surname': 'Surname3', 'password': '******', 'passwordRetype': 'test123', 'email': '*****@*****.**'}) self.bidding_round = BiddingRound.objects.create(is_active=True) stock_order_1 = StockOrder() stock_order_1.owner = self.person_1 stock_order_1.order_type = BUY stock_order_1.order_price_per_share = 8.5 stock_order_1.order_amount_of_shares = 10 stock_order_1.bidding_round = self.bidding_round stock_order_2 = StockOrder() stock_order_2.owner = self.person_1 stock_order_2.order_type = BUY stock_order_2.order_price_per_share = 7.5 stock_order_2.order_amount_of_shares = 5 stock_order_2.bidding_round = self.bidding_round stock_order_3 = StockOrder() stock_order_3.owner = self.person_1 stock_order_3.order_type = BUY stock_order_3.order_price_per_share = 6.5 stock_order_3.order_amount_of_shares = 15 stock_order_3.bidding_round = self.bidding_round stock_order_arch = StockOrder() stock_order_arch.owner = self.person_1 stock_order_arch.order_type = SELL stock_order_arch.order_price_per_share = 5 stock_order_arch.order_amount_of_shares = 100 stock_order_arch.bidding_round = self.bidding_round stock_order_arch.is_archived = True self.order_1_person_1 = self.order_manager.place_order(stock_order_1) self.order_2_person_1 = self.order_manager.place_order(stock_order_2) self.order_3_person_1 = self.order_manager.place_order(stock_order_3) self.order_archived_person_1 = create_stock_order(stock_order_arch) self.order_1_person_2 = StockOrder.objects.create(owner=self.person_2) self.order_2_person_2 = StockOrder.objects.create(owner=self.person_2) self.order_1_person_3 = StockOrder.objects.create(owner=self.person_2) def test_can_place_order(self): """ checks if user can place order: * bidding period is active (first, second and third complete week of october) - first bidding round for third party and staff - second bidding round for staff - third bidding round for moderator * user has not exceeded his maximal bidding order number * total of non-archived SELL orders incl this one does not exceeded persons number_of_stocks (exp moderator_person) returns error message, None otherwise """ self.person_1.number_of_orders_max = 6 self.person_1.number_of_stocks = 50 stock_order = StockOrder() stock_order.order_amount_of_shares = 10 stock_order.owner = self.person_1 stock_order.order_type = SELL # create_stock_order(stock_order) # ================================================================= # test: NoBiddingRoundException # ================================================================= try: self.order_manager.can_place_order(self.person_1, stock_order) raise AssertionError('NoBiddingRoundException expected') except NoBiddingRoundException: pass # create bidding round bidding_round = BiddingRound.objects.create(is_active=True) stock_order.bidding_round = bidding_round # valid order self.assertIsNone(self.order_manager.can_place_order(self.person_1, stock_order)) # ================================================================= # test: BiddingRoundNotActiveException # ================================================================= bidding_round.is_active = False try: self.order_manager.can_place_order(self.person_1, stock_order) raise AssertionError('BiddingRoundNotActiveException expected') except BiddingRoundNotActiveException: pass bidding_round.is_active = True self.assertIsNone(self.order_manager.can_place_order(self.person_1, stock_order)) # ================================================================= # test: UserTypeException # ================================================================= bidding_round.round_type = bidding_constants.STAFF_ROUND try: self.order_manager.can_place_order(self.person_1, stock_order) raise AssertionError('UserTypeException expected') except UserTypeException: pass self.person_1.user_type = person_constants.STAFF self.assertIsNone(self.order_manager.can_place_order(self.person_1, stock_order)) bidding_round.round_type = bidding_constants.MODERATOR_ROUND try: self.order_manager.can_place_order(self.person_1, stock_order) raise AssertionError('UserTypeException expected') except UserTypeException: pass self.person_1.user_type = person_constants.MODERATOR self.assertIsNone(self.order_manager.can_place_order(self.person_1, stock_order)) self.person_1.user_type = person_constants.THIRD_PARTY try: self.order_manager.can_place_order(self.person_1, stock_order) raise AssertionError('UserTypeException expected') except UserTypeException: pass bidding_round.round_type = bidding_constants.THIRD_PARTY_ROUND self.assertIsNone(self.order_manager.can_place_order(self.person_1, stock_order)) # ================================================================= # test: ExceedMaxSellSharesException # ================================================================= stock_order.order_amount_of_shares = 51 try: self.order_manager.can_place_order(self.person_1, stock_order) raise AssertionError('ExceedMaxSellSharesException expected') except ExceedMaxSellSharesException: pass stock_order.order_amount_of_shares = 49 self.assertIsNone(self.order_manager.can_place_order(self.person_1, stock_order)) stock_order_4 = StockOrder() stock_order_4.owner = self.person_1 stock_order_4.order_type = SELL stock_order_4.order_price_per_share = 5.5 stock_order_4.bidding_round = self.bidding_round stock_order_4.order_amount_of_shares = 1 self.order_manager.place_order(stock_order_4) self.assertIsNone(self.order_manager.can_place_order(self.person_1, stock_order)) stock_order_5 = StockOrder() stock_order_5.owner = self.person_1 stock_order_5.order_type = SELL stock_order_5.bidding_round = self.bidding_round stock_order_5.order_amount_of_shares = 1 stock_order_5.order_price_per_share = 8.5 self.order_manager.place_order(stock_order_5) try: self.order_manager.can_place_order(self.person_1, stock_order) raise AssertionError('ExceedMaxSellSharesException expected') except ExceedMaxSellSharesException: pass # ================================================================= # test: ExceedMaxOrderException # ================================================================= stock_order.order_type = BUY stock_order_5 = StockOrder() stock_order_5.owner = self.person_1 stock_order_5.order_type = BUY stock_order_5.bidding_round = self.bidding_round stock_order_5.order_amount_of_shares = 50 stock_order_5.order_price_per_share = 6.5 self.order_manager.place_order(stock_order_5) try: self.order_manager.can_place_order(self.person_1, stock_order) raise AssertionError('ExceedMaxOrderException expected') except ExceedMaxOrderException: pass def test_is_valid_order(self): """ checks if stock order is valid: * order must have a order_type BUY or SELL * order must have order_price_per_share (float) * order must have order_amount_of_shares (int) * order must have owner (Person) returns error message, None otherwise """ stock_order = StockOrder() stock_order.order_type = BUY stock_order.order_price_per_share = 5.5 stock_order.order_amount_of_shares = 10 stock_order.bidding_round = self.bidding_round # ================================================================= # test: OwnerNotFoundException # ================================================================= try: self.order_manager.is_valid_order(stock_order) raise AssertionError('OwnerNotFoundException expected') except OwnerNotFoundException: pass stock_order.owner = self.person_1 self.assertIsNone(self.order_manager.is_valid_order(stock_order)) # ================================================================= # test: InvalidOrderTypeException # ================================================================= stock_order.order_type = UNDEFINED try: self.order_manager.is_valid_order(stock_order) raise AssertionError('InvalidOrderTypeException expected') except InvalidOrderTypeException: pass stock_order.order_type = SELL self.assertIsNone(self.order_manager.is_valid_order(stock_order)) # ================================================================= # test: OrderPriceTypeException # ================================================================= stock_order.order_price_per_share = "0.01" try: self.order_manager.is_valid_order(stock_order) raise AssertionError('OrderPriceTypeException expected') except OrderPriceTypeException: pass stock_order.order_price_per_share = 123456789012345678901234567890 try: self.order_manager.is_valid_order(stock_order) raise AssertionError('OrderPriceTypeException expected') except OrderPriceTypeException: pass stock_order.order_price_per_share = 2312.34 self.assertIsNone(self.order_manager.is_valid_order(stock_order)) # ================================================================= # test: OrderShareAmountException # ================================================================= stock_order.order_amount_of_shares = "0.01" try: self.order_manager.is_valid_order(stock_order) raise AssertionError('OrderShareAmountException expected') except OrderShareAmountException: pass stock_order.order_amount_of_shares = 123456789012345678901234567890 try: self.order_manager.is_valid_order(stock_order) raise AssertionError('OrderShareAmountException expected') except OrderShareAmountException: pass stock_order.order_amount_of_shares = 2312.34 try: self.order_manager.is_valid_order(stock_order) raise AssertionError('OrderShareAmountException expected') except OrderShareAmountException: pass stock_order.order_amount_of_shares = 23120 self.assertIsNone(self.order_manager.is_valid_order(stock_order)) def test_place_order(self): stock_order_4 = StockOrder() stock_order_4.owner = self.person_1 stock_order_4.order_type = SELL stock_order_4.bidding_round = self.bidding_round stock_order_4.is_archived = True stock_order_4.order_amount_of_shares = 5 stock_order_4.order_definite_number_of_shares = 4 stock_order_4.order_definite_price = 12.5321 stock_order_4.order_price_per_share = 24.5321 stock_order_4.order_result = ASSIGNED_PARTIAL stock_order_4.order_status = USER_ACCEPTED stock_order_created = self.order_manager.place_order(stock_order_4) # check values self.is_equal_stock_order(stock_order_4, stock_order_created) self.assertEquals(len(stock_order_created.encrypted_order_id), 32) # ================================================================= # test: PlaceOrderException # ================================================================= stock_order_4.order_amount_of_shares = 10 try: self.order_manager.place_order(stock_order_4) raise AssertionError('PlaceOrderException expected') except PlaceOrderException: pass def test_accept_oder(self): # ================================================================= # test: increase / decrease stock numbers and status # ================================================================= self.assertEquals(self.person_1.number_of_orders_accepted, 0) self.assertEquals(self.person_1.number_of_orders_pending, 3) encrypted_order_id = self.order_1_person_1.encrypted_order_id stock_order = StockOrder.objects.get(owner=self.person_1, encrypted_order_id=encrypted_order_id) self.assertEquals(stock_order.order_status, NEW) self.order_manager.accept_oder(self.person_1, encrypted_order_id) self.assertEquals(self.person_1.number_of_orders_accepted, 1) self.assertEquals(self.person_1.number_of_orders_pending, 2) stock_order = StockOrder.objects.get(owner=self.person_1, encrypted_order_id=encrypted_order_id) self.assertEquals(stock_order.order_status, USER_ACCEPTED) # ================================================================= # test: AlreadyAcceptedException # ================================================================= try: self.order_manager.accept_oder(self.person_1, encrypted_order_id) raise AssertionError('AlreadyAcceptedException expected') except AlreadyAcceptedException: pass # second time accept_oder should have no consequence self.assertEquals(self.person_1.number_of_orders_accepted, 1) self.assertEquals(self.person_1.number_of_orders_pending, 2) stock_order = StockOrder.objects.get(owner=self.person_1, encrypted_order_id=encrypted_order_id) self.assertEquals(stock_order.order_status, USER_ACCEPTED) # ================================================================= # test: OrderNotFoundException # ================================================================= try: self.order_manager.accept_oder(self.person_1, "XXX") raise AssertionError('OrderNotFoundException expected') except OrderNotFoundException: pass try: self.order_manager.accept_oder(self.person_2, encrypted_order_id) raise AssertionError('OrderNotFoundException expected') except OrderNotFoundException: pass # ================================================================= # test: OrderIsArchivedException # ================================================================= encrypted_order_id = self.order_archived_person_1.encrypted_order_id stock_order = StockOrder.objects.get(owner=self.person_1, encrypted_order_id=encrypted_order_id) try: self.order_manager.accept_oder(self.person_1, encrypted_order_id) raise AssertionError('OrderIsArchivedException expected') except OrderIsArchivedException: pass self.is_equal_stock_order(self.order_archived_person_1, stock_order) def is_equal_stock_order(self, real, expected): self.assertEquals(real.order_amount_of_shares, expected.order_amount_of_shares) self.assertEquals(real.order_price_per_share, expected.order_price_per_share) self.assertEquals(real.order_definite_number_of_shares, expected.order_definite_number_of_shares) self.assertEquals(real.order_definite_price, expected.order_definite_price) self.assertEquals(real.is_archived, expected.is_archived) self.assertEquals(real.owner, expected.owner) self.assertEquals(real.order_type, expected.order_type) self.assertEquals(real.order_result, expected.order_result) self.assertEquals(real.order_status, expected.order_status)
class PriceArbitrage: # class variables logger = logging.getLogger('price arbitrage') def __init__(self, exchange): self.exchange = exchange self.orderManager = OrderManager() self.logger.info("Initiate Price Arbitrage Algo") self._buildFxTree() # build fx tree for all possible conversions # build list of leaves root = self.tree.root # get root w = Walker() # tree walker # unwrap nested tuple returned by Walker to a flat list of FXPair def unwrapWalkerToFlatList(x): if isinstance(x, tuple): if len(x) == 0: return [] s = [] for t in x: s.extend(unwrapWalkerToFlatList(t)) return s else: if x.getFXPair() is None: return [] # skip root element else: return [x.getFXPair()] self.conversion_paths = {} # all conversion paths for the pair <pair: [pair1, pair2...]> # build list of all conversion paths for k in FXNode.treeNodesWithSamePair.keys(): # iterate all pairs alternative_list = FXNode.treeNodesWithSamePair[k] # get list of leaves representing same pair but with different conversion path paths = [] for c in alternative_list: # iterate all leaves (same pair but different paths) if not c.is_leaf: continue # iterate only leaves path = unwrapWalkerToFlatList(w.walk(root, c)) # get path from root to this leaf paths.append(path) # list of lists if not k in self.conversion_paths.keys(): self.conversion_paths[k] = list(paths) else: self.conversion_paths[k].append(list(paths)) # set event triggers self.exchange.setEventHandler(tradeHandler=self.updateTradeHandler, orderHandler=self.updateOrderHandler) #bild tree representing all possible fx conversion rates def _buildFxTree(self): # build all fx conversion paths pairs = self.exchange.getFxPairs() #self.logger.info(pairs) # Generate tree for all possible conversion rate (recursive) def generateFxTree(tree, pairs): # climb up the tree (recursive) to check if pair is above the node to prevent loops def isNodeInTheTree(c, tree): # tree is the terminal leaf a = c.getPairCode() b = tree.getPairCode() if a == b: return True else: if tree.parent is not None: return isNodeInTheTree(c, tree.parent) else: return False # reached the root for c in pairs: if isNodeInTheTree(c, tree): continue else: base = tree.getBase() quote = c.getQuote() if base != quote and base is not None and quote is not None: continue else: fx_node = FXNode(c.getPairCode(), c, parent=tree) generateFxTree(fx_node, pairs) return tree # generate currency exchange options root = FXNode("root") self.tree = generateFxTree(root, pairs) #print(RenderTree(root)) print("----******-----") for pre, _, node in RenderTree(root): treestr = u"%s%s" % (pre, node.name) print(treestr.ljust(8)) self.logger.info("-------FX pairs------------") #self.logger.info(pairs) # update algo for data change def updateTradeHandler(self, currencyPair): self.logger.info("Process trade update for pair %s" % (currencyPair.getPairCode())) def updateOrderHandler(self, pair): self.logger.info("Process ORDER update for pair %s" % (pair.getPairCode())) nodes = FXNode.treeNodesWithSamePair[pair] visited_leaves = [] # check all paths (terminal leaves) which include this pair for n in nodes: descendants = n.descendants + (n,) for r in descendants: if not r.is_leaf: continue p = r.getFXPair() if p in visited_leaves: continue visited_leaves.append(p) if not self.is_book_data_available_in_the_tree(r): continue self.checkArbitrageOpportunity(p, pair) # check if book data is available for all nodes in the route to this node def is_book_data_available_in_the_tree(self, node): return True # maximum conversion path, default is long / ask def estimateLongPathMaxThroughoutput(self, path, startQuoteValue = None, bid=False): startValue = path[0].getMaxBookQuote(bid) if startQuoteValue is None else startQuoteValue b = startValue for p in path: b = p.limitedConvertQnt2Base(b, bid) lastPair = path[- 1] res = { 'result_val': b, 'result_currency': lastPair.getBase(), 'start_val': startValue, 'start_currency': path[0].getQuote() } return res #(b, lastPair.getBase(), startValue) # in base currency of the final leaf # Estimate short route, path is given from root to leaf def estimateShortPathMaxThroughoutput(self, path, startBaseValue = None, ask=False): startValue = path[-1].getMaxBookBase() if startBaseValue is None else startBaseValue q = startValue for p in reversed(path): q = p.limitedConvertBase2Qnt(q, ask) lastPair = path[0] # reverse order res = { 'result_val' : q, 'result_currency' : lastPair.getQuote(), 'start_val' : startValue, 'start_currency' : path[-1].getBase() } return res #(q, lastPair.getQuote(), startValue) # in base quote of the final leaf # estimate maximum possible value of the arbitrage transaction def estimateMaximumThroughOutput(self, pair, longPath, shortPath): # first time estimate max throughoutput a = self.estimateLongPathMaxThroughoutput(longPath, bid = False) # root -> leaf, use inverse mode (True) to get actual max initial value b = self.estimateShortPathMaxThroughoutput(shortPath, a['result_val'], ask = False) # leaf -> root return b # Check if bid and ask data is available for all pairs in the path def bookDataAvailableInPath(self, path): a = True for x in path: a = a and x.isBidAvailable() and x.isAskAvailable() if not a: break return a def checkArbitrageOpportunity(self, pair, updatedPair): arbitrageDescriptor = { "long" : { "return" : 0.0, "path": [], 'max_start_val' : 0.0, 's1' : None, 's2' : None }, "short" : { "return" : 0, "path" : [], 's1' : None, 's2' : None }, 'max_transaction' : { 'currency' : '', 'val' : 0.0 } } for path in self.conversion_paths[pair]: #for p in path: # iterate all leaves (each leaf is the same pair but different conversion path) #long leg if not updatedPair in path or not self.bookDataAvailableInPath(path): continue longMaxVal = self.estimateLongPathMaxThroughoutput(path) # estimate max value if longMaxVal['result_val'] == 0: continue # convert half (to make sure it goes through) of the max value into original currency using ask book s = self.estimateShortPathMaxThroughoutput(path, longMaxVal['result_val'] / 2, ask = True) #startLongValue = s ['result_val'] #longVal = self.estimateLongPathMaxThroughoutput(path, startLongValue) # put through half of the max possible value #long_ret = longVal['result_val'] / longVal['start_val'] # normalize: 1 Quote currency -> x Base currency, then x is a if s['result_val'] == 0: continue long_ret = s['start_val'] / s['result_val'] ex = self.exchange.convert_amt(longMaxVal['start_currency'], 'BTC', 1.0) if ex == 0: self.logger.info('cant conver from %s to BTC' % longMaxVal['start_currency'] ) continue long_ret /= ex # 1 btc - > xx base currency, so all conversions start with 1 btc and thus we can compare then if long_ret > arbitrageDescriptor['long']['return']: arbitrageDescriptor['long']['return'] = long_ret arbitrageDescriptor['long']['path'] = path arbitrageDescriptor['long']['s1'] = longMaxVal arbitrageDescriptor['long']['s2'] = s arbitrageDescriptor['long']['max_start_val'] = s['result_val']*2 arbitrageDescriptor['max_transaction']['val'] = s['start_val']*2 # in base currency arbitrageDescriptor['max_transaction']['currency'] = s['start_currency'] # short leg shortMaxVal = self.estimateShortPathMaxThroughoutput(path) if shortMaxVal['result_val'] == 0: continue # convert hald of the max value into the original currency s1 = self.estimateLongPathMaxThroughoutput(path, shortMaxVal['result_val'] / 2, bid = True) #startShortValue = self.exchange.convert_amt(shortMaxVal[1], path[-1].getBase(), shortMaxVal[0]) #startShortValue = s['result_val'] #shortVal = self.estimateShortPathMaxThroughoutput(path, startShortValue) #short_ret = self.exchange.convert_amt(shortVal['result_currency'], 'BTC', shortVal['result_val']) #short_ret = shortVal['result_val'] / shortVal ['start_val'] # normalize short_ret = s1['start_val'] / s1['result_val'] short_ret = self.exchange.convert_amt(s1['start_currency'],'BTC', short_ret) if short_ret > arbitrageDescriptor['short']['return']: arbitrageDescriptor['short']['return'] = short_ret arbitrageDescriptor['short']['path'] = path arbitrageDescriptor['short']['s1'] = shortMaxVal arbitrageDescriptor['short']['s2'] = s1 # calculate arbitrage return ret = arbitrageDescriptor['long']['return'] * arbitrageDescriptor['short']['return'] - 1 if ret == - 1: return print("Arbitrage %s return: %.4f" % (pair.getPairCode(), ret)) if ret > 0: curr = arbitrageDescriptor['max_transaction']['currency'] currVal = arbitrageDescriptor['max_transaction']['val'] * ret btc = 0 #self.exchange.convert_amt(curr,'BTC', currVal) print('**** ARBITRAGE OPPORTUNITY. Earn %.4f %s (%.4f BTC)' % (currVal, curr, btc)) self.debug_arbitrage(pair, arbitrageDescriptor) # arbitrage opportunity # recalculate arbitrage for a given pair def checkArbitrageOpportunity_old(self, pair): arbitrageDescriptor = { "long" : { "val" : 0, "path": [] }, "short" : { "val" : 0, 'btc_val' : 0, "path" : [] } } for path in self.conversion_paths[pair]: # calculate conversion values: we begin with 1 BTC on a long path and 1 unit of local currency on a short path firstPair = path[0] # first element should be the first pair (zero/0 element is a fake "root" element) # start with value of 1 btc in local currency longVal = float(self.exchange.convert_amt('BTC', firstPair.getQuote(), 1.0, _bid = False)) # use ASK for algo initialization if longVal == 0: continue shortVal = 1.0 for p in path: # iterate all leaves (each leaf is the same pair but different conversion path) # estimate long value: quote -> base conversion which is considered long ex_rate1 = float(p.get_average_ask_price_for_quote_amt(longVal)) # at what price I can buy 1 unit of base currency if ex_rate1 == 0: break # no data - skip path longVal = longVal / ex_rate1 # convert quote currency to base currency # estimate short value ( base -> quote) ex_rate2 = float(p.get_average_bid_price_for_base_amt(1.0) ) # at what price I can sell 1 unit of base currency and get quote curreny if ex_rate2 == 0: break # no data - skip path shortVal = shortVal * ex_rate2 # keep track of max # all longVal are expressed in terms of base / local currency of the pair, so we can compare them if longVal > arbitrageDescriptor['long']['val']: arbitrageDescriptor['long']['val'] = longVal arbitrageDescriptor['long']['path'] = path # on the other hand, all shortVal are expressed in terms of quote currency of the path root which are different # so we need to convert shortVal to btc in order to compare them shortVal_btc = self.exchange.convert_amt(firstPair.getQuote(), 'BTC', shortVal, _bid = False) # buy btc if shortVal_btc == 0: continue # no data if shortVal_btc > arbitrageDescriptor['short']['btc_val']: arbitrageDescriptor['short']['btc_val'] = shortVal_btc arbitrageDescriptor['short']['path'] = path arbitrageDescriptor['short']['val'] = shortVal arbitrageDescriptor['arb_return'] = arbitrageDescriptor['long']['val'] * arbitrageDescriptor['short']['btc_val'] - 1 #self.estimateMaximumThroughOutput(pair) a = pair.getPairCode() b = arbitrageDescriptor['arb_return'] self.logger.info("Arbitrage %s return: %.2f" % (a,b) ) if arbitrageDescriptor['arb_return'] > 0: self.arbitrageHandler(pair, arbitrageDescriptor) # process arbitrage # Process arbitrage event def arbitrageHandler(self, pair, arbitrage): print(" ****** ARBITRAGE FOR THE PAIR %s " % pair.getPairCode()) #firstPair = arbitrage['long']['path'][0] # first element should be first pair (zero/0 element is a fake "root" element) # Estimate maximum possible value of the transaction on long-short path (expressed in terms of the last node of short path) (transaction_max_amt, arb_val_currency,x) = self.estimateMaximumThroughOutput(pair, arbitrage['long']['path'], arbitrage['short']['path']) arb_max_profit = arbitrage['arb_return'] * transaction_max_amt # max possible arbitrage value #shortPath = arbitrage['short']['path'] #arb_val_currency = shortPath[len(shortPath) - 1].getQuote() # currency in which arbitrage value is expressed # get btc value of arbitrage profit arbitrage['max_transaction'] = {'val': transaction_max_amt, 'currency' : arb_val_currency } arb_max_profit_btc = self.exchange.convert_amt(arb_val_currency, 'BTC', arb_max_profit, _bid = False) # buy BTC print('Arbitrage return: %f. Maximum transaction amt %f %s. Arbitrage profit %f %s (%f BTC)' % (arbitrage['arb_return'], transaction_max_amt, arb_val_currency, arb_max_profit, arb_val_currency, arb_max_profit_btc )) self.debug_arbitrage(pair, arbitrage) # execute arbitrage sequence self.execute_arbitrage(pair, arbitrage) def execute_arbitrage(self, pair, arbitrage): # long leg longPath = arbitrage['long']['path'] firstPair = longPath[0] # first element should be the first pair (zero/0 element is a fake "root" element) # start with value of 1 btc in local currency longVal = self.exchange.convert_amt( arbitrage['max_transaction']['currency'], firstPair.getQuote(), arbitrage['max_transaction']['val'], _bid=False) # use ASK for algo initialization/ for p in longPath: e = p.get_average_ask_price_for_quote_amt(longVal) longVal = longVal / e # create buy order o = Order(p, 'BUY', longVal, type = 'LIMIT', price = 0 ) self.orderManager.execute_order(o) status = o.get_status() if status == 'OK': # IN_PROGRESS, COMPLETED, FAILED, PARTIALLY_COMPLETED pass elif status == 'CANCELED': pass elif status == 'FAILED': pass elif status == 'PARTIAL': pass def debug_arbitrage(self, pair, arbitrage): longPath = arbitrage['long']['path'] firstPair = longPath[0] # first element should be the first pair (zero/0 element is a fake "root" element) # start with value of 1 btc in local currency longVal = arbitrage['long']['max_start_val'] #self.exchange.convert_amt(arbitrage['max_transaction']['currency'], firstPair.getQuote(), arbitrage['max_transaction']['val'], _bid=False) # use ASK for algo initialization/ s= "" for p in longPath: l = longVal e = p.get_average_ask_price_for_quote_amt(longVal) s = str(longVal) + " " + p.getQuote() + " -> " longVal = longVal / e s += str(longVal) + " " + p.getBase() + "@" + str(e) print(s) print("Ask book: AverageAskPrie(%f)=%f" % (l, e)) print(p.asks) shortPath = arbitrage['short']['path'] print("**** SHORTING:") shortVal = longVal firstPair = shortPath[- 1] for index, p in enumerate(reversed(shortPath)): k = shortVal e = p.get_average_bid_price_for_base_amt(shortVal) s = str(shortVal) + " " + p.getBase() + " -> " shortVal = shortVal * e s += str(shortVal) + " " + p.getQuote() + "@" + str(e) print(s) print("Bid book: AverageBidPrie(%f)=%f" % (k, e)) print(p.bids) shortVal_original = self.exchange.convert_amt(firstPair.getQuote(), longPath[0].getQuote(), shortVal, _bid=False) # buy btc print(str(shortVal) + " " + firstPair.getQuote()+ "->" + str(shortVal_original) + longPath[0].getQuote() + "@" + str(e) ) a = 5
def test_init(self): self.x = OrderManager() assert type(self.x._orders) == dict assert self.x._up_to_id == 0
class Test: def test_init(self): self.x = OrderManager() assert type(self.x._orders) == dict assert self.x._up_to_id == 0 def test_setters(self): self.x = OrderManager() id1 = self.x.create_new_order() assert len(self.x.orders) == 1 assert type(self.x.orders[0]) == Order assert type(self.x.get_order_by_id(id1)) == Order id2 = self.x.create_new_order() assert len(self.x.orders) == 2 def test_checker(self): #we expect the first order created to have an id of 0 self.x = OrderManager() assert self.x.id_exists('0') == False self.x.create_new_order() assert self.x.id_exists('0') == True def test_invalid_cases(self): self.x = OrderManager() with pytest.raises(TypeError): self.x.get_order_by_id('1.1') with pytest.raises(TypeError): self.x.get_order_by_id(1.1) with pytest.raises(KeyError): self.x.get_order_by_id('1') assert self.x.id_exists('a') == False
def setUp(self): self.order_manager = OrderManager()
# process_order(signal_dict) # data.db_append_history(signal_dict) # print('Signal "%s" zpracovan s nasledujicimi parametry:' % signal_dict['puvodni_zprava']) # print("Operace: ", signal_dict['operace']) # print("Mnozstvi:", int(signal_dict['mnozstvi'])*int(signal_dict['nasobeni'])) # print("Cena (signal/skutecnost): %d/%d" % (signal_dict['cena'], signal_dict['skutecna_cena'])) # print("Vysledek: %s - ID: %d" % (signal_dict['vysledek'], signal_dict['order_id'])) except Exception as loop_error: tg_client.send_message("me", "CHYBA: %s" % loop_error) raise if __name__ == "__main__": print("Spoustim pripojeni k API") try: tg_client, tws_client = get_clients() orderman = OrderManager(tws_client, tws_queue) tg_client.start() # TODO: Vytvorit sjednocenou inicializacni metodu obsahujici server clock a ID printout while tws_client.is_error(): print(tws_client.get_error()) tws_client.refresh_next_id() except Exception as e: print("[CHYBA!]: Nepovedlo se pripojit k TWS nebo Telegramu") traceback.print_exc() the_loop()
def test_get_signature(self): om = OrderManager('btcusd') self.assertDictEqual(om._OrderManager__get_signature(), {'key': 'abcdefghijklmnopqrstuvwxyz123456', 'signature': '7728462B38496C189AFAED03A0C51FAB7D2358FA0FE1995C976FF755E794489D', 'nonce': '1563871382'})
def main(): parser = argparse.ArgumentParser() parser.add_argument('market', type=str, choices=constants.MARKETS, help='currency pair - btcusd, ltcusd, etc') market = (parser.parse_args()).market logging.info('the market {} was chosen'.format(market)) ts = TradingStrategy(market) om = OrderManager(market) md = MarketDataInterface(market) running = True while running: action = ts.get_final_strategy() price = Decimal(str((md.get_ticker_data(False))[3])) time = datetime.datetime.now() if abs((time - datetime.datetime.strptime( md.get_ticker_data(False)[2], '%Y-%m-%d %H:%M:%S')).seconds) > 600: logging.error('database is out of date, exiting') running = False balance = om.get_balance() if None in balance.values(): logging.info('failed to get account balance') try: if action['action'] == 'buy': amount = (Decimal(str(action['risk'])) * Decimal(balance['second_available']) / price) elif action['action'] == 'sell': amount = (Decimal(str(action['risk'])) * Decimal(balance['available'])) else: amount = Decimal('0') except TypeError: logging.exception('could not determine amount') amount = Decimal('0') if action['action'] in ['buy', 'sell']: if market[-3:] in ['usd', 'eur']: if (amount * price) < constants.EUR_USD_MIN_TRANSACTION_SIZE: action['action'] = 'wait' amount = Decimal('0') logging.info( 'do not have minimum amount ({}) to trade'.format( constants.EUR_USD_MIN_TRANSACTION_SIZE)) price = price.quantize(Decimal('.01')) if market[:3] in ['xrp', 'usd', 'eur']: amount = amount.quantize(Decimal('.00001')) else: amount = amount.quantize(Decimal('.00000001')) elif market[-3:] == 'btc': if (amount * price) < constants.BTC_MIN_TRANSACTION_SIZE: action['action'] = 'wait' amount = Decimal('0') logging.info( 'do not have minimum amount ({}) to trade'.format( constants.BTC_MIN_TRANSACTION_SIZE)) price = price.quantize(Decimal('.00000001')) if action['action'] == 'buy': sleep(1) order_id = om.buy(price=price, amount=amount) if order_id: logging.info( 'successfully bought {amount}{currency_one} at {price}{currency_two} each' .format(amount=amount, currency_one=market[:3], price=price, currency_two=market[-3:])) elif action['action'] == 'sell': sleep(1) order_id = om.sell(price=price, amount=amount) if order_id: logging.info( 'successfully sold {amount}{currency_one} at {price}{currency_two} each' .format(amount=amount, currency_one=market[:3], price=price, currency_two=market[-3:])) elif action['action'] == 'wait': logging.info('waiting {}s, did not trade'.format( settings.MAIN_TIMER)) else: running = False logging.error( 'exiting trader - unsupported action (supported actions: buy, sell, wait), {}' .format(action)) sleep(1) open_orders = om.get_open_orders() if open_orders: for order in open_orders: time = datetime.datetime.now().timestamp() sleep(1) if datetime.datetime.strptime( order['datetime'], '%Y-%m-%d %H:%M:%S').timestamp() < time - 21600: om.cancel_order(order['id']) sleep(settings.MAIN_TIMER) logging.info('waited {}s to trade again'.format(settings.MAIN_TIMER))
class TestOrderManager(unittest.TestCase): def __init__(self, *args, **kwargs): super(TestOrderManager, self).__init__(*args, **kwargs) self.server = app.test_client() self.order_manager = OrderManager(self.server) self.test_data_key = "1" self.test_data = {"Toppings": "beef", "Sizes": "Large"} self.test_data_key2 = "2" self.test_data2 = {"Toppings": "Chicken", "Sizes": "Small"} self.test_data_key3 = "3" self.test_data3 = {"Toppings": "Fish", "Sizes": "Medium"} #reset what is on the test_client first due to other test r = self.server.get(self.order_manager._URL).get_json() for k in r.keys(): self.server.delete(self.order_manager._URL, json=k) #initialize the server and push the test_data first #use dumps because it is more consistent with the ordermanager adding method self.server.post(self.order_manager._URL, json={self.test_data_key: json.dumps(self.test_data)}) self.server.post( self.order_manager._URL, json={self.test_data_key2: json.dumps(self.test_data2)}) def test_get_all_order(self): #data is a dict where key is string and value is json.dumps dict actual = self.order_manager.get_all_orders() expected = { self.test_data_key: json.dumps(self.test_data), self.test_data_key2: json.dumps(self.test_data2) } assert actual == expected def test_get_order_num_exist(self): actual = json.loads(self.order_manager.get_order(1)) expected = self.test_data assert actual == expected def test_get_order_num_not_exist(self): actual = self.order_manager.get_order(4) expected = 404 assert actual == expected def test_add_new_order_num_exist(self): actual = self.order_manager.add_new_order(self.test_data_key, self.test_data) expected = 404 assert actual == expected def test_add_new_order_num_not_exist(self): actual = self.order_manager.add_new_order(self.test_data_key3, self.test_data3) expected = 201 #after adding need to delete, otherwise test_get_all will record one more self.server.delete(self.order_manager._URL, json=2) assert actual == expected def test_delete_order_num_exist(self): actual = self.order_manager.delete_order(self.test_data_key) expected = 201 assert actual == expected def test_delete_order_num_not_exist(self): actual = self.order_manager.delete_order(4) expected = 404 assert actual == expected def test_update_order_num_exist(self): updated_data2 = {"Toppings": "Pork", "Sizes": "Small"} actual = self.order_manager.update_order(self.test_data_key2, updated_data2) expected = 201 assert actual == expected def test_update_order_num_not_exist(self): actual = self.order_manager.update_order(4, None) expected = 404 assert actual == expected def test_get_seed(self): actual = self.order_manager.get_seed_for_lotto() expected = 10 assert actual == expected def test_set_seed(self): self.order_manager.set_seed_for_lotto(100) actual = self.order_manager.get_seed_for_lotto() expected = 100 assert actual == expected # back to original self.order_manager.set_seed_for_lotto(10) actual = self.order_manager.get_seed_for_lotto() expected = 10 assert actual == expected
class GourmetBurgerSystem: def __init__(self): self._stock_levels = {} self._sides = item.initialise_sides(self._stock_levels) self._drinks = item.initialise_drinks(self._stock_levels) self._ingredients = item.initialise_ingredients(self._stock_levels) self._buns = item.initialise_buns(self._stock_levels) self._order_manager = OrderManager() self._lookup = {} obj_list = (*self._sides, *self._drinks, *self._ingredients, *self._buns) for obj in obj_list: self._lookup[obj.name] = obj standard_burger_buns = [self.get_object_by_name("Sesame bun")] * 2 standard_burger_fillings = [ self.get_object_by_name(name) for name in ("Beef Patty", "Cheddar Cheese", "Tomato Sauce") ] standard_wrap_fillings = [ self.get_object_by_name(name) for name in ("Chicken Patty", "Tomato", "Lettuce") ] self._standard_burger = Burger(standard_burger_fillings, standard_burger_buns) self._standard_wrap = Wrap(standard_wrap_fillings) @property def sides(self): return list(self._sides) def get_object_by_name(self, name): return self._lookup[name] @property def drinks(self): return list(self._drinks) @property def ingredients(self): return list(self._ingredients) @property def buns(self): return list(self._buns) @property def stock_levels(self): return dict(self._stock_levels) @property def orders(self): return self._order_manager.orders @property def standard_burger(self): return self._standard_burger @property def standard_wrap(self): return self._standard_wrap def update_stock_levels(self, stock_levels): processed_stock_levels = {} errors = {} messages = {} for (key, value) in stock_levels.items(): if key not in self._stock_levels: continue try: new_value = int(value) except ValueError: errors[key] = 'Please enter an integer.' else: if new_value < 0: errors[key] = 'Please enter a stock level greater than 0.' elif new_value != self._stock_levels[key][0]: processed_stock_levels[key] = [ new_value, self._stock_levels[key][1] ] messages[key] = 'Stock level updated succesfully' if errors: self._stock_levels.update(processed_stock_levels) raise StockSetterError(errors, messages) else: self._stock_levels.update(processed_stock_levels) return messages def create_new_order(self): return self._order_manager.create_new_order() def id_exists(self, id): return self._order_manager.id_exists(id) def get_order_by_id(self, id): return self._order_manager.get_order_by_id(id) def print_order(self, id): print(self._order_manager.get_order_by_id(id)) @classmethod def load(cls): try: with open("database", "rb") as file: system = pickle.load(file) except FileNotFoundError: system = GourmetBurgerSystem() return system def save(self): with open("database", "wb") as file: pickle.dump(self, file) @classmethod def checkout(cls, order): errors = [] items = order.list_all() cls._increment_all(-1, items) items_no_duplicates = list(dict.fromkeys(items)) errors += cls._list_of_names_with_less_than_zero(items_no_duplicates) if errors: cls._increment_all(1, items) raise OutOfStockError(errors) else: order.status = "being prepared" @classmethod def check_item_list(cls, items): cls._increment_all(-1, items) errors = cls._list_of_names_with_less_than_zero(items) cls._increment_all(1, items) errors = list(dict.fromkeys(errors)) if errors: raise OutOfStockError(errors) @classmethod def _list_of_names_with_less_than_zero(cls, items): shortages = [] for item in items: if item.stock < 0: shortages.append(item.name) return shortages @classmethod def _increment_all(cls, sign, items): for item in items: item.increment(sign * item.quantity_per_serving) def create_burger(self, ingredients, buns): return Burger(ingredients, buns) def create_wrap(self, ingredients): return Wrap(ingredients) def add_standard_burger_items(self, item_list): for item in self.standard_burger.ingredients: item_list.append(item) item_list += [self.standard_burger.bun ] * self.standard_burger.number_of_buns def add_standard_wrap_items(self, item_list): for item in self.standard_wrap.ingredients: item_list.append(item)
class TestTradingSimulation(unittest.TestCase): def setUp(self): self.lp_2_gateway = deque() self.ob_2_ts = deque() self.ts_2_om = deque() self.ms_2_om = deque() self.om_2_ts = deque() self.gw_2_om = deque() self.om_2_gw = deque() self.liquidityProvider = LiquidityProvider(self.lp_2_gateway) self.bookBuilder = OrderBook(self.lp_2_gateway, self.ob_2_ts) self.tradingStrategy = TradingStrategy(self.ob_2_ts, self.ts_2_om, self.om_2_ts) self.marketSimulator = MarketSimulator(self.om_2_gw, self.gw_2_om) self.orderManager = OrderManager(self.ts_2_om, self.om_2_ts, self.om_2_gw, self.gw_2_om) def test_add_liquidity(self): # Order sent from the exchange to the trading system order1 = { 'id': 1, 'price': 219, 'quantity': 10, 'side': 'bid', 'action': 'new' } # Add Order from Gateway self.liquidityProvider.insert_manual_order(order1) self.assertEqual(len(self.lp_2_gateway), 1) # Book Builder self.bookBuilder.handle_order_from_gateway() self.assertEqual(len(self.ob_2_ts), 1) # Trading Strategy self.tradingStrategy.handle_input_from_bb() self.assertEqual(len(self.ts_2_om), 0) # Second Order order2 = { 'id': 2, 'price': 218, 'quantity': 10, 'side': 'ask', 'action': 'new' } self.liquidityProvider.insert_manual_order(order2.copy()) self.assertEqual(len(self.lp_2_gateway), 1) self.bookBuilder.handle_order_from_gateway() self.assertEqual(len(self.ob_2_ts), 1) self.tradingStrategy.handle_input_from_bb() self.assertEqual(len(self.ts_2_om), 2) self.orderManager.handle_input_from_ts() self.assertEqual(len(self.ts_2_om), 1) self.assertEqual(len(self.om_2_gw), 1) self.orderManager.handle_input_from_ts() self.assertEqual(len(self.ts_2_om), 0) self.assertEqual(len(self.om_2_gw), 2) self.marketSimulator.handle_order_from_gw() self.assertEqual(len(self.gw_2_om), 1) self.marketSimulator.handle_order_from_gw() self.assertEqual(len(self.gw_2_om), 2) self.orderManager.handle_input_from_market() self.orderManager.handle_input_from_market() self.assertEqual(len(self.om_2_ts), 2) self.tradingStrategy.handle_response_from_om() self.assertEqual(self.tradingStrategy.get_pnl(), 0) self.marketSimulator.fill_all_orders() self.assertEqual(len(self.gw_2_om), 2) self.orderManager.handle_input_from_market() self.orderManager.handle_input_from_market() self.assertEqual(len(self.om_2_ts), 3) self.tradingStrategy.handle_response_from_om() self.assertEqual(len(self.om_2_ts), 2) self.tradingStrategy.handle_response_from_om() self.assertEqual(len(self.om_2_ts), 1) self.tradingStrategy.handle_response_from_om() self.assertEqual(len(self.om_2_ts), 0) self.assertEqual(self.tradingStrategy.get_pnl(), 10)