Skip to content

fix(dashboard): correct performance display for accounts with negative start value#759

Merged
afadil merged 7 commits intomainfrom
fix/tracking-mode-switch
Mar 19, 2026
Merged

fix(dashboard): correct performance display for accounts with negative start value#759
afadil merged 7 commits intomainfrom
fix/tracking-mode-switch

Conversation

@afadil
Copy link
Owner

@afadil afadil commented Mar 19, 2026

Summary

  • Root cause: Accounts with buy transactions recorded before any deposit have a negative starting balance in daily_account_valuation. This caused period_return = gain / negative_start = -283% and similar nonsensical values on the dashboard.
  • Performance fix: period_return now returns None (→ null in JSON) when start_value ≤ 0, in both the summary and full-history calculation paths. Frontend type updated to number | null.
  • Health check: New NegativeAccountBalance consistency check queries daily_account_valuation for accounts with negative total value and surfaces a warning in the health panel.
  • Tracking mode switch: Switching an account from Holdings → Transactions now triggers a portfolio recalculation (previously silently skipped).
  • Dashboard UI: Accounts with null return % and non-zero value show an amber warning dot (with tooltip explaining the cause). Zero-value/empty accounts show nothing in the gain row.
  • Dashboard polish: Group toggle and filter buttons aligned to ghost + hover:bg-success/10 to match the "View All" button style.

Test plan

  • Account with buys-before-deposits shows gain row and amber dot on dashboard; tooltip reads "Return % unavailable — activity history may be inconsistent (e.g. buys without deposits)"
  • Healthy accounts still show correct gain amount + return %
  • Empty/zero-value accounts show no dot and no gain row
  • Health panel shows warning for accounts with any negative total_value in history
  • Switching a broker account from Holdings → Transactions mode triggers recalculation
  • periodReturn: null does not break addon-sdk consumers

afadil added 3 commits March 18, 2026 15:42
…dation and sync

During CSV validation (check_activities_import) and broker sync
(prepare_activities_for_sync / build_asset_spec), resolve_symbol_quote
was called once per activity row, causing N provider hits for a CSV
with N rows of the same symbol.

Add fetch_provider_quote_ccy, which caches the raw Option<String>
provider result keyed by (symbol, mic, instrument_type). The cache is
scoped to a single validation run or sync pass, so the provider is hit
at most once per unique symbol. Per-row precedence resolution
(resolve_quote_ccy_precedence) runs locally with actual per-row inputs
after the cached lookup, keeping terminal_fallback and existing-asset
currency correct for every row.
…t dedup

The review step (check_activities_import) was computing idempotency keys
using symbol@mic strings, while the apply step used the resolved asset
UUID. On re-import, the review showed 0 duplicates (keys mismatched the
DB), then apply correctly skipped them all — confusing UX with no data
corruption.

Two-part fix:

1. Store the resolved asset UUID on ActivityImport.asset_id during
   check_activities_import when the asset already exists. Falls back to
   symbol@mic for new assets (first-time import), where no DB key
   exists yet to match against.

2. Normalize quantity, unit_price, amount (abs values) and minor-unit
   currencies (GBp → GBP with factor conversion) in
   build_import_idempotency_key, matching the normalization that
   prepare_activities_internal applies before the apply-step key
   computation.
…art value

- Return period_return: None when start_value <= 0 in both summary and
  full performance paths, serialising as null to the frontend
- Show amber warning dot (with tooltip) on accounts with null return %
  but non-zero value; hide gain row for empty/zero-value accounts
- Add NegativeAccountBalance health check via daily_account_valuation query
- Trigger portfolio recalc when tracking mode switches Holdings→Transactions
- Align group/filter/view-all button styles on dashboard (ghost + hover:bg-success/10)
- Fix periodReturn type to number | null in types.ts and addon-sdk
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 00a53b10ba

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +442 to +443
(acc.totalGainLossPercent ?? 0) *
(Number(acc.totalValueBaseCurrency) / totalValueBaseCurrency),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Don't coerce null account returns to zero in group totals

When a member account has totalGainLossPercent === null (the new non-computable return case), this aggregation treats it as 0 and still weights it by that account's market value. That produces a seemingly precise group return that is mathematically wrong for mixed groups and can hide the fact that some accounts have unavailable returns (for example, one null-return account plus one positive-return account gets diluted instead of marked unavailable). Group return should stay null (or be computed only from known-return accounts with reweighting), not coerced to zero.

Useful? React with 👍 / 👎.

@afadil afadil merged commit 8b81b11 into main Mar 19, 2026
1 of 3 checks passed
@afadil afadil deleted the fix/tracking-mode-switch branch March 19, 2026 16:52
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