# MVP Ledger Block: Cash, Weighted Average Cost, Positions

Session pattern captured from implementing Tasks 14–16 in the FinanceManager repo with synthetic data only.

## Scope

Use this reference when adding or reviewing finance-ledger calculations before dashboard work:

- Cash calculation from ledger transactions
- Weighted Average Cost (WAC) cost basis
- Position calculation from initial snapshots + transactions
- Data-quality handling for missing FX or market prices
- Auditability for confirmed/manual calculations

## Cash ledger rules

- Treat `initial_cash_snapshot` as the starting truth for cash.
- After system start, derive current cash from `transactions`; do not make `cash_balances` the primary truth.
- `cash_balances` should remain a snapshot/cache/control view.
- Calculate cash separately per `(account_id, currency)`.
- Supported MVP transaction effects:
  - `cash_deposit`: increase cash
  - `cash_withdrawal`: decrease cash
  - `buy`: decrease cash by net amount or gross + fee + tax
  - `partial_sell` / `full_sell`: increase cash by net proceeds or gross - fee - tax
  - `dividend` / `etf_distribution`: increase cash by net income
  - `fee`: decrease cash
  - `tax`: decrease cash
  - `fx_conversion`: support as signed cash movement where MVP data is available
  - `manual_cash_correction`: signed cash movement, only with note + audit log
- Convert to CHF only when FX exists; otherwise mark result incomplete.
- Negative cash should create a warning/alert but must not be silently corrected.

## Weighted Average Cost rules

WAC is the MVP internal performance method, not a complete tax method.

- Buys increase quantity and cost basis.
- Buy fees increase cost basis.
- Partial sells reduce quantity and cost basis proportionally.
- Realized P&L = net sale proceeds in CHF - proportional removed CHF cost basis.
- Full sells set quantity and remaining cost basis to zero.
- Dividends/distributions increase income but do not alter quantity or cost basis.
- Do not implement FIFO/LIFO/tax-lot logic in MVP 1; keep granular transactions so a later tax-lot module can be added.
- Use `Decimal` for money/quantity calculations and explicit quantization for money outputs.

## Position calculation rules

- Derive positions from `initial_position_snapshot` plus later transactions.
- Key positions by `(account_id, instrument_id)`.
- Keep positions with quantity `0` visible if there is sale history, so realized P&L/history is not lost.
- Track at least:
  - quantity
  - original cost basis
  - CHF cost basis
  - average cost original/CHF
  - realized P&L CHF
  - unrealized P&L CHF when market price + FX quality is sufficient
  - income CHF
  - fees CHF
  - taxes CHF
  - total return CHF when quality is sufficient
  - data-quality status/warnings
- Missing market price should mark the position incomplete and raise a data-quality warning.
- Missing historic FX should mark precise CHF return as unavailable and raise a critical data-quality alert.
- Confirmed snapshot/calculation writes should be auditable, preferably by inserting `positions_snapshot` rows and audit-log entries.

## Test cases to preserve

At minimum, synthetic tests should cover:

- `initial_cash_snapshot` as cash start truth
- buy reduces cash
- sell increases cash
- dividend increases cash and income
- buy fee reduces cash and increases cost basis
- CHF buy calculates quantity/cost basis correctly
- USD buy uses historical FX for CHF cost basis
- partial sell calculates realized P&L via WAC
- full sell sets quantity to zero while preserving historical visibility
- dividend does not change quantity or cost basis
- missing market price creates data-quality warning
- missing FX prevents precise Total Return CHF
- confirmed/manual correction or snapshot action creates audit evidence

## Safety pattern

- Use only synthetic data in tests/fixtures.
- Do not touch real portfolio files such as holdings spreadsheets/PDFs while building this block.
- Before commit/push run:
  - `PYTHONPATH=src python -m compileall src tests`
  - `PYTHONPATH=src pytest tests -q`
  - `PYTHONPATH=src python -m jarvis_finance.cli.main git-safety-scan .`
  - `git status`
- Remove generated `__pycache__` before safety scan if needed.
