Debt sizing calculator (DSCR, LTV and debt yield)
Debt sizing calculator: maximum commercial loan under DSCR, LTV and debt yield tests, the binding constraint, stress scenarios and refinance shortfall.
What it computes
Debt sizing finds the largest loan a property supports under a lender's tests. The calculator applies any combination of a maximum loan-to-value (LTV), a minimum debt service coverage ratio (DSCR) and a minimum debt yield, and the lowest of the resulting loan amounts is the maximum loan. It reports which test binds, the annual debt service, and the LTV, DSCR and debt yield of the final loan. It can also produce a stress table and a refinance shortfall against an existing balance.
Method and conventions
Debt service is based on an annual loan constant k. For an
amortizing loan with monthly payments,
k = 12 × r ÷ (1 − (1 + r)^−n), where
r = rate_annual ÷ 12 and
n = amortization_years × 12. At a zero rate the constant is
12 ÷ n. When amortization_years is 0 the loan is
interest-only and k = rate_annual.
Each supplied test gives a loan amount:
- LTV:
value × max_ltv - DSCR:
noi ÷ min_dscr ÷ k - Debt yield:
noi ÷ min_debt_yield
The maximum loan is the smallest of these, rounded down to
round_down_to. Before rounding, the amount is reduced to 15
significant digits so that floating-point noise (such as 0.57 × 10,000,000
evaluating just under 5,700,000) does not cost a whole increment. When two
tests give the same loan, the one listed first in the order LTV, DSCR, debt
yield is reported as binding. Annual debt service is
max loan × k, rounded to the cent. The resulting DSCR and debt
yield use that rounded loan and debt service.
Lenders differ on what income the tests use. Some size DSCR on net operating
income (NOI) and others on net cash flow after reserves, tenant improvements
and leasing commissions. FactLot applies both the DSCR and the debt-yield
tests to the single noi figure supplied, so a net cash flow
figure passed as noi sizes on net cash flow. Lenders also differ
on the payment basis. FactLot always uses monthly payments at the annual rate
÷ 12; it does not size on an actual/360 constant. Some lenders size an
interest-only loan on an amortizing constant; the DSCR test uses whatever
amortization_years is given, and 0 sizes on interest-only debt
service.
The optional stress table sizes every combination of NOI, rate
and value shocks under the same tests and rounding: NOI ×
(1 + noi_shock), rate + rate_shock, and value ×
(1 + value_shock). With value_moves_with_noi, value
is also scaled by each NOI shock, which holds the cap rate constant. A
scenario that supports less than one rounding increment reports a maximum loan
of 0 and null metrics. With existing_loan_balance, the refinance
shortfall is max(0, existing − max loan) and the excess proceeds
are max(0, max loan − existing).
For a period-by-period payment table on the sized loan, including an
interest-only period, a balloon at maturity, quarterly payments, or actual/360
and actual/365 interest, FactLot has a separate tool,
calc_amortization_schedule.
Inputs that matter
-
noi: underwritten annual income; it drives both the DSCR and the debt-yield tests. -
value: appraised or underwritten value; required whenmax_ltvis set. -
rate_annual: annual interest rate as a decimal, for example 0.065. -
amortization_years: amortization used for the loan constant; 0 means interest-only. max_ltv: maximum loan as a share of value.-
min_dscr: minimum NOI ÷ annual debt service, for example 1.25. min_debt_yield: minimum NOI ÷ loan amount.-
round_down_to: increment the final loan is floored to, such as 1,000 or 10,000. -
stressandexisting_loan_balance: optional scenario table and refinance comparison; the base result does not change.
Limits
- It does not build NOI or net cash flow from a rent roll or operating statement. The income figure is taken as given.
- Fixed rate only. Floating-rate loans, index caps, rate floors and interest reserves are not modeled.
- There is no loan-to-cost test, no loan term or maturity, and no fees or closing costs.
- One loan only. Mezzanine debt, preferred equity and combined-leverage tests are not covered.
-
At least one of
max_ltv,min_dscrandmin_debt_yieldis required. Inputs that allow a non-positive loan, or less than one rounding increment, return an error. - Stress rate shocks must keep the rate at or above 0 and below 1. A stress table allows at most ten shocks per dimension (1,000 scenarios).
Worked example
Inputs from FactLot's shared test case "LTV binds", which the TypeScript and Python libraries must both reproduce:
{
"noi": 1000000,
"rate_annual": 0.06,
"amortization_years": 30,
"max_ltv": 0.65,
"min_dscr": 1.25,
"min_debt_yield": 0.09,
"value": 15000000
}
Result
| Result | Value |
|---|---|
max_loan | 9,750,000 |
binding_constraint | ltv |
annual_constant | 0.071946 |
annual_debt_service | 701,474.11 |
Audit trail
Every intermediate value, in order, with the formula that produced it. Formula calc.debt_sizing@3.
| Step | Value | Formula |
|---|---|---|
| Annual constant | 0.071946 | 12 × r ÷ (1 − (1 + r)^−n), r = 0.06/12, n = 360 |
| Loan at max LTV | $9,750,000.00 | $15,000,000.00 × 0.65 |
| Loan at min DSCR | $11,119,440.96 | ($1,000,000.00 ÷ 1.25) ÷ 0.071946 |
| Loan at min debt yield | $11,111,111.11 | $1,000,000.00 ÷ 0.09 |
| Max loan | $9,750,000.00 | min(ltv $9,750,000.00, dscr $11,119,440.96, debt_yield $11,111,111.11), rounded down to 1 |
| Binding constraint | ltv |
Check it in Excel
The lender-debt-sizing.xlsx workbook recomputes this calculator with live Excel formulas beside FactLot's numbers and a difference column. Its inputs are synthetic; the reconciliation guide explains each sheet.
Use it from an agent or your code
- MCP: tool
calc_debt_sizingonhttps://api.factlot.com/mcp(connect a client). - Python:
factlot.run_tool("calc_debt_sizing", input)runs the same calculation offline (Python SDK). - Input schema: every field is described in tools.json.
curl -s https://api.factlot.com/v1/calc/debt_sizing \
-H 'content-type: application/json' \
-d '{"noi":1000000,"rate_annual":0.06,"amortization_years":30,"max_ltv":0.65,"min_dscr":1.25,"min_debt_yield":0.09,"value":15000000}'