Exemplo n.º 1
0
def test_kucoin_exchange_assets_are_known(mock_kucoin):
    request_url = f'{mock_kucoin.base_uri}/api/v1/currencies'
    try:
        response = requests.get(request_url)
    except requests.exceptions.RequestException as e:
        raise RemoteError(
            f'Kucoin get request at {request_url} connection error: {str(e)}.',
        ) from e

    if response.status_code != HTTPStatus.OK:
        raise RemoteError(
            f'Kucoin query responded with error status code: {response.status_code} '
            f'and text: {response.text}', )
    try:
        response_dict = jsonloads_dict(response.text)
    except JSONDecodeError as e:
        raise RemoteError(
            f'Kucoin returned invalid JSON response: {response.text}') from e

    # Extract the unique symbols from the exchange pairs
    unsupported_assets = set(UNSUPPORTED_KUCOIN_ASSETS)
    common_items = unsupported_assets.intersection(
        set(WORLD_TO_KUCOIN.values()))
    assert not common_items, f'Kucoin assets {common_items} should not be unsupported'
    for entry in response_dict['data']:
        symbol = entry['currency']
        try:
            asset_from_kucoin(symbol)
        except UnsupportedAsset:
            assert symbol in unsupported_assets
        except UnknownAsset as e:
            test_warnings.warn(
                UserWarning(
                    f'Found unknown asset {e.asset_name} in kucoin. '
                    f'Support for it has to be added', ))
Exemplo n.º 2
0
def deserialize_trade_pair(trade_pair_symbol: str) -> Tuple[Asset, Asset]:
    """May raise:
    - UnprocessableTradePair
    - UnknownAsset
    - UnsupportedAsset
    """
    try:
        base_asset_symbol, quote_asset_symbol = trade_pair_symbol.split('-')
    except ValueError as e:
        raise UnprocessableTradePair(trade_pair_symbol) from e

    base_asset = asset_from_kucoin(base_asset_symbol)
    quote_asset = asset_from_kucoin(quote_asset_symbol)

    return base_asset, quote_asset
Exemplo n.º 3
0
    def _deserialize_accounts_balances(
        self,
        response_dict: Dict[str, List[Dict[str, Any]]],
    ) -> Dict[Asset, Balance]:
        """May raise RemoteError
        """
        try:
            accounts_data = response_dict['data']
        except KeyError as e:
            msg = 'Kucoin balances JSON response is missing data key'
            log.error(msg, response_dict)
            raise RemoteError(msg) from e

        assets_balance: DefaultDict[Asset, Balance] = defaultdict(Balance)
        for raw_result in accounts_data:
            try:
                amount = deserialize_asset_amount(raw_result['balance'])
                if amount == ZERO:
                    continue

                asset_symbol = raw_result['currency']
            except (KeyError, DeserializationError) as e:
                msg = str(e)
                if isinstance(e, KeyError):
                    msg = f'Missing key in account: {msg}.'

                log.error(
                    'Failed to deserialize a kucoin balance',
                    error=msg,
                    raw_result=raw_result,
                )
                self.msg_aggregator.add_error(
                    'Failed to deserialize a kucoin balance. Ignoring it.', )
                continue

            try:
                asset = asset_from_kucoin(asset_symbol)
            except DeserializationError as e:
                log.error(
                    'Unexpected asset symbol in a kucoin balance',
                    error=str(e),
                    raw_result=raw_result,
                )
                self.msg_aggregator.add_error(
                    'Failed to deserialize a kucoin balance. Ignoring it.', )
                continue
            except (UnknownAsset, UnsupportedAsset) as e:
                asset_tag = 'unknown' if isinstance(
                    e, UnknownAsset) else 'unsupported'
                self.msg_aggregator.add_warning(
                    f'Found {asset_tag} kucoin asset {e.asset_name} while deserializing '
                    f'a balance. Ignoring it.', )
                continue
            try:
                usd_price = Inquirer().find_usd_price(asset=asset)
            except RemoteError:
                self.msg_aggregator.add_error(
                    f'Failed to deserialize a kucoin balance after failing to '
                    f'request the USD price of {asset.identifier}. Ignoring it.',
                )
                continue

            assets_balance[asset] += Balance(
                amount=amount,
                usd_value=amount * usd_price,
            )

        return dict(assets_balance)
Exemplo n.º 4
0
        try:
            timestamp_ms = deserialize_timestamp(raw_result['createdAt'])
            timestamp = Timestamp(int(timestamp_ms / 1000))
            address = raw_result['address']
            # The transaction id can have an @ which we should just get rid of
            transaction_id = raw_result['walletTxId'].split('@')[0]
            amount = deserialize_asset_amount(raw_result['amount'])
            fee = deserialize_fee(raw_result['fee'])
            fee_currency_symbol = raw_result['currency']
            link_id = raw_result.get('id',
                                     '')  # NB: id only exists for withdrawals
        except KeyError as e:
            raise DeserializationError(f'Missing key: {str(e)}.') from e

        fee_asset = asset_from_kucoin(fee_currency_symbol)

        asset_movement = AssetMovement(
            timestamp=timestamp,
            location=Location.KUCOIN,
            category=category,
            address=address,
            transaction_id=transaction_id,
            asset=fee_asset,
            amount=amount,
            fee_asset=fee_asset,
            fee=fee,
            link=link_id,
        )
        return asset_movement