Annualized rate of return
An investment that grew from 10,000 to 16,105.10 in five years gained 61.05% in total, which is exactly 10% a year once compounding is counted. Compare holdings of any length on the same per-year basis. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- Initial value
- 10,000
- Final value
- 16,105.1
- Years
- 5
- Annualized return pct
- 10
- Annualized return
- 0.1
- Total return pct
- 61.051
You provide the initial value, the final value and the holding period in years, and it returns the constant yearly percentage that would have carried the first number to the second — the geometric annualized return — together with the total return over the whole period. It runs deterministically, with no market data and no assumptions about intermediate cash flows, so the same inputs always produce the same answer, whether you call it once in a browser or a million times from a reporting pipeline.
What the annualized rate of return actually measures
An investment that grows from 10,000 to 16,105.10 over five years gained 61.05 percent in total, but that figure is useless for comparing it against something held for eighteen months. The annualized rate of return converts any holding period into a per-year figure by asking which constant yearly growth rate, compounded, reproduces the observed change. Mathematically it is r = (final / initial)^(1 / years) − 1, expressed here as a percentage.
For the example above the answer is exactly 10 percent per year. Because the formula takes the n-th root of the growth multiple, it properly accounts for compounding: two consecutive years of 10 percent produce 21 percent in total, not 20. The result is the geometric annualized return, which is the correct measure when gains are reinvested and you want a single comparable yearly figure.
Inputs, validation and how to read the output
All three inputs are required. A negative annualized figure means the investment lost value on a per-year compounded basis. If any field is missing or not a finite number, the error message names the offending field so a form or pipeline can highlight exactly what to fix.
What you can do with it
Compare investments held for different periods
Normalize a three-year stock position and an eighteen-month flip to the same per-year basis before deciding which performed better.
Backfill yearly performance in a report
Feed start and end balances into a reporting pipeline and attach a consistent annualized figure to every account, fund or portfolio.
Check whether a target was met
Verify that an investment that was supposed to return 8 percent per year actually did, given what you put in and what you got out.
FAQ
What happens if the holding period is zero or negative?
The holding period must be greater than zero.
Can the final value be zero?
Yes. A final value of zero represents a total loss and produces an annualized return of minus 100 percent.
Does it handle contributions or withdrawals during the period?
No. It assumes a single buy-and-hold position between two valuations. For cash flows in between, you need an internal rate of return calculation instead.
Is a negative result possible?
Yes. Whenever the final value is below the initial value, the annualized return is negative, reflecting a compounded yearly loss.
Why isn't the annualized return just the total return divided by the years?
Because gains compound. Two consecutive years of 10% produce 21% in total, not 20%, so the calculator takes the root of the growth multiple instead of dividing, which gives the true rate per year.
Related tools
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/fin/annualized-rate-of-return \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"initial_value":10000,"final_value":16105.1,"years":5}'const res = await fetch("https://api.kit.forhosting.com/fin/annualized-rate-of-return", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"initial_value": 10000,
"final_value": 16105.1,
"years": 5
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/fin/annualized-rate-of-return",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"initial_value": 10000,
"final_value": 16105.1,
"years": 5
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/fin/annualized-rate-of-return", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"initial_value":10000,"final_value":16105.1,"years":5}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"initial_value":10000,"final_value":16105.1,"years":5}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/fin/annualized-rate-of-return", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"initial_value": 10000,
"final_value": 16105.1,
"years": 5
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "fin.annualized_rate_of_return",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |
Technical notes
The annualized rate of return API answers the one question every investment comparison eventually reduces to: what did this earn per year?
What the annualized rate of return actually measures
The endpoint requires only three numbers — initial value, final value and years — and the years value may be fractional, so a position held for thirty months is simply 2.5 years.
Inputs, validation and how to read the output
The initial value must be strictly greater than zero, because a growth multiple relative to zero is undefined; the final value may be zero, which represents a total loss and yields an annualized return of minus 100 percent; and the holding period must be positive — a request with zero or negative years is rejected with an invalid_input error and is never charged. The response echoes the three inputs so your records stay self-describing, then adds the annualized return both as a percentage and as a decimal fraction, plus the total return over the full period for context.
When to use it — and when not to
Do not use it when money moved in or out during the period — contributions and withdrawals distort the simple two-point formula, and the right tool there is an internal rate of return calculation over the actual cash flows. Use this endpoint whenever you hold only the two endpoints of an investment: the purchase and sale price of a property, the starting and ending balance of an account with no intermediate contributions, or the value of a position at two report dates. It is ideal for normalizing investments held for different lengths of time so they can be ranked fairly, and for backfilling a yearly performance figure in dashboards and client reports. It also smooths volatility by construction: an asset that doubled, halved and doubled again shows only the net path between the two endpoints. The calculation costs $0.002 per call via the API and runs free in your browser on this page, with exactly the same code on both sides, so the number you test with is the number you pay for.
Technical questions
What does it cost?
$0.002 per request via the API. It is also free to run in your browser on this page.
Which formula does it use?
r = (final_value / initial_value)^(1 / years) − 1, returned as a percentage. This is the geometric annualized return, which accounts for compounding.