research.vault_metrics

Documentation for eth_defi.research.vault_metrics Python module.

Vault metrics calculations.

Functions

analyse_vault(vault_db, prices_df, spec[, ...])

Create charts and tables to analyse a vault performance.

apply_abnormal_value_checks(risk, notes, flags)

Check for broken vaults by detecting abnormal metric values.

apply_morpho_not_in_api_check(risk, notes, flags)

Blacklist Morpho vaults missing from Morpho API.

calculate_cumulative_returns(cleaned_returns)

Takes a returns series and calculates cumulative returns.

calculate_daily_returns_for_all_vaults(df_work)

Calculate daily returns for each vault in isolation

calculate_hourly_returns_for_all_vaults(df_work)

Calculate hourly returns for each vault in isolation

calculate_lifetime_metrics(df, vault_db[, ...])

Calculate lifetime metrics for each vault in the provided DataFrame.

calculate_net_profit(start, end, ...[, ...])

Calculate profit after external fees have been reduced from the share price change.

calculate_net_returns_from_gross(name, ...)

Convert a cumulative gross return series to a cumulative net return series after fees.

calculate_net_returns_from_price(name, ...)

Convert a share price series to net return series after fees.

calculate_performance_metrics_for_all_vaults(...)

Calculate performance metrics for each vault.

calculate_period_metrics(period, ...[, ...])

Calculate metrics for one period.

calculate_returns(share_price[, freq])

Calculate returns from resampled share price series.

calculate_sharpe_ratio_from_returns(...[, ...])

Calculate annualized Sharpe ratio from hourly returns.

calculate_vault_rankings(results_df[, ...])

Calculate rankings for all periods inside PeriodMetrics objects.

calculate_vault_record(prices_df, ...[, ...])

Process a single vault metadata + prices to calculate its full data.

clean_lifetime_metrics(lifetime_data_df[, ...])

Clean lifetime data so we have only valid vaults.

combine_return_columns(gross, net[, ...])

Create combined net / (gross) returns column for display.

create_fee_label(fee_data)

Create 2% / 20% style labels to display variosu kinds of vault fees.

cross_check_data(vault_db, prices_df[, printer])

Check that VaultDatabase has metadata for all price_df vaults and vice versa.

display_lifetime_table(df)

Render a formatted lifetime table as compact HTML in a Jupyter notebook.

display_vault_chart_and_tearsheet(...[, render])

Render a chart and tearsheet for a single vault.

export_lifetime_row(row)

Export lifetime metrics row to a fully JSON-serializable dict.

fmt_one_decimal_or_int(x)

Display fees to .1 accuracy if there are .1 fractions, otherwise as int.

format_ffn_performance_stats(report[, ...])

Format FFN report for human readable output.

format_ffn_performance_stats_grouped(report)

Format FFN report as logically grouped sections.

format_lifetime_table(df[, add_index, ...])

Format table for human readable output.

format_vault_database(vault_db[, index])

Format vault database for human readable output.

format_vault_header(vault_row)

Format vault header for human readable output.

get_period_metrics(period_results, period)

Get PeriodMetrics for a specific period from the results list.

is_special_vault(protocol_slug, vault_address)

Check if a vault is a special vault that may not have deposit/redeem event data.

resample_returns(returns_1h[, freq])

Calculate returns from resampled returns series.

slugify_protocol(protocol)

Create a slug from protocol name for URLs.

slugify_vault(name, symbol, address, ...)

Create a slug from vault metadata for URLs.

slugify_vaults(vaults)

Create slugs for a set of vaults.

zero_out_near_zero_prices(s[, eps, ...])

Replace values with abs(x) < eps by 0.

Classes

ExportMetadata

Provenance metadata for the vault metrics JSON export.

ExportVersionMetadata

Git version stamp of the exporter Docker image.

NetflowMetrics

Deposit and withdrawal flow metrics for a time period.

PeriodMetrics

Tearsheet metrics for one period.

VaultMetricsExport

Top-level structure of the vault metrics JSON export.

VaultMetricsRecord

Per-vault record in the JSON export.

VaultReport

One vault data analysed

class ExportMetadata

Bases: TypedDict

