def test_basics(): print("\ntokens_json():", token_utils.tokens_json()) print("\ntokens():", token_utils.tokens()) print("\ntokens_decimals():", token_utils.token_decimals()) print("\nselect_tokens():", token_utils.select_tokens()) print("\ntradable_tokens():", token_utils.tradable_tokens()) print("\nTradable Tokens:", sorted(token_utils.tradable_tokens().keys())) print("\bUSD Tokens:", [ t for t in token_utils.tradable_tokens().keys() if t.find('USD') >= 0 ])
def print_top_tokens_by_vol_and_mkt_cap(): tradable_tokens = token_utils.tradable_tokens() top_by_volume = top_tokens.top_tokens_by_volume(100, day_volume=90) top_by_mkt_cap = top_tokens.top_tokens_by_market_cap(100) top_both = set(top_by_volume) & set(top_by_mkt_cap) print(f"TOKEN\tVOL RANK\tMKT CAP RANK\tTRADABLE") for token in top_both: if token not in tradable_tokens: print( f"{token:<6} number {top_by_volume.index(token) + 1} by 90-day volume, number {top_by_mkt_cap.index(token) + 1} by market cap" )
def print_totle_cex_overlap(): totle_tokens = token_utils.tradable_tokens() kraken_overlap_pairs = kraken_client.get_overlap_pairs(totle_tokens) binance_overlap_pairs = binance_client.get_overlap_pairs(totle_tokens) huobi_overlap_pairs = huobi_client.get_overlap_pairs(totle_tokens) totle_kraken_binance_tokens = sorted([ b for b, q in kraken_overlap_pairs if (b, q) in binance_overlap_pairs ]) print(f"totle_kraken_binance_tokens={totle_kraken_binance_tokens}") totle_kraken_huobi_tokens = sorted( [b for b, q in kraken_overlap_pairs if (b, q) in huobi_overlap_pairs]) print(f"totle_kraken_huobi_tokens={totle_kraken_huobi_tokens}") totle_binance_huobi_tokens = sorted( [b for b, q in binance_overlap_pairs if (b, q) in huobi_overlap_pairs]) print(f"totle_binance_huobi_tokens={totle_binance_huobi_tokens}")
def tradable_tokens_by_market_cap(top_n=100): """List tradable tokens ordered by market cap (does not include those not in the top_n""" top_by_market_cap = list( enumerate(top_tokens.top_tokens_by_market_cap(top_n))) tokens_by_market_cap = [] for t in token_utils.tradable_tokens(): vr = [r + 1 for r, s in top_by_market_cap if s == t] if vr: tokens_by_market_cap.append((vr[0], t)) # # PAX #9 by market_cap ADD THIS TO ORDER SPLITTING # MCO #24 by market_cap ADD THIS TO ORDER SPLITTING # NEXO #25 by market_cap ADD THIS TO ORDER SPLITTING # SNT #33 by market_cap ADD THIS TO ORDER SPLITTING for r, t in sorted(tokens_by_market_cap): add = 'ADD THIS TO ORDER SPLITTING' if r < 100 and t not in OS_TOKENS else '' print(f"{t:<8} #{r} by market_cap\t{add}")
def tradable_tokens_by_volume(top_n=100, day_volume=90): """List tradable tokens ordered by volume (does not include those not in the top_n""" top_by_volume = list( enumerate(top_tokens.top_tokens_by_volume(top_n, day_volume))) tokens_by_volume = [] for t in token_utils.tradable_tokens(): vr = [r + 1 for r, s in top_by_volume if s == t] if vr: tokens_by_volume.append((vr[0], t)) # WBTC, VERI, XDCE, BMC, PAX, MCO, NEXO, SNT # WBTC # 7 by 90-day volume ADD THIS TO ORDER SPLITTING # VERI # 17 by 90-day volume ADD THIS TO ORDER SPLITTING # XDCE # 33 by 90-day volume ADD THIS TO ORDER SPLITTING # BMC # 47 by 90-day volume ADD THIS TO ORDER SPLITTING for r, t in sorted(tokens_by_volume): add = 'ADD THIS TO ORDER SPLITTING' if r < 100 and t not in OS_TOKENS else '' print(f"{t} #{r} by {day_volume}-day volume\t{add}")
def top_tokens_not_tradable_on_totle(top_n=100, day_volume=90): tradable_tokens = token_utils.tradable_tokens() print(f"tradable_tokens={sorted(tradable_tokens.keys())}") print( f"Below is a list of tokens in the top {top_n} by {day_volume}-day volume that are not tradable on Totle" ) top_by_volume = list( enumerate(top_tokens.top_tokens_by_volume(top_n, day_volume))) # print(f"top_by_volume={top_by_volume}") for rank, token in top_by_volume: if not token in tradable_tokens: print(f"{rank:>3}. {token}") all_tokens = token_utils.tokens() print( f"Below is a list of tokens in the top {top_n} by {day_volume}-day volume that are not even in Totle's tokens API" ) for rank, token in top_by_volume: if not token in all_tokens: print(f"{rank:>3}. {token}")
def get_token_prices(tokens=None): all_tradable_tokens = tokens or token_utils.tradable_tokens() all_tradable_tokens.pop('ETH') # TODO: remove ETH it's not really an ERC-20 cmc_data = json.load(open(f'data/cmc_tokens.json'))['data'] usd_prices = { t['symbol']: float(t['quote']['USD']['price']) for t in cmc_data if t['symbol'] in all_tradable_tokens } skipped_tokens, missing_tokens = set( ), set(all_tradable_tokens) - set(usd_prices) print( f"CMC had prices for {len(usd_prices)}/{len(all_tradable_tokens)} tokens. Querying Totle for prices on the remaining {len(missing_tokens)} tokens" ) for missing_token in missing_tokens: if missing_token == 'CETH': usd_prices[missing_token] = 2.83 else: totle_quote = totle_client.try_swap(totle_client.name(), missing_token, 'ETH', params={'toAmount': 0.1}, verbose=False, debug=False) if totle_quote: # set the from_amount so it's roughly the same across all swaps usd_prices[missing_token] = ETH_PRICE / totle_quote['price'] else: # If we can't get a price from CMC or Totle, then just discard this token. Other aggs may have the pair, but if you can't # buy it for ETH on Totle, then it is essentially not a "tradable" token as curated by Totle, and thus not in this study. skipped_tokens.add(missing_token) print( f"Skipping {skipped_tokens} because we couldn't get a price from CMC or Totle" ) return usd_prices
def main(): working_dir = os.path.dirname(__file__) if working_dir: os.chdir(working_dir) CEX_CLIENTS = [binance_client, huobi_client, kraken_client] # TOTLE_BINANCE_HUOBI_TOKENS = ['ADX', 'AST', 'BAT', 'CVC', 'ENG', 'KNC', 'LINK', 'MANA', 'MCO', 'NPXS', 'OMG', 'POWR', 'QSP', 'RCN', 'RDN', 'REQ', 'SALT', 'THETA', 'WTC', 'ZIL', 'ZRX'] # TOKENS = ['BAT', 'LINK', 'OMG'] # Only 3 tokens overlap Totle and all three CEXs CEX_NAMES = [ 'binance', 'bitfinex', 'bittrex', 'coinbase-pro', 'hitbtc', 'huobi', 'kraken', 'poloniex' ] QUOTE_TOKEN = 'ETH' TRADE_SIZES = [ 0.1, 0.5, 1.0, 5.0, 10.0, 50.0, 100.0, 200.0, 300.0, 400.0, 500.0 ] CSV_FIELDS = "time action trade_size token exchange exchange_price totle_used totle_price pct_savings splits ex_prices".split( ) all_savings = defaultdict(lambda: defaultdict(lambda: defaultdict( dict))) # extra lambda prevents KeyError in print_savings tradable_tokens = token_utils.tradable_tokens() select_token_cexs = parse_markets('data/cryptowatch-markets-prices.json', tradable_tokens, CEX_NAMES, min_cexs=3) for order_type in ['buy', 'sell']: filename = get_filename_base(prefix='totle_vs_cexs', suffix=order_type) with SavingsCSV(filename, fieldnames=CSV_FIELDS) as csv_writer: for token, cex_list in select_token_cexs.items( ): # Each token has it's own list of CEXs that support token/ETH pair # Get books for the 8 CEXs from cryptowatch bids, asks = {}, {} for cex_name in cex_list: # these have all-lowercase keys, so we have to capitalize them later bids[cex_name], asks[ cex_name] = cryptowatch_client.get_books( cex_name, token, QUOTE_TOKEN) # Get books from 3 clients (BinanceC, HuobiC, KrakenC) cex_name_client = {} for cex_client in CEX_CLIENTS: if cex_client.name().lower() in cex_list: cex_name_c = cex_client.name().capitalize( ) + 'C' # capitalize, since we're choosing a unique key and a client map anyway try: bids[cex_name_c], asks[ cex_name_c] = cex_client.get_depth( token, QUOTE_TOKEN) cex_name_client[cex_name_c] = cex_client except (binance_client.BinanceAPIException, huobi_client.HuobiAPIException, kraken_client.KrakenAPIException) as e: print( f"{cex_name_c} get_depth({token}/{QUOTE_TOKEN}) raised {e}" ) # Now loop over trade sizes and compare against 8, then 3 CEXs books = asks if order_type == 'buy' else bids for trade_size in TRADE_SIZES: # compare to the 8 CEXs in cex_list cex_savings, totle_quote = compare_totle_and_cexs_same_fee( cex_list, token, QUOTE_TOKEN, trade_size, books, order_type) for cex_name, savings in cex_savings.items(): # Save the capitalized version of the cex_name, not the lowercase cryptowatch name cap_cex_name = cex_name.capitalize() savings['exchange'] = cap_cex_name all_savings[cap_cex_name][token][trade_size] = savings csv_writer.append(savings) # Re-do comparisons on 3 CEXs (BinanceC, HuobiC, and KrakenC) using the exchange API clients, but use Totle's fee (FIXED_FEE_PCT) cex_c_savings = compare_totle_and_cexs( cex_name_client, token, QUOTE_TOKEN, trade_size, books, order_type, totle_quote=totle_quote, fee_override=FIXED_FEE_PCT) for cex_name_c, savings in cex_c_savings.items(): all_savings[cex_name_c][token][trade_size] = savings csv_writer.append(savings) # Prints a savings dict, token => trade_size => savings values for cex_name in all_savings: print_savings(order_type, all_savings[cex_name], TRADE_SIZES, title=f"Savings vs. {cex_name}")