]> git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Trader.git/blobdiff - script.py
Add order processing functions
[perso/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Trader.git] / script.py
index 473253309441b5da16c5983096f941a05ef20c03..c5ac4aa9ba42630ebe1cfeeaaad1e8210d239443 100644 (file)
--- a/script.py
+++ b/script.py
@@ -1,12 +1,14 @@
 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,
@@ -16,23 +18,51 @@ repartition_pertenthousand = {
         "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 = {}
@@ -43,7 +73,7 @@ def assets_value(assets, market, base_currency="BTC"):
             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"):
@@ -53,7 +83,7 @@ def dispatch_assets(base_currency_value, repartition_pertenthousand, market, bas
         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()])
 
@@ -63,32 +93,97 @@ def give_orders(current_assets, repartition_pertenthousand, market, base_currenc
     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)