X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=portfolio.py;h=eb3390ed70d2c156f90002afa994e91a14ddf651;hb=2033e7fef780298be2ec15455a0ec1d26515de55;hp=0797de0a0489542ce02c20863625d33a2bb3eab8;hpb=d24bb10c3cad1f144b76022481f46b4524873f4b;p=perso%2FImmae%2FProjets%2FCryptomonnaies%2FCryptoportfolio%2FTrader.git diff --git a/portfolio.py b/portfolio.py index 0797de0..eb3390e 100644 --- a/portfolio.py +++ b/portfolio.py @@ -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_):