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 when max_ltv is 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.
  • stress and existing_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_dscr and min_debt_yield is 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 values
ResultValue
max_loan9,750,000
binding_constraintltv
annual_constant0.071946
annual_debt_service701,474.11

Audit trail

Every intermediate value, in order, with the formula that produced it. Formula calc.debt_sizing@3.

Audit trail
StepValueFormula
Annual constant0.07194612 × 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.00min(ltv $9,750,000.00, dscr $11,119,440.96, debt_yield $11,111,111.11), rounded down to 1
Binding constraintltv

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_sizing on https://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}'