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 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 12000annual_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 365compounding_per_year(integer, optional): min 1; max 365timing(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 12rate_scale(integer, optional): min 0; max 12rounding(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 1000000method(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:
{
"solve_for": "payment",
"periods": 10,
"annual_rate": "0.08",
"present_value": "10000"
}
Response:
{
"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), then call execute with:
{
"id": "tvm-solve",
"version": "1.0.0",
"input": {
"solve_for": "payment",
"periods": 10,
"annual_rate": "0.08",
"present_value": "10000"
}
}
HTTP (no key)
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.
CLI
node cli.mjs run tvm-solve 1.0.0 --input input.json --base-url https://computefirst.net
Get the client at /clients/cli/.
Related 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: MIRR of periodic cash flows from a finance rate and a reinvestment rate, with compounded and discounted totals.
- Cashflow npv: NPV of equally spaced cash flows, time-0 or Excel time-1, with inflow PV, outflow PV and profitability index.
- 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: Cent-exact level-payment loan schedule with per-period rounding, extra payments, dates and a row window.
- Bond cashflow schedule: Coupon dates, coupons remaining, accrued days and accrued interest for a regular fixed-coupon bond (Excel COUP* rules).