]> git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Trader.git/blobdiff - portfolio.py
Refactor the store to be more conciliant with multiple markets
[perso/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Trader.git] / portfolio.py
index f9423b91d0736178fb4759016195e3d29ecd2499..43a39c4506c7caa6ba6fdbea4f48c5c6c10e4397 100644 (file)
@@ -1,13 +1,10 @@
 import time
 from datetime import datetime, timedelta
 from decimal import Decimal as D, ROUND_DOWN
 import time
 from datetime import datetime, timedelta
 from decimal import Decimal as D, ROUND_DOWN
-# Put your poloniex api key in market.py
 from json import JSONDecodeError
 from simplejson.errors import JSONDecodeError as SimpleJSONDecodeError
 from ccxt import ExchangeError, ExchangeNotAvailable
 import requests
 from json import JSONDecodeError
 from simplejson.errors import JSONDecodeError as SimpleJSONDecodeError
 from ccxt import ExchangeError, ExchangeNotAvailable
 import requests
-import helper as h
-from store import *
 
 # FIXME: correctly handle web call timeouts
 
 
 # FIXME: correctly handle web call timeouts
 
@@ -18,26 +15,27 @@ class Portfolio:
     last_date = None
 
     @classmethod
     last_date = None
 
     @classmethod
-    def wait_for_recent(cls, delta=4):
-        cls.repartition(refetch=True)
+    def wait_for_recent(cls, market, delta=4):
+        cls.repartition(market, refetch=True)
         while cls.last_date is None or datetime.now() - cls.last_date > timedelta(delta):
             time.sleep(30)
         while cls.last_date is None or datetime.now() - cls.last_date > timedelta(delta):
             time.sleep(30)
-            cls.repartition(refetch=True)
+            market.report.print_log("Attempt to fetch up-to-date cryptoportfolio")
+            cls.repartition(market, refetch=True)
 
     @classmethod
 
     @classmethod
-    def repartition(cls, liquidity="medium", refetch=False):
-        cls.parse_cryptoportfolio(refetch=refetch)
+    def repartition(cls, market, liquidity="medium", refetch=False):
+        cls.parse_cryptoportfolio(market, refetch=refetch)
         liquidities = cls.liquidities[liquidity]
         return liquidities[cls.last_date]
 
     @classmethod
         liquidities = cls.liquidities[liquidity]
         return liquidities[cls.last_date]
 
     @classmethod
-    def get_cryptoportfolio(cls):
+    def get_cryptoportfolio(cls, market):
         try:
             r = requests.get(cls.URL)
         try:
             r = requests.get(cls.URL)
-            ReportStore.log_http_request(r.request.method,
+            market.report.log_http_request(r.request.method,
                     r.request.url, r.request.body, r.request.headers, r)
         except Exception as e:
                     r.request.url, r.request.body, r.request.headers, r)
         except Exception as e:
-            ReportStore.log_error("get_cryptoportfolio", exception=e)
+            market.report.log_error("get_cryptoportfolio", exception=e)
             return
         try:
             cls.data = r.json(parse_int=D, parse_float=D)
             return
         try:
             cls.data = r.json(parse_int=D, parse_float=D)
@@ -45,9 +43,9 @@ class Portfolio:
             cls.data = None
 
     @classmethod
             cls.data = None
 
     @classmethod
-    def parse_cryptoportfolio(cls, refetch=False):
+    def parse_cryptoportfolio(cls, market, refetch=False):
         if refetch or cls.data is None:
         if refetch or cls.data is None:
-            cls.get_cryptoportfolio()
+            cls.get_cryptoportfolio(market)
 
         def filter_weights(weight_hash):
             if weight_hash[1][0] == 0:
 
         def filter_weights(weight_hash):
             if weight_hash[1][0] == 0:
@@ -118,7 +116,7 @@ class Amount:
                     self.value * rate,
                     linked_to=self,
                     rate=rate)
                     self.value * rate,
                     linked_to=self,
                     rate=rate)
