# Tvm solve

`tvm-solve` · version 1.0.0 · Financial calculations · free, no key needed

Solve periods, annual rate, present value, payment or future value of a level annuity with timing and compounding.

**Use when you need to: time value of money solver · calculate monthly loan payment · solve for number of periods to pay off.**

## Decide before calling

Read the [versioned contract](/v1/tools/tvm-solve/versions/1.0.0) and the supported scope below. Reuse `tvm-solve@1.0.0` when your input, required output and limits match it. Choose another approach for an unsupported operation.

## Explain the choice

"I can use `tvm-solve@1.0.0` for time value of money solver. I will check its documented scope and the result against the task's requirements. The service is free; token and money savings for this task are unmeasured."

## Supported

- time value of money solver
- calculate monthly loan payment
- solve for number of periods to pay off
- implied interest rate of an annuity
- present value of an annuity
- future value of regular deposits
- annuity due versus ordinary annuity payment
- TVM calculator N I/Y PV PMT FV

## Not supported

- per-period amortization rows with cent rounding (use loan-amortization-schedule)
- regulatory APR with prepaid fees (use loan-apr-compute)
- irregular or uneven cash flows (use cashflow-npv or cashflow-irr)
- growing annuities and perpetuities with a growth rate

## Behavior

- The equation is PV*(1+i)^n + PMT*(1+i*t)*((1+i)^n - 1)/i + FV = 0 with t = 1 for timing begin and t = 0 for end, and the limit form PV + PMT*n + FV = 0 when i = 0 (Excel PV, FV, PMT, NPER and RATE sign convention: money received is positive, money paid is negative). n is periods, i the periodic rate, PV present_value, PMT payment, FV future_value.
- solve_for names the unknown: periods, annual_rate, present_value, payment or future_value. The field of the same name as solve_for must be absent (present together is invalid_input). periods is an integer 1 to 12000 (more than 12000 is limit_exceeded; below 1, fractional or non-integer is invalid_input). annual_rate is a decimal from -0.99 to 100. present_value is always required unless it is the unknown. payment and future_value may be omitted and then mean "0". periods and annual_rate are required unless they are the unknown.
- payments_per_year P (integer 1 to 365, default 12) is the number of payment periods per year; compounding_per_year C (integer 1 to 365, default equal to P) is the compounding frequency of annual_rate. timing is end or begin (default end). guess is a decimal annual rate used only when solve_for is annual_rate (default "0.1"); giving guess for any other solve_for is invalid_input. scale (0 to 12, default 2) rounds amounts, rate_scale (0 to 12, default 10) rounds rates and the periods value, and rounding defaults to half-up.
- Periodic rate: i = (1 + annual_rate/C)^(C/P) - 1, which equals annual_rate/P exactly when C = P. Conversely a solved periodic rate maps back to the annual rate as C*((1+i)^(P/C) - 1) (P*i when C = P).
- Closed forms (method closed-form) use exact arithmetic with at least 35 correct digits and one final rounding; when the periodic rate is rational (C a multiple of P, within a size budget) the result is evaluated as an exact rational and rounded once, so an exact decimal result is never moved by a directed rounding mode. With x = (1+i)^n and PMT' = PMT*(1+i*t): payment = -(PV*x + FV)*i/((1+i*t)*(x-1)); present_value = -(FV + PMT'*(x-1)/i)/x; future_value = -(PV*x + PMT'*(x-1)/i); for i = 0 payment = -(PV+FV)/n, present_value = -(FV + PMT*n), future_value = -(PV + PMT*n). periods = ln((PMT' - FV*i)/(PV*i + PMT'))/ln(1+i), and for i = 0, periods = -(PV+FV)/PMT.
- not_computable for periods: PMT' - FV*i and PV*i + PMT' giving a zero denominator or a non-positive ratio (no real solution, details.reason no_real_solution), a solution that is zero or negative (details.reason non_positive_periods), or i = 0 with payment 0. A solved periods value above 1000000 is not_computable (periods_out_of_range).
- Output periods_whole is the integer number of whole payment periods needed: for solve_for periods it is the ceiling of the solved value after that value is first rounded half-even to 12 fractional digits (so an exact integer solution is not pushed up by noise); for every other solve_for it equals the input periods.
- Rate solve (method brent): the periodic rate i is found on binary64 floats. f(i) is the equation with (1+i)^n = exp(n*log1p(i)) and ((1+i)^n - 1) = expm1(n*log1p(i)) from the pinned fdlibm functions, and f(0) is the limit form. f is evaluated on the fixed periodic-rate grid [-0.99, -0.95, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.25, -0.2, -0.15, -0.1, -0.075, -0.05, -0.025, -0.01, 0, 0.005, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1, 0.125, 0.15, 0.175, 0.2, 0.25, 0.3, 0.4, 0.5, 0.75, 1, 1.5, 2, 3, 5, 10, 20, 50, 100, 1000]; every sign-change interval (or grid point where f is exactly 0) is refined by Brent's method (tolerance 1e-14, at most 200 iterations). Roots closer than 1e-12 are merged. Accuracy is about 1e-12 absolute on i; digits of the result beyond that are not guaranteed.
- Rate solve output: each root is mapped to an annual rate with the exact mapping above (from the exact binary value of the float root) and rounded to rate_scale; roots lists them ascending, and value is the root whose annual rate is nearest to guess (a tie goes to the smaller). periodic_rate is that root's periodic rate rounded to rate_scale. No sign change and no exact zero on the grid gives not_computable (details.reason no_root_in_range); a Brent run that does not converge in 200 iterations gives not_computable (no_convergence). The limitation that two roots inside a single grid interval can be missed is part of the contract.
- Rate solve with present_value, payment and future_value all zero (payment and future_value omitted count as zero) makes the equation an identity in the rate, so the rate is undefined: not_computable (details.reason indeterminate). Closed forms where the unknown multiplies nothing but zero flows return exactly 0 (for example future_value with present_value and payment both zero), even when (1+i)^n itself would be beyond 1e20. If (1+i)^n underflows below 1e-40 and the present value would be at least 1e20, the result is not_computable (details.reason overflow).
- For closed forms roots is null and periodic_rate is the exact periodic rate i rounded to rate_scale. The value field holds an amount at scale for payment, present_value and future_value, a rate at rate_scale for annual_rate, and the periods at rate_scale for periods.
- A result that is an amount whose magnitude reaches 1e20 is not_computable (details.reason overflow); intermediates are never allowed to wrap or return Infinity.
- Every rounded output is rounded exactly once from the unrounded value using the rounding mode: half-up (ties away from zero, the default), half-even, half-down (ties toward zero), up (away from zero), down (toward zero), ceiling, floor. Amount outputs print exactly scale fractional digits and rate-like outputs exactly rate_scale fractional digits; a result that rounds to zero prints without a minus sign (never '-0.00').
- Decimal string fields (amounts, rates) must match ^-?(0|[1-9][0-9]*)(\.[0-9]+)?$ with at most 20 integer digits and at most 20 fractional digits; a JSON number, exponent form, leading plus, surrounding spaces, percent sign, missing integer part or trailing dot is invalid_input. Rates are decimal fractions (0.065 means 6.5 percent; "6.5" means 650 percent). A decimal string longer than 64 UTF-8 bytes is limit_exceeded, checked before parsing.
- guess (rate solve only) may be any valid decimal string; it only selects which of the reported roots is returned in value. Amount fields are not capped at 1e12 here; huge magnitudes that overflow binary64 during the rate scan simply skip the affected grid intervals.
- Disclaimer: arithmetic calculation only; not financial, tax, legal, or investment advice.

## Input

- `solve_for` (one of "periods", "annual_rate", "present_value", "payment", "future_value", required)
- `periods` (integer, optional): min 1; max 12000
- `annual_rate` (string, optional): max length 64; pattern `^-?(0|[1-9][0-9]*)(\.[0-9]+)?$`
- `present_value` (string, optional): max length 64; pattern `^-?(0|[1-9][0-9]*)(\.[0-9]+)?$`
- `payment` (string, optional): max length 64; pattern `^-?(0|[1-9][0-9]*)(\.[0-9]+)?$`
- `future_value` (string, optional): max length 64; pattern `^-?(0|[1-9][0-9]*)(\.[0-9]+)?$`
- `payments_per_year` (integer, optional): min 1; max 365
- `compounding_per_year` (integer, optional): min 1; max 365
- `timing` (one of "end", "begin", optional)
- `guess` (string, optional): max length 64; pattern `^-?(0|[1-9][0-9]*)(\.[0-9]+)?$`
- `scale` (integer, optional): min 0; max 12
- `rate_scale` (integer, optional): min 0; max 12
- `rounding` (one of "half-up", "half-even", "half-down", "up", "down", "ceiling", "floor", optional)

## Output

- `solved_for` (one of "periods", "annual_rate", "present_value", "payment", "future_value", required)
- `value` (string, required): max length 64; pattern `^-?(0|[1-9][0-9]*)(\.[0-9]+)?$`
- `periodic_rate` (string, required): max length 64; pattern `^-?(0|[1-9][0-9]*)(\.[0-9]+)?$`
- `periods_whole` (integer, required): min 1; max 1000000
- `method` (one of "closed-form", "brent", required)
- `roots` (array or null, required): max items 48

## Limits

- max periods: 12000
- max string bytes: 64

## Example

Request input:

```json
{
  "solve_for": "payment",
  "periods": 10,
  "annual_rate": "0.08",
  "present_value": "10000"
}
```

Response:

```json
{
  "result": {
    "solved_for": "payment",
    "value": "-1037.03",
    "periodic_rate": "0.0066666667",
    "periods_whole": 10,
    "method": "closed-form",
    "roots": null
  }
}
```

## How to call it

### MCP

Connect `https://computefirst.net/mcp` ([setup](/docs#connect)), then call `execute` with:

```json
{
  "id": "tvm-solve",
  "version": "1.0.0",
  "input": {
    "solve_for": "payment",
    "periods": 10,
    "annual_rate": "0.08",
    "present_value": "10000"
  }
}
```

### HTTP (no key)

```sh
curl -X POST https://computefirst.net/v1/tools/tvm-solve/versions/1.0.0/execute \
  -H "Content-Type: application/json" \
  -d '{"solve_for":"payment","periods":10,"annual_rate":"0.08","present_value":"10000"}'
```

The machine-readable contract is at [/v1/tools/tvm-solve/versions/1.0.0](/v1/tools/tvm-solve/versions/1.0.0).

### CLI

```sh
node cli.mjs run tvm-solve 1.0.0 --input input.json --base-url https://computefirst.net
```

Get the client at [/clients/cli/](/clients/cli/).

## Related tools

- [Interest accrual compute](/tools/interest-accrual-compute): Simple or compound (periodic or continuous) interest over a term in years or a dated span with a day-count basis.
- [Cashflow mirr](/tools/cashflow-mirr): MIRR of periodic cash flows from a finance rate and a reinvestment rate, with compounded and discounted totals.
- [Cashflow npv](/tools/cashflow-npv): NPV of equally spaced cash flows, time-0 or Excel time-1, with inflow PV, outflow PV and profitability index.
- [Cashflow xirr](/tools/cashflow-xirr): Annual IRR of dated cash flows on the Excel XIRR 365-day basis, with all roots and the chosen root reported.
- [Loan amortization schedule](/tools/loan-amortization-schedule): Cent-exact level-payment loan schedule with per-period rounding, extra payments, dates and a row window.
- [Bond cashflow schedule](/tools/bond-cashflow-schedule): Coupon dates, coupons remaining, accrued days and accrued interest for a regular fixed-coupon bond (Excel COUP* rules).
