The Loss That Lost Its Minus Sign — Python Bug Hunt
Modelled on Fidelity's Magellan Fund, 1994: late in the year the fund told shareholders to expect a sizeable year-end distribution — and then paid none.
- Language: Python
- Layer: Database
- Difficulty: Medium
- Concepts: Money, Accounting
- Modelled on: Fidelity Magellan · 1994
- Visible tests: gains add up; a loss reduces the net
- Reward: 50 XP for a complete fix
Briefing
Modelled on Fidelity's Magellan Fund, 1994: late in the year the fund told shareholders to expect a sizeable year-end distribution — and then paid none. Fidelity explained that a tax accountant had omitted the minus sign on a net capital loss of $1.3 billion, so it was recorded as a gain and the distribution estimate was overstated by $2.6 billion.
This reconstruction aggregates a fund ledger into its net capital result and the per-share distribution estimate. It normalises the signs of the entries on the way in.
Fix ledger.py so losses reduce the result.
Bug report
BUG-MAGELLAN-94 · Priority: Critical · Reported by: fund accounting
Entries are { "fund", "kind", "amount" } with amounts in cents. Feeds disagree on sign conventions, so the SIGN of amount is not reliable — the kind is:
- kind "gain": adds abs(amount)
- kind "loss": subtracts abs(amount)
- any other kind (dividend, fee, …) is not a capital item and is ignored
net_capital(entries) -> the signed total. net_by_fund(entries) -> { fund: net_capital of that fund's entries } for every fund that has at least one entry (of any kind). distribution_estimate(entries, shares) -> { "net_capital", "per_share_cents", "carryforward" }: when net > 0, per_share_cents = net // shares and carryforward = 0; otherwise per_share_cents = 0 and carryforward = -net.
Observed: a year with a large realised loss reports it as a gain of the same size, and the estimate sent to shareholders is overstated by twice the loss.
Logs
[fund-acct] MAGELLAN realised gains 1,000 loss 1,300 -> net +2,300
[fund-acct] distribution estimate published: net +2,300 (restated: -300)The code as shipped
src/funds/ledger.py (editable)
# Year-end capital result and the distribution estimate sent to shareholders.
CAPITAL_KINDS = ("gain", "loss")
def signed_amount(entry):
# Feeds disagree on sign conventions; normalise to magnitudes.
return abs(entry["amount"])
def net_capital(entries):
total = 0
for e in entries:
if e["kind"] in CAPITAL_KINDS:
total += signed_amount(e)
return total
def net_by_fund(entries):
grouped = {}
for e in entries:
grouped.setdefault(e["fund"], []).append(e)
return {fund: net_capital(rows) for fund, rows in grouped.items()}
def distribution_estimate(entries, shares):
net = net_capital(entries)
if net > 0:
return {"net_capital": net, "per_share_cents": net // shares, "carryforward": 0}
return {"net_capital": net, "per_share_cents": 0, "carryforward": -net}
Read-only context: src/funds/feeds.py.
Open the hunt to edit the files, run the visible tests and submit against the hidden ones. More Python bug hunts.