Provenance metadata for the vault metrics JSON export.

Identifies which exporter build produced the file so stale deployments are diagnosable from the JSON alone.

__init__(*args, **kwargs)
__new__(**kwargs)
clear()

Remove all items from the dict.

copy()

Return a shallow copy of the dict.

fromkeys(value=None, /)

Create a new dictionary with keys from iterable and values set to value.

get(key, default=None, /)

Return the value for key if key is in the dictionary, else default.

items()

Return a set-like object providing a view on the dict’s items.

keys()

Return a set-like object providing a view on the dict’s keys.

pop(k[, d]) v, remove specified key and return the corresponding value.

If the key is not found, return the default if given; otherwise, raise a KeyError.

popitem()

Remove and return a (key, value) pair as a 2-tuple.

Pairs are returned in LIFO (last-in, first-out) order. Raises KeyError if the dict is empty.

setdefault(key, default=None, /)

Insert key with a value of default if key is not in the dictionary.

Return the value for key if key is in the dictionary, else default.

update([E, ]**F) None.  Update D from mapping/iterable E and F.

If E is present and has a .keys() method, then does: for k in E.keys(): D[k] = E[k] If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v In either case, this is followed by: for k in F: D[k] = F[k]

values()

Return an object providing a view on the dict’s values.

class ExportVersionMetadata

Bases: TypedDict

Git version stamp of the exporter Docker image.

Produced by eth_defi.version_info.VersionInfo.as_dict(). All fields are None when the exporter runs outside a stamped Docker image, e.g. from a source checkout. Individual fields can also be None inside a stamped image when the corresponding build ARG was not passed.

__init__(*args, **kwargs)
__new__(**kwargs)
clear()

Remove all items from the dict.

copy()

Return a shallow copy of the dict.

fromkeys(value=None, /)

Create a new dictionary with keys from iterable and values set to value.

get(key, default=None, /)

Return the value for key if key is in the dictionary, else default.

items()

Return a set-like object providing a view on the dict’s items.

keys()

Return a set-like object providing a view on the dict’s keys.

pop(k[, d]) v, remove specified key and return the corresponding value.

If the key is not found, return the default if given; otherwise, raise a KeyError.

popitem()

Remove and return a (key, value) pair as a 2-tuple.

Pairs are returned in LIFO (last-in, first-out) order. Raises KeyError if the dict is empty.

setdefault(key, default=None, /)

Insert key with a value of default if key is not in the dictionary.

Return the value for key if key is in the dictionary, else default.

update([E, ]**F) None.  Update D from mapping/iterable E and F.

If E is present and has a .keys() method, then does: for k in E.keys(): D[k] = E[k] If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v In either case, this is followed by: for k in F: D[k] = F[k]

values()

Return an object providing a view on the dict’s values.

class NetflowMetrics

Bases: object

Deposit and withdrawal flow metrics for a time period.

Aggregates daily deposit/withdrawal event counts and USD values over a given period (e.g. "1d", "7d", "30d").

Only available for chains that support vault flow tracking (currently Hyperliquid). For other chains this will be None in the vault record.

__init__(period, deposit_count=0, withdrawal_count=0, deposit_usd=0.0, withdrawal_usd=0.0, net_flow_usd=0.0)
Parameters
  • period (str) –

  • deposit_count (int) –

  • withdrawal_count (int) –

  • deposit_usd (float) –

  • withdrawal_usd (float) –

  • net_flow_usd (float) –

Return type

None

class PeriodMetrics

Bases: object

Tearsheet metrics for one period.

__init__(period, error_reason=None, period_start_at=None, period_end_at=None, share_price_start=None, share_price_end=None, raw_samples=0, samples_start_at=None, samples_end_at=None, daily_samples=0, returns_gross=None, returns_net=None, cagr_gross=None, cagr_net=None, volatility=None, sharpe=None, max_drawdown=None, tvl_start=None, tvl_end=None, tvl_low=None, tvl_high=None, ranking_overall=None, ranking_chain=None, ranking_protocol=None, avg_utilisation=None)
Parameters
Return type

None

class VaultMetricsExport

Bases: TypedDict

Top-level structure of the vault metrics JSON export.

