hyperliquid.daily_metrics
Documentation for eth_defi.hyperliquid.daily_metrics Python module.
Hyperliquid daily vault metrics with DuckDB storage.
This module provides a daily pipeline for scanning Hyperliquid native vault
metrics and storing them in a DuckDB database. It computes ERC-4626-style
share prices using the time-weighted return approach, reusing the share
price calculation from eth_defi.hyperliquid.combined_analysis.
The pipeline:
Bulk-fetches all vaults from the stats-data API
Filters by TVL and open status
Fetches per-vault portfolio history via
vaultDetailsComputes share prices from portfolio history
Stores daily prices and metadata in DuckDB
Example:
from eth_defi.hyperliquid.session import create_hyperliquid_session
from eth_defi.hyperliquid.daily_metrics import run_daily_scan, HyperliquidDailyMetricsDatabase
session = create_hyperliquid_session(requests_per_second=2.75)
db = run_daily_scan(session, min_tvl=5_000, max_vaults=500)
print(f"Stored metrics for {db.get_vault_count()} vaults")
db.close()
Functions
|
Fetch a single vault's details and store metrics in the database. |
Convert vaultDetails portfolio history into a combined DataFrame with share prices. |
|
|
Run the daily Hyperliquid vault metrics scan. |
Classes
DuckDB database for storing Hyperliquid vault daily metrics. |
|
A single Hyperliquid daily price row ready for DuckDB upsert. |
- class HyperliquidDailyPriceRow
Bases:
objectA single Hyperliquid daily price row ready for DuckDB upsert.
- __init__(vault_address, date, share_price, tvl, cumulative_pnl, cumulative_volume=None, daily_pnl=0.0, daily_return=0.0, follower_count=None, apr=None, is_closed=None, allow_deposits=None, leader_fraction=None, leader_commission=None, daily_deposit_count=None, daily_withdrawal_count=None, daily_deposit_usd=None, daily_withdrawal_usd=None, epoch_reset=None, data_source='api')
- Parameters
vault_address (eth_typing.evm.HexAddress) –
date (datetime.date) –
share_price (float) –
tvl (float) –
cumulative_pnl (float) –
cumulative_volume (float | None) –
daily_pnl (float) –
daily_return (float) –
follower_count (int | None) –
apr (float | None) –
is_closed (bool | None) –
allow_deposits (bool | None) –
leader_fraction (float | None) –
leader_commission (float | None) –
daily_deposit_count (int | None) –
daily_withdrawal_count (int | None) –
daily_deposit_usd (float | None) –
daily_withdrawal_usd (float | None) –
epoch_reset (bool | None) –
data_source (str) –
- Return type
None
- portfolio_to_combined_dataframe(portfolio_all_time=None, *, portfolio=None)
Convert vaultDetails portfolio history into a combined DataFrame with share prices.
Derives
pnl_updateandnetflow_updatefrom the portfolio history, then feeds them through_calculate_share_price()to compute ERC-4626-style share prices.When
portfolio(the full period dict) is provided, all available periods (day,week,month,allTime) are merged to produce a higher-resolution time series. This yields more data points for recent history compared to usingallTimealone.The derivation:
pnl_update[i] = pnl_history[i] - pnl_history[i-1]netflow_update[i] = (account_value[i] - account_value[i-1]) - pnl_update[i]cumulative_account_value[i] = account_value[i]
- Parameters
portfolio_all_time (eth_defi.hyperliquid.vault.PortfolioHistory | None) – The
allTimePortfolioHistoryfromvaultDetailsendpoint. Kept for backward compatibility.portfolio (dict[str, eth_defi.hyperliquid.vault.PortfolioHistory] | None) – Full portfolio period dict from
VaultInfo.portfolio. When provided, all periods are merged for higher resolution. Takes precedence overportfolio_all_time.
- Returns
DataFrame with timestamp index and columns:
pnl_update,netflow_update,cumulative_pnl,cumulative_netflow,cumulative_account_value,total_assets,total_supply,share_price,epoch_reset- Return type
- class HyperliquidDailyMetricsDatabase
Bases:
objectDuckDB database for storing Hyperliquid vault daily metrics.
Stores daily share price time series and vault metadata. The share prices are computed using time-weighted returns from the Hyperliquid API portfolio history.
Example:
from pathlib import Path from eth_defi.hyperliquid.daily_metrics import HyperliquidDailyMetricsDatabase db = HyperliquidDailyMetricsDatabase(Path("/tmp/metrics.duckdb")) # Query vault data df = db.get_all_daily_prices() print(df) db.close()Initialise the database connection.
- Parameters
path – Path to the DuckDB file. Parent directories will be created if needed.
- __init__(path)
Initialise the database connection.
- Parameters
path (pathlib.Path) – Path to the DuckDB file. Parent directories will be created if needed.
- upsert_vault_metadata(vault_address, name, leader, description, is_closed, relationship_type, create_time, commission_rate, follower_count, tvl, apr, allow_deposits=True, flow_data_earliest_date=None)
Insert or update a vault’s metadata.
- Parameters
vault_address (eth_typing.evm.HexAddress) – Vault address (will be lowercased).
flow_data_earliest_date (datetime.date | None) – Earliest date for which daily deposit/withdrawal flow data has been backfilled.
Nonemeans no flow data yet.name (str) –
leader (eth_typing.evm.HexAddress) –
description (str | None) –
is_closed (bool) –
relationship_type (str) –
create_time (datetime.datetime | None) –
commission_rate (float | None) –
follower_count (int | None) –
tvl (float | None) –
apr (float | None) –
allow_deposits (bool) –
- update_vault_tvl_bulk(updates)
Bulk-update TVL, is_closed, and APR for existing vaults.
Only updates rows that already exist in
vault_metadata. Does not insert new rows. Used to refresh TVL for vaults that fell below the processing threshold but still appear in the bulk stats-data API.
- mark_vaults_disappeared(known_addresses)
Set TVL to zero for vaults that have disappeared from the API.
For any vault in
vault_metadatawhose address is NOT inknown_addresses, setstvl=0. Does not changeis_closed— disappearing from the bulk listing does not necessarily mean the vault is permanently closed.
- upsert_daily_prices(rows, cutoff_date=None)
Bulk upsert daily price rows for a vault.
- Parameters
rows (list[eth_defi.hyperliquid.daily_metrics.HyperliquidDailyPriceRow]) –
List of
HyperliquidDailyPriceRowitems.The
is_closed,allow_deposits,leader_fraction, andleader_commissionfields should beNonefor historical rows and only set for the latest (today’s) row, so that we track how these values evolve over time.The flow columns (
daily_deposit_countetc.) should beNonefor dates outside the backfill window and0for dates with no activity within the backfill window.COALESCEpreserves existing values whenNoneis passed.cutoff_date (datetime.date | None) – If provided, only store rows up to this date (inclusive). Used for incremental scanning / testing.
- get_all_daily_prices()
Get all daily price data across all vaults.
- Returns
DataFrame with all daily price records, ordered by vault then date.
- Return type
- get_vault_daily_prices(vault_address)
Get daily price data for a specific vault.
- Parameters
vault_address (eth_typing.evm.HexAddress) – Vault address to query.
- Returns
DataFrame with price records for this vault, ordered by date.
- Return type
- get_existing_dates(vault_address)
Get all dates with existing data for a vault.
- Parameters
vault_address (eth_typing.evm.HexAddress) – Vault address to query.
- Returns
Set of dates that already have data in the database.
- Return type
- get_all_vault_metadata()
Get metadata for all vaults.
- Returns
DataFrame with one row per vault.
- Return type
- get_recently_tracked_addresses(within_days=4)
Return vault addresses that have price data recorded within the last within_days days.
Used to identify vaults that recently dropped below the TVL processing threshold but still need a few more daily bars to capture the closing share price at near-zero TVL.
- get_vault_daily_price_count(vault_address)
Get the number of daily price records for a vault.
- Parameters
vault_address (eth_typing.evm.HexAddress) – Vault address to query.
- Returns
Number of daily price records.
- Return type
- get_vault_last_date(vault_address)
Get the last date with price data for a vault.
- Parameters
vault_address (eth_typing.evm.HexAddress) – Vault address to query.
- Returns
The latest date, or None if no data.
- Return type
datetime.date | None
- get_latest_leader_fractions()
Get the latest leader_fraction for each vault.
Queries the most recent row per vault that has a non-NULL
leader_fractionvalue.
- get_leader_fraction_history(vault_address)
Get the recorded leader_fraction snapshots for a vault.
Returns only rows where
leader_fractionwas recorded (non-NULL). Each row represents a day when the scanner ran and observed the value. Over time, daily scans build up a sparse history of leader capital ownership that can be used to detect threshold crossings.- Parameters
vault_address (str) – Vault address to query (will be lowercased).
- Returns
DataFrame with columns
dateandleader_fraction, ordered by date ascending. Empty if no snapshots recorded.- Return type
- delete_vault_daily_prices(vault_address)
Delete all daily price records for a vault.
Used by the healing script to clear corrupted share prices before re-computing from fresh API data.
- Parameters
vault_address (eth_typing.evm.HexAddress) – Vault address to delete.
- Returns
Number of rows deleted.
- Return type
Recompute share prices for a vault from stored tvl/pnl data.
Uses the stored
tvl(total_assets),daily_pnl(pnl_update), andcumulative_pnlcolumns to reconstructnetflow_update, then feeds the data through_calculate_share_price()with the current chain-linked epoch reset logic.This allows healing of share price data without re-fetching from the Hyperliquid API.
- Parameters
vault_address (eth_typing.evm.HexAddress) – Vault address to recompute.
- Returns
Dict with before/after statistics:
{"rows": int, "old_sp_min": float, "old_sp_max": float, "new_sp_min": float, "new_sp_max": float, "epoch_resets": int, "changed_rows": int}- Return type
Recompute share prices for all vaults in the database.
Iterates over every vault and calls
recompute_vault_share_prices()for each.- Returns
Summary dict:
{"total_vaults": int, "vaults_with_changes": int, "vaults_with_epoch_resets": int, "total_changed_rows": int, "per_vault": dict[str, dict]}- Return type
- detect_broken_vaults()
Detect vaults with anomalous share price data.
Checks for four classes of breakage:
Extreme daily returns (> 10,000%): typically epoch reset artefacts where share price jumped to/from 1.0
Share price at cap (>= 9,999): overflow from zero total_supply
Share price stuck at 1.0: share price identical for 5+ rows, suggesting failed epoch reset logic
Missing epoch_reset column: rows computed with old code that lacked the
epoch_resetcolumn (all NULL)
- Returns
DataFrame with columns:
vault_address,name,issue_type,affected_rows,example_value- Return type
- save()
Force a checkpoint to ensure data is written to disk.
- close()
Close the database connection.
- fetch_and_store_vault(session, db, summary, cutoff_date=None, timeout=30.0, flow_backfill_days=7)
Fetch a single vault’s details and store metrics in the database.
- Parameters
session (eth_defi.hyperliquid.session.HyperliquidSession) – HTTP session with rate limiting.
db (eth_defi.hyperliquid.daily_metrics.HyperliquidDailyMetricsDatabase) – The metrics database to write into.
summary (eth_defi.hyperliquid.vault.VaultSummary) – Vault summary from the bulk listing.
cutoff_date (datetime.date | None) – If provided, only store price data up to this date.
timeout (float) – HTTP request timeout.
flow_backfill_days (int) – Number of complete days to backfill deposit/withdrawal flow data. Only complete days are fetched (up to yesterday). Set to
0to disable flow fetching.
- Returns
True if the vault was successfully processed.
- Return type
- run_daily_scan(session, db_path=PosixPath('/home/runner/.tradingstrategy/vaults/hyperliquid-vaults.duckdb'), min_tvl=5000, max_vaults=20000, max_workers=16, cutoff_date=None, timeout=30.0, vault_addresses=None, flow_backfill_days=7)
Run the daily Hyperliquid vault metrics scan.
Bulk-fetches all vaults from stats-data API
Filters by TVL and vault limit (or by explicit address list)
Fetches per-vault details and computes share prices
Fetches deposit/withdrawal events for flow metrics
Stores everything in DuckDB
- Parameters
session (eth_defi.hyperliquid.session.HyperliquidSession) – HTTP session with rate limiting. Use
create_hyperliquid_session().db_path (pathlib.Path) – Path to the DuckDB database file.
min_tvl (float) – Minimum TVL in USD to include a vault. Ignored when
vault_addressesis provided.max_vaults (int) – Maximum number of vaults to process (sorted by TVL descending). Ignored when
vault_addressesis provided.max_workers (int) – Number of parallel workers for fetching vault details.
cutoff_date (datetime.date | None) – If provided, only store price data up to this date. Used for incremental scanning / testing.
timeout (float) – HTTP request timeout.
vault_addresses (list[str] | None) – If provided, only scan these specific vault addresses. Overrides
min_tvlandmax_vaultsfilters.flow_backfill_days (int) – Number of complete days to backfill deposit/withdrawal flow data. Only complete days are fetched (up to yesterday). Set to
0to disable flow fetching. Use a large value (e.g.365) for initial deep backfill.
- Returns
The metrics database instance.
- Return type
eth_defi.hyperliquid.daily_metrics.HyperliquidDailyMetricsDatabase