From 3c86792e64d2bc2bab4dc075d21d97996bf45eb6 Mon Sep 17 00:00:00 2001 From: Tom Van Braeckel Date: Sun, 3 Dec 2017 14:03:20 +0100 Subject: [PATCH 1/5] Improve updating of tradelist --- python/etherdeltaclientservice.py | 30 ++++++++++++++++++++------ python/etherdeltaclientservice_test.py | 12 +++++++++++ 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/python/etherdeltaclientservice.py b/python/etherdeltaclientservice.py index 001c4f8..11e3322 100644 --- a/python/etherdeltaclientservice.py +++ b/python/etherdeltaclientservice.py @@ -61,6 +61,7 @@ import random import sys import web3 +import pdb from web3 import Web3, HTTPProvider from operator import itemgetter @@ -150,6 +151,24 @@ def updateOneSideOfOrderBook(self, myTokenKey, token, orderbook, new_orders): #print("Orderbook size changed by " + str(len(orderbook) - orderbook_before) + " orders") return orderbook + def updateTradeList(self, token, tradelist, new_trades): + #pdb.set_trace() + tradelistsize_before = len(tradelist) + for trade in new_trades: + # Delete deleted trades if getting the 'deleted' property does not return the 'no such property' default value (which is 'None') + if trade.get('deleted', None) != None: + print("Deleting this trade from the trade list: " + str(trade)) + tradelist = [x for x in tradelist if x['txHash'].lower() != trade['txHash'].lower()] + elif len([x for x in tradelist if x['txHash'].lower() == trade['txHash'].lower()]) > 0: + newtradebook = [] + for y in tradelist: + if y['txHash'].lower() == trade['txHash'].lower(): newtradebook.append(trade) + tradelist = newtradebook + elif trade['tokenAddr'].lower() == token.lower(): + tradelist.append(trade) + print("Trade list size changed by " + str(len(tradelist) - tradelistsize_before) + " trades") + return tradelist + def updateOrders(self, newOrders): self.orders_sells = self.updateOneSideOfOrderBook('tokenGive', self.token, self.orders_sells, newOrders['sells']) self.my_orders_sells = self.updateOneSideOfOrderBook('tokenGive', self.token, self.my_orders_sells, [x for x in newOrders['sells'] if x['user'].lower() == self.userAccount.lower()]) @@ -162,12 +181,11 @@ def updateOrders(self, newOrders): self.orders_buys = sorted(self.orders_buys, key=itemgetter('price'), reverse=True) def updateTrades(self, newTrades): - valid_new_trades = [x for x in newTrades if ('tokenAddr' not in x or x['tokenAddr'].lower() == self.token.lower()) and x not in self.trades] - if len(valid_new_trades) > 0: - #print("Adding " + str(len(valid_new_trades)) + " new trades to the list...") - self.trades.extend(valid_new_trades) - self.trades = sorted(self.trades, key=itemgetter('date', 'amount'), reverse=True) - # TODO: also maintain my_trades list + self.trades = self.updateTradeList(self.token, self.trades, newTrades) + self.my_trades = self.updateTradeList(self.token, self.my_trades, [x for x in newTrades if x['user'].lower() == self.userAccount.lower()]) + + self.trades = sorted(self.trades, key=itemgetter('amount'), reverse=True) + self.trades = sorted(self.trades, key=itemgetter('price')) def printMyOrderBook(self): print() diff --git a/python/etherdeltaclientservice_test.py b/python/etherdeltaclientservice_test.py index b0e6656..da2b3ea 100644 --- a/python/etherdeltaclientservice_test.py +++ b/python/etherdeltaclientservice_test.py @@ -21,6 +21,11 @@ item2 = {'expires': '104468244', 'amount': '1e+24', 'r': '0x9bd8cb2564ba8369e3ebbd5af9c3638e0cb2a929e8d5683d60baa523d3a1056e', 'updated': '2017-11-20T06:06:11.498Z', 'ethAvailableVolumeBase': '0.09999999998012342', 'v': 27, 'availableVolume': '9.9999999980123425774079e+23', 'nonce': '1950327344', 'ethAvailableVolume': '999999.9998012343', 'user': '0x1a4cfe7277bfdbd108ef42a3db9e8a1c05428c6c', 'tokenGet': '0x219218f117dc9348b358b8471c55a073e5e0da0b', 'availableVolumeBase': '99999999980123420', 'amountGet': '1e+24', 's': '0x5d287a474c8573e8d369eaf1067cfae6577ca8846044dc7ef014dc3e49479790', 'price': '0.0000001', 'amountFilled': None, 'id': '45fb9c61e6ffc5b4bd340f04f02e2bc6c3adb33514a091131fcc3a7d28c40374_buy', 'amountGive': '100000000000000000', 'tokenGive': '0x0000000000000000000000000000000000000000'} +trade_sellside = {"txHash":"0xddbe429d859666217ef28a2abc74832f0bfe340f7f772058d5e885d54bff8312","date":"2017-11-15T18:32:08.000Z","price":"0.00491","side":"sell","amount":"546","amountBase":"2.68086","buyer":"0xabbb9f579d421a72301abffbfa85b7caa998f7bd","seller":"0xde57392f4ee115dfd457404215ecb590bf6c9fc2","tokenAddr":"0x219218f117dc9348b358b8471c55a073e5e0da0b"} +trade_buyside = {"txHash":"0x5a0818b4ceae815fededd82c511ccfe0f08d62d2f309cdaa7e54583ac5c4129f","date":"2017-11-15T18:32:57.000Z","price":"0.0036555","side":"buy","amount":"1200","amountBase":"4.3866","buyer":"0x3a9420663811a77617bc5809149bb2bc235facfa","seller":"0x73ced35ea2e3cab70fcb94a846ecffc008704b39","tokenAddr":"0x219218f117dc9348b358b8471c55a073e5e0da0b"} + +#{"txHash":"0x5b06767bcb1ec2f87e43e2b89c0004335bea57b10d0ca298ffdfebd9a2427806","date":"2017-11-15T18:32:57.000Z","price":"0.00333","side":"buy","amount":"375","amountBase":"1.24875","buyer":"0x3a9420663811a77617bc5809149bb2bc235facfa","seller":"0xed7b254309b8e5c69409dcf40e2b119677fce144","tokenAddr":"0x56ba2ee7890461f463f7be02aac3099f6d5811a8"},{"txHash":"0x85cd0d02a436f9c186669aab46aaaf53b081867aa94239a8e300a115f63802f1","date":"2017-11-15T18:32:57.000Z","price":"0.0000427","side":"sell","amount":"20000","amountBase":"0.854","buyer":"0x8dc030c3078ab6af850d069d2a0e5ad473327202","seller":"0xca17b82dd20e95ba3c012c6a53bc5f8a706483e1","tokenAddr":"0x6aac8cb9861e42bf8259f5abdc6ae3ae89909e11"},{"txHash":"0x90d7d9b0a086843eddd12ae91ce2e5b998e2eb1850bc6b688e8e7f0e6efa5501","date":"2017-11-15T18:32:57.000Z","price":"0.002","side":"sell","amount":"597.806","amountBase":"1.195612","buyer":"0xb42c4b5eda4035d3898af3b5fe4118841b96de1c","seller":"0x23f2030563a7bbb9369eea4447eb1475f51b6bdf","tokenAddr":"0xba5f11b16b155792cf3b2e6880e8706859a8aeb6"} + # This class tests the function: class TestTaker(unittest.TestCase): @@ -89,6 +94,13 @@ def test_updateOneSideOfOrderBook_add_updated(self): self.assertEqual(len(orderbook), 1) self.assertEqual(orderbook[0]['amountFilled'], 42) + def test_updateTradeList(self): + tradelist = [trade_sellside] + new_trades = [trade_buyside] + self.assertEqual(len(tradelist), 1) + tradelist = self.es.updateTradeList(token, tradelist, new_trades) + self.assertEqual(len(tradelist), 2) + def test_createSellOrder(self): result = self.es.createOrder('sell', 10000, 4, 2, token, userAccount, private_key, 42) From 943971be30d88a64ae96964f5b5ef37767cf4824 Mon Sep 17 00:00:00 2001 From: Tom Van Braeckel Date: Sun, 3 Dec 2017 14:15:33 +0100 Subject: [PATCH 2/5] Improve unit tests --- python/etherdeltaclientservice.py | 11 ++++++++++- python/etherdeltaclientservice_test.py | 18 ++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/python/etherdeltaclientservice.py b/python/etherdeltaclientservice.py index 11e3322..08b05b0 100644 --- a/python/etherdeltaclientservice.py +++ b/python/etherdeltaclientservice.py @@ -182,7 +182,7 @@ def updateOrders(self, newOrders): def updateTrades(self, newTrades): self.trades = self.updateTradeList(self.token, self.trades, newTrades) - self.my_trades = self.updateTradeList(self.token, self.my_trades, [x for x in newTrades if x['user'].lower() == self.userAccount.lower()]) + self.my_trades = self.updateTradeList(self.token, self.my_trades, [x for x in newTrades if x['buyer'].lower() == self.userAccount.lower() or x['seller'].lower() == self.userAccount.lower()]) self.trades = sorted(self.trades, key=itemgetter('amount'), reverse=True) self.trades = sorted(self.trades, key=itemgetter('price')) @@ -221,6 +221,15 @@ def printTrades(self): for trade in self.trades[0:numTrades]: print(trade['date'] + " " + trade['side'] + " " + trade['amount'] + " @ " + trade['price']) + def printMyTrades(self): + print() + print('My recent trades') + print('----------------') + numTrades = 10 + for trade in self.my_trades[0:numTrades]: + print(trade['date'] + " " + trade['side'] + " " + trade['amount'] + " @ " + trade['price']) + + def createOrder(self, side, expires, price, amount, token, userAccount, user_wallet_private_key, randomseed = None): global addressEtherDelta, web3 diff --git a/python/etherdeltaclientservice_test.py b/python/etherdeltaclientservice_test.py index da2b3ea..3a63d76 100644 --- a/python/etherdeltaclientservice_test.py +++ b/python/etherdeltaclientservice_test.py @@ -13,6 +13,7 @@ # Real GRX token token = '0x219218f117dc9348b358b8471c55a073e5e0da0b' +# Orders # These are from the buy side of the order book because they have tokenGet so they are buying token and giving ETH for it item1 = {'expires': '104468244', 'amount': '1e+24', 'r': '0x9bd8cb2564ba8369e3ebbd5af9c3638e0cb2a929e8d5683d60baa523d3a1056e', 'updated': '2017-11-20T06:06:11.498Z', 'ethAvailableVolumeBase': '0.09999999998012342', 'v': 27, 'availableVolume': '9.9999999980123425774079e+23', 'nonce': '1950327344', 'ethAvailableVolume': '999999.9998012343', 'user': '0x1a4cfe7277bfdbd108ef42a3db9e8a1c05428c6c', 'tokenGet': '0x219218f117dc9348b358b8471c55a073e5e0da0b', 'availableVolumeBase': '99999999980123420', 'amountGet': '1e+24', 's': '0x5d287a474c8573e8d369eaf1067cfae6577ca8846044dc7ef014dc3e49479790', 'price': '0.0000001', 'amountFilled': None, 'id': '44fb9c61e6ffc5b4bd340f04f02e2bc6c3adb33514a091131fcc3a7d28c40374_buy', 'amountGive': '100000000000000000', 'tokenGive': '0x0000000000000000000000000000000000000000'} item1_deleted = {'deleted': True, 'expires': '104468244', 'amount': '1e+24', 'r': '0x9bd8cb2564ba8369e3ebbd5af9c3638e0cb2a929e8d5683d60baa523d3a1056e', 'updated': '2017-11-20T06:06:11.498Z', 'ethAvailableVolumeBase': '0.09999999998012342', 'v': 27, 'availableVolume': '9.9999999980123425774079e+23', 'nonce': '1950327344', 'ethAvailableVolume': '999999.9998012343', 'user': '0x1a4cfe7277bfdbd108ef42a3db9e8a1c05428c6c', 'tokenGet': '0x219218f117dc9348b358b8471c55a073e5e0da0b', 'availableVolumeBase': '99999999980123420', 'amountGet': '1e+24', 's': '0x5d287a474c8573e8d369eaf1067cfae6577ca8846044dc7ef014dc3e49479790', 'price': '0.0000001', 'amountFilled': None, 'id': '44fb9c61e6ffc5b4bd340f04f02e2bc6c3adb33514a091131fcc3a7d28c40374_buy', 'amountGive': '100000000000000000', 'tokenGive': '0x0000000000000000000000000000000000000000'} @@ -21,9 +22,12 @@ item2 = {'expires': '104468244', 'amount': '1e+24', 'r': '0x9bd8cb2564ba8369e3ebbd5af9c3638e0cb2a929e8d5683d60baa523d3a1056e', 'updated': '2017-11-20T06:06:11.498Z', 'ethAvailableVolumeBase': '0.09999999998012342', 'v': 27, 'availableVolume': '9.9999999980123425774079e+23', 'nonce': '1950327344', 'ethAvailableVolume': '999999.9998012343', 'user': '0x1a4cfe7277bfdbd108ef42a3db9e8a1c05428c6c', 'tokenGet': '0x219218f117dc9348b358b8471c55a073e5e0da0b', 'availableVolumeBase': '99999999980123420', 'amountGet': '1e+24', 's': '0x5d287a474c8573e8d369eaf1067cfae6577ca8846044dc7ef014dc3e49479790', 'price': '0.0000001', 'amountFilled': None, 'id': '45fb9c61e6ffc5b4bd340f04f02e2bc6c3adb33514a091131fcc3a7d28c40374_buy', 'amountGive': '100000000000000000', 'tokenGive': '0x0000000000000000000000000000000000000000'} +# Trades trade_sellside = {"txHash":"0xddbe429d859666217ef28a2abc74832f0bfe340f7f772058d5e885d54bff8312","date":"2017-11-15T18:32:08.000Z","price":"0.00491","side":"sell","amount":"546","amountBase":"2.68086","buyer":"0xabbb9f579d421a72301abffbfa85b7caa998f7bd","seller":"0xde57392f4ee115dfd457404215ecb590bf6c9fc2","tokenAddr":"0x219218f117dc9348b358b8471c55a073e5e0da0b"} trade_buyside = {"txHash":"0x5a0818b4ceae815fededd82c511ccfe0f08d62d2f309cdaa7e54583ac5c4129f","date":"2017-11-15T18:32:57.000Z","price":"0.0036555","side":"buy","amount":"1200","amountBase":"4.3866","buyer":"0x3a9420663811a77617bc5809149bb2bc235facfa","seller":"0x73ced35ea2e3cab70fcb94a846ecffc008704b39","tokenAddr":"0x219218f117dc9348b358b8471c55a073e5e0da0b"} +mytrade_buyside = {"txHash":"0x5a0818b4ceae815fededd82c511ccfe0f08d62d2f309cdaa7e54583ac5c4129f","date":"2017-11-15T18:32:57.000Z","price":"0.0036555","side":"buy","amount":"1200","amountBase":"4.3866","buyer":"0x51df0000000000000000000000052F2e7808Ee2b","seller":"0x73ced35ea2e3cab70fcb94a846ecffc008704b39","tokenAddr":"0x219218f117dc9348b358b8471c55a073e5e0da0b"} +# More trades #{"txHash":"0x5b06767bcb1ec2f87e43e2b89c0004335bea57b10d0ca298ffdfebd9a2427806","date":"2017-11-15T18:32:57.000Z","price":"0.00333","side":"buy","amount":"375","amountBase":"1.24875","buyer":"0x3a9420663811a77617bc5809149bb2bc235facfa","seller":"0xed7b254309b8e5c69409dcf40e2b119677fce144","tokenAddr":"0x56ba2ee7890461f463f7be02aac3099f6d5811a8"},{"txHash":"0x85cd0d02a436f9c186669aab46aaaf53b081867aa94239a8e300a115f63802f1","date":"2017-11-15T18:32:57.000Z","price":"0.0000427","side":"sell","amount":"20000","amountBase":"0.854","buyer":"0x8dc030c3078ab6af850d069d2a0e5ad473327202","seller":"0xca17b82dd20e95ba3c012c6a53bc5f8a706483e1","tokenAddr":"0x6aac8cb9861e42bf8259f5abdc6ae3ae89909e11"},{"txHash":"0x90d7d9b0a086843eddd12ae91ce2e5b998e2eb1850bc6b688e8e7f0e6efa5501","date":"2017-11-15T18:32:57.000Z","price":"0.002","side":"sell","amount":"597.806","amountBase":"1.195612","buyer":"0xb42c4b5eda4035d3898af3b5fe4118841b96de1c","seller":"0x23f2030563a7bbb9369eea4447eb1475f51b6bdf","tokenAddr":"0xba5f11b16b155792cf3b2e6880e8706859a8aeb6"} # This class tests the function: @@ -101,6 +105,20 @@ def test_updateTradeList(self): tradelist = self.es.updateTradeList(token, tradelist, new_trades) self.assertEqual(len(tradelist), 2) + def test_updateTrades(self): + tradelist = [trade_sellside] + new_trades = [trade_buyside] + self.assertEqual(len(tradelist), 1) + # Setup self.es + self.es.trades = tradelist + self.es.my_trades = [] + self.es.token = token + self.es.userAccount = userAccount + # Test self.es + self.es.updateTrades(new_trades) + self.assertEqual(len(self.es.my_trades), 0) + self.assertEqual(len(self.es.trades), 2) + def test_createSellOrder(self): result = self.es.createOrder('sell', 10000, 4, 2, token, userAccount, private_key, 42) From 0e56bea4d366f8ba16078d61d504b4226e79e853 Mon Sep 17 00:00:00 2001 From: Tom Van Braeckel Date: Sun, 3 Dec 2017 14:28:39 +0100 Subject: [PATCH 3/5] More testing --- python/etherdeltaclientservice.py | 5 +++-- python/etherdeltaclientservice_test.py | 13 +++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/python/etherdeltaclientservice.py b/python/etherdeltaclientservice.py index 08b05b0..9a32c9c 100644 --- a/python/etherdeltaclientservice.py +++ b/python/etherdeltaclientservice.py @@ -61,7 +61,9 @@ import random import sys import web3 -import pdb + +# for debugging, enable this line and add pdb.set_trace() where you want a breakpoint: +# import pdb from web3 import Web3, HTTPProvider from operator import itemgetter @@ -152,7 +154,6 @@ def updateOneSideOfOrderBook(self, myTokenKey, token, orderbook, new_orders): return orderbook def updateTradeList(self, token, tradelist, new_trades): - #pdb.set_trace() tradelistsize_before = len(tradelist) for trade in new_trades: # Delete deleted trades if getting the 'deleted' property does not return the 'no such property' default value (which is 'None') diff --git a/python/etherdeltaclientservice_test.py b/python/etherdeltaclientservice_test.py index 3a63d76..117ab1a 100644 --- a/python/etherdeltaclientservice_test.py +++ b/python/etherdeltaclientservice_test.py @@ -119,6 +119,19 @@ def test_updateTrades(self): self.assertEqual(len(self.es.my_trades), 0) self.assertEqual(len(self.es.trades), 2) + def test_updateTrades_my_trades(self): + tradelist = [trade_sellside] + new_trades = [mytrade_buyside] + # Setup self.es + self.es.trades = tradelist + self.es.my_trades = [] + self.es.token = token + self.es.userAccount = userAccount + # Test self.es + self.es.updateTrades(new_trades) + self.assertEqual(len(self.es.my_trades), 1) + self.assertEqual(len(self.es.trades), 2) # trade should also get added to the general trade list + def test_createSellOrder(self): result = self.es.createOrder('sell', 10000, 4, 2, token, userAccount, private_key, 42) From 1694d7b12087562b2925522abc466bbbcc304591 Mon Sep 17 00:00:00 2001 From: Tom Van Braeckel Date: Sun, 3 Dec 2017 20:16:10 +0100 Subject: [PATCH 4/5] Fix trade sort --- python/etherdeltaclientservice.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/etherdeltaclientservice.py b/python/etherdeltaclientservice.py index 9a32c9c..2f857fd 100644 --- a/python/etherdeltaclientservice.py +++ b/python/etherdeltaclientservice.py @@ -185,8 +185,8 @@ def updateTrades(self, newTrades): self.trades = self.updateTradeList(self.token, self.trades, newTrades) self.my_trades = self.updateTradeList(self.token, self.my_trades, [x for x in newTrades if x['buyer'].lower() == self.userAccount.lower() or x['seller'].lower() == self.userAccount.lower()]) - self.trades = sorted(self.trades, key=itemgetter('amount'), reverse=True) - self.trades = sorted(self.trades, key=itemgetter('price')) + self.trades = sorted(self.trades, key=itemgetter('amount')) + self.trades = sorted(self.trades, key=itemgetter('date'), reverse=True) def printMyOrderBook(self): print() From 9638be3e3932323fbb16f30dfa9d1d6c5219017d Mon Sep 17 00:00:00 2001 From: Tom Van Braeckel Date: Sun, 3 Dec 2017 20:21:28 +0100 Subject: [PATCH 5/5] Generalize printBalances --- python/etherdeltaclientservice.py | 8 ++++++++ python/maker.py | 9 +-------- python/taker.py | 9 +-------- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/python/etherdeltaclientservice.py b/python/etherdeltaclientservice.py index 2f857fd..e9877b6 100644 --- a/python/etherdeltaclientservice.py +++ b/python/etherdeltaclientservice.py @@ -230,6 +230,13 @@ def printMyTrades(self): for trade in self.my_trades[0:numTrades]: print(trade['date'] + " " + trade['side'] + " " + trade['amount'] + " @ " + trade['price']) + def printBalances(self, token, userAccount): + print("Account balances:") + print("=================") + print("Wallet account balance: %.18f ETH" % self.getBalance('ETH', userAccount)) + print("Wallet token balance: %.18f tokens" % self.getBalance(token, userAccount)) + print("EtherDelta ETH balance: %.18f ETH" % self.getEtherDeltaBalance('ETH', userAccount)) + print("EtherDelta token balance: %.18f tokens" % self.getEtherDeltaBalance(token, userAccount)) def createOrder(self, side, expires, price, amount, token, userAccount, user_wallet_private_key, randomseed = None): global addressEtherDelta, web3 @@ -324,6 +331,7 @@ def trade(self, order, etherAmount, user_wallet_private_key=''): # Build binary representation of the function call with arguments abidata = self.contractEtherDelta.encodeABI('trade', kwargs=kwargs) print("abidata: " + str(abidata)) + # Use the transaction count as the nonce nonce = web3.eth.getTransactionCount(self.userAccount) # Override to have same as other transaction: #nonce = 53 diff --git a/python/maker.py b/python/maker.py index cc55f45..cfffae3 100644 --- a/python/maker.py +++ b/python/maker.py @@ -51,14 +51,7 @@ es.start(userAccount, token) print("EtherDeltaClientService started") - print("") - print("Account balances:") - print("=================") - print("Wallet account balance: %.18f ETH" % es.getBalance('ETH', userAccount)) - print("Wallet token balance: %.18f tokens" % es.getBalance(token, userAccount)) - print("EtherDelta ETH balance: %.18f ETH" % es.getEtherDeltaBalance('ETH', userAccount)) - print("EtherDelta token balance: %.18f tokens" % es.getEtherDeltaBalance(token, userAccount)) - print("") + es.printBalances(token, userAccount) while es.getBestSellOrder() == None or es.getBestBuyOrder() == None: print("Waiting until best sell and buy orders are known...") diff --git a/python/taker.py b/python/taker.py index 20e1c32..4b93ba6 100644 --- a/python/taker.py +++ b/python/taker.py @@ -46,14 +46,7 @@ es.start(userAccount, token) print("EtherDeltaService started") - print("") - print("Account balances:") - print("=================") - print("Wallet account balance: %.18f ETH" % es.getBalance('ETH', userAccount)) - print("Wallet token balance: %.18f tokens" % es.getBalance(token, userAccount)) - print("EtherDelta ETH balance: %.18f ETH" % es.getEtherDeltaBalance('ETH', userAccount)) - print("EtherDelta token balance: %.18f tokens" % es.getEtherDeltaBalance(token, userAccount)) - print("") + es.printBalances(token, userAccount) while es.getBestSellOrder() == None: print("Waiting until best sell order to buy is known...")