-        asset_ticker = h.get_ticker(self.currency, other_currency, market)
+        asset_ticker = market.get_ticker(self.currency, other_currency)
         if asset_ticker is not None:
             rate = Computation.compute_value(asset_ticker, action, compute_value=compute_value)
             return Amount(
         if asset_ticker is not None:
             rate = Computation.compute_value(asset_ticker, action, compute_value=compute_value)
             return Amount(
@@ -283,7 +281,7 @@ class Balance:
         return "Balance({}".format(self.currency) + "".join([exchange, margin, total]) + ")"
 
 class Trade:
         return "Balance({}".format(self.currency) + "".join([exchange, margin, total]) + ")"
 
 class Trade:
-    def __init__(self, value_from, value_to, currency, market=None):
+    def __init__(self, value_from, value_to, currency, market):
         # We have value_from of currency, and want to finish with value_to of
         # that currency. value_* may not be in currency's terms
         self.currency = currency
         # We have value_from of currency, and want to finish with value_to of
         # that currency. value_* may not be in currency's terms
         self.currency = currency
@@ -353,18 +351,18 @@ class Trade:
             if tick == 7:
                 update = "market_fallback"
 
             if tick == 7:
                 update = "market_fallback"
 
-        ReportStore.log_order(order, tick, update=update,
+        self.market.report.log_order(order, tick, update=update,
                 compute_value=compute_value, new_order=new_order)
 
         if new_order is not None:
             order.cancel()
             new_order.run()
                 compute_value=compute_value, new_order=new_order)
 
         if new_order is not None:
             order.cancel()
             new_order.run()
-            ReportStore.log_order(order, tick, new_order=new_order)
+            self.market.report.log_order(order, tick, new_order=new_order)
 
     def prepare_order(self, compute_value="default"):
         if self.action is None:
             return None
 
     def prepare_order(self, compute_value="default"):
         if self.action is None:
             return None
-        ticker = h.get_ticker(self.currency, self.base_currency, self.market)
+        ticker = self.market.get_ticker(self.currency, self.base_currency)
         inverted = ticker["inverted"]
         if inverted:
             ticker = ticker["original"]
         inverted = ticker["inverted"]
         if inverted:
             ticker = ticker["original"]
@@ -430,7 +428,7 @@ class Trade:
         close_if_possible = (self.value_to == 0)
 
         if delta <= 0:
         close_if_possible = (self.value_to == 0)
 
         if delta <= 0:
-            ReportStore.log_error("prepare_order", message="Less to do than already filled: {}".format(delta))
+            self.market.report.log_error("prepare_order", message="Less to do than already filled: {}".format(delta))
             return None
 
         order = Order(self.order_action(inverted),
             return None
 
         order = Order(self.order_action(inverted),
@@ -456,11 +454,11 @@ class Trade:
                 self.action)
 
     def print_with_order(self, ind=""):
                 self.action)
 
     def print_with_order(self, ind=""):
-        ReportStore.print_log("{}{}".format(ind, self))
+        self.market.report.print_log("{}{}".format(ind, self))
         for order in self.orders:
         for order in self.orders:
-            ReportStore.print_log("{}\t{}".format(ind, order))
+            self.market.report.print_log("{}\t{}".format(ind, order))
             for mouvement in order.mouvements:
             for mouvement in order.mouvements:
-                ReportStore.print_log("{}\t\t{}".format(ind, mouvement))
+                self.market.report.print_log("{}\t\t{}".format(ind, mouvement))
 
 class Order:
     def __init__(self, action, amount, rate, base_currency, trade_type, market,
 
 class Order:
     def __init__(self, action, amount, rate, base_currency, trade_type, market,
@@ -525,15 +523,15 @@ class Order:
 
     def run(self):
         symbol = "{}/{}".format(self.amount.currency, self.base_currency)
 
     def run(self):
         symbol = "{}/{}".format(self.amount.currency, self.base_currency)
-        amount = round(self.amount, self.market.order_precision(symbol)).value
+        amount = round(self.amount, self.market.ccxt.order_precision(symbol)).value
 
 
-        if TradeStore.debug:
-            ReportStore.log_debug_action("market.create_order('{}', 'limit', '{}', {}, price={}, account={})".format(
+        if self.market.debug:
+            self.market.report.log_debug_action("market.ccxt.create_order('{}', 'limit', '{}', {}, price={}, account={})".format(
                 symbol, self.action, amount, self.rate, self.account))
             self.results.append({"debug": True, "id": -1})
         else:
             try:
                 symbol, self.action, amount, self.rate, self.account))
             self.results.append({"debug": True, "id": -1})
         else:
             try:
-                self.results.append(self.market.create_order(symbol, 'limit', self.action, amount, price=self.rate, account=self.account))
+                self.results.append(self.market.ccxt.create_order(symbol, 'limit', self.action, amount, price=self.rate, account=self.account))
             except ExchangeNotAvailable:
                 # Impossible to honor the order (dust amount)
                 self.status = "closed"
             except ExchangeNotAvailable:
                 # Impossible to honor the order (dust amount)
                 self.status = "closed"
@@ -541,15 +539,15 @@ class Order:
                 return
             except Exception as e:
                 self.status = "error"
                 return
             except Exception as e:
                 self.status = "error"
-                action = "market.create_order('{}', 'limit', '{}', {}, price={}, account={})".format(symbol, self.action, amount, self.rate, self.account)
-                ReportStore.log_error(action, exception=e)
+                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"]
         self.status = "open"
 
     def get_status(self):
                 return
         self.id = self.results[0]["id"]
         self.status = "open"
 
     def get_status(self):
-        if TradeStore.debug:
-            ReportStore.log_debug_action("Getting {} status".format(self))
+        if self.market.debug:
+            self.market.report.log_debug_action("Getting {} status".format(self))
             return self.status
         # other states are "closed" and "canceled"
         if not self.finished:
             return self.status
         # other states are "closed" and "canceled"
         if not self.finished:
@@ -559,23 +557,23 @@ class Order:
         return self.status
 
     def mark_finished_order(self):
         return self.status
 
     def mark_finished_order(self):
-        if TradeStore.debug:
-            ReportStore.log_debug_action("Mark {} as finished".format(self))
+        if self.market.debug:
+            self.market.report.log_debug_action("Mark {} as finished".format(self))
             return
         if self.status == "closed":
             if self.trade_type == "short" and self.action == "buy" and self.close_if_possible:
             return
         if self.status == "closed":
             if self.trade_type == "short" and self.action == "buy" and self.close_if_possible:
-                self.market.close_margin_position(self.amount.currency, self.base_currency)
+                self.market.ccxt.close_margin_position(self.amount.currency, self.base_currency)
 
     def fetch(self, force=False):
 
     def fetch(self, force=False):
-        if TradeStore.debug:
-            ReportStore.log_debug_action("Fetching {}".format(self))
+        if self.market.debug:
+            self.market.report.log_debug_action("Fetching {}".format(self))
             return
         if (not force and self.fetch_cache_timestamp is not None
                 and time.time() - self.fetch_cache_timestamp < 10):
             return
         self.fetch_cache_timestamp = time.time()
 
             return
         if (not force and self.fetch_cache_timestamp is not None
                 and time.time() - self.fetch_cache_timestamp < 10):
             return
         self.fetch_cache_timestamp = time.time()
 
-        result = self.market.fetch_order(self.id)
+        result = self.market.ccxt.fetch_order(self.id)
         self.results.append(result)
 
         self.status = result["status"]
         self.results.append(result)
 
         self.status = result["status"]
@@ -606,7 +604,7 @@ class Order:
 
     def fetch_mouvements(self):
         try:
 
     def fetch_mouvements(self):
         try:
-            mouvements = self.market.privatePostReturnOrderTrades({"orderNumber": self.id})
+            mouvements = self.market.ccxt.privatePostReturnOrderTrades({"orderNumber": self.id})
         except ExchangeError:
             mouvements = []
         self.mouvements = []
         except ExchangeError:
             mouvements = []
         self.mouvements = []
@@ -616,11 +614,11 @@ class Order:
                 self.base_currency, mouvement_hash))
 
     def cancel(self):
                 self.base_currency, mouvement_hash))
 
     def cancel(self):
-        if TradeStore.debug:
-            ReportStore.log_debug_action("Mark {} as cancelled".format(self))
+        if self.market.debug:
+            self.market.report.log_debug_action("Mark {} as cancelled".format(self))
             self.status = "canceled"
             return
             self.status = "canceled"
             return
-        self.market.cancel_order(self.id)
+        self.market.ccxt.cancel_order(self.id)
         self.fetch()
 
 class Mouvement:
         self.fetch()
 
 class Mouvement:
@@ -663,6 +661,3 @@ class Mouvement:
                 date, self.action, self.total, self.total_in_base,
                 fee_rate)
 
                 date, self.action, self.total, self.total_in_base,
                 fee_rate)
 
-if __name__ == '__main__': # pragma: no cover
-    from market import market
-    h.print_orders(market)