4
\$\begingroup\$

I have created a simple tool that takes in a dictionary of cryptocurrencies and finds the ones with the highest % differences between exchanges. I would be grateful if someone could help me optimize this code and perhaps make it less complicated. The structure of the code is:

for coin in data:
 for market in coin.markets()
 if conditions_are_met:
 if is_highest_price:
 high_price = new_high_price
 if is_lowest_price:
 low_price = new_low_price
 coin_differences = append([coin.name, high_price-low_price])
display_top_10(coin_differences)

This is the actual code:

#!/usr/bin/env python3
import decimal
import argparse
from operator import itemgetter
try:
 import pymarketcap
except Exception as e:
 print('Make sure to install {0} (python3 -m pip {0}.'.format(str(e).split("'")[1]))
 exit()
# arguments
parser = argparse.ArgumentParser()
parser.add_argument('-m', '--minimum_vol', type=float, help='Minimum Percent volume per exchange to have to count', default=1)
parser.add_argument('-p', '--pairs', nargs='*', default=[], help='Pairs the coins can be arbitraged with - default=all')
parser.add_argument('-c', '--coins_shown', type=int, default=10, help='Number of coins to show')
parser.add_argument('-e', '--exchanges', nargs='*', help='Acceptable Exchanges - default=all', default=[])
parser.add_argument('-s', '--simple', help='Toggle off errors and settings', default=False, action="store_true")
parser.add_argument('-t', '--top', type=int, help='Set the number of coins to run with', default=100)
args = parser.parse_args()
# setup
cmc = pymarketcap.Pymarketcap()
info = []
count = 1
lowercase_exchanges = [x.lower() for x in args.exchanges]
all_exchanges = not bool(args.exchanges)
all_trading_pairs = not bool(args.pairs)
coin_format = '{: <25} {: >6}% {: >10} {: >15} {: <10} {: <10} {: <15} {: <5}'
if not args.simple:
 print('CURRENT SETTINGS',
 '* MINIMUM_PERCENT_VOL: {}'.format(args.minimum_vol),
 '* TRADING_PAIRS: {}'.format(args.pairs),
 '* COINS_SHOWN: {}'.format(args.coins_shown),
 '* EXCHANGES: {}'.format(lowercase_exchanges),
 '* ALL_TRADING_PAIRS: {}'.format(all_trading_pairs),
 '* ALL_EXCHANGES: {}'.format(all_exchanges),
 '* TOP: {}'.format(args.top),
 sep='\n')
# retrieve coin data
coin_data = cmc.ticker(limit=args.top)['data']
for id_, coin in coin_data.items():
 try:
 markets = cmc.markets(coin["id"])
 except Exception as e:
 markets = cmc.markets(coin["symbol"])
 best_price = 0
 best_exchange = ''
 best_pair = ''
 worst_price = 999999 # TODO is this value high enough? one day some cryptocurrencies will be worth several millions... i hope :)
 worst_exchange = ''
 worst_pair = ''
 has_markets = False
 for market in markets["markets"]:
 trades_into = market["pair"].replace(coin["symbol"],"").replace("-","").replace("/","")
 if (market['percent_volume'] >= args.minimum_vol and 
 market['updated'] and 
 (trades_into in args.pairs or all_trading_pairs) and 
 (market['source'].lower() in lowercase_exchanges or all_exchanges)
 ):
 has_markets = True
 if market['price'] >= best_price:
 best_price = market['price']
 best_exchange = market['source']
 best_pair = trades_into
 if market['price'] <= worst_price:
 worst_price = market['price']
 worst_exchange = market['source']
 worst_pair = trades_into
 if has_markets:
 info.append([coin['name'],
 round((best_price/worst_price-1)*100,2),
 worst_price,
 worst_exchange,
 worst_pair,
 best_price,
 best_exchange,
 best_pair
 ])
 elif not args.simple:
 print(coin['name'],'had no markets that fit the criteria.')
 print('[{}/{}]'.format(count, args.top),end='\r')
 count += 1
# show data
info = sorted(info, key=itemgetter(1), reverse=True)
print(coin_format.format("COIN","CHANGE","BUY PRICE","BUY AT","BUY WITH","SELL PRICE","SELL AT","SELL WITH"))
for coin in info[0:args.coins_shown]:
 print(coin_format.format(*coin))
Phrancis
20.5k6 gold badges69 silver badges155 bronze badges
asked May 29, 2018 at 18:49
\$\endgroup\$
1
  • \$\begingroup\$ Welcome to Code Review! I hope you get some good answers. \$\endgroup\$ Commented May 29, 2018 at 18:57

1 Answer 1

1
\$\begingroup\$

Some random advice:

Consider using ArgumentDefaultsHelpFormatter. It's a nice thing to use when you have so many defaults set.

I would lose the try/import/except. It's just as good to let the default failure take place. You can specify pip requirements in requirements.txt.

Group up your code into functions, even if they're only called once. There are many reasons for this - stack traces are improved, code folding is actually useful, and code legibility goes up.

Your explicit calls to bool() are no-ops. Python already treats everything as truthy/falsy.

Indexing [0 :x] is the same as indexing [:x].

answered May 29, 2018 at 19:56
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.