]> git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Trader.git/blobdiff - portfolio.py
Merge branch 'dev'
[perso/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Trader.git] / portfolio.py
index 146ee79b29611da8b58c8bfc9cf2c83663fd7712..1d291069bfa08c7cb497e90046de010e6d7f2e02 100644 (file)
@@ -4,6 +4,10 @@ from decimal import Decimal as D, ROUND_DOWN
 from ccxt import ExchangeError, InsufficientFunds, ExchangeNotAvailable, InvalidOrder, OrderNotCached, OrderNotFound, RequestTimeout, InvalidNonce
 
 class Computation:
+    @staticmethod
+    def eat_several(market):
+        return lambda x, y: market.ccxt.fetch_nth_order_book(x["symbol"], y, 15)
+
     computations = {
             "default": lambda x, y: x[y],
             "average": lambda x, y: x["average"],
@@ -48,7 +52,7 @@ class Amount:
                     ticker=asset_ticker,
                     rate=rate)
         else:
-            raise Exception("This asset is not available in the chosen market")
+            return Amount(other_currency, 0, linked_to=self, ticker=None, rate=0)
 
     def as_json(self):
         return {
@@ -261,12 +265,12 @@ class Trade:
 
     @property
     def is_fullfiled(self):
-        return abs(self.filled_amount(in_base_currency=(not self.inverted))) >= abs(self.delta)
+        return abs(self.filled_amount(in_base_currency=(not self.inverted), refetch=True)) >= abs(self.delta)
 
-    def filled_amount(self, in_base_currency=False):
+    def filled_amount(self, in_base_currency=False, refetch=False):
         filled_amount = 0
         for order in self.orders:
-            filled_amount += order.filled_amount(in_base_currency=in_base_currency)
+            filled_amount += order.filled_amount(in_base_currency=in_base_currency, refetch=refetch)
         return filled_amount
 
     tick_actions = {
@@ -288,8 +292,12 @@ class Trade:
         if tick in self.tick_actions:
             update, compute_value = self.tick_actions[tick]
         elif tick % 3 == 1:
-            update = "market_adjust"
-            compute_value = "default"
+            if tick < 20:
+                update = "market_adjust"
+                compute_value = "default"
+            else:
+                update = "market_adjust_eat"
+                compute_value = Computation.eat_several(self.market)
         else:
             update = "waiting"
             compute_value = None
@@ -311,13 +319,15 @@ class Trade:
         if self.action is None:
             return None
         ticker = self.market.get_ticker(self.currency, self.base_currency)
+        if ticker is None:
+            self.market.report.log_error("prepare_order",
+                    message="Unknown ticker {}/{}".format(self.currency, self.base_currency))
+            return None
         self.inverted = ticker["inverted"]
         if self.inverted:
             ticker = ticker["original"]
         rate = Computation.compute_value(ticker, self.order_action(), compute_value=compute_value)
 
-        # FIXME: Dust amount should be removed from there if they werent
-        # honored in other sales
         delta_in_base = abs(self.delta)
         # 9 BTC's worth of move (10 - 1 or 1 - 10 depending on case)
 
@@ -576,18 +586,18 @@ class Order:
         self.fetch_mouvements()
 
         self.mark_disappeared_order()
-
+        self.mark_dust_amount_remaining_order()
         self.mark_finished_order()
-        # FIXME: consider open order with dust remaining as closed
 
-    def dust_amount_remaining(self):
-        return self.remaining_amount() < Amount(self.amount.currency, D("0.001"))
+    def mark_dust_amount_remaining_order(self):
+        if self.status == "open" and self.market.ccxt.is_dust_trade(self.remaining_amount().value, self.rate):
+            self.status = "closed_dust_remaining"
 
-    def remaining_amount(self):
-        return self.amount - self.filled_amount()
+    def remaining_amount(self, refetch=False):
+        return self.amount - self.filled_amount(refetch=refetch)
 
-    def filled_amount(self, in_base_currency=False):
-        if self.status == "open":
+    def filled_amount(self, in_base_currency=False, refetch=False):
+        if refetch and self.status == "open":
             self.fetch()
         filled_amount = 0
         for mouvement in self.mouvements:
@@ -614,7 +624,7 @@ class Order:
             self.market.report.log_debug_action("Mark {} as cancelled".format(self))
             self.status = "canceled"
             return
-        if self.open and self.id is not None:
+        if (self.status == "closed_dust_remaining" or self.open) and self.id is not None:
             try:
                 self.market.ccxt.cancel_order(self.id)
             except OrderNotFound as e: # Closed inbetween
@@ -646,7 +656,6 @@ class Order:
             return True
 
         similar_trades = self.market.ccxt.fetch_my_trades(symbol=symbol, since=start_timestamp)
-        # FIXME: use set instead of sorted(list(...))
         for order_id in sorted(list(map(lambda x: x["order"], similar_trades))):
             trades = list(filter(lambda x: x["order"] == order_id, similar_trades))
             if any(x["timestamp"] < start_timestamp for x in trades):