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', ))
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
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)
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