Skip to content

Transaction totals and invested-capital recovery

Ticket #369: Transaction summary and invested-capital recovery.
Type: Feature / Data reliability / User experience.
Affected Component: Stock detail pages, transactions, dashboard, and demo.

1. Context and goals

The transaction ledger for each holding already allowed users to review and manage buys and sells in the application. What was still missing was a summary showing the number of shares in the current position, their average cost, and how much of the invested capital had been recovered through sales.

The goal was to make this summary easy to read on each holding page and to keep dashboard values current after each transaction, without requiring a separate calculation or another file import.

2. Delivered improvements

A Total row was added to the transaction table on secure and demo holding pages. It brings together three figures:

  • Shares in the current position, calculated as recorded purchases minus recorded sales.
  • Average cost per share in the current position and average sale price, shown side by side. The average cost is the remaining transaction cost divided by the remaining share count. When shares are sold, their cost is removed at the average cost immediately before the sale; the sale price does not change the cost of the shares kept. The average sale price is weighted by the number of shares sold. NA means no shares remain or no sales exist for the corresponding average.
  • Net cash flow, calculated as recorded sale proceeds minus recorded purchase payments. Red indicates that purchases have not yet been recovered, bold black indicates they are equal, and green indicates that proceeds exceed payments.

The summary refreshes after each transaction. Purchases are displayed as cash outflows and sales as inflows; the stored transaction amounts are unchanged. Tooltips explain the displayed totals on desktop and mobile.

Dashboard values also refresh on the next visit: total value in Canadian dollars, total value in U.S. dollars, and consolidated value in Canadian dollars. No new import is required after a transaction.

3. Reliable, distinct measures

To keep the new summary from being mistaken for a profit calculation, I clarified the distinct meaning of average cost, recovered capital, and current market value.

Understanding the financial figures

Average cost describes the shares in the current position. Net cash flow shows how much of the purchase payments has been recovered through sales. The dashboard's market value applies the latest available price to the current position. These figures answer different questions.

For example, 10 shares bought at $20 cost $200, and 30 bought at $40 cost $1,200. The 40 shares therefore cost $1,400, or $35 per share. After selling 10 shares, the ledger shows 30 remaining. Their cost is $1,050 (30 × $35), so the average remains $35 per share. The $350 cost assigned to the 10 shares sold is removed from the remaining cost; their sale price does not enter this average.

Likewise, buying 50 shares at $1 and selling 25 at $2 produces $0 net cash flow: the $50 paid has been recovered, and 25 shares remain in the ledger. Net cash flow measures capital recovery; it is neither accounting profit nor the market value of the remaining shares. A negative balance means purchases have not yet been fully recovered, but does not by itself indicate a loss. Fees, dividends, and taxes are counted only when recorded in the ledger.

Separate roles for the ledger and CSV

Recorded purchases and sales determine the shares held. The CSV supplies the list of tracked holdings and their metrics; its share quantities do not replace the ledger.

New market records use the ledger quantity for the date of each record, and small positions are identified from the ledger. Existing historical records remain unchanged. A holding with no transactions has zero shares, and a complete sale does not remove it. A holding absent from the new CSV is removed along with its transactions and market records.

See the feature documentation for the current rules.

4. Verification and its limitations

Calculations and user journeys were checked with data isolated from the real portfolio. Coverage included buys, partial sales, edits, deletions, CSV imports, and dashboard refreshes. Colors and tooltips were checked in Google Chrome on desktop and a simulated phone viewport.

Check Local result as of October 29, 2026
Baseline before these changes 332 tests passed and 83% coverage.
Automated test suite 418 of 418 tests passed.
Lines of code covered by tests 83.76%, up from 83% at baseline. This does not guarantee the absence of defects.
Google Chrome journeys 30 passed, covering capital recovery, signed amounts, transactions, imports, and tooltips.

The browser-test files also passed their validation. The project quality score was 91.88/100 under the project's formula; it complements the test results but does not replace owner review.

An intermediate measurement had recorded 403 passing pytest tests, 83.65% coverage (84% rounded), 24 passing Chrome workflows out of 24 and a successful TypeScript noEmit check. ESLint could not complete because of the pre-existing jiti issue. The Docker engine was unavailable for MariaDB migration and concurrency checks, and no remote CI execution had been observed in that assessment. These results therefore provide neither evidence of MariaDB serialization nor an attestation of deployment.

5. Token usage

Usage tracking covers the full work on issue #369: preparation, implementation, verification, and documentation.

Item Status
Work session duration (estimated) 15 hours
Copilot AI credits consumed 4,936.55
Total cost $49.29