1. current_rate (required)
Technical: The borrower's current quoted mortgage rate in percent (e.g. 6.0 = 6%). This is the starting point r0 for all Monte Carlo simulation paths in the Vasicek model: r(t+1) = r(t) + kappa(theta - r(t))dt + sigma*epsilon.
Intuitive: "What rate did the borrower lock in (or get quoted)?" Every simulation path starts here and wanders from this point. It's the baseline everything is measured against — "will rates drop enough below this number to make refinancing worth it?"
2. historical_rates (optional)
Technical: An optional array of historical rate values (oldest-first, in %). When omitted, the server pulls the Freddie Mac PMMS 30-year weekly series from FRED. Requires minimum 3 data points. Used to derive three key model parameters: the long-run mean (theta), the volatility of rate changes (sigma), and optionally kappa via OLS regression.
Intuitive: "What past rate data should we learn from?" By default it uses real-world Freddie Mac weekly averages — decades of actual mortgage rate history. You'd override this if you wanted to analyze a specific product, a different loan type, or a custom scenario. The model looks at this history to figure out: "what's normal?", "how jumpy are rates?", and "how fast do they snap back?"
3. simulation_years (optional, default: 5)
Technical: The forward time horizon in years for the Monte Carlo simulation. Each path is simulated with monthly time steps (dt = 1/12) for this many years. Minimum 1 year.
Intuitive: "How far into the future are we looking for a refinance opportunity?" 5 years means: "what are the odds rates drop enough to refi sometime in the next 5 years?" A shorter horizon is more conservative ("I need rates to drop soon"), a longer one gives more chances for rates to dip low enough.
4. refi_trigger_bps (optional, default: 75)
Technical: The basis-point drop below current_rate that constitutes a refinancing opportunity. 75 means the borrower needs rates to fall 0.75% below their current rate. A Monte Carlo path "triggers" a refi event the first time r(t) <= current_rate - trigger/100.
Intuitive: "How big a rate drop does the borrower need before refinancing makes financial sense?" This accounts for closing costs — a tiny rate drop isn't worth the fees. 75 bps (0.75%) is a common rule of thumb. A borrower with a large loan balance might set this lower (even a small drop saves a lot), while someone with a small loan might need a bigger drop to justify the costs.
5. num_paths (optional, default: 1,000, max: 5,000)
Technical: The number of independent Monte Carlo simulation paths. Each path is a random walk of monthly rate values drawn from the Vasicek process. The refi probability is estimated as (paths that trigger) / (total paths), with a Wilson score 95% confidence interval.
Intuitive: "How many times do we roll the dice?" More paths = more precise probability estimates, but slower computation. 1,000 gives you a reasonable estimate. 5,000 gives you tighter confidence intervals. Think of it like polling — more respondents means a smaller margin of error. For most users, the default is fine.
6. kappa (optional, default: 0.15, range: 0.01-2.0)
Technical: The mean-reversion speed parameter (yr^-1) in the Vasicek model. Governs the drift term kappa(theta - r)dt — how strongly rates are pulled toward the long-run mean theta. Half-life of a deviation is approximately ln(2)/kappa. Ignored when auto_kappa is true.
Intuitive: "When rates get weird, how long do they stay weird?" At the default 0.15, a rate spike has a half-life of about 4.6 years — it takes that long for half the deviation to correct. At kappa=1.0, the half-life is about 8 months — spikes are short blips. At kappa=0.05, it is about 14 years — rates can stay elevated for a very long time. Higher kappa means "the market always corrects quickly." Lower kappa means "rate environments can persist for years."
7. auto_kappa (optional, default: false)
Technical: When true, kappa is estimated from the historical rate series via OLS regression on the discrete Vasicek equation: delta_r(t) = a + b*r(t) + epsilon, where kappa = -b*12 (annualized from monthly). Clamped to [0.01, 2.0]. Falls back to 0.15 if the series is too short. Takes precedence over the manual kappa field.
Intuitive: "Should the model figure out mean-reversion from the data itself?" Instead of you guessing how fast rates snap back, it measures how fast they actually snapped back historically. This is data-driven rather than assumption-driven. The tradeoff: historical mean-reversion might not reflect the future (e.g., if the Fed changes its policy approach). Manual kappa lets you inject your own view of the market.
8. sensitivity_triggers_bps (optional, max 5 values)
Technical: Additional refi trigger thresholds (in basis points) to include in the sensitivity grid. Combined with the default refi_trigger_bps value and the sensitivity horizons to produce a matrix of Monte Carlo results. Each cell in the grid runs 500 paths. Total grid capped at 20 cells.
Intuitive: "What if the borrower needs a different rate drop to justify refinancing?" This lets you see probabilities across multiple scenarios side-by-side. For example, pass [50, 75, 100, 125] to answer: "What are the odds of a half-point drop? Three-quarters? A full point? A point and a quarter?" Great for showing borrowers a range of outcomes instead of a single number.
9. sensitivity_horizons_years (optional, max 4 values)
Technical: Additional time horizons (in years) for the sensitivity grid. Combined with the trigger values to produce the full matrix. Each cell runs 500 independent Monte Carlo paths.
Intuitive: "What if the borrower is willing to wait longer — or needs it sooner?" Pass [1, 3, 5, 7] to show: "Here's the probability of a refi opportunity within 1 year, 3 years, 5 years, and 7 years." Paired with multiple triggers, you get a complete picture — a grid the loan officer can walk through with the borrower: "If you can wait 5 years and need a 75bp drop, there's an X% chance."
"Given where rates are today (current_rate), what we know about how rates have behaved (historical_rates), how quickly they revert to normal (kappa/auto_kappa), how far into the future we're looking (simulation_years), and how big a drop the borrower needs (refi_trigger_bps) — what's the probability a refinance opportunity appears?"
The sensitivity grid parameters (sensitivity_triggers_bps + sensitivity_horizons_years) then expand that single question into a matrix of scenarios the loan officer can present to clients.