Skip to content

fix(portfolio): count unified Hyperliquid collateral once in history and Telegram totals - #223

Open
eilyashko wants to merge 1 commit into
hummingbot:mainfrom
eilyashko:fix/portfolio-unified-hyperliquid-dedup
Open

fix(portfolio): count unified Hyperliquid collateral once in history and Telegram totals#223
eilyashko wants to merge 1 commit into
hummingbot:mainfrom
eilyashko:fix/portfolio-unified-hyperliquid-dedup

Conversation

@eilyashko

Copy link
Copy Markdown

Problem

For unified Hyperliquid accounts, the spot connector (hyperliquid) and the perp connector (hyperliquid_perpetual) report the same USDC collateral. GET /servers/{name}/portfolio already drops the duplicate via _dedupe_hyperliquid_unified, so the Portfolio tile and the holdings table are correct.

Two other views still count that collateral twice:

  • GET /servers/{name}/portfolio/history sums stored snapshots as they are. The Portfolio Evolution chart shows an inflated total and disagrees with the tile right above it.
  • The Telegram /portfolio command totals the raw get_state() payload.

Example from a live unified account holding 2,646 USDC: the tile shows $9,471 while the chart and Telegram show $12,118.

Fix

  • Move the dedup into utils/portfolio_dedupe.py as dedupe_hyperliquid_unified(state). It works on the raw {account: {connector: [balances]}} shape, so every consumer shares one implementation.
  • The function is pure and returns an adjusted copy. Trading views read the same SDS-cached state and must keep seeing the real perp collateral. That money is tradable. It just must not be valued twice.
  • Only the overlap (min of the two stable totals) is removed from the perp side, with units scaled along with value. A small genuine difference between the legs survives.
  • Live endpoint: dedupe the raw state before parsing. The UNIFIED note on hyperliquid_perpetual is unchanged.
  • History endpoint: dedupe each snapshot at read time and recompute the total whenever the dedup applies. Stored snapshots predate the fix, so this also corrects history that was recorded with the double count. No migration needed.
  • Telegram /portfolio: dedupe after both fetches (initial and Refresh).

Detection is unchanged from the existing helper: both legs hold stable value and the perp total matches the spot total within 1%. Known limit, same as before: with an open Hyperliquid perp position, perp equity can drift outside the band and the dedup stands down until the position closes.

Testing

  • New unit tests in tests/test_portfolio_dedupe.py: 11 cases covering the numbers above, purity, idempotency, alias keys, per-account independence, and the drift guard.
  • tests/test_portfolio_history_sds.py still passes, so the history payload is unchanged for non-Hyperliquid data.
  • Full suite: 2469 passed, 5 skipped.
  • Verified against a live unified account: the state total went from $12,119.47 to $9,472.69 and now matches the tile. History points dedupe the same way, including old snapshots.

For unified Hyperliquid accounts, the spot connector (hyperliquid) and the
perp connector (hyperliquid_perpetual) report the same USDC collateral. The
live portfolio endpoint already dropped the duplicate, but the history
endpoint and the Telegram /portfolio command still counted it twice, so the
Portfolio Evolution chart and the Telegram total disagreed with the tile.

Move the dedup into utils/portfolio_dedupe.py as a pure function over the
raw {account: {connector: [balances]}} state and apply it in all three
places: the live endpoint (UNIFIED note preserved), each history snapshot at
read time (which also corrects history recorded before the fix), and both
Telegram fetches. Only the overlap between the two stable totals is removed,
so a small genuine difference between the legs survives.

The function never mutates its input: trading views read the same cached
state and must keep seeing the real perp collateral.
@greptile-apps

greptile-apps Bot commented Aug 24, 2026

Copy link
Copy Markdown

Greptile Summary

The PR centralizes unified Hyperliquid collateral deduplication in a pure shared utility and applies it consistently to current web portfolios, historical snapshots, and Telegram portfolio views.

  • Removes only the overlapping stable value from the perpetual leg while proportionally adjusting quantity fields.
  • Recomputes historical totals and token breakdowns from deduplicated snapshot state when unified collateral is detected.
  • Preserves the raw shared server-data cache for trading consumers.
  • Adds focused coverage for detection, aliases, purity, idempotency, account isolation, and drift behavior.

Confidence Score: 5/5

The PR appears safe to merge, with no concrete changed-code defect identified.

The shared helper preserves raw trading state through deep copying, scopes detection per account, adjusts only confirmed near-equal stable overlap, and is consistently integrated into live, historical, and Telegram valuation paths.

Important Files Changed

Filename Overview
utils/portfolio_dedupe.py Introduces a pure, account-scoped deduplication utility that detects near-equal Hyperliquid stable balances and proportionally removes their overlap from a copied perpetual balance.
condor/web/routes/portfolio.py Uses the shared utility for current portfolios and each historical snapshot, recomputing adjusted totals and building breakdowns from resolved state.
handlers/portfolio.py Applies the valuation adjustment consistently before rendering and caching both initial and refreshed Telegram portfolio views.
tests/test_portfolio_dedupe.py Covers the primary unified-account scenario, purity, idempotency, aliases, account isolation, tolerance behavior, and detection guardrails.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
    Raw[Raw portfolio state] --> Copy[Deep-copy dedupe]
    Copy --> Detect{Near-equal Hyperliquid stable totals?}
    Detect -->|No| Unchanged[Return unchanged copy]
    Detect -->|Yes| Adjust[Remove overlap from perpetual stable balance]
    Adjust --> Live[Web current portfolio]
    Adjust --> History[History total and token breakdown]
    Adjust --> Telegram[Telegram overview and refresh]
    Raw --> Trading[Trading views retain raw collateral]
Loading

Reviews (1): Last reviewed commit: "fix(portfolio): count unified Hyperliqui..." | Re-trigger Greptile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant