The morning a portfolio doubled
Take a scheme that announces a 1:1 bonus. Every holder gets one extra unit for each unit held, and the NAV per unit halves. A client with 500 units at ₹80 has 1,000 units at ₹40. Their portfolio is worth exactly what it was worth yesterday, which is the entire point of a bonus issue.
Now consider a system that stores units in one table and gets NAV from a feed. The bonus units are applied by a job on the morning of the ex-date. The revised NAV arrives from the AMC that evening, because that's when NAVs arrive.
For most of a working day, that client's portfolio shows double its actual value. Advisors saw it. One of them called.
Nothing was broken in the sense of a stack trace, and every individual component did what it was written to do. The mistake was earlier and more conceptual: treating a corporate action as an update to a number rather than as an event with its own set of dates.
Three dates, and they are all different
A corporate action has an announcement date, an ex-date, a record date and a payment date. They can be days apart, and which one governs depends on the action.
Units change on the ex-date. Entitlement is determined by who holds on the record date. Cash moves on the payment date. If your model has a single effective_date column you have already lost, because the client who sells between the record date and the payment date is still entitled to the dividend, and your system now needs to pay someone who no longer holds the position.
That case is not rare, and it's the one that exposes whether a design is right. Entitlement is computed from the holding as of the record date, stored as a receivable, and settled on the payment date independently of what the client does with the units in between.
What each type actually does
Splits and consolidations change the unit count and the NAV in inverse proportion. Value is unchanged. Cost basis per unit changes but total cost does not, so the existing cost has to be redistributed across the new unit count rather than recalculated.
Bonus issues look like splits from a distance and are not the same thing. The new units arrive with zero cost. Total cost is unchanged, spread over more units, and for tax purposes the acquisition date of bonus units is their own, not the original purchase date. Anything computing capital gains has to know the difference. We got this wrong initially by treating bonus units as a split, and the gains reports were subtly wrong for the folios that had them.
Dividend payout is the simple one: cash leaves the scheme, NAV drops, the client gets a credit.
Dividend reinvestment is the same event followed immediately by a purchase at the ex-dividend NAV, and it is the single largest source of reconciliation breaks I've dealt with. Everything hinges on which NAV the reinvestment uses and how the resulting fractional units are rounded. If your rounding differs from the registrar's by a fraction in the third decimal, you don't get one break, you get a permanent divergence that compounds with every subsequent reinvestment on that folio.
Scheme mergers are the messy ones. Units in the merging scheme convert to units in the surviving scheme at a swap ratio, the old scheme code stops existing, and historical transactions still reference it. Old data cannot be rewritten to point at the new scheme, because then a statement for a period before the merger would show a scheme the client never held. The mapping lives alongside the ledger, and reporting resolves through it based on the date being reported.
Segregated portfolios, or side-pocketing, is the one that's genuinely specific to this market and genuinely hard. When a debt scheme has an issuer default, the affected holding is segregated into a separate portfolio with its own scheme code. Clients wake up holding two things where they held one, and the segregated part often has a NAV of zero pending recovery.
Zero is not the same as worthless, and it is definitely not a realised loss. If your reporting treats it as either, you've told a client they lost money that may well come back years later. Side-pocketed holdings need their own display treatment and their own exclusion from return calculations, and that requirement reaches surprisingly far up the stack, into charts and XIRR and the summary tiles on a dashboard.
They are ledger entries, not mutations
Every one of these is applied as an entry in the transaction ledger, never as an update to a holdings row. Holdings are derived by replaying the ledger in order, which is the same design the rest of the platform uses for ordinary transactions.
The reason is the same reason. Corporate actions arrive late, get revised, and occasionally get cancelled after being announced. A ratio gets corrected. An ex-date moves. If the action mutated a holdings row, reversing it means reconstructing a state you no longer have. As a ledger entry, a correction is another entry, the snapshots from that date forward are invalidated, and the position recomputes.
Idempotency deserves paranoia here. Feeds re-send corporate actions, sometimes days later, sometimes in a bulk file alongside new ones. Applying a 1:1 bonus twice quadruples a holding, and unlike a duplicated NAV it does not stand out as obviously wrong. Every action carries a natural key of scheme, action type and ex-date with a unique constraint behind it, and reapplication is a no-op unless the ratio has actually changed, in which case the previous entry is superseded rather than edited.
The ordering rule that saved us: corporate actions apply before transactions on the same date. A client redeeming on the ex-date of a bonus is redeeming from the post-bonus unit count. Getting that backwards produces a negative balance, which at least fails loudly, and the day it fails loudly is the day you find out your ordering was undefined.
The fix for the doubled portfolio
Valuation no longer runs against a unit count and a NAV independently. A holding is only valued with a NAV whose date is consistent with the unit count as of that date, and where the two are out of step, the position shows as pending revaluation rather than as a number.
It's less satisfying than a clever solution and it means an advisor occasionally sees "awaiting NAV" against a scheme on a bonus morning. Every advisor I've spoken to prefers that to the alternative, which is finding out from a client that the portfolio doubled overnight and then having to explain that it didn't.
Everything here sits on top of the ledger and reconciliation design I wrote about separately. If holdings in your system are a stored running total rather than something you derive, none of this is available to you, and corporate actions are where you find that out.