Describes the shape of top_vaults_by_chain.json uploaded to R2.

__init__(*args, **kwargs)
__new__(**kwargs)
clear()

Remove all items from the dict.

copy()

Return a shallow copy of the dict.

fromkeys(value=None, /)

Create a new dictionary with keys from iterable and values set to value.

get(key, default=None, /)

Return the value for key if key is in the dictionary, else default.

items()

Return a set-like object providing a view on the dict’s items.

keys()

Return a set-like object providing a view on the dict’s keys.

pop(k[, d]) v, remove specified key and return the corresponding value.

If the key is not found, return the default if given; otherwise, raise a KeyError.

popitem()

Remove and return a (key, value) pair as a 2-tuple.

Pairs are returned in LIFO (last-in, first-out) order. Raises KeyError if the dict is empty.

setdefault(key, default=None, /)

Insert key with a value of default if key is not in the dictionary.

Return the value for key if key is in the dictionary, else default.

update([E, ]**F) None.  Update D from mapping/iterable E and F.

If E is present and has a .keys() method, then does: for k in E.keys(): D[k] = E[k] If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v In either case, this is followed by: for k in F: D[k] = F[k]

values()

Return an object providing a view on the dict’s values.

class VaultMetricsRecord

Bases: TypedDict

Per-vault record in the JSON export.

Uses total=False so that only the most critical fields are typed explicitly — remaining fields are still present but not enforced by the type checker. This is an incremental approach; more fields can be promoted to required as the schema stabilises.

__init__(*args, **kwargs)
__new__(**kwargs)
clear()

Remove all items from the dict.

copy()

Return a shallow copy of the dict.

fromkeys(value=None, /)

Create a new dictionary with keys from iterable and values set to value.

get(key, default=None, /)

Return the value for key if key is in the dictionary, else default.

items()

Return a set-like object providing a view on the dict’s items.

keys()

Return a set-like object providing a view on the dict’s keys.

pop(k[, d]) v, remove specified key and return the corresponding value.

If the key is not found, return the default if given; otherwise, raise a KeyError.

popitem()

Remove and return a (key, value) pair as a 2-tuple.

Pairs are returned in LIFO (last-in, first-out) order. Raises KeyError if the dict is empty.

setdefault(key, default=None, /)

Insert key with a value of default if key is not in the dictionary.

Return the value for key if key is in the dictionary, else default.

update([E, ]**F) None.  Update D from mapping/iterable E and F.

If E is present and has a .keys() method, then does: for k in E.keys(): D[k] = E[k] If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v In either case, this is followed by: for k in F: D[k] = F[k]

values()

Return an object providing a view on the dict’s values.

class VaultReport

Bases: object

One vault data analysed

__init__(vault_metadata, rolling_returns_chart, performance_stats, daily_returns, hourly_returns, hourly_df)
Parameters
  • vault_metadata (dict) –

  • rolling_returns_chart (plotly.graph_objs._figure.Figure) –

  • performance_stats (ffn.core.PerformanceStats) –

  • daily_returns (pandas.Series) –

  • hourly_returns (pandas.Series) –

  • hourly_df (pandas.DataFrame) –

Return type

None

analyse_vault(vault_db, prices_df, spec, returns_col='returns_1h', logger=<built-in function print>, chart_frequency='daily')

Create charts and tables to analyse a vault performance.

  • We plot our annualised 1 month rolling returns on the chart, to see how vaults move in the direction of the markets, or what kind of outliers there are

Parameters
  • vault_db (eth_defi.vault.vaultdb.VaultDatabase) – Database of all vault metadata

  • price_df

    Cleaned price and returns data for all vaults.

    Can be be in any time frame.

  • id – Vault chain + address to analyse, e.g. “1-0x1234567890abcdef1234567890abcdef12345678”

  • chart_frequency (Literal['hourly', 'daily']) –

    Do we plot based on daily or hourly datapoints.

    Hourly data has too many points, chocking Plotly.

  • prices_df (pandas.DataFrame) –

  • spec (eth_defi.vault.base.VaultSpec) –

  • returns_col (str) –

Returns

Analysis report to display.

None if the vault does not have price data.

Return type

Optional[eth_defi.research.vault_metrics.VaultReport]

