Ejemplo n.º 1
0
    def get_profit(self, currency) -> U[Tuple, Float]:
        """Returns current profit for a currency and its weighted average buy cost.

        :param Text currency: a valid currency to use at profit and cost calc
        :return: current profit and weighted average buy cost as a tuple
        """
        currency = Currency(str(currency))
        btc_symbol = currency + Currency('BTC')  # type: Symbol
        balance = self.get_balance(currency)

        if balance.used > 0.0:
            cost = self.get_cost(symbol=btc_symbol)
            return balance.to_btc - (cost * balance.total)
        else:
            return 0.0, 0.0
Ejemplo n.º 2
0
    def altname(self, name) -> U[Currency, Symbol]:
        """Retrieve alternative currency or symbol name used in a specific exchange.

        >>> PandaXT('binance').altname('YOYOW')
        'YOYOW'
        >>> PandaXT('binance').altname('YOYOW/BTC')
        (Symbol:YOYOW/BTC)
        >>> PandaXT('binance').altname('YOYOW/BTC')
        (Symbol:YOYOW/BTC)

        :param name: currency or symbol name to check for alternative name.
        :type name: Text or Currency or Symbol
        :return: currency alternative name as Currency or Symbol instance.
        :rtype: Currency or Symbol
        """
        _symbol = str(name).upper()
        if '/' in _symbol.strip('/'):
            # print(_symbol)
            base, quote = _symbol.split('/')
            assert quote in self.base_markets, f'{quote} is not a valid base market.'
            base = self.get_currency(base)
            s = self.get_currency(base) + Currency(quote)
            s.price2precision = functools.partial(self.price2precision, s)
            s.cost2precision = functools.partial(self.cost2precision, s)
            s.amount2precision = functools.partial(self.amount2precision, s)
            return s
        else:
            return self.get_currency(_symbol)
Ejemplo n.º 3
0
    def get_cost(self, symbol, **kwargs) -> Float:
        """FIXME do not work well sometimes giving a bad result by unknown reason.

        Get weighted average (from buy trades data) cost for a symbol.

        >>> api = PandaXT('binance')
        >>> symbol_cost = api.get_cost('AGI/BTC')
        >>> symbol_cost
        True

        :param U[Symbol,Text] symbol: a valid exchange symbol.
        :param kwargs: accepted keys are: balance (Balance) and trades (pd.DataFrame)
        :return: cost calculation result as float type.
        """
        symbol = self.altname(symbol)
        if isinstance(symbol or 0, Currency):
            symbol = symbol + Currency('BTC')

        base, quote = symbol.parts

        # reuse provided balance and trades data (for rate limit save)
        if 'balance' in kwargs:
            cached = kwargs.get('balance')  # type: Balance
            balance = cached[base] if isinstance(cached, Wallet) else cached
        else:
            balance = self.get_balance(base, field='total')  # type: Balance

        total_balance = balance.total if balance and hasattr(
            balance, 'total') else balance

        if total_balance > 0.0:
            trades = kwargs.get('trades', [])
            if not trades:
                trades = self.get_user_trades(symbol, side='buy')
            elif not isinstance(trades, pd.DataFrame):
                trades = pd.DataFrame(trades)
            if trades['order'].isna().all():
                trades['order'].update(trades['id'])

            # group-by operations per column
            columns_op = {'amount': 'mean',
                          'price': 'mean',
                          'cost': 'mean',
                          'timestamp': 'mean'}

            trades = trades.groupby('order').agg(columns_op).sort_index(
                ascending=False)  # type: pd.DataFrame
            trades = trades[['price', 'amount']].reset_index(drop=True)

            for index, price, amount in trades.itertuples():
                if round(total_balance - amount, 8) <= 0.0:
                    if round(total_balance - amount, 8) != 0.0:
                        prices = trades[:index + 1]['price'].values
                        amounts = trades[:index + 1]['amount'].values
                        amounts[-1] = total_balance
                    else:
                        prices, amounts = trades[:index + 1].T.values
                    return round(pd.np.average(prices, weights=amounts), 10)
                else:
                    total_balance -= amount
Ejemplo n.º 4
0
 def get_currency(self, currency) -> Currency:
     """Currency name sanitizer."""
     if currency:
         if currency in self._api.commonCurrencies:
             currency = self._api.commonCurrencies.get(currency)
         if currency not in self.currencies:
             log.debug(f'Currency {str(currency)} is not supported by exchange.')
         return Currency(currency)
Ejemplo n.º 5
0
    def currencies(self) -> List[Currency]:
        """Get supported currencies by exchange as "Currency" list.

        >>> currencies = PandaXT('binance').currencies
        >>> len(currencies) > 0
        True

        """
        # Initialize markets, symbols, currencies and basemarkets
        if self._currencies is None:
            delisted = {d.base for d in self.delisted}
            self._currencies = sorted([
                Currency(c) for c in self._api.currencies if c not in delisted
            ])

        return self._currencies
