fix(portfolio): count unified Hyperliquid collateral once in history and Telegram totals - #223
Open
eilyashko wants to merge 1 commit into
Open
Conversation
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 SummaryThe 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.
Confidence Score: 5/5The 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.
|
| 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]
Reviews (1): Last reviewed commit: "fix(portfolio): count unified Hyperliqui..." | Re-trigger Greptile
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
For unified Hyperliquid accounts, the spot connector (
hyperliquid) and the perp connector (hyperliquid_perpetual) report the same USDC collateral.GET /servers/{name}/portfolioalready 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/historysums stored snapshots as they are. The Portfolio Evolution chart shows an inflated total and disagrees with the tile right above it./portfoliocommand totals the rawget_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
utils/portfolio_dedupe.pyasdedupe_hyperliquid_unified(state). It works on the raw{account: {connector: [balances]}}shape, so every consumer shares one implementation.hyperliquid_perpetualis unchanged./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
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.pystill passes, so the history payload is unchanged for non-Hyperliquid data.