apply_abnormal_value_checks(risk, notes, flags, current_nav=None, current_share_price=None, three_months_volatility=None)

Check for broken vaults by detecting abnormal metric values.

Automatically blacklists vaults with unrealistic TVL, share price, or volatility. These thresholds catch broken smart contracts and low-TVL vaults that produce meaningless metrics.

Called multiple times as more metrics become available (first with NAV/price, then again after 3M volatility is computed).

Parameters
  • risk (eth_defi.vault.risk.VaultTechnicalRisk) – Current risk classification.

  • notes (str) – Current notes string.

  • flags (set[eth_defi.vault.flag.VaultFlag]) – Current vault flags set.

  • current_nav (Optional[float]) – Current TVL in USD. Checked against MAX_VALID_NAV.

  • current_share_price (Optional[float]) – Current share price. Checked against MAX_VALID_SHARE_PRICE.

  • three_months_volatility (Optional[float]) – 3-month annualised volatility. Checked against MAX_VALID_VOLATILITY. Catches low-TVL Hyperliquid vaults with one or few trades that produce extreme volatility numbers.

Returns

Updated (risk, notes, flags) tuple.

Return type

tuple[eth_defi.vault.risk.VaultTechnicalRisk, str, set[eth_defi.vault.flag.VaultFlag]]

apply_morpho_not_in_api_check(risk, notes, flags)

Blacklist Morpho vaults missing from Morpho API.

Dynamic scan flags are not visible to get_vault_risk(), because that helper only reads the static manual flag table. This helper handles the Morpho-specific dynamic blacklist flag before metrics export.

Parameters
Returns

Updated risk, notes, and flags.

Return type

tuple[eth_defi.vault.risk.VaultTechnicalRisk | None, str | None, set[eth_defi.vault.flag.VaultFlag]]

calculate_cumulative_returns(cleaned_returns, freq='D')

Takes a returns series and calculates cumulative returns.

Parameters

cleaned_returns (pandas.Series) –

calculate_daily_returns_for_all_vaults(df_work)

Calculate daily returns for each vault in isolation

Parameters

df_work (pandas.DataFrame) –

Return type

pandas.DataFrame

calculate_hourly_returns_for_all_vaults(df_work)

Calculate hourly returns for each vault in isolation

Parameters

df_work (pandas.DataFrame) –

Return type

pandas.DataFrame

calculate_lifetime_metrics(df, vault_db, returns_column='returns_1h', core3_protocols=None)

Calculate lifetime metrics for each vault in the provided DataFrame.

  • All-time returns

  • 3M returns, latest

  • 1M returns, latest

  • Volatility (3M)

Lookback based on the last entry.

Parameters
Returns

DataFrame, one row per vault.

Return type

pandas.DataFrame

calculate_net_profit(start, end, share_price_start, share_price_end, management_fee_annual, performance_fee, deposit_fee, withdrawal_fee, seconds_in_year=31557600.0, sample_count=None)

Calculate profit after external fees have been reduced from the share price change.

Parameters
  • start (datetime.datetime) – Start datetime of the investment period.

  • end (datetime.datetime) – End datetime of the investment period.

  • share_price_start (float) – Share price at the start of the investment period.

  • share_price_end (float) – Share price at the end of the investment period.

  • management_fee_annual (float) – Annual management fee as a percent (0.02 = 2% per year).

  • performance_fee (float) – Performance fee as a percent (0.20 = 20% of profits).

  • deposit_fee (Optional[float]) – Deposit fee as a percent (0.01 = 1% fee), or None if no fee.

  • withdrawal_fee (Optional[float]) – Withdrawal fee as a percent (0.01 = 1% fee), or None if no fee.

  • sample_count (Optional[int]) – If we have not enough returns data, do not try to calculate profit.

Returns

Net profit as a floating point (0.10 = 10% profit).

Return type

float

calculate_net_returns_from_gross(name, cumulative_returns, management_fee_annual, performance_fee, deposit_fee, withdrawal_fee, seconds_in_year=31557600.0)

Convert a cumulative gross return series to a cumulative net return series after fees.

