Skip to content

Fix Depot Transfer Cost Basis#73

Open
ma4nn wants to merge 3 commits into
masterfrom
fix-depot-transfer-cost-basis
Open

Fix Depot Transfer Cost Basis#73
ma4nn wants to merge 3 commits into
masterfrom
fix-depot-transfer-cost-basis

Conversation

@ma4nn

@ma4nn ma4nn commented Jul 15, 2026

Copy link
Copy Markdown
Owner

Summary

This is a follow-up PR for #59 to separate the multiple changes in that PR into single ones.

It teaches the FIFO cost-basis engine to respect Portfolio Performance depot transfers. On a linked TRANSFER_OUT/TRANSFER_IN pair, the cost-basis lot is relocated from the source to the destination account, preserving original acquisition date, price, and (prorated) fees — so per-account cost basis, view securities, and simulate share-sell stay correct after transfers.

  • Engine (cost_basis.py): relocate lots on linked transfers; split + prorate on partial transfers; destination
    consumes by original acquisition date; FIFO scoped per (account, security).
  • Link (pp_portfolio_builder.py, schemas.py): destination read from PP's xact_cross_entry, surfaced as
    transferTargetAccount.
  • Vorabpauschale (tax.py): deemed income attributed per lot, fixing a double-count / crash when a transfer creates
    two lots sharing one (date, account, security) key.
  • share-sell (simulate_share_sell.py): --account-id scopes by net share balance; cross-account FIFO resolves
    transferred lots.
  • Validation (rules.py): built-in unlinked-depot-transfer rule (a warning, on by default) flags transfers with
    no cross-entry link.

Behavior changes

  • share-sell --shares without --account-id now picks the globally-oldest lot across accounts (was per-account).
  • share-sell --account-id <source> no longer offers an unlinked transfer's net-0 source lots; cost-basis totals stay
    correct, and the data is surfaced by the default-on validation rule plus an engine WARNING during computation.

Known limitations

  • Same-day ordering is ambiguous (PP dates are day-granular) — resolved deterministically but a same-day cross-account transfer may not match PP's attribution; shares are always conserved. Same cause can strand shares in a chained same-day A → B → C (logs a warning).
  • Unlinked transfers: cost basis kept in source (flagged by the default-on unlinked-depot-transfer warning and an engine log warning), not sellable via --account-id.
  • A stale pre-feature .cache.db can OperationalError on the new join (low probability; delete cache or use --no-cache).

Testing

New tests cover full/partial/chained/round-trip/over transfers, cross-account FIFO by acquisition date, per-lot
Vorabpauschale, share-sell scoping, per-security FIFO isolation, and the validation rule. Full suite passes; pylint 10/10;
bandit clean.

@ma4nn ma4nn added the bug Something isn't working label Jul 15, 2026
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant