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
-current_assets = {
- "ETH": int(2.00000000 * 10**max_digits),
- "BTC": int(1.23000000 * 10**max_digits),
- "ZEC": int(2.00000000 * 10**max_digits),
- "SC" : int(2.000000000 * 10**max_digits),
- }
repartition_pertenthousand = {
"BTC": 2857,
"SC": 623,
}
-market = ccxt.poloniex()
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:
- return market.fetch_ticker("{}/{}".format(c1, c2))
+ 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:
- ticker = market.fetch_ticker("{}/{}".format(c2, c1))
- return {
- "bid": float(1/ticker["ask"]),
- "ask": float(1/ticker["bid"]),
- }
+ 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:
- return None
+ 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 = {}
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["bid"] * asset_value)
+ 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"):
repartition_in_base_currency[currency] = int(ptt * base_currency_value / sum_pertenthousand)
return repartition_in_base_currency
-def give_orders(current_assets, repartition_pertenthousand, market, base_currency="BTC"):
+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()])
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)
- print("assets before repartition:")
- for currency, value in current_assets.items():
- print("holding {} {}".format(
- formatted_price(value),
- currency))
- print("------------")
- for currency, value in mouvements.items():
- if currency == base_currency:
- continue
- asset_ticker = get_ticker(currency, base_currency, market)
+ 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:
- action = "sell"
- currency_price = int(value / asset_ticker["bid"])
+ rate = asset_ticker["askA"]
+ return ["buy", rate, True]
else:
- action = "buy"
- currency_price = int(value / asset_ticker["ask"])
- if value != 0:
+ 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(value)),
- base_currency,
- currency,
- formatted_price(abs(currency_price)),
- currency))
- print("------------\nassets after repartition:")
- for currency, value in new_repartition.items():
- print("holding {} {}".format(formatted_price(value), currency))
+ formatted_price(abs(v1)), c1,
+ c2,
+ formatted_price(abs(v2)), c2))
-give_orders(current_assets, repartition_pertenthousand, market)
+current_assets = fetch_balances(market)
+print_orders(current_assets, repartition_pertenthousand, market)