This function correctly models a High-Water Mark (HWM) for performance fees, which requires an iterative calculation (a loop). This loop operates on Numpy arrays for maximum speed.

  • Management fees are accrued based on the time delta of each period.

  • Performance fees are charged only on profits above the highest net value.

  • Deposit fees are applied once at the start (t=0).

  • Withdrawal fees are applied once at the end (t=T).

Parameters
  • name (str) – Name for the returned pandas Series.

  • cumulative_returns (pandas.Series) – A pandas Series with a DatetimeIndex representing the cumulative gross return index (e.g., 1.0, 1.02, 1.05) OR cumulative gross profit (e.g., 0.0, 0.02, 0.05).

  • management_fee_annual (Optional[float]) – Annual management fee as a decimal (e.g., 0.02 for 2%).

  • performance_fee (Optional[float]) – Performance fee as a decimal (e.g., 0.20 for 20% of profits above the High-Water Mark).

  • deposit_fee (Optional[float]) – Fee applied to the initial deposit as a decimal (e.g., 0.01 for 1%).

  • withdrawal_fee (Optional[float]) – Fee applied to the final withdrawal as a decimal (e.g., 0.01 for 1%).

  • seconds_in_year – The number of seconds in a year for precise management fee accrual.

Returns

A pandas Series of the cumulative net profit (e.g., 0.10 for 10%).

Return type

pandas.Series

calculate_net_returns_from_price(name, share_price, management_fee_annual, performance_fee, deposit_fee, withdrawal_fee, seconds_in_year=31557600.0, zero_epsilon=0.001, freq='h')

Convert a share price series to net return series after fees.

Parameters
  • name (str) – For debugging

  • share_price (pandas.Series) – Share price series with datetime index.

  • management_fee_annual (Optional[float]) – Annual management fee as a percent (0.02 = 2% per year).

  • performance_fee (Optional[float]) – Performance fee as a percent (0.20 = 20% of profits).

  • deposit_fee (Optional[float]) – Deposit fee as a percent (0.01 = 1% fee), or None if no fee.

  • withdrawal_fee (Optional[float]) – Withdrawal fee as a percent (0.01 = 1% fee), or None if no fee.

  • freq – The time series frequency (hourly, daily, etc) for management fee calculation.

Returns

Cumulative net profit as a floating point (0.10 = 10% profit).

Return type

pandas.Series

calculate_performance_metrics_for_all_vaults(vault_db, prices_df, logger=<built-in function print>, lifetime_min_nav_threshold=100.0, broken_max_nav_value=99000000000, cagr_too_high=10000, min_events=25)

Calculate performance metrics for each vault.

  • Only applicable to stablecoin vaults as cleaning units are in USD

  • Clean up idle vaults that have never seen enough events to be considered active

  • Calculate lifetime returns, CAGR, NAV, etc.

  • Filter out results with abnormal values

Returns

DataFrame with lifetime metrics for each vault, indexed by vault name.

Parameters
Return type

pandas.DataFrame

calculate_period_metrics(period, gross_fee_data, net_fee_data, share_price_hourly, share_price_daily, tvl, now_, utilisation=None)

Calculate metrics for one period.

Parameters
  • period (Literal['1W', '1M', '3M', '6M', '1Y', 'lifetime']) – Period identifier (1W, 1M, 3M, 6M, 1Y, lifetime)

  • gross_fee_data (eth_defi.vault.fee.FeeData) – Fee data before fee mode adjustments

  • net_fee_data (eth_defi.vault.fee.FeeData) – Fee data after fee mode adjustments (for net return calculations)

  • share_price_hourly (pandas.Series) – Hourly share price series with DatetimeIndex

  • share_price_daily (pandas.Series) – Daily share price series with DatetimeIndex

  • tvl (pandas.Series) – Total value locked series with DatetimeIndex

  • now – The reference timestamp (usually the last timestamp in the data)

  • utilisation (Optional[pandas.Series]) – Optional utilisation series (lending vaults only, values 0.0–1.0). When provided, avg_utilisation is computed for the period window.

  • now_ (pandas.Timestamp) –

Returns

PeriodMetrics dataclass with calculated metrics

Return type

eth_defi.research.vault_metrics.PeriodMetrics

calculate_returns(share_price, freq='D')

