hyperliquid.combined_analysis

Documentation for eth_defi.hyperliquid.combined_analysis Python module.

Combined position and deposit analysis for Hyperliquid vaults.

This module provides functionality to combine position PnL data with deposit/withdrawal data to create a comprehensive view of vault performance including:

  • Cumulative account value over time

  • Net capital flows (deposits minus withdrawals)

  • Trading PnL separated from capital movements

  • Internal share price calculation (similar to ERC-4626 vaults)

The share price mechanism works as follows:

  • total_assets tracks the account value (NAV) at each point in time

  • total_supply tracks the number of shares outstanding

  • share_price is calculated as total_assets / total_supply

  • When a deposit occurs, new shares are minted: shares_minted = deposit_amount / share_price

  • When a withdrawal occurs, shares are burned: shares_burned = withdrawal_amount / share_price

  • Share price starts at 1.00 at vault inception

  • When all shares are redeemed (total_supply reaches 0) but total_assets > 0 (e.g. vault leader’s equity remains), the epoch resets using chain-linked pricing: the last epoch’s share price is carried forward and new shares are minted at that price, keeping the price series continuous. This also triggers when the computed share price would exceed SHARE_PRICE_RESET_THRESHOLD.

Example:

from datetime import datetime, timedelta
from eth_defi.hyperliquid.session import create_hyperliquid_session
from eth_defi.hyperliquid.position import fetch_vault_fills, reconstruct_position_history
from eth_defi.hyperliquid.position_analysis import create_account_dataframe
from eth_defi.hyperliquid.deposit import fetch_vault_deposits, create_deposit_dataframe
from eth_defi.hyperliquid.combined_analysis import analyse_positions_and_deposits

session = create_hyperliquid_session()
vault_address = "0x3df9769bbbb335340872f01d8157c779d73c6ed0"
start_time = datetime.now() - timedelta(days=30)

# Fetch position data
fills = fetch_vault_fills(session, vault_address, start_time=start_time)
events = reconstruct_position_history(fills)
position_df = create_account_dataframe(events)

# Fetch deposit data
deposit_events = fetch_vault_deposits(session, vault_address, start_time=start_time)
deposit_df = create_deposit_dataframe(list(deposit_events))

# Combine for comprehensive analysis
combined_df = analyse_positions_and_deposits(position_df, deposit_df)

print(f"Final account value: ${combined_df['cumulative_account_value'].iloc[-1]:,.2f}")
print(f"Share price: ${combined_df['share_price'].iloc[-1]:.4f}")
print(f"Total supply: {combined_df['total_supply'].iloc[-1]:,.2f}")

Module Attributes

SHARE_PRICE_RESET_THRESHOLD

When the computed share price exceeds this threshold, the epoch resets (total_supply absorbs total_assets, share_price → 1.0).

EPOCH_RESET_MIN_ASSETS

Minimum total_assets value to trigger an epoch reset when total_supply drops to zero.

Functions

align_share_price_curve_to_anchor(prices_df, ...)

Resume a reconstructed share-price curve from one persisted price.

analyse_positions_and_deposits(position_df, ...)

Combine position and deposit DataFrames into a unified timeline.

get_combined_summary(combined_df)

Generate a summary of combined position and deposit analysis.

rescale_share_price_rows(prices_df, factor)

Rescale synthetic share prices without changing the represented NAV.

SHARE_PRICE_RESET_THRESHOLD: float = 10000.0

When the computed share price exceeds this threshold, the epoch resets (total_supply absorbs total_assets, share_price → 1.0). This prevents share price corruption when total_supply approaches zero while total_assets remains nonzero (e.g. after all followers withdrew from a vault but the leader’s equity persists).

EPOCH_RESET_MIN_ASSETS: float = 10.0

Minimum total_assets value to trigger an epoch reset when total_supply drops to zero. Sub-threshold residual amounts are ignored (treated as zero) to avoid creating phantom shares from negligible dust that can then produce negative share prices on subsequent losses.

rescale_share_price_rows(prices_df, factor, row_positions=None)

Rescale synthetic share prices without changing the represented NAV.

Hyperliquid does not publish an investable vault share price or share supply. The scanners derive both values from rolling portfolio windows, so an otherwise equivalent re-read can use a different arbitrary unit. Multiplying share_price and dividing total_supply by the same factor preserves the invariant total_assets == share_price * total_supply while choosing a consistent unit.

