diff --git a/apps/dashboard_app/helpers/load_data.py b/apps/dashboard_app/helpers/load_data.py index 9a1b28a9..682315c3 100644 --- a/apps/dashboard_app/helpers/load_data.py +++ b/apps/dashboard_app/helpers/load_data.py @@ -20,7 +20,7 @@ get_supply_stats, get_utilization_stats, ) -from dashboard_app.helpers.tools import get_prices +from dashboard_app.helpers.tools import add_leading_zeros, get_prices logger = logging.getLogger(__name__) @@ -54,7 +54,9 @@ def _init_zklend_state(self) -> ZkLendState: logger.info("Initializing ZkLend state.") zklend_state = ZkLendState() start = monotonic() - zklend_data = self.data_connector.fetch_data(self.data_connector.ZKLEND_SQL_QUERY) + zklend_data = self.data_connector.fetch_data( + self.data_connector.ZKLEND_SQL_QUERY + ) zklend_interest_rate_data = self.data_connector.fetch_data( self.data_connector.ZKLEND_INTEREST_RATE_SQL_QUERY ) @@ -114,7 +116,7 @@ def _set_underlying_addresses_to_decimals(self): ) self.underlying_addresses_to_decimals.update( { - x.address: int(math.log10(x.decimal_factor)) + add_leading_zeros(x.address): int(math.log10(x.decimal_factor)) for x in TOKEN_SETTINGS.values() } ) diff --git a/apps/dashboard_app/helpers/protocol_stats.py b/apps/dashboard_app/helpers/protocol_stats.py index b79cfadf..af101c41 100644 --- a/apps/dashboard_app/helpers/protocol_stats.py +++ b/apps/dashboard_app/helpers/protocol_stats.py @@ -6,6 +6,7 @@ from collections import defaultdict from decimal import Decimal +import numpy as np import pandas as pd from data_handler.handlers import blockchain_call from shared.constants import TOKEN_SETTINGS @@ -16,7 +17,11 @@ get_protocol, get_supply_function_call_parameters, ) -from dashboard_app.helpers.tools import get_addresses, get_underlying_address +from dashboard_app.helpers.tools import ( + add_leading_zeros, + get_addresses, + get_underlying_address, +) def get_general_stats( @@ -116,7 +121,11 @@ def get_supply_stats( df = pd.DataFrame(data) df["Total supply (USD)"] = sum( df[column] - * Decimal(prices[TOKEN_SETTINGS[column.replace(" supply", "")].address]) + * Decimal( + prices[ + add_leading_zeros(TOKEN_SETTINGS[column.replace(" supply", "")].address) + ] + ) for column in df.columns if "supply" in column ).apply(lambda x: round(x, 4)) @@ -248,35 +257,48 @@ def get_utilization_stats( ) -> pd.DataFrame: """ Get utilization stats for the dashboard. - :param stats: DataFrame containing - general_stats, supply_stats, debt_stat. + :param general_stats: DataFrame containing general stats. + :param supply_stats: DataFrame containing supply stats. + :param debt_stats: DataFrame containing debt stats. :return: DataFrame with utilization stats """ + + general_stats.columns = general_stats.columns.str.lower() + supply_stats.columns = supply_stats.columns.str.lower() + debt_stats.columns = debt_stats.columns.str.lower() + + required_columns_general = {"protocol", "total debt (usd)"} + required_columns_supply = {"total supply (usd)"} + if not required_columns_general.issubset( + general_stats.columns + ) or not required_columns_supply.issubset(supply_stats.columns): + return pd.DataFrame() + data = pd.DataFrame( { - "Protocol": general_stats["Protocol"], - "Total utilization": general_stats["Total debt (USD)"] - / (general_stats["Total debt (USD)"] + supply_stats["Total supply (USD)"]), - "ETH utilization": debt_stats["ETH debt"] - / (supply_stats["ETH supply"] + debt_stats["ETH debt"]), - "WBTC utilization": debt_stats["WBTC debt"] - / (supply_stats.get("WBTC supply") + debt_stats.get("WBTC debt")), - "USDC utilization": debt_stats["USDC debt"] - / (supply_stats["USDC supply"] + debt_stats["USDC debt"]), - "DAI utilization": debt_stats["DAI debt"] - / (supply_stats["DAI supply"] + debt_stats["DAI debt"]), - "USDT utilization": debt_stats["USDT debt"] - / (supply_stats["USDT supply"] + debt_stats["USDT debt"]), - "wstETH utilization": debt_stats["wstETH debt"] - / (supply_stats["wstETH supply"] + debt_stats["wstETH debt"]), - "LORDS utilization": debt_stats["LORDS debt"] - / (supply_stats["LORDS supply"] + debt_stats["LORDS debt"]), - "STRK utilization": debt_stats["STRK debt"] - / (supply_stats["STRK supply"] + debt_stats["STRK debt"]), - }, + "Protocol": general_stats["protocol"], + } ) - utilization_columns = [x for x in data.columns if "utilization" in x] - # NOTE: .map doesn't work for some reason. apply works - data[utilization_columns] = data[utilization_columns].apply(lambda x: x.round(4)) - # data[utilization_columns] = data[utilization_columns].map(lambda x: round(x, 4)) + + total_debt = general_stats["total debt (usd)"].astype(float) + total_supply = supply_stats["total supply (usd)"].astype(float) + total_utilization = total_debt / (total_debt + total_supply) + total_utilization = total_utilization.replace([np.inf, -np.inf], 0).fillna(0) + data["Total utilization"] = total_utilization.round(4) + + tokens = ["eth", "wbtc", "usdc", "dai", "usdt", "wsteth", "lords", "strk"] + + for token in tokens: + debt_col = f"{token} debt" + supply_col = f"{token} supply" + + if debt_col in debt_stats.columns and supply_col in supply_stats.columns: + debt = debt_stats[debt_col].astype(float) + supply = supply_stats[supply_col].astype(float) + utilization = debt / (debt + supply) + utilization = utilization.replace([np.inf, -np.inf], 0).fillna(0) + data[f"{token.upper()} utilization"] = utilization.round(4) + else: + data[f"{token.upper()} utilization"] = 0.0 + return data diff --git a/apps/dashboard_app/helpers/tools.py b/apps/dashboard_app/helpers/tools.py index 376bd707..52016756 100644 --- a/apps/dashboard_app/helpers/tools.py +++ b/apps/dashboard_app/helpers/tools.py @@ -40,7 +40,7 @@ def get_collateral_token_range( collateral_token_price: float, ) -> list[float]: """ - Generates a range of prices for a collateral token and + Generates a range of prices for a collateral token and Returns: A list of float values representing the range of prices for the collateral token. """ target_number_of_values = 50 @@ -54,7 +54,7 @@ def get_collateral_token_range( difference = [ abs(50 - stop_price / (k * magnitude)) for k in step_factors ] # Stores the difference between the target value and - #number of values generated from each step factor. + # number of values generated from each step factor. readable_step = ( step_factors[difference.index(min(difference))] * magnitude ) # Gets readable step from step factor with values closest to the target value. @@ -98,19 +98,9 @@ def get_prices(token_decimals: dict[str, int]) -> dict[str, float]: tokens_info = response.json() - # Define the addresses for which you do not want to apply add_leading_zeros - skip_leading_zeros_addresses = { - TOKEN_SETTINGS["STRK"].address, - } - # Create a map of token addresses to token information, applying add_leading_zeros conditionally token_info_map = { - ( - token["address"] - if token["address"] in skip_leading_zeros_addresses - else add_leading_zeros(token["address"]) - ): token - for token in tokens_info + add_leading_zeros(token["address"]): token for token in tokens_info } prices = {} @@ -123,8 +113,11 @@ def get_prices(token_decimals: dict[str, int]) -> dict[str, float]: if decimals != token_info.get("decimals"): logging.error( - "Decimal mismatch for token %s: expected %d, got %d" - ,token, decimals, token_info.get('decimals')) + "Decimal mismatch for token %s: expected %d, got %d", + token, + decimals, + token_info.get("decimals"), + ) continue prices[token] = token_info.get("currentPrice")