docs/lots-valuation.md
Move Wealthfolio from precomputed aggregate rows and account-local valuation math to scoped, base-currency, flow-aware valuation and performance.
Primary outcomes:
AccountScope::All, saved portfolios, single accounts, and ad-hoc account
groups use the same scoped engine.AccountScope as the public scope type.ResolvedAccountScope::TotalSnapshot; resolved scopes always contain
real account IDs.daily_account_valuation remains unsynced. holdings_snapshots sync must
drop legacy aggregate snapshots after the rollout.portfolio_accounts has no historical membership dates.pub struct ResolvedAccountScope {
pub scope_id: String,
pub account_ids: Vec<String>,
pub base_currency: String,
}
Canonical scope_id rules:
allaccount:<account_id>portfolio:<portfolio_id>accounts:<sha16> from lex-sorted, deduped account IDsAdd explicit return fields:
returns.twrreturns.annualized_twrreturns.irr as selected-period money-weighted returnreturns.annualized_irr as annualized XIRRreturns.value_returnGoal:
Implementation:
AccountScope::All resolution to active, non-archived real accounts.ResolvedAccountScope::TotalSnapshot.AccountScope union, removes string shortcut hooks like
useHoldings(string), and uses scope object query keys.holdings_snapshots
and daily_account_valuation.holdings_snapshots.Checks:
AccountScope::All resolves to real accounts only.Goal:
Implementation:
daily_account_valuation:
cash_balance_baseinvestment_market_value_basetotal_value_basecost_basis_basenet_contribution_baseexternal_inflow_baseexternal_outflow_baseperformance_eligible_value_basepub enum FxContext {
ValuationDate,
AcquisitionDate,
FlowDate,
}
Checks:
daily_account_valuation(account_id, valuation_date) index exists and
supports range replacement.holdings_snapshots.cash_total_base_currency
== daily_account_valuation.cash_balance_base
Goal:
Implementation:
Checks:
Goal:
source_group_id corrections.Implementation:
flow_classifier.rs from account/portfolio-only classification to
scope-aware classification.metadata.flow.is_external = true forces externalChecks:
Goal:
Implementation:
r_D = (V_D + outflow_D - V_{D-1} - inflow_D) / (V_{D-1} + inflow_D)
<= 0 or crosses through zero, exclude the period from
compounding and surface a warning.Checks:
PerformanceResult.returns fields.Goal:
Implementation:
(instance_id or db_path, scope_id, base_currency, max(calculated_at), membership_hash)
user_id.AccountScope.Checks:
All scope and a saved portfolio containing all active accounts match.Goal:
Implementation:
Checks:
Goal:
Implementation:
lot_disposals accounting read model generated from FIFO lot reductions.income_events read model for dividends, interest, withholding tax, and
received/source currency.lot_disposals stores proceeds, fees, sold cost basis, realized P&L,
currencies, FX rate to base, and basis_source = accounting_fifo.Checks:
Goal:
Implementation:
split_ratio < 1.Checks: