Skip to content

Examples

Real-world DSCR scenarios using dscr-ratio. Every example is runnable Rust; copy any block into cargo run or the DSCRRadar DSCR loan calculator to see the full line-item breakdown.

1. A clean single-family rental

$100k loan at 7% for 30 years, $2,000/mo rent, ~$600/mo operating expenses.

use dscr_ratio::{monthly_payment, annual_debt_service, dscr, verdict};

let principal = 100_000.0;
let rate      = 0.07;
let months    = 360;

let monthly_pmt = monthly_payment(principal, rate, months); // ≈ 665.30
let debt        = annual_debt_service(monthly_pmt);          // ≈ 7,983.61

// NOI = (rent - opex) * 12, debt service excluded
let gross_rent  = 2_000.0 * 12.0;   // 24,000
let opex        = 600.0  * 12.0;    //  7,200
let noi         = gross_rent - opex; // 16,800

let ratio = dscr(noi, debt);        // ≈ 2.10
println!("DSCR = {:.2} ({})", ratio, verdict(ratio)); // 2.10 (strong)

This deal clears most DSCR lender thresholds with room to spare.

2. Break-even property

NOI exactly equals annual debt service — DSCR = 1.00, verdict marginal.

use dscr_ratio::{dscr, verdict};

let ratio = dscr(20_000.0, 20_000.0);  // exactly 1.00
assert!((ratio - 1.0).abs() < 1e-9);
assert_eq!(verdict(ratio), "marginal"); // 1.00 is in the [1.00, 1.15) band

1.00 is not a pass

The crate buckets 1.00 as marginal, but in practice most DSCR lenders require ≥ 1.20–1.25. A 1.00 deal leaves zero margin for vacancy, repairs, or rate increases.

3. Tight deal — sizing the max loan

Given a target DSCR of 1.25, what's the largest loan the NOI supports? Work backwards: annual_debt_service_max = noi / 1.25, then solve for principal.

use dscr_ratio::{dscr, monthly_payment, annual_debt_service, verdict};

let noi   = 18_000.0;
let rate  = 0.075;
let months = 360;
let target = 1.25;

// Max annual debt service the NOI can carry at target DSCR
let max_debt   = noi / target;                       // 14,400
let max_monthly = max_debt / 12.0;                   // 1,200

// Invert the amortization: principal that produces max_monthly at this rate/term
let r = rate / 12.0;
let n  = months as f64;
let max_principal = max_monthly * ((1.0 + r).powf(n) - 1.0)
                               / (r * (1.0 + r).powf(n));

// Verify
let check = dscr(noi, annual_debt_service(monthly_payment(max_principal, rate, months)));
println!("max loan ≈ ${:.0}, check DSCR = {:.2} ({})",
         max_principal, check, verdict(check));
// max loan ≈ $171,xxx, check DSCR = 1.25 (good)

4. Comparing two quotes

Same NOI, two different rate/term quotes — see which lands the better verdict.

use dscr_ratio::{monthly_payment, annual_debt_service, dscr, verdict};

let noi = 15_000.0;

let a = dscr(noi, annual_debt_service(monthly_payment(120_000.0, 0.075, 360)));
let b = dscr(noi, annual_debt_service(monthly_payment(120_000.0, 0.0825, 360)));

println!("7.50%: {:.2} ({})", a, verdict(a)); // ≈ 1.46 (strong)
println!("8.25%: {:.2} ({})", b, verdict(b)); // ≈ 1.39 (strong)

Both qualify; the lower rate widens the cushion.

5. Zero-interest / interest-only edge case

monthly_payment handles a zero rate as straight-line principal, so a $120k, 0%, 360-month "loan" just returns $333.33/mo — useful for modeling seller financing or deferred balances.

use dscr_ratio::monthly_payment;

assert!((monthly_payment(120_000.0, 0.0, 360) - 333.3333).abs() < 1e-3);

Next steps

For full underwriting — reserves, vacancy assumptions, multiple rate sheets — paste your NOI and loan terms into the DSCRRadar DSCR loan calculator.