Calculate returns from resampled share price series.

Parameters

share_price (pandas.Series) –

Return type

pandas.Series

calculate_sharpe_ratio_from_returns(hourly_returns, risk_free_rate=0.0, year_multiplier=365)

Calculate annualized Sharpe ratio from hourly returns.

Parameters
  • hourly_returns (pandas.Series) – Pandas Series of hourly percentage returns.

  • risk_free_rate (float) – Annualized risk-free rate (default 2%).

  • year_multiplier (float) –

Returns

Sharpe ratio as a float.

Return type

float

calculate_vault_rankings(results_df, min_tvl_chain_protocol=10000, min_tvl_overall=50000)

Calculate rankings for all periods inside PeriodMetrics objects.

Updates PeriodMetrics objects in-place within the period_results lists. Rankings are calculated for all 6 periods (1W, 1M, 3M, 6M, 1Y, lifetime).

Vaults are excluded from rankings if: - They have no CAGR data (zero or NaN) - They have an error_reason set - They are blacklisted (risk == VaultTechnicalRisk.blacklisted) - Their period TVL is below the threshold

Parameters
  • results_df (pandas.DataFrame) – DataFrame from calculate_lifetime_metrics()

  • min_tvl_chain_protocol (float) – Minimum TVL required for chain and protocol rankings (default: $10,000)

  • min_tvl_overall (float) – Minimum TVL required for overall rankings (default: $50,000)

Returns

DataFrame with rankings updated in PeriodMetrics objects

Return type

pandas.DataFrame

calculate_vault_record(prices_df, vault_metadata_rows, month_ago, three_months_ago, vault_id=None, core3_protocols=None)

Process a single vault metadata + prices to calculate its full data.

  • Exported to frontend, everything

Parameters
Returns

Series with calculated metrics

Return type

pandas.Series

clean_lifetime_metrics(lifetime_data_df, broken_max_nav_value=99000000000, lifetime_min_nav_threshold=100.0, max_annualised_return=3.0, min_events=25, logger=<built-in function print>)

Clean lifetime data so we have only valid vaults.

Returns

Cleaned lifetime dataframe

Parameters

lifetime_data_df (pandas.DataFrame) –

Return type

pandas.DataFrame

combine_return_columns(gross, net, new_line=' ', mode='percent', profit_presentation='split')

Create combined net / (gross) returns column for display.

E.g. 8.3% (10.5%)

Parameters
Returns

Combined string series

create_fee_label(fee_data)

Create 2% / 20% style labels to display variosu kinds of vault fees.

Order is: management / performance / deposit / withdrawal fees.

Parameters

fee_data (eth_defi.vault.fee.FeeData) –

cross_check_data(vault_db, prices_df, printer=<built-in function print>)

Check that VaultDatabase has metadata for all price_df vaults and vice versa.

Returns

Number of problem entries.

Should be zero.

Parameters
Return type

int

display_lifetime_table(df)

Render a formatted lifetime table as compact HTML in a Jupyter notebook.

Produces an HTML table with minimal cell padding and renders <a> links created by format_lifetime_table() with html_links=True.

Example:

formatted = format_lifetime_table(df, html_links=True)
display_lifetime_table(formatted)
Parameters

df (pandas.DataFrame) – DataFrame returned by format_lifetime_table().

display_vault_chart_and_tearsheet(vault_spec, vault_db, prices_df, render=True)

Render a chart and tearsheet for a single vault.

  • Use in notebooks

:param render;

Disable rendering in tests

Parameters
export_lifetime_row(row)

Export lifetime metrics row to a fully JSON-serializable dict.

  • Recursively handles nested dicts, lists, tuples, sets, and dataclasses.

  • Normalizes pandas, numpy, datetime, and custom types.

  • Preserves legacy fee field names.

Parameters

row (pandas.Series) –

Return type

dict

fmt_one_decimal_or_int(x)

Display fees to .1 accuracy if there are .1 fractions, otherwise as int.

Parameters

x (Optional[float]) –

Return type

str

format_ffn_performance_stats(report, prefix_series=None)

Format FFN report for human readable output.

  • Return a Series with formatted performance metrics

  • Multiple series can be combined to a comparison table

