import ccxt # Put your poloniex api key in market.py from market import market def static_var(varname, value): def decorate(func): setattr(func, varname, value) return func return decorate max_digits = 18 repartition_pertenthousand = { "BTC": 2857, "ZEC": 3701, "DOGE": 1805, "DGB": 1015, "SC": 623, } def formatted_price(value): return round(value / 10**max_digits, 8) @static_var("cache", {}) def get_ticker(c1, c2, market): def invert(ticker): return { "inverted": True, "bid": float(1/ticker["ask"]), "ask": float(1/ticker["bid"]), "bidA": float(1/ticker["askA"]), "askA": float(1/ticker["bidA"]), } def augment_ticker(ticker): # FIXME: need to do better than just a multiplier ticker.update({ "inverted": False, "bidA": ticker["bid"] * 0.99, "askA": ticker["ask"] * 1.01, }) if (c1, c2, market.__class__) in get_ticker.cache: return get_ticker.cache[(c1, c2, market.__class__)] if (c2, c1, market.__class__) in get_ticker.cache: return invert(get_ticker.cache[(c2, c1, market.__class__)]) try: get_ticker.cache[(c1, c2, market.__class__)] = market.fetch_ticker("{}/{}".format(c1, c2)) augment_ticker(get_ticker.cache[(c1, c2, market.__class__)]) except ccxt.ExchangeError: try: get_ticker.cache[(c2, c1, market.__class__)] = market.fetch_ticker("{}/{}".format(c2, c1)) augment_ticker(get_ticker.cache[(c2, c1, market.__class__)]) except ccxt.ExchangeError: get_ticker.cache[(c1, c2, market.__class__)] = None return get_ticker(c1, c2, market) def fetch_balances(market): balances = {} fetched_balance = market.fetch_balance() for key, value in fetched_balance["total"].items(): if value > 0: balances[key] = int(value * 10**max_digits) return balances def assets_value(assets, market, base_currency="BTC"): repartition_in_base_currency = {} for currency, asset_value in assets.items(): if currency == base_currency: repartition_in_base_currency[currency] = asset_value else: asset_ticker = get_ticker(currency, base_currency, market) if asset_ticker is None: raise Exception("This asset is not available in the chosen market") repartition_in_base_currency[currency] = int(asset_ticker["bidA"] * asset_value) return repartition_in_base_currency def dispatch_assets(base_currency_value, repartition_pertenthousand, market, base_currency="BTC"): sum_pertenthousand = sum([v for k, v in repartition_pertenthousand.items()]) repartition_in_base_currency = {} for currency, ptt in repartition_pertenthousand.items(): repartition_in_base_currency[currency] = int(ptt * base_currency_value / sum_pertenthousand) return repartition_in_base_currency def compute_moves(current_assets, repartition_pertenthousand, market, base_currency="BTC"): value_in_base = assets_value(current_assets, market, base_currency=base_currency) total_base_value = sum([ v for k, v in value_in_base.items()]) new_repartition = dispatch_assets(total_base_value, repartition_pertenthousand, market, base_currency=base_currency) mouvements = {} for key in set(value_in_base.keys()).union(set(new_repartition.keys())): mouvements[key] = value_in_base.get(key, 0) - new_repartition.get(key, 0) return mouvements def compute_order(currency, value, market, base_currency="BTC"): if currency == base_currency or value == 0: return [None, 0, False] asset_ticker = get_ticker(currency, base_currency, market) if asset_ticker["inverted"]: asset_ticker = get_ticker(base_currency, currency, market) if value > 0: rate = asset_ticker["askA"] return ["buy", rate, True] else: rate = asset_ticker["bidA"] return ["sell", rate, True] else: if value > 0: rate = asset_ticker["bidA"] return ["sell", rate, False] else: rate = asset_ticker["askA"] return ["buy", rate, False] def make_order(currency, value, market, base_currency="BTC"): action, rate, inverted = compute_order(currency, value, market, base_currency=base_currency) amount = formatted_price(abs(value)) if not inverted: symbol = "{}/{}".format(currency, base_currency) else: symbol = "{}/{}".format(base_currency, currency) return market.create_order(symbol, 'limit', action, amount, price=rate) def make_orders(current_assets, repartition_pertenthousand, market, base_currency="BTC"): mouvements = compute_moves( current_assets, repartition_pertenthousand, market, base_currency=base_currency) results = [] for currency, value in sorted(mouvements.items(), key=lambda x: x[1]): # FIXME: wait for sales to finish results.append(make_order(currency, value, market, base_currency=base_currency)) return results def print_assets(assets, indent="", market=None, base_currency="BTC"): if market is not None: format_string = "{}{} {} ({} {})" else: format_string = "{}{} {}" base_currency_price = 0 for currency, value in assets.items(): if market is not None: asset_ticker = get_ticker(currency, base_currency, market) base_currency_price = asset_ticker["bidA"] * value print(format_string.format( indent, formatted_price(value), currency, formatted_price(base_currency_price), base_currency)) def print_orders(current_assets, repartition_pertenthousand, market, base_currency="BTC"): mouvements = compute_moves( current_assets, repartition_pertenthousand, market, base_currency=base_currency) for currency, value in mouvements.items(): action, rate, inverted = compute_order( currency, value, market, base_currency=base_currency) if action is not None: currency_price = int(value / rate) if not inverted: c1, c2 = [base_currency, currency] v1, v2 = [value, currency_price] else: c1, c2 = [currency, base_currency] v1, v2 = [currency_price, value] print("need to {} {} {}'s worth of {}, i.e. {} {}".format( action, formatted_price(abs(v1)), c1, c2, formatted_price(abs(v2)), c2)) current_assets = fetch_balances(market) print_orders(current_assets, repartition_pertenthousand, market)