Parameters
  • prices_df (pandas.DataFrame) – DataFrame containing a finite positive share_price column and, optionally, a total_supply column. Rows are modified in place.

  • factor (float) – Finite positive multiplier applied to share_price.

  • row_positions (Optional[collections.abc.Sequence[int]]) – Optional positional rows to rescale. When omitted every row is rescaled.

Returns

The same DataFrame instance after the unit rescaling.

Return type

pandas.DataFrame

align_share_price_curve_to_anchor(prices_df, anchor_timestamp, anchor_share_price)

Resume a reconstructed share-price curve from one persisted price.

A positive persisted price is aligned at its exact timestamp, or interpolated in log-price space between bracketing observations for the high-frequency scanner. The resulting constant factor is applied with rescale_share_price_rows(), preserving NAV and supply.

A persisted zero may be a valid observation for a Hyperliquid vault whose NAV was completely wiped out while synthetic supply remained. The scanner cannot classify the zero as durable or transient at resume time, but zero cannot be used as a scale factor in either case. The reconstructed curve is therefore returned unchanged. Any later recapitalisation epoch is selected and normalised by the wrangle pipeline. Negative and non-finite persisted prices indicate invalid stored data and raise ValueError.

Parameters
  • prices_df (pandas.DataFrame) – Chronologically sorted DataFrame with a DatetimeIndex and share_price, total_supply and total_assets columns.

  • anchor_timestamp (Union[datetime.datetime, pandas.Timestamp]) – Timestamp of the already persisted price.

  • anchor_share_price (float) – Finite non-negative persisted share price. Zero denotes a lifecycle boundary that cannot anchor the reconstructed scale.

Returns

Rescaled or unchanged DataFrame, or None when a positive anchor lies outside the curve or cannot be interpolated.

Return type

Optional[pandas.DataFrame]

analyse_positions_and_deposits(position_df, deposit_df, initial_balance=0.0)

Combine position and deposit DataFrames into a unified timeline.

This function merges trading activity (positions/PnL) with capital flows (deposits/withdrawals) to create a comprehensive view of vault performance.

The resulting DataFrame contains:

  • pnl_update: Change in realised PnL at this timestamp (from trading)

  • netflow_update: Change in capital at this timestamp (deposits positive, withdrawals negative)

  • cumulative_pnl: Running total of realised trading PnL

  • cumulative_netflow: Running total of capital flows (deposits - withdrawals)

  • cumulative_account_value: Total account value (initial_balance + netflow + pnl)

  • total_assets: Alias for cumulative_account_value (NAV)

  • total_supply: Number of shares outstanding

  • share_price: Share price calculated as total_assets / total_supply

The share price calculation follows ERC-4626 vault mechanics:

  • Share price starts at 1.00 when the first deposit occurs

  • When deposits occur, new shares are minted at the current share price

  • When withdrawals occur, shares are burned at the current share price

  • PnL changes affect total_assets but not total_supply, thus changing share price

The DataFrame is indexed by timestamp and sorted chronologically, combining events from both position changes and deposit/withdrawal activity.

Example:

from eth_defi.hyperliquid.combined_analysis import analyse_positions_and_deposits

# Assuming position_df and deposit_df are already created
combined = analyse_positions_and_deposits(position_df, deposit_df, initial_balance=1000.0)

# Get final values
final_pnl = combined["cumulative_pnl"].iloc[-1]
final_netflow = combined["cumulative_netflow"].iloc[-1]
final_value = combined["cumulative_account_value"].iloc[-1]
final_share_price = combined["share_price"].iloc[-1]

print(f"Trading PnL: ${final_pnl:,.2f}")
print(f"Net capital flow: ${final_netflow:,.2f}")
print(f"Account value: ${final_value:,.2f}")
print(f"Share price: ${final_share_price:.4f}")
Parameters
Returns

DataFrame with unified timeline containing PnL, capital flow, and share price metrics.

Return type

pandas.DataFrame

get_combined_summary(combined_df)

Generate a summary of combined position and deposit analysis.

Parameters

combined_df (pandas.DataFrame) – DataFrame from analyse_positions_and_deposits()

Returns

Dict with summary statistics including share price metrics

Return type

dict