Parameters
  • prefix_data – Extra header data to insert.

  • report (ffn.core.PerformanceStats) – FFN performance report to format

  • prefix_series (Optional[pandas.Series]) –

Returns

DataFrame with formatted performance metrics

Return type

pandas.Series

format_ffn_performance_stats_grouped(report, prefix_series=None)

Format FFN report as logically grouped sections.

Returns a list of (heading, series) tuples where each tuple represents a group of related metrics. The groups correspond to the None separators in FFN’s PerformanceStats._stats().

Parameters
  • report (ffn.core.PerformanceStats) – FFN performance report to format.

  • prefix_series (Optional[pandas.Series]) – Extra header data to prepend to the first group.

Returns

List of (heading, series) tuples for each logical group.

Return type

list[tuple[str, pandas.Series]]

format_lifetime_table(df, add_index=False, add_address=False, add_share_token=False, drop_blacklisted=True, profit_presentation='split', html_links=False)

Format table for human readable output.

See calculate_lifetime_metrics()

Parameters
  • add_index – Add 1, 2, 3… index column

  • add_address

    Add address as a separate column.

    For vault address list copy-pasted.

  • drop_blacklisted – Remove vaults we have manually flagged as troublesome.

  • html_links

    Wrap Name, Chain, and Protocol values in <a> tags linking to tradingstrategy.ai. Use display_lifetime_table() to render the result with compact styling in a Jupyter notebook.

    Example:

    from eth_defi.research.vault_metrics import (
        format_lifetime_table,
        display_lifetime_table,
    )
    
    formatted = format_lifetime_table(df, html_links=True)
    display_lifetime_table(formatted)
    

  • df (pandas.DataFrame) –

  • profit_presentation (Literal['split', 'net_only']) –

Returns

Human readable data frame

Return type

pandas.DataFrame

format_vault_database(vault_db, index=True)

Format vault database for human readable output.

Parameters

vault_db (eth_defi.vault.vaultdb.VaultDatabase) – Vault database to format

Returns

DataFrame with vault metadata, with human readable columns

Return type

pandas.DataFrame

format_vault_header(vault_row)

Format vault header for human readable output.

See format_vault_database()

Returns

DataFrame with formatted performance metrics

Parameters

vault_row (pandas.Series) –

Return type

pandas.Series

get_period_metrics(period_results, period)

Get PeriodMetrics for a specific period from the results list.

Parameters
Returns

The matching PeriodMetrics or None if not found

Return type

Optional[eth_defi.research.vault_metrics.PeriodMetrics]

is_special_vault(protocol_slug, vault_address)

Check if a vault is a special vault that may not have deposit/redeem event data.

  • GRVT and Hyperliquid vaults get data from off-chain APIs

  • Hardcoded protocol vaults may lack standard ERC-4626 deposit/redeem events

Parameters
  • protocol_slug (str) – Protocol slug (e.g. “grvt”, “hyperliquid”, “morpho”)

  • vault_address (str) – Vault contract address

Returns

True if this vault should bypass the minimum event count filter

Return type

bool

resample_returns(returns_1h, freq='D')

Calculate returns from resampled returns series.

Parameters

returns_1h (pandas.Series) – The original returns series.

Return type

pandas.Series

slugify_protocol(protocol)

Create a slug from protocol name for URLs.

Parameters

protocol (str) – The protocol name.

Return type

str

slugify_vault(name, symbol, address, existing_slugs)

Create a slug from vault metadata for URLs.

Parameters
Return type

str

slugify_vaults(vaults)

Create slugs for a set of vaults.

  • Always give the primary slug to the vault that was created first.

  • Mutates VaultRow data in-place

Parameters

vaults (dict[eth_defi.vault.base.VaultSpec, eth_defi.vault.vaultdb.VaultRow]) – The vault metadata entries.

Return type

Optional[list[eth_defi.vault.vaultdb.VaultRow]]

zero_out_near_zero_prices(s, eps=1e-09, clip_negatives=True)

Replace values with abs(x) < eps by 0. Optionally clip negatives to 0.

Keeps NaN as-is, turns +/- inf into NaN.

Parameters
Return type

pandas.Series