Appearance
TSR & Attribution
Total shareholder return is the rate of return a shareholder earns on a position over a window. EqtyTrk computes both raw TSR and a five-bar drag waterfall that decomposes TSR into its driving components.
Total Shareholder Return
Where
EqtyTrk's /v1/companies/{ticker}/tsr endpoint computes the dividend-reinvested variant: each dividend buys additional shares at the ex-date close. Final value = (1 + accumulated shares) ×
TSR drag waterfall
The waterfall decomposes TSR into five additive components on a per-original-shareholder basis:
Where
Multiplying by the original-holder's starting position (
How the chain decomposes
The waterfall is path-dependent. Each bar is the incremental delta from applying that one factor on top of the prior factors:
Component contributions (signed dollar amounts):
The dilution bar is positive for buybacks (which transfer value to holders that don't sell), negative for net share issuance.
Per-original-shareholder framing
This is the load-bearing convention: the waterfall describes value gained by an original shareholder, not by current shareholders.
Why: when a company buys back shares, it transfers value to the holders who don't sell. Their stake is worth more even though the corporate market cap may have grown by less. The two framings give different totals:
| Framing | Total value created |
|---|---|
| Current-shareholder (corporate) | |
| Per-original-shareholder |
For AAPL FY20→FY25 the two framings diverge by ~$485B — roughly the value transferred to non-selling holders through buybacks.
EqtyTrk uses per-original-shareholder framing throughout the attribution view. It matches the actual experience of an investor who held through the period.
Worked example: AAPL FY20 → FY25
| Endpoint | Value |
|---|---|
| Start (2020-09-26) | |
| End (2025-09-27) | |
| Revenue | |
| Net margin | |
| P/E | |
| Shares | |
| DPS total (5y) |
Running the multiplicative chain:
| Step | Running MC | Contrib |
|---|---|---|
| Start | — | |
| After revenue | ||
| After margin | ||
| After multiple | ||
| After buybacks | ||
| Dividends | — | |
| Total | — |
Note that "After shares" (
How to read it
- Revenue + margin > multiple change signals operations-driven appreciation. Healthy. In this example revenue ($813B) and margin ($401B) together account for roughly half the gain.
- Multiple change > revenue + margin signals re-rating. Sustainability depends on whether the new multiple is justified by forward growth.
- Negative dilution (net issuance) is value destruction unless paired with a productive use of proceeds (acquisition that contributed to margin or revenue).
- Positive dilution (buybacks) is value transfer to holders who didn't sell. Whether it's a good use of cash depends on whether buybacks were funded from earnings or debt, and whether the shares were bought below intrinsic value.
Limitations
- DPS approximation. The dividend contrib uses
rather than tracking per-payment shares. Slight overcount when shares were lower at the time of earlier dividends; slight undercount the other way. - No reinvestment. The waterfall assumes the original shareholder pocketed dividends rather than reinvested. For comparison with reinvested-TSR, the reinvested number is typically a few percentage points higher.
- Path-dependent. Reordering the chain (margin before revenue, etc.) shifts each component's contribution while preserving the total. The convention is revenue → margin → multiple → shares; swapping them changes individual bars.
- Multi-period DPS. Treats all dividends as paid against
. Real-world dividend yields evolve. - Insufficient history. When a company is younger than the requested window, or revenue is zero / non-positive at the start endpoint, the decomposition isn't computable. The UI surfaces an empty state with an explanation.
- Degenerate margins. When net income is non-positive at either endpoint, the margin + multiple math is degenerate. The waterfall collapses to a single "operations" bar plus the dilution and dividend bars. A note surfaces in the UI when this happens.
Implementation notes
compute_tsr_drag()insrc/eqtytrk/attribution/tsr_drag.py- Frontend rendering:
frontend/src/components/AttributionView.tsx - Picks the FY-end nearest to (today − N years) using a ±90 day window. Returns
Nonewhen historical price data or financials are missing. - Falls back to a collapsed "operations" bar when net income is non-positive at either endpoint (margin/multiple math is degenerate).
- Price lookup walks back up to 14 calendar days from the FY end to handle weekends and holidays (
_price_on_or_before).
References
- Morgan Stanley equity research methodology, TSR Decomposition (mid-2010s).
- McKinsey Insights, "The CEO's guide to corporate finance" (2011).