3.10.0 introduces a new calculation engine and adds cost basis methods, loan tracking and encrypted cloud backups.
Highlights
- New portfolio engine. Holdings, cash, valuations and returns now come from one engine on desktop, mobile and the server. It fixes many edge cases in transfers, shorts, splits, FX and rounding. (#1847, #1875, #1880, #1894, #1897, #1905, #1923, #1990)
- Cost basis methods. Each transaction-tracked account can use FIFO, weighted average cost (WAC), LIFO or HIFO. Not yet supported: cross-account ACB and picking specific lots. (#1872, #1898, #1904)
- Loans and mortgages. A liability can be tracked as a loan, with an amortization schedule, payments from a cash account, extra repayments, renewals and confirmed balances. (#1868, #1869, #1888, #1895, #1900, #1903, #1909, #1991)
- Encrypted cloud backups for Wealthfolio Connect subscribers: a daily backup of one profile, plus Back up now. Backups are encrypted before upload, so the cloud only sees ciphertext, and can be up to 256 MiB. Restore works on desktop only; the web server restores with the offline CLI. (#1918, #1980)
- Return of capital and notional distributions adjust cost basis instead of counting as income. (#1902)
- Money flow chart in Spending Insights. You can zoom into a category's subcategories, and subcategories also show in the spending plan. (#1935, #2004)
- AI agent (MCP) tools for linking transfers, importing quotes, updating activities and categorizing transactions. (#1896, #1911, #1913, #1937)
Upgrading
- The first launch recalculates your history, after making a backup. On a 13-account portfolio this took about 20 seconds.
- Where the old calculation was wrong, some derived numbers can change slightly: cost basis, realized gains and past values. Your activities and prices are not changed.
- If you use device sync, update all your devices. 3.9.1 can't calculate accounts set to WAC, LIFO or HIFO, or read the new return-of-capital entries.
- Self-hosting needs no configuration changes.
Improvements
- Activities: clicking a row opens it for editing. Duplicating an activity uses today's date and keeps its notes. (#1864, #1929)
- CSV import: investment imports no longer require an Amount column. (#1528, #1979)
- Transfers: credit card accounts can send cash transfers, and a cash transfer can use a different currency on each side. (#1796, #1901)
- Exchanges come from the full ISO 10383 list. Four old non-standard exchange codes are updated. (#1828)
- Custom price providers: new ones apply only to the securities assigned to them. Existing ones keep their fallback. (#1887, #1921)
- Investments dashboard: filter by a saved portfolio; the choice is remembered per profile. (#1940)
- Hidden accounts count in their group's total. (#1428, #1882, #1917)
- Health Center flags accounts with negative cash. (#1926)
- Long performance charts load faster. (#1930)
- Backups: a simpler Backups tab. (#1971, #1826)
- Connect moves above Settings in the desktop sidebar, with links where data is entered by hand. The Sync & Connections page is redesigned around what needs attention. Broker sync requests now include each account's type and the broker's account label, which Connect stores to diagnose mapping problems. (#1984, #1995, #1941)
- Spending: merchant rules for France, Germany and the Netherlands. (#1829, #1998, #1997)
- Formatting regions: India, Austria, Romania and Bulgaria are new. (#1968, #1908)
- Windows: installers are signed (Teymz Inc.). SmartScreen may still warn for a while. (#1910)
Fixes
- Asset and loan details: unsaved edits are no longer reset by a background portfolio update. (#1994)
- Linux AppImage: no longer opens a blank window on distributions with recent Mesa, such as Ubuntu 26.04. It now runs natively on Wayland; set
GDK_BACKEND=x11to use X11. (#223, #2005) - Connect: a brief connection drop no longer signs you out. "Last synced" now shows when sync last ran, not the broker's latest activity date. (#1843, #1995)
- Self-hosted server: CSV imports over 2 MB (a few thousand rows) no longer fail with
413 Payload Too Large, and an unusable secrets file gives a clear error. (#2000, #1932, #1886) - Fund classification: ETFs no longer show part of their value as Unknown in Sectors. Weights reported above 100% (rounding or leverage) are read correctly, and a fund's sectors are saved together. (#1854, #1855)
- Asset pages: after a full transfer to another account, income and gains from both accounts are shown, not only the receiving account's. (#1919)
- Accented, Chinese or emoji characters no longer make some operations fail: AI assistant replies, holdings export, symbol search, and entering or importing activities whose symbol contains them. (#1879)
- Transactions: the table remembers which columns you show. (#1999)
- Benchmarks: all-time benchmarks start where your accounts start. (#1933)
- Bonds: a synced bond reported by CUSIP and by ISIN stays one security. Treasury prices are no longer calculated from incomplete terms. (#1838, #1891)
- Quotes: the quote CSV import shows the server's error, no longer gets stuck after a failed import, and no longer mixes up two files picked one after the other. An Open, High or Low left untouched saves as the close. (#1950, #1951, #1966, #1973, #1993, #1994)
- Mobile: Theme "System" follows the phone. Editing a quote keeps focus in the field and saves. (#1959, #1685, #1989)
- Linux: the app starts with a
CorPOSIXlocale. (#1726, #1876) - Desktop: the database is closed cleanly on exit. (#1890)
- Recovery screen: when the device's secure storage is locked, it suggests unlocking it and trying again before restoring a backup. (#1996)
- Schwab "as of" dates import correctly. (#1878)
- Spending: completed months compare against the full previous month, and savings categories appear in the rule editor. (#1858, #1827)
- AI assistant and MCP: activities added west of UTC keep their date, and imports report failed rows correctly. (#1892)
- Dependencies: security updates. (#1899, #1927)
- Other: fixes to layout, translations, toasts, transfer editing, and navigation after a page error. (#1755, #1798, #1964, #1981, #1846, #1865, #1893, #1928, #1955, #1914)
Thanks to everyone who contributed and reported issues, including @jay-tau, @daviddphillips, @theluckystrike, @kryofin, @Jonjon-prog, @Bubbles840, @tiann, @salmonumbrella, @oliviertassinari, @markrickert, @kinhsman, @giovacalle, @bogdanr, @blastik, @Neallin-917, @DamienKCorp and @taufderl.
Full changelog: v3.9.1...v3.10.0
What's Changed
- release: prepare 3.9.2 backup and diagnostics fixes by @afadil in #1826
- fix(spending): show savings categories in rule editor by @afadil in #1827
- docs(self-host): clarify database encryption requirement by @afadil in #1831
- feat(market-data): resolve exchanges with ISO MIC catalog by @afadil in #1828
- fix(profiles): recover sessions after transient connection failures by @afadil in #1843
- fix: align bond identity, Treasury pricing, and Docker profile paths by @afadil in #1838
- fix(desktop): preserve exit status with Tauri 2.12 by @jay-tau in #1842
- fix(dev,network): allow development-mode addons to make declared whitelisted network calls by @markrickert in #1845
- fix(spending): compare completed months in full by @Neallin-917 in #1858
- fix(classification): replace auto assignments atomically per taxonomy by @daviddphillips in #1855
- fix(classification): preserve provider fractional weights by @daviddphillips in #1854
- fix(frontend): stretch pinned add-on sidebar items to full width by @kinhsman in #1846
- feat(portfolio): replace the portfolio calculators with the portfolio engine by @afadil in #1847
- feat(engine): per-account cost basis method behind one relief seam by @afadil in #1872
- fix(formatting): fall back when the system locale is unusable by @afadil in #1876
- fix(portfolio): read accounting settings per account and strictly by @afadil in #1875
- fix(import): read Schwab "as of" dates instead of an epoch date by @afadil in #1878
- fix(activities): store a type override as it reads on every write by @afadil in #1877
- fix: stop byte-offset string cuts from panicking on non-ASCII text by @afadil in #1879
- fix(portfolio): keep history reads off the async workers by @afadil in #1880
- chore(lint): reject unwrap and panic outside tests by @afadil in #1884
- fix(storage): keep database ownership until pooled connections close by @afadil in #1886
- feat(custom-provider): use custom providers only for their assigned securities by @afadil in #1887
- feat(loans): track loans and mortgages with a shared dated engine by @afadil in #1868
- feat(loans): check and apply loan actions in Rust by @afadil in #1869
- feat(loans): pay loans with withdrawals from a cash account by @afadil in #1888
- fix(desktop): release the profile database before exit by @afadil in #1890
- fix(market-data): prevent Xetra-Gold from being classified as a bond by @afadil in #1891
- fix: keep bare activity dates on their day and report failed MCP imports by @afadil in #1892
- fix(engine): split-rounding dust in lot relief and transfer covers; carry P-HOLD snapshots across splits by @afadil in #1894
- fix(engine): net a transfer pair whose sender falls short by a rounding by @afadil in #1897
- feat(engine): add weighted average cost (WAC) as a per-account cost basis method by @afadil in #1898
- feat(loans): own loan writes in Rust and count each repayment once by @afadil in #1895
- feat(mcp): find, link and unlink transfers by @afadil in #1896
- feat(loans): give Holdings cards each loan's summary from its valuation by @afadil in #1900
- fix(engine): count expiry and transfer-cover P&L, and carried charges once, in attribution by @afadil in #1905
- fix(loans): review follow-ups: statuses, form errors, escrow and payment dates by @afadil in #1903
- feat(engine): add LIFO and HIFO cost basis methods by @afadil in #1904
- fix(deps): patch dependency security vulnerabilities by @afadil in #1899
- refactor(loans): date payments in core, not in storage by @afadil in #1909
- test(e2e): make the loan lifecycle and loan editing specs deterministic by @afadil in #1912
- feat(mcp): preview and save reviewed historical quotes by @afadil in #1911
- feat(mcp): preview and apply updates to existing activities by @afadil in #1913
- fix: Health Center crash on an oversold transaction, and keep navigation usable when a page fails by @afadil in #1914
- fix(spending): load transfer counterpart when editing from the Spending tab by @giovacalle in #1755
- fix(account): show activities for hidden accounts on the account page by @kryofin in #1882
- fix(account): keep a hidden account editable from its own page by @afadil in #1917
- fix(activities): allow independent currencies for cash transfers by @tiann in #1901
- ci(windows): sign installers with Azure Artifact Signing by @afadil in #1910
- fix: preserve asset income after account transfers by @afadil in #1919
- fix: generate unique selectors for detected HTML prices by @afadil in #1921
- fix: preserve LF line endings for snapshot fixtures by @afadil in #1922
- fix(spending): translate cash activity type labels by @Jonjon-prog in #1865
- feat(engine): returns of capital and notional distributions by @daviddphillips in #1902
- feat(connect): add encrypted cloud backups and direct snapshot transfers by @afadil in #1918
- fix(health): detect unfunded buys and link negative balances by @afadil in #1926
- ci: seed the PR Rust cache on main and stop per-PR cache writes by @afadil in #1925
- feat(spending rules): categorization rules for France by @DamienKCorp in #1829
- fix(engine): an account that has not started no longer blanks a scope's performance by @afadil in #1923
- fix(goals): translate goal, plan and funding toasts by @theluckystrike in #1893
- fix(deps): bump proxy-addr and source-map-js to patched releases by @afadil in #1927
- fix(activities): use today and preserve notes when duplicating by @afadil in #1929
- fix(goals): show one toast when saving a save-up plan by @afadil in #1928
- fix(performance): stop the chart's hidden vertical grid from blocking first render by @afadil in #1930
- feat(activities): allow transfers out of credit card accounts by @Bubbles840 in #1796
- fix(performance): start all-time benchmarks where the accounts start by @afadil in #1933
- fix(server): diagnose an unusable secrets file behind profile deletion failures by @afadil in #1932
- feat(spending): money flow Sankey on Where I am by @afadil in #1935
- feat(dashboard): filter investments by saved portfolio by @afadil in #1940
- ci: keep every build on the repo's Node and pnpm versions by @jay-tau in #1943
- ci: drop the pnpm cache from PR checks by @jay-tau in #1958
- ci(rust): stop per-PR Rust cache saves by @jay-tau in #1945
- feat(connect): send account context with brokerage activity requests by @afadil in #1941
- fix(settings): follow the system theme on mobile by @jay-tau in #1959
- ci(docker): reuse compiled dependencies from a GHCR registry cache by @jay-tau in #1946
- fix(docker): refresh the final stage when storage hosts change by @jay-tau in #1957
- fix(quotes): show the backend error when a quote CSV import fails by @jay-tau in #1950
- fix(build): don't watch a missing .env in build scripts by @jay-tau in #1953
- fix(android): stop initializing ndk-context twice at launch by @afadil in #1961
- refactor(frontend): rename adapter isDesktop to isTauri by @afadil in #1962
- fix(quotes): send the custom provider code with existing-asset search results by @jay-tau in #1951
- fix(settings): use one desktop window check for every theme mode by @afadil in #1963
- test(server): keep SYSTEMROOT after env_clear in child-process tests by @theluckystrike in #1938
- feat(backups): simplify the Backups tab and fix cloud restore in dev builds by @afadil in #1971
- fix(mcp): Show "AI Agent Access" when available by @oliviertassinari in #1955
- build: optimize portfolio-engine and rust_decimal in test builds by @jay-tau in #1972
- fix(dashboard): count hidden accounts in group stats, keep groups of one by @kryofin in #1428
- feat(mcp): save reviewed transaction categories by @salmonumbrella in #1937
- fix(quotes): stop the quote CSV import wizard from mixing up files by @jay-tau in #1973
- fix(import): make amount optional for investment CSVs by @jay-tau in #1528
- test(settings): mock usePlatform in the settings layout test by @afadil in #1978
- fix(quotes): stop the import progress timer when a quote import fails by @jay-tau in #1966
- fix(ui): keep dialog and side-sheet max-width between 640 and 1024 px by @afadil in #1964
- feat(settings): add India as a formatting region by @jay-tau in #1968
- fix(import): list amount as optional in import help by @afadil in #1979
- ci: run the Windows IPC test step explicitly in PowerShell by @jay-tau in #1965
- feat(activity): open a row for editing when it is clicked by @Jonjon-prog in #1864
- fix(ui): preserve page scroll when activity tabs mount by @afadil in #1981
- fix(mobile): number inputs stealing focus back to date pickers by @blastik in #1685
- fix(activities): treat the reserved cash symbol as cash on save paths by @Bubbles840 in #1798
- feat(backups): back up to the cloud on demand by @afadil in #1980
- feat(connect): add discreet Connect account links by @afadil in #1984
- ci(docker): pin tonistiigi/xx to 1.10.0 by @jay-tau in #1985
- feat: add Austria, Romania and Bulgaria formatting regions by @bogdanr in #1908
- fix(holdings): count realized P&L from a short covered by a transfer in by @afadil in #1990
- fix(mobile): save quotes from the mobile quote editor by @afadil in #1989
- fix(loans): preserve manual liability origination and balances by @afadil in #1991
- fix(quotes): disable the exiting import preview by @Neallin-917 in #1993
- fix: release QA findings for 3.9.2 (loan details reset, quote zeros, Android status bar, restore dialog, first-run job, E2E isolation) by @afadil in #1994
- feat(connect): redesign Sync & Connections and fix its sync status by @afadil in #1995
- fix(desktop): suggest unlocking secure storage before backup recovery by @afadil in #1996
- fix(activity): persist transaction column visibility by @afadil in #1999
- fix(import): accept import requests larger than 2 MB by @taufderl in #2000
- feat(spending): show subcategories in the money flow and spending plan by @afadil in #2004
- fix: update Tauri (CLI 2.12.2, runtime 2.12.3) for Linux AppImages and Xcode 27 by @afadil in #2005
- feat(spending): add Dutch categorization preset by @taufderl in #1997
- feat(spending): add German categorization preset by @taufderl in #1998
- chore(release): bump version to 3.10.0 by @afadil in #2006
New Contributors
- @jay-tau made their first contribution in #1842
- @daviddphillips made their first contribution in #1855
- @kinhsman made their first contribution in #1846
- @giovacalle made their first contribution in #1755
- @tiann made their first contribution in #1901
- @theluckystrike made their first contribution in #1893
- @Bubbles840 made their first contribution in #1796
- @oliviertassinari made their first contribution in #1955
- @salmonumbrella made their first contribution in #1937
- @bogdanr made their first contribution in #1908
- @taufderl made their first contribution in #2000
Full Changelog: v3.9.1...v3.10.0