def from_unpack_list(cls, trader_id, timestamp, order_number, recipient_trader_id, recipient_order_number, proposal_id, asset1_amount, asset1_type, asset2_amount, asset2_type, ip, port): return TradePayload( TraderId(trader_id), Timestamp(timestamp), OrderNumber(order_number), OrderId(TraderId(recipient_trader_id), OrderNumber(recipient_order_number)), proposal_id, AssetPair(AssetAmount(asset1_amount, asset1_type), AssetAmount(asset2_amount, asset2_type)), SocketAddress(ip, port))
def from_block(cls, block_info): """ Create a Transaction object based on information in a tx_init/tx_done block. """ trader_id = block_info["tx"]["trader_id"] transaction_number = block_info["tx"]["transaction_number"] order_trader_id = block_info["tx"]["trader_id"] order_number = block_info["tx"]["order_number"] partner_trader_id = block_info["tx"]["partner_trader_id"] partner_order_number = block_info["tx"]["partner_order_number"] asset1_amount = block_info["tx"]["assets"]["first"]["amount"] asset1_type = block_info["tx"]["assets"]["first"]["type"] asset1_transferred = block_info["tx"]["transferred"]["first"]["amount"] asset2_amount = block_info["tx"]["assets"]["second"]["amount"] asset2_type = block_info["tx"]["assets"]["second"]["type"] asset2_transferred = block_info["tx"]["transferred"]["second"][ "amount"] transaction_timestamp = block_info["tx"]["timestamp"] sent_wallet_info = False received_wallet_info = False incoming_address = None outgoing_address = None partner_incoming_address = None partner_outgoing_address = None match_id = '' transaction_id = TransactionId(TraderId(bytes(trader_id)), TransactionNumber(transaction_number)) transaction = cls( transaction_id, AssetPair(AssetAmount(asset1_amount, str(asset1_type)), AssetAmount(asset2_amount, str(asset2_type))), OrderId(TraderId(bytes(order_trader_id)), OrderNumber(order_number)), OrderId(TraderId(bytes(partner_trader_id)), OrderNumber(partner_order_number)), Timestamp(float(transaction_timestamp))) transaction._transferred_assets = AssetPair( AssetAmount(asset1_transferred, str(asset1_type)), AssetAmount(asset2_transferred, str(asset2_type))) transaction.sent_wallet_info = sent_wallet_info transaction.received_wallet_info = received_wallet_info transaction.incoming_address = WalletAddress(str(incoming_address)) transaction.outgoing_address = WalletAddress(str(outgoing_address)) transaction.partner_incoming_address = WalletAddress( str(partner_incoming_address)) transaction.partner_outgoing_address = WalletAddress( str(partner_outgoing_address)) transaction.match_id = str(match_id) return transaction
def test_insert_ask_bid(self): """ Test whether an ask is successfully inserted when a tick block is received """ ask = TestMarketCommunitySingle.get_tick_block(True, AssetPair(AssetAmount(30, 'BTC'), AssetAmount(30, 'MB'))) bid = TestMarketCommunitySingle.get_tick_block(False, AssetPair(AssetAmount(30, 'BTC'), AssetAmount(29, 'MB'))) bid.transaction["tick"]["order_number"] = 2 # To give it a different order number self.nodes[0].overlay.trustchain.persistence.get_linked = lambda _: True self.nodes[0].overlay.received_block(ask) self.nodes[0].overlay.received_block(bid) self.assertEqual(len(self.nodes[0].overlay.order_book.asks), 1) self.assertEqual(len(self.nodes[0].overlay.order_book.bids), 1)
def test_create_bid_order(self): # Test for create bid order bid_order = self.order_manager.create_bid_order( AssetPair(AssetAmount(100, 'BTC'), AssetAmount(10, 'MC')), Timeout(0)) self.assertFalse(bid_order.is_ask()) self.assertEquals(OrderId(TraderId(b"0"), OrderNumber(1)), bid_order.order_id) self.assertEquals( AssetPair(AssetAmount(100, 'BTC'), AssetAmount(10, 'MC')), bid_order.assets) self.assertEquals(100, bid_order.total_quantity) self.assertEquals(0, int(bid_order.timeout))
def from_unpack_list(cls, trader_id, timestamp, tx_trader_id, transaction_number, order_trader_id, order_number, recipient_trader_id, recipient_order_number, proposal_id, asset1_amount, asset1_type, asset2_amount, asset2_type): return StartTransactionPayload( TraderId(trader_id), Timestamp(timestamp), TransactionId(TraderId(tx_trader_id), TransactionNumber(transaction_number)), OrderId(TraderId(order_trader_id), OrderNumber(order_number)), OrderId(TraderId(recipient_trader_id), OrderNumber(recipient_order_number)), proposal_id, AssetPair(AssetAmount(asset1_amount, asset1_type), AssetAmount(asset2_amount, asset2_type)))
def from_unpack_list(cls, trader_id, timestamp, order_number, asset1_amount, asset1_type, asset2_amount, asset2_type, timeout, traded, recipient_order_number, match_quantity, match_trader_id, matchmaker_trader_id, match_id): return MatchPayload( TraderId(trader_id), Timestamp(timestamp), OrderNumber(order_number), AssetPair(AssetAmount(asset1_amount, asset1_type), AssetAmount(asset2_amount, asset2_type)), Timeout(timeout), traded, OrderNumber(recipient_order_number), match_quantity, TraderId(match_trader_id), TraderId(matchmaker_trader_id), match_id)
def test_cancel(self): """ Test cancelling an order """ yield self.introduce_nodes() ask_order = yield self.nodes[0].overlay.create_ask( AssetPair(AssetAmount(1, 'DUM1'), AssetAmount(1, 'DUM2')), 3600) self.nodes[0].overlay.cancel_order(ask_order.order_id) yield self.sleep(0.5) self.assertTrue(self.nodes[0].overlay.order_manager.order_repository.find_by_id(ask_order.order_id).cancelled)
def get_tx_done_block(ask_amount, bid_amount, traded_amount, ask_total_traded, bid_total_traded): ask_pair = AssetPair(AssetAmount(ask_amount, 'BTC'), AssetAmount(ask_amount, 'MB')) bid_pair = AssetPair(AssetAmount(bid_amount, 'BTC'), AssetAmount(bid_amount, 'MB')) ask = Order(OrderId(TraderId('0' * 40), OrderNumber(1)), ask_pair, Timeout(3600), Timestamp.now(), True) ask._traded_quantity = ask_total_traded bid = Order(OrderId(TraderId('1' * 40), OrderNumber(1)), bid_pair, Timeout(3600), Timestamp.now(), False) bid._traded_quantity = bid_total_traded tx = Transaction( TransactionId(TraderId('0' * 40), TransactionNumber(1)), AssetPair(AssetAmount(traded_amount, 'BTC'), AssetAmount(traded_amount, 'MB')), OrderId(TraderId('0' * 40), OrderNumber(1)), OrderId(TraderId('1' * 40), OrderNumber(1)), Timestamp(0.0)) tx.transferred_assets.first += AssetAmount(traded_amount, 'BTC') tx.transferred_assets.second += AssetAmount(traded_amount, 'MB') tx_done_block = MarketBlock() tx_done_block.type = 'tx_done' tx_done_block.transaction = { 'ask': ask.to_status_dictionary(), 'bid': bid.to_status_dictionary(), 'tx': tx.to_dictionary(), 'version': MarketCommunity.PROTOCOL_VERSION } tx_done_block.transaction['ask']['address'], tx_done_block.transaction[ 'ask']['port'] = "1.1.1.1", 1234 tx_done_block.transaction['bid']['address'], tx_done_block.transaction[ 'bid']['port'] = "1.1.1.1", 1234 return tx_done_block
def from_database(cls, data): trader_id, order_number, asset1_amount, asset1_type, asset2_amount, asset2_type, timeout, timestamp,\ is_ask, traded, block_hash = data tick_cls = Ask if is_ask else Bid order_id = OrderId(TraderId(str(trader_id)), OrderNumber(order_number)) return tick_cls(order_id, AssetPair(AssetAmount(asset1_amount, str(asset1_type)), AssetAmount(asset2_amount, str(asset2_type))), Timeout(timeout), Timestamp(timestamp), traded=traded, block_hash=str(block_hash))
def setUp(self, annotate=True): yield super(MatchingEngineTestSuite, self).setUp(annotate=annotate) # Object creation self.ask = Ask( OrderId(TraderId('2'), OrderNumber(1)), AssetPair(AssetAmount(3000, 'BTC'), AssetAmount(30, 'MB')), Timeout(30), Timestamp.now()) self.bid = Bid( OrderId(TraderId('4'), OrderNumber(2)), AssetPair(AssetAmount(3000, 'BTC'), AssetAmount(30, 'MB')), Timeout(30), Timestamp.now()) self.ask_order = Order( OrderId(TraderId('5'), OrderNumber(3)), AssetPair(AssetAmount(3000, 'BTC'), AssetAmount(30, 'MB')), Timeout(30), Timestamp.now(), True) self.bid_order = Order( OrderId(TraderId('6'), OrderNumber(4)), AssetPair(AssetAmount(3000, 'BTC'), AssetAmount(30, 'MB')), Timeout(30), Timestamp.now(), False) self.order_book = OrderBook() self.matching_engine = MatchingEngine( PriceTimeStrategy(self.order_book)) self.ask_count = 2 self.bid_count = 2
def test_cancel_order_invalid(self): """ Test whether an error is returned when we try to cancel an order that has expired """ order = self.session.lm.market_community.order_manager.create_ask_order( AssetPair(AssetAmount(3, 'DUM1'), AssetAmount(4, 'DUM2')), Timeout(0)) order.set_verified() self.session.lm.market_community.order_manager.order_repository.update( order) self.should_check_equality = False return self.do_request('market/orders/1/cancel', request_type='POST', expected_code=400)
def test_create_bid(self): """ Test creating a bid and sending it to others """ yield self.introduce_nodes() yield self.nodes[0].overlay.create_bid(AssetPair(AssetAmount(1, 'DUM1'), AssetAmount(2, 'DUM2')), 3600) yield self.sleep(0.5) orders = self.nodes[0].overlay.order_manager.order_repository.find_all() self.assertTrue(orders) self.assertTrue(orders[0].verified) self.assertFalse(orders[0].is_ask()) self.assertEqual(len(self.nodes[2].overlay.order_book.bids), 1)
def setUp(self): yield super(TickEntryTestSuite, self).setUp() # Object creation tick = Tick(OrderId(TraderId(b'0'), OrderNumber(1)), AssetPair(AssetAmount(60, 'BTC'), AssetAmount(30, 'MB')), Timeout(0), Timestamp(0.0), True) tick2 = Tick( OrderId(TraderId(b'0'), OrderNumber(2)), AssetPair(AssetAmount(63400, 'BTC'), AssetAmount(30, 'MB')), Timeout(100), Timestamp.now(), True) self.price_level = PriceLevel(Price(100, 'MB', 'BTC')) self.tick_entry = TickEntry(tick, self.price_level) self.tick_entry2 = TickEntry(tick2, self.price_level)
def setUp(self): # Object creation tick = Tick(OrderId(TraderId(b'0'), OrderNumber(1)), AssetPair(AssetAmount(60, 'BTC'), AssetAmount(30, 'MC')), Timeout(100), Timestamp.now(), True) tick2 = Tick(OrderId(TraderId(b'0'), OrderNumber(2)), AssetPair(AssetAmount(30, 'BTC'), AssetAmount(30, 'MC')), Timeout(100), Timestamp.now(), True) self.price_level = PriceLevel(Price(10, 'MC', 'BTC')) self.tick_entry1 = TickEntry(tick, self.price_level) self.tick_entry2 = TickEntry(tick, self.price_level) self.tick_entry3 = TickEntry(tick, self.price_level) self.tick_entry4 = TickEntry(tick, self.price_level) self.tick_entry5 = TickEntry(tick2, self.price_level)
def setUp(self): # Object creation self.payment = Payment(TraderId("0"), TransactionId(TraderId('2'), TransactionNumber(2)), AssetAmount(3, 'BTC'), WalletAddress('a'), WalletAddress('b'), PaymentId('aaa'), Timestamp(4.0), True)
def test_subtraction(self): # Test for subtraction self.assertEqual(AssetAmount(98, 'BTC'), self.assetamount2 - self.assetamount1) self.assertEqual(NotImplemented, self.assetamount1.__sub__(10)) self.assertEqual(NotImplemented, self.assetamount1.__sub__(self.assetamount4))
def test_churn_matchmaker(self): """ Test whether we finish constructing a tick as soon as the first matchmaker comes online """ deferred = self.nodes[0].overlay.create_ask(AssetPair(AssetAmount(1, 'DUM1'), AssetAmount(2, 'DUM2')), 3600) yield self.introduce_nodes() yield deferred
def test_get_orders(self): """ Test whether the API returns the right orders when we perform a request """ def on_response(response): json_response = json.loads(response) self.assertIn('orders', json_response) self.assertEqual(len(json_response['orders']), 1) self.session.lm.market_community.order_manager.create_ask_order( AssetPair(AssetAmount(3, 'DUM1'), AssetAmount(4, 'DUM2')), Timeout(3600)) self.should_check_equality = False return self.do_request('market/orders', expected_code=200).addCallback(on_response)
def test_failing_payment(self): """ Test trading between two persons when a payment fails """ yield self.introduce_nodes() for node_nr in [0, 1]: self.nodes[node_nr].overlay.wallets['DUM1'].transfer = lambda *_: fail(RuntimeError("oops")) self.nodes[node_nr].overlay.wallets['DUM2'].transfer = lambda *_: fail(RuntimeError("oops")) yield self.nodes[0].overlay.create_ask(AssetPair(AssetAmount(1, 'DUM1'), AssetAmount(1, 'DUM2')), 3600) yield self.nodes[1].overlay.create_bid(AssetPair(AssetAmount(1, 'DUM1'), AssetAmount(1, 'DUM2')), 3600) yield self.sleep(0.5) self.assertEqual(self.nodes[0].overlay.transaction_manager.find_all()[0].status, "error") self.assertEqual(self.nodes[1].overlay.transaction_manager.find_all()[0].status, "error")
def test_from_network(self): # Test for from network data = Payment.from_network( type('Data', (object,), {"trader_id": TraderId("0"), "transaction_id": TransactionId(TraderId('2'), TransactionNumber(2)), "transferred_assets": AssetAmount(3, 'BTC'), "address_from": WalletAddress('a'), "address_to": WalletAddress('b'), "payment_id": PaymentId('aaa'), "timestamp": Timestamp(4.0), "success": True})) self.assertEquals(TraderId("0"), data.trader_id) self.assertEquals(TransactionId(TraderId('2'), TransactionNumber(2)), data.transaction_id) self.assertEquals(AssetAmount(3, 'BTC'), data.transferred_assets) self.assertEquals(Timestamp(4.0), data.timestamp) self.assertTrue(data.success)
def create_ask_bid_from_params(parameters): """ Create an ask/bid from the provided parameters in a request. This method returns a tuple with the price, quantity and timeout of the ask/bid. """ timeout = 3600 if has_param(parameters, 'timeout'): timeout = int(get_param(parameters, 'timeout')) first_asset_amount = int(get_param(parameters, 'first_asset_amount')) second_asset_amount = int(get_param(parameters, 'second_asset_amount')) first_asset_type = get_param(parameters, 'first_asset_type') second_asset_type = get_param(parameters, 'second_asset_type') return AssetPair(AssetAmount(first_asset_amount, first_asset_type), AssetAmount(second_asset_amount, second_asset_type)), timeout
def test_decline_trade(self): """ Test declining a trade """ yield self.introduce_nodes() order = yield self.nodes[0].overlay.create_ask(AssetPair(AssetAmount(1, 'DUM1'), AssetAmount(1, 'DUM2')), 3600) order._traded_quantity = 1 # So it looks like this order has already been fulfilled yield self.sleep(0.5) self.assertEqual(len(self.nodes[2].overlay.order_book.asks), 1) self.nodes[1].overlay.create_bid(AssetPair(AssetAmount(1, 'DUM1'), AssetAmount(1, 'DUM2')), 3600) yield self.sleep(0.5) # The ask should be removed since this node thinks the order is already completed self.assertEqual(len(self.nodes[2].overlay.order_book.asks), 0)
def test_cancel_order(self): """ Test whether an error is returned when we try to cancel an order that has expired """ order = self.session.lm.market_community.order_manager.create_ask_order( AssetPair(AssetAmount(3, 'DUM1'), AssetAmount(4, 'DUM2')), Timeout(3600)) def on_response(response): json_response = json.loads(response) self.assertTrue(json_response['cancelled']) cancelled_order = self.session.lm.market_community.order_manager.order_repository.find_by_id( order.order_id) self.assertTrue(cancelled_order.cancelled) self.should_check_equality = False return self.do_request('market/orders/1/cancel', request_type='POST', expected_code=200)\ .addCallback(on_response)
def setUp(self): # Object creation self.transaction_id = TransactionId(TraderId("0"), TransactionNumber(1)) self.transaction = Transaction( self.transaction_id, AssetPair(AssetAmount(100, 'BTC'), AssetAmount(100, 'MB')), OrderId(TraderId('3'), OrderNumber(2)), OrderId(TraderId('2'), OrderNumber(1)), Timestamp(0.0)) self.proposed_trade = Trade.propose( TraderId('0'), OrderId(TraderId('0'), OrderNumber(2)), OrderId(TraderId('1'), OrderNumber(3)), AssetPair(AssetAmount(100, 'BTC'), AssetAmount(100, 'MB')), Timestamp(0.0)) self.payment = Payment( TraderId("0"), TransactionId(TraderId('2'), TransactionNumber(2)), AssetAmount(3, 'MB'), WalletAddress('a'), WalletAddress('b'), PaymentId('aaa'), Timestamp(4.0), True)
def test_addition(self): # Test for addition self.assertEqual(AssetAmount(102, 'BTC'), self.assetamount1 + self.assetamount2) self.assertFalse( self.assetamount1 is (self.assetamount1 + self.assetamount2)) self.assertEqual(NotImplemented, self.assetamount1.__add__(10)) self.assertEqual(NotImplemented, self.assetamount1.__add__(self.assetamount4))
def test_counter_trade(self): """ Test making a counter trade """ yield self.introduce_nodes() order = yield self.nodes[0].overlay.create_ask(AssetPair(AssetAmount(2, 'DUM1'), AssetAmount(2, 'DUM2')), 3600) order._traded_quantity = 1 # Partially fulfill this order yield self.sleep(0.5) # Give it some time to complete the trade self.assertEqual(len(self.nodes[2].overlay.order_book.asks), 1) self.nodes[1].overlay.create_bid(AssetPair(AssetAmount(2, 'DUM1'), AssetAmount(2, 'DUM2')), 3600) yield self.sleep(0.5) self.assertTrue(self.nodes[0].overlay.transaction_manager.find_all()) self.assertTrue(self.nodes[1].overlay.transaction_manager.find_all())
def test_get_asks(self): """ Test whether the API returns the right asks in the order book when performing a request """ def on_response(response): json_response = json.loads(response) self.assertIn('asks', json_response) self.assertEqual(len(json_response['asks']), 1) self.assertIn('ticks', json_response['asks'][0]) self.assertEqual(len(json_response['asks'][0]['ticks']), 1) self.session.lm.market_community.trustchain.send_block_pair = lambda *_: None self.session.lm.market_community.create_new_tick_block = \ lambda _: succeed(self.create_fake_block_pair()) self.session.lm.market_community.create_ask( AssetPair(AssetAmount(10, 'DUM1'), AssetAmount(10, 'DUM2')), 3600) self.should_check_equality = False return self.do_request('market/asks', expected_code=200).addCallback(on_response)
def test_pagerank_3(self): """ Test a more involved example of a Temporal Pagerank computation """ self.insert_transaction(b'a', b'b', AssetPair(AssetAmount(1, 'BTC'), AssetAmount(1, 'MB'))) self.insert_transaction(b'b', b'c', AssetPair(AssetAmount(100, 'BTC'), AssetAmount(10000, 'MB'))) self.insert_transaction(b'b', b'd', AssetPair(AssetAmount(100, 'BTC'), AssetAmount(10000, 'MB'))) self.insert_transaction(b'b', b'e', AssetPair(AssetAmount(100, 'BTC'), AssetAmount(10000, 'MB'))) rep_dict = self.compute_reputations() self.assertEqual(len(rep_dict.keys()), 5) for rep in rep_dict.values(): self.assertGreater(rep, 0)
def setUp(self): # Object creation self.memory_transaction_repository = MemoryTransactionRepository("0") self.transaction_manager = TransactionManager(self.memory_transaction_repository) self.transaction_id = TransactionId(TraderId(b"0"), TransactionNumber(1)) self.transaction = Transaction(self.transaction_id, AssetPair(AssetAmount(100, 'BTC'), AssetAmount(30, 'MB')), OrderId(TraderId(b'3'), OrderNumber(2)), OrderId(TraderId(b'2'), OrderNumber(1)), Timestamp(0.0)) self.proposed_trade = Trade.propose(TraderId(b'0'), OrderId(TraderId(b'0'), OrderNumber(1)), OrderId(TraderId(b'1'), OrderNumber(2)), AssetPair(AssetAmount(30, 'BTC'), AssetAmount(30, 'MB')), Timestamp(1462224447.117)) self.start_transaction = StartTransaction(TraderId(b'0'), TransactionId(TraderId(b"0"), TransactionNumber(1)), OrderId(TraderId(b'0'), OrderNumber(1)), OrderId(TraderId(b'1'), OrderNumber(2)), 1235, AssetPair(AssetAmount(20, 'BTC'), AssetAmount(20, 'MB')), Timestamp(0.0))
def from_unpack_list(cls, trader_id, timestamp, transaction_trader_id, transaction_number, transferred_amount, transferred_type, address_from, address_to, payment_id, success): return PaymentPayload( TraderId(trader_id), Timestamp(timestamp), TransactionId(TraderId(transaction_trader_id), TransactionNumber(transaction_number)), AssetAmount(transferred_amount, transferred_type), WalletAddress(address_from), WalletAddress(address_to), PaymentId(payment_id), success)
def setUp(self): # Object creation self.assetamount1 = AssetAmount(2, 'BTC') self.assetamount2 = AssetAmount(100, 'BTC') self.assetamount3 = AssetAmount(0, 'BTC') self.assetamount4 = AssetAmount(2, 'MC')
class TestAssetAmount(unittest.TestCase): """ Test the asset amount class """ def setUp(self): # Object creation self.assetamount1 = AssetAmount(2, 'BTC') self.assetamount2 = AssetAmount(100, 'BTC') self.assetamount3 = AssetAmount(0, 'BTC') self.assetamount4 = AssetAmount(2, 'MC') def test_init(self): """ Test the initialization of a price """ with self.assertRaises(ValueError): AssetAmount('1', 'MC') with self.assertRaises(ValueError): AssetAmount(1, 2) def test_addition(self): # Test for addition self.assertEqual(AssetAmount(102, 'BTC'), self.assetamount1 + self.assetamount2) self.assertFalse(self.assetamount1 is (self.assetamount1 + self.assetamount2)) self.assertEqual(NotImplemented, self.assetamount1.__add__(10)) self.assertEqual(NotImplemented, self.assetamount1.__add__(self.assetamount4)) def test_subtraction(self): # Test for subtraction self.assertEqual(AssetAmount(98, 'BTC'), self.assetamount2 - self.assetamount1) self.assertEqual(NotImplemented, self.assetamount1.__sub__(10)) self.assertEqual(NotImplemented, self.assetamount1.__sub__(self.assetamount4)) def test_comparison(self): # Test for comparison self.assertTrue(self.assetamount1 < self.assetamount2) self.assertTrue(self.assetamount2 > self.assetamount1) self.assertEqual(NotImplemented, self.assetamount1.__le__(10)) self.assertEqual(NotImplemented, self.assetamount1.__lt__(10)) self.assertEqual(NotImplemented, self.assetamount1.__ge__(10)) self.assertEqual(NotImplemented, self.assetamount1.__gt__(10)) self.assertEqual(NotImplemented, self.assetamount1.__le__(self.assetamount4)) self.assertEqual(NotImplemented, self.assetamount1.__lt__(self.assetamount4)) self.assertEqual(NotImplemented, self.assetamount1.__ge__(self.assetamount4)) self.assertEqual(NotImplemented, self.assetamount1.__gt__(self.assetamount4)) def test_equality(self): # Test for equality self.assertTrue(self.assetamount1 == AssetAmount(2, 'BTC')) self.assertTrue(self.assetamount1 != self.assetamount2) self.assertFalse(self.assetamount1 == 2) self.assertFalse(self.assetamount1 == self.assetamount4) def test_hash(self): # Test for hashes self.assertEqual(self.assetamount1.__hash__(), AssetAmount(2, 'BTC').__hash__()) self.assertNotEqual(self.assetamount1.__hash__(), self.assetamount2.__hash__()) def test_str(self): """ Test the string representation of a Price object """ self.assertEqual(str(self.assetamount1), "2 BTC")