# Returns and performance

zfin reports returns in a few different forms. This page explains what
each means so you can read [`perf`](../reference/cli/perf.md),
[`review`](../reference/cli/review.md), and the portfolio summary
correctly.

## Price-only vs. total return

Two columns show up throughout zfin:

- **Price only** -- the change in share price alone.
- **Total return** -- price change **plus** reinvested dividends. This
  is the number that reflects what you actually earned.

```
                           Price Only   Total Return
  1-Year Return:              27.29%        28.79%
  3-Year Return:              20.75%        22.22%  ann.
```

Total return needs dividend history, which comes from Polygon -- so it
requires `POLYGON_API_KEY`. Without it, you still get price-only
returns. For a dividend payer like SCHD the gap between the two columns
is large; for a non-payer it's near zero.

## Annualized (CAGR)

Multi-year returns are **annualized** -- expressed as a compound annual
growth rate (the constant yearly rate that produces the same total
growth), marked `ann.` in the output. A "3-Year Return: 22.22% ann."
means the holding grew as if by 22.22% every year for three years, not
22.22% total. One-year figures are already annual, so they carry no
`ann.` tag.

## As-of vs. month-end

[`perf`](../reference/cli/perf.md) prints two tables:

- **As-of** -- returns through the latest available close. The most
  current view.
- **Month-end** -- returns through the most recent calendar month-end.
  This matches how mutual funds and Morningstar quote their trailing
  numbers, so it's the apples-to-apples figure for comparison.

```
As-of 2026-06-04:        ...
Month-end (2026-05-31):  ...
```

## Risk metrics

[`perf`](../reference/cli/perf.md) and
[`review`](../reference/cli/review.md) also report risk, computed from
periodic returns:

- **Volatility** -- how much returns vary; higher means a bumpier ride.
- **Sharpe ratio** -- return earned per unit of volatility (risk-
  adjusted return). Higher is better; a negative Sharpe means the
  asset underperformed cash on a risk-adjusted basis over the window.
- **Max drawdown** -- the largest peak-to-trough decline over the
  period; a worst-case-loss gut check.

```
  3Y-Vol  10Y-Vol    3Y-SR   10Y-SR   5Y-MaxDD
   13.4%    15.8%     1.29     0.90      24.8%
```

### Reading the Sharpe ratio

Sharpe divides an asset's *excess* return -- its annualized return
**minus the risk-free rate** -- by its volatility. It answers "how much
extra return did I earn for the bumpiness I took on, versus just parking
the money risk-free?"

zfin uses the average 3-month US T-bill rate (FRED series DTB3) over the
same window as the return. That rate table is **hand-maintained**: it's
refreshed about once a year, and when it falls behind zfin prints a
`T-bill risk-free rate table is overdue for refresh` warning on stderr
(also shown by [`zfin doctor`](../reference/cli/doctor.md)). It blocks
nothing -- it's a nudge. Because the same rate feeds every holding, a
slightly stale rate barely shifts comparisons between them; refresh it
when the nag appears.

**Rough guide to what's "good":**

| Sharpe    | Read                                                                  |
|-----------|-----------------------------------------------------------------------|
| `> 1.0`   | Standout -- strong reward for the risk taken                          |
| `0.5-1.0` | Healthy -- where most solid long-term holdings sit                    |
| `0-0.5`   | Mediocre -- barely beating cash once risk is accounted for            |
| `< 0`     | Lost to cash on a risk-adjusted basis (the negative case noted above) |

These are the bands zfin uses to color the [`review`](../reference/cli/review.md)
dashboard: green above 0.5, yellow from 0 to 0.5, red below 0.

**Prefer the longer window.** A Sharpe measured over a single year is
noisy -- one strong or weak quarter swings it. The 10-year figure
averages across market regimes and is the steadier read, which is why
zfin reports Sharpe at **3Y and 10Y** rather than 1Y. When the two
disagree, lean on the longer window to judge a holding's risk-adjusted
quality.

## Portfolio-level returns

The portfolio summary's **Historical** line and the
[`projections`](../reference/cli/projections.md) benchmark block show
your holdings' *blended* return -- each position's return weighted by
its market value. It's a quick "how have my holdings done together"
read, and it includes the effect of your allocation (a bond-heavy
portfolio will trail an all-equity one, as you'd expect).

> These returns describe the securities, not your personal money-
> weighted return. They don't account for the timing of your
> contributions. To separate new money from market movement over a
> period, use [contributions](../guides/track-contributions.md).

The market value that weights these returns reflects zfin's
covered-call cap: an in-the-money written call holds its covered shares
at the strike rather than the live price, so it doesn't price the
option contract itself. See
[covered-call valuation](../guides/read-your-portfolio.md#covered-calls).

## See also

- [`zfin perf`](../reference/cli/perf.md) / [`zfin review`](../reference/cli/review.md)
- [Read your portfolio](../guides/read-your-portfolio.md) -- interpreting the dashboards.
