- fees_cache = {}
- @classmethod
- def fetch_fees(cls, market):
- if market.__class__ not in cls.fees_cache:
- cls.fees_cache[market.__class__] = market.fetch_fees()
- return cls.fees_cache[market.__class__]
-
- ticker_cache = {}
- ticker_cache_timestamp = time.time()
- @classmethod
- def get_ticker(cls, c1, c2, market, refresh=False):
- def invert(ticker):
- return {
- "inverted": True,
- "average": (1/ticker["bid"] + 1/ticker["ask"]) / 2,
- "original": ticker,
- }
- def augment_ticker(ticker):
- ticker.update({
- "inverted": False,
- "average": (ticker["bid"] + ticker["ask"] ) / 2,
- })
-
- if time.time() - cls.ticker_cache_timestamp > 5:
- cls.ticker_cache = {}
- cls.ticker_cache_timestamp = time.time()
- elif not refresh:
- if (c1, c2, market.__class__) in cls.ticker_cache:
- return cls.ticker_cache[(c1, c2, market.__class__)]
- if (c2, c1, market.__class__) in cls.ticker_cache:
- return invert(cls.ticker_cache[(c2, c1, market.__class__)])
-
- try:
- cls.ticker_cache[(c1, c2, market.__class__)] = market.fetch_ticker("{}/{}".format(c1, c2))
- augment_ticker(cls.ticker_cache[(c1, c2, market.__class__)])
- except ExchangeError:
- try:
- cls.ticker_cache[(c2, c1, market.__class__)] = market.fetch_ticker("{}/{}".format(c2, c1))
- augment_ticker(cls.ticker_cache[(c2, c1, market.__class__)])
- except ExchangeError:
- cls.ticker_cache[(c1, c2, market.__class__)] = None
- return cls.get_ticker(c1, c2, market)
-
- @classmethod
- def compute_trades(cls, values_in_base, new_repartition, only=None, market=None):
- base_currency = sum(values_in_base.values()).currency
- for currency in Balance.currencies():
- if currency == base_currency:
- continue
- value_from = values_in_base.get(currency, Amount(base_currency, 0))
- value_to = new_repartition.get(currency, Amount(base_currency, 0))
- if value_from.value * value_to.value < 0:
- trade_1 = cls(value_from, Amount(base_currency, 0), currency, market=market)
- if only is None or trade_1.action == only:
- cls.trades.append(trade_1)
- trade_2 = cls(Amount(base_currency, 0), value_to, currency, market=market)
- if only is None or trade_2.action == only:
- cls.trades.append(trade_2)
- else:
- trade = cls(
- value_from,
- value_to,
- currency,
- market=market
- )
- if only is None or trade.action == only:
- cls.trades.append(trade)
- return cls.trades
-
- @classmethod
- def prepare_orders(cls, only=None, compute_value="default"):
- for trade in cls.trades:
- if only is None or trade.action == only:
- trade.prepare_order(compute_value=compute_value)
-
- @classmethod
- def move_balances(cls, market, debug=False):
- needed_in_margin = {}
- for trade in cls.trades:
- if trade.trade_type == "short":
- if trade.value_to.currency not in needed_in_margin:
- needed_in_margin[trade.value_to.currency] = 0
- needed_in_margin[trade.value_to.currency] += abs(trade.value_to)
- for currency, needed in needed_in_margin.items():
- current_balance = Balance.known_balances[currency].margin_free
- delta = (needed - current_balance).value
- # FIXME: don't remove too much if there are open margin position
- if delta > 0:
- if debug:
- print("market.transfer_balance({}, {}, 'exchange', 'margin')".format(currency, delta))
- else:
- market.transfer_balance(currency, delta, "exchange", "margin")
- elif delta < 0:
- if debug:
- print("market.transfer_balance({}, {}, 'margin', 'exchange')".format(currency, -delta))
- else:
- market.transfer_balance(currency, -delta, "margin", "exchange")