Ejemplo n.º 6
0
        def is_tradeable(currency, tickers, balance, base_market=None):
            """Check if a currency balance is over minimum tradeable amount for a base market.

            :param currency:
            :type currency: str or Currency
            :param tickers:
            :type tickers: Tickers
            :param balance:
            :type balance: dict or float
            :param base_market:
            :type base_market: str or Currency
            :return:
            :rtype:
            """
            base_market = Currency(base_market or 'BTC')
            symbol: Symbol = self.altname(currency) + base_market

            market: Market = self.markets.get(symbol, False)
            if not market:
                return False
            # min amount in quote currency
            limits: Limit = market.limits
            quote_min_amount = limits.amount

            ticker = tickers[symbol]  # type: Ticker
            if currency == 'BTC' and 'USD' in base_market:
                last = 1.0 / ticker.last
            else:
                last = ticker.last
            # converting min_amount to base currency

            base_min_amount = last * quote_min_amount
            # subtracting a 0.01% fee
            base_min_amount = base_min_amount * 0.999
            if isinstance(balance or [], dict):
                balance = balance.get('total', 0.0)
            else:
                balance = balance or 0.0
            return balance > base_min_amount
Ejemplo n.º 7
0
    def get_balances(self, field=None, tradeables_only=True, fiat=None) -> Wallet:
        """Get balances.

        >>> balances = PandaXT('binance').get_balances('total')
        >>> isinstance(balances, Wallet)
        True

        :param Text field: accepted values: if None all balances will be loaded, (values; "total", "used", "free")
        :param Bool tradeables_only:
        :return: positive balances.
        """

        def is_zero(v) -> U[Float, Dict]:
            if isinstance(v, float):
                return v <= 0.0
            elif isinstance(v, dict):
                return v.get('total', 0.0) <= 0.0
            else:
                return 0.0

        def is_tradeable(currency, _tickers, balance, base_market=None) -> Bool:
            """Check if a currency balance is over minimum tradeable amount for a base market.

            :param Text currency:
            :param Tickers _tickers:
            :param balance:
            :type balance: Dict or Float
            :param Text base_market:
            :return: True if currency is tradeable
            """
            if currency in self.base_markets:
                return True

            base_market = Currency(base_market or 'BTC')
            symbol: Symbol = self.altname(currency) + base_market

            market: Market = self.markets.get(symbol, False)
            if not market:
                return False
            # min amount in quote currency
            limits: Limit = market.limits
            quote_min_amount = limits.amount

            ticker: Ticker = _tickers[symbol]
            if currency == 'BTC' and 'USD' in base_market:
                last = 1.0 / ticker.last
            else:
                last = ticker.last
            # converting min_amount to base currency

            base_min_amount = last * quote_min_amount
            # subtracting a 0.01% fee
            base_min_amount = base_min_amount * 0.999
            if isinstance(balance or [], dict):
                balance = balance.get('total', 0.0)
            else:
                balance = balance or 0.0
            return balance > base_min_amount

        try:
            data = self._api.fetch_balance()

            if 'info' in data:
                del data['info']

            data: dict = data.pop(field) if field else data

            data = {str(k): v
                    for k, v in data.items()
                    if not is_zero(v)}

            if tradeables_only:
                symbols = {Currency(c) + Currency('BTC') for c in data}
                tickers = self.get_tickers(symbols)
                data = {str(k): v
                        for k, v in data.items()
                        if k in self._basemarkets or is_tradeable(k, tickers, v)}
            wallet = Wallet(**data)
            if str(fiat or '').lower() in ['EUR', 'USD']:
                acum = 0
                for k, v in Wallet(**data).items():
                    if fiat.lower() == 'eur':
                        acum += v.to_eur
                    elif fiat.lower() == 'usd':
                        acum += v.to_usd
                wallet.update({fiat.upper(): acum})
            return wallet
        except ccxt.NetworkError as err:
            print('PandaXT::get_ohlc', str(err))
Ejemplo n.º 8
0
    def get_balances(self, field=None, tradeables_only=True):
        """Get balances.

        >>> balances = PandaXT('binance').get_balances('total')
        >>> isinstance(balances, Wallet)
        True

        :param Text field: accepted values: if None all balances will be loaded, (values; "total", "used", "free")
        :return Wallet: positive balances.
        """
        def is_tradeable(currency, tickers, balance, base_market=None):
            """Check if a currency balance is over minimum tradeable amount for a base market.

            :param currency:
            :type currency: str or Currency
            :param tickers:
            :type tickers: Tickers
            :param balance:
            :type balance: dict or float
            :param base_market:
            :type base_market: str or Currency
            :return:
            :rtype:
            """
            base_market = Currency(base_market or 'BTC')
            symbol: Symbol = self.altname(currency) + base_market

            market: Market = self.markets.get(symbol, False)
            if not market:
                return False
            # min amount in quote currency
            limits: Limit = market.limits
            quote_min_amount = limits.amount

            ticker = tickers[symbol]  # type: Ticker
            if currency == 'BTC' and 'USD' in base_market:
                last = 1.0 / ticker.last
            else:
                last = ticker.last
            # converting min_amount to base currency

            base_min_amount = last * quote_min_amount
            # subtracting a 0.01% fee
            base_min_amount = base_min_amount * 0.999
            if isinstance(balance or [], dict):
                balance = balance.get('total', 0.0)
            else:
                balance = balance or 0.0
            return balance > base_min_amount

        data = self._api.fetch_balance()

        if 'info' in data:
            del data['info']

        data = data.pop(field) if field else data  # type: dict

        def is_zero(v):
            if isinstance(v, float):
                return v <= 0.0
            else:
                return v.get('total', 0.0) <= 0.0

        data = {str(k): v for k, v in data.items() if not is_zero(v)}

        if tradeables_only:
            symbols = {Currency(c) + Currency('BTC') for c in data}
            tickers = self.get_tickers(symbols)
            data = {
                str(k): v
                for k, v in data.items() if is_tradeable(k, tickers, v)
            }

        return Wallet(**data)