]> git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Trader.git/blobdiff - portfolio.py
Add make_order and get_user_market helpers
[perso/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Trader.git] / portfolio.py
index 0797de0a0489542ce02c20863625d33a2bb3eab8..eb3390ed70d2c156f90002afa994e91a14ddf651 100644 (file)
@@ -3,7 +3,8 @@ from datetime import datetime, timedelta
 from decimal import Decimal as D, ROUND_DOWN
 from json import JSONDecodeError
 from simplejson.errors import JSONDecodeError as SimpleJSONDecodeError
-from ccxt import ExchangeError, ExchangeNotAvailable, InvalidOrder
+from ccxt import ExchangeError, InsufficientFunds, ExchangeNotAvailable, InvalidOrder
+from retry import retry
 import requests
 
 # FIXME: correctly handle web call timeouts
@@ -359,7 +360,7 @@ class Trade:
             new_order.run()
             self.market.report.log_order(order, tick, new_order=new_order)
 
-    def prepare_order(self, compute_value="default"):
+    def prepare_order(self, close_if_possible=None, compute_value="default"):
         if self.action is None:
             return None
         ticker = self.market.get_ticker(self.currency, self.base_currency)
@@ -425,7 +426,8 @@ class Trade:
                 delta = delta - filled
                 # I already sold 4 BTC, only 5 left
 
-        close_if_possible = (self.value_to == 0)
+        if close_if_possible is None:
+            close_if_possible = (self.value_to == 0)
 
         if delta <= 0:
             self.market.report.log_error("prepare_order", message="Less to do than already filled: {}".format(delta))
@@ -476,6 +478,7 @@ class Order:
         self.close_if_possible = close_if_possible
         self.id = None
         self.fetch_cache_timestamp = None
+        self.tries = 0
 
     def as_json(self):
         return {
@@ -521,7 +524,9 @@ class Order:
     def finished(self):
         return self.status == "closed" or self.status == "canceled" or self.status == "error"
 
+    @retry(InsufficientFunds)
     def run(self):
+        self.tries += 1
         symbol = "{}/{}".format(self.amount.currency, self.base_currency)
         amount = round(self.amount, self.market.ccxt.order_precision(symbol)).value
 
@@ -530,16 +535,25 @@ class Order:
                 symbol, self.action, amount, self.rate, self.account))
             self.results.append({"debug": True, "id": -1})
         else:
+            action = "market.ccxt.create_order('{}', 'limit', '{}', {}, price={}, account={})".format(symbol, self.action, amount, self.rate, self.account)
             try:
                 self.results.append(self.market.ccxt.create_order(symbol, 'limit', self.action, amount, price=self.rate, account=self.account))
-            except (ExchangeNotAvailable, InvalidOrder):
+            except InvalidOrder:
                 # Impossible to honor the order (dust amount)
                 self.status = "closed"
                 self.mark_finished_order()
                 return
+            except InsufficientFunds as e:
+                if self.tries < 5:
+                    self.market.report.log_error(action, message="Retrying with reduced amount", exception=e)
+                    self.amount = self.amount * D("0.99")
+                    raise e
+                else:
+                    self.market.report.log_error(action, message="Giving up {}".format(self), exception=e)
+                    self.status = "error"
+                    return
             except Exception as e:
                 self.status = "error"
-                action = "market.ccxt.create_order('{}', 'limit', '{}', {}, price={}, account={})".format(symbol, self.action, amount, self.rate, self.account)
                 self.market.report.log_error(action, exception=e)
                 return
         self.id = self.results[0]["id"]
@@ -573,7 +587,7 @@ class Order:
             return
         self.fetch_cache_timestamp = time.time()
 
-        result = self.market.ccxt.fetch_order(self.id)
+        result = self.market.ccxt.fetch_order(self.id, symbol=self.amount.currency)
         self.results.append(result)
 
         self.status = result["status"]
@@ -619,7 +633,7 @@ class Order:
             self.status = "canceled"
             return
         self.market.ccxt.cancel_order(self.id)
-        self.fetch()
+        self.fetch(force=True)
 
 class Mouvement:
     def __init__(self, currency, base_currency, hash_):