TRIR calculator
Yearly returns of 8%, -2% and 5% link to a total of 11.132%, because each period compounds on the one before instead of being averaged. You also get the compounded annualized return for any number of periods per year. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- Returns
- 8, -2, 5
- Periods per year
- 1
- N
- 3
- Years
- 3
- Growth factor
- 1.11132
- Total return
- 11.132
The total integrated rate of return, often abbreviated TRIR, is the compound growth a sequence of periodic results actually produced once those sub-period rates are geometrically linked rather than averaged. A simple mean of plus eight, minus two, and plus five percent overstates the path a portfolio took, because a loss shrinks the base on which later gains compound. This calculator accepts a non-empty list of periodic returns as percents, multiplies the growth factors one plus each rate, and annualizes the product with the number of periods per year so the headline figure is a compounded annualized return. An empty returns list is invalid input and is not billed.
What TRIR means and how the product is annualized
A list of periodic returns is not a single rate until the growth factors are multiplied. If period one earned eight percent, period two lost two percent, and period three earned five percent, the wealth relative is 1.08 times 0.98 times 1.05, not the arithmetic mean of those three percents. That product minus one is the total integrated rate of return over the whole window: the holding-period result you would have earned by leaving one unit invested through every listed period.
Comparing windows of different length still needs a common clock, so the calculator raises the same product to p over n and subtracts one, where n is the number of listed periods and p is how many of those periods fit in a calendar year. With p equal to one the list is treated as annual observations and the annualized figure is the geometric mean of the growth factors minus one.
With p equal to twelve a year of monthly observations annualizes in one step; twenty-four monthly observations span two years and the exponent becomes one half. A full minus one hundred percent period is a wipeout: the product is zero and the annualized return is minus one hundred percent. A return worse than minus one hundred percent would make a growth factor negative, which leaves the real numbers under a fractional exponent, so that entry is rejected instead of returning a complex value.
What you can do with it
Annualize a chain of sub-period portfolio returns
Link monthly or quarterly percent returns into one holding-period TRIR and the matching compounded annualized return, without collapsing the path into a begin-and-end CAGR.
Classroom and CFA time-weighted answer keys
Generate reproducible geometric-link results that distinguish an arithmetic mean of periodic rates from the product of growth factors on the same list.
FAQ
How is the total integrated rate of return (TRIR) calculated?
Each periodic percent is converted to a growth factor 1 + r. The product of those factors minus one is the holding-period TRIR.
Are the returns percents or decimals?
Percents. Send 8 for an eight percent period. Sending 0.08 would be treated as eight hundredths of a percent, not eight percent.
What happens if the returns list is empty?
A non-empty list is required; an empty array is rejected and is not billed.
How do I annualize monthly returns?
Set the periods per year to 12. A year of monthly figures then annualizes in one step, and twenty-four monthly figures span two years, so the linked product is raised to one half before subtracting one.
What happens with a -100% period?
It is a wipeout: the linked product becomes zero and the annualized return is -100%. A figure worse than -100% is refused, because a negative growth factor has no real annualized value.
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/trir \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"returns":[8,-2,5]}'const res = await fetch("https://api.kit.forhosting.com/fin/trir", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"returns": [
8,
-2,
5
]
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/fin/trir",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"returns": [
8,
-2,
5
]
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/fin/trir", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"returns":[8,-2,5]}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"returns":[8,-2,5]}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/fin/trir", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"returns": [
8,
-2,
5
]
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "fin.trir",
"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.
Limits
max_items | 10000 |
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
Input contract, empty lists, and the response shape
Eight means eight percent for that period, not a decimal 0.08 unless you truly intend eight hundredths of a percent. Use one for annual series, four for quarterly, twelve for monthly, fifty-two for weekly, or three hundred sixty-five for daily. A zero, a negative value, or a fraction such as 2.5 is rejected rather than rounded in silence. Failed validation does not consume balance. Keep lists at or below ten thousand periods. POST a JSON body whose required field is returns, a non-empty array of finite percents. Aliases periodic_returns, rates, and r map to the same list so a spreadsheet column can keep a familiar name. If returns is missing, empty, or not a list of finite numbers, the task fails with invalid_input naming returns and is not billed; the contracted empty-list message states that returns must be a non-empty list of periodic returns. Optional periods_per_year is a positive integer from one through three hundred sixty-five and defaults to one when omitted; aliases frequency, ppy, and compounds_per_year are accepted. Each scalar may arrive as a JSON number or a numeric string; the list itself may be a JSON array or a comma-separated string. On success the body echoes returns, reports n and periods_per_year, gives years as n divided by p, and returns growth_factor together with total_return as a percent, total_return_decimal as a fraction, annualized_return as a percent, and annualized_return_decimal as a fraction, plus a formula string restating the product identity.
Where a TRIR calculator earns its keep
Portfolio teams use a total integrated rate of return calculator when they already have a chain of sub-period results — monthly fund sheets, quarterly mandate reports, or annual contribution-adjusted time-weighted returns — and the question is the compounded annualized equivalent, not a begin-and-end CAGR that would ignore the path. Students and CFA candidates need a deterministic oracle that geometrically links a homework series and rejects an empty list instead of silently showing NaN that a buggy form might treat as success. Product teams wire the same contract into onboarding demos so a user who pastes twelve monthly percents with periods_per_year equal to twelve sees the identical annualized_return the API will later return in production tests. Keep requests small, pin rounded annualized_return in tests, and you get reproducible TRIR figures for worksheets, LMS plugins, and edge workers without standing up a spreadsheet service of your own.
Integration use cases
Product demos and CI fixtures
Seed performance widgets and automated tests with deterministic annualized_return values that match the free browser widget byte-for-byte.
Technical questions
How does periods_per_year change the annualized figure?
It sets p in G^(p/n) − 1. Default 1 treats each listed return as annual. Use 12 for monthly series, 4 for quarterly, 52 for weekly, or 365 for daily so a longer window annualizes over the correct number of years.
What does the TRIR calculator cost?
The browser tool is free. API requests use prepaid KIT balance at $0.002 per successful call; invalid input, including an empty returns list, is not billed.