Background Specifically, the 2026 value of Deriving the model We can derive the Hull–White analytical solution where the continuous-time Vasicek SDE is given by: (Note: We use for the speed of mean reversion and for the long-term mean here to follow standard mathematical notation). Step 1 (Use an Integrating Factor) Rewrite the SDE by expanding the drift term: Multiply both sides by the integrating factor to simplify the left-hand side: Notice that the left-hand side is precisely the product rule for differentiation applied to : Step 2 (Integrate from to ) Integrate both sides from a starting time to a future time : Evaluating the integrals: Step 3 (Solve for ) Divide the entire equation by (which is equivalent to multiplying by ): Deterministic Component (Expected Path): As the time horizon grows large, , meaning the expected future rate converges entirely to the long-term mean . If current rates are high ( ), the exponential decay pulls them down. If they are low ( ), they are pulled up. Stochastic Component (Random Shocks): Because it is an integral of a deterministic function with respect to a Wiener process, the stochastic term is normally distributed. Its conditional variance can be computed via Itô's isometry as: My attempt Let's use a 18-year time horizon ( years, starting from in 2008). Our parameters: Initial yield ( ): Speed of mean reversion ( ): Volatility ( ): Time horizon ( ): years For the long-term mean, because it shifted from to post-2021, the effective long-term target over the latter half averages out roughly near . Step 1 (Calculate the Exponential Decay Factor) (Notice that because years is very long relative to , this term becomes almost zero, meaning the starting rate has virtually no impact left by 2026—the process has fully settled around the long-term mean). Step 2 (Calculate the Expected Value (Mean)) \begin{align*} \mathbb{E}[r_t \mid r_s] &= r_s e^{-\kappa(t-s)} + \theta \left( 1 - e^{-\kappa(t-s)} \right)\ &= (4.65 \times 0.00183) + 4.2 \left( 1 - 0.00183 \right)\ &\approx 0.0085 + 4.2 \left( 0.99817 \right)\ &\approx 0.0085 + 4.1923\ &\approx 4.20% \end{align*} Step 3 (Calculate the Standard Deviation) \begin{align*} \text{Var}(r_t \mid r_s) &= \frac{\sigma^2}{2\kappa} \left( 1 - e^{-2\kappa(t-s)} \right)\ &= \frac{0.55^2}{2 \times 0.35} \left( 1 - e^{-2(0.35 \times 18)} \right)\ &= \frac{0.3025}{0.7} \left( 1 - e^{-12.6} \right)\ &\approx 0.4321 \times (1 - 0.000003)\ &\approx 0.4321 \end{align*} Taking the square root gives the standard deviation ( ): Step 4 (Final Simulated Outcome) In the python code below, the random shock drawn ( ) happened to be positive (about standard deviations above the mean due to the aggressive 2022–2026 inflation/rate hike cycle): \begin{align*} Z&=\frac{\text{Actual Final Value}\text{−Expected Deterministic Mean}}{\text{Total Standard Deviation}}\ &= \frac{5.01 - 4.20}{0.657}\ &= \frac{0.81}{0.657}\ &\approx +1.23 \end{align*} where: Actual Final Value: (the terminal yield produced by the stochastic simulation) Expected Deterministic Mean: (the baseline long-term target under the Hull–White regime-shift model) Total Standard Deviation ( total): (the cumulative volatility calculated via Itô's isometry over the -year period) \begin{align*} \text{Result} &= \text{Mean} + (Z \times \text{StdDev})\ &= 4.20% + (1.23 \times 0.657%)\ &\approx \boxed{5.01%} \end{align*} import numpy as np
Let's run a simulation for CIR (Cox-Ingersoll-Ross) and Hull-White models
np.newaxis np.random.seed(42)
N = 216 # Monthly steps from 2008 to 2026 dt = 1 / 12
1. CIR Model simulation: dr = theta * (mu - r_t)dt + sigma * sqrt(r_t) * dW_t
theta_cir = 0.4 mu_cir = 3.3 sigma_cir = 0.35 # Must satisfy Feller condition: 2 * theta * mu >= sigma^2 to stay positive
r_cir = np.zeros(N) r_cir[0] = 4.65
for i in range(1, N): # Ensure non-negative inside sqrt r_prev = max(0.0, r_cir[i-1]) dr = theta_cir * (mu_cir - r_prev) * dt + sigma_cir * np.sqrt(r_prev) * np.sqrt(dt) * np.random.randn() r_cir[i] = r_prev + dr
2. Hull-White Model (Time-varying mean theta(t) or drift to fit term structure)
Simplest time-varying mean formulation: theta(t) matches a shifting trend
theta_hw = 0.35 sigma_hw = 0.55
r_hw = np.zeros(N) r_hw[0] = 4.65
for i in range(1, N): t_val = 2008 + i * dt # Let the long-term mean drift higher post-2021 to capture the inflation regime shift mu_t = 3.0 if t_val < 2021 else 4.2
dr = theta_hw * (mu_t - r_hw[i-1]) * dt + sigma_hw * np.sqrt(dt) * np.random.randn()
r_hw[i] = r_hw[i-1] + dr
print(f"CIR Model 2026 Terminal Value: {r_cir[-1]:.2f}%") print(f"Hull-White (Regime-Shift) 2026 Terminal Value: {r_hw[-1]:.2f}%") ##CIR Model 2026 Terminal Value: 4.71% ##Hull-White (Regime-Shift) 2026 Terminal Value: 5.01% My question Would this derivation be succinct? I believe that I have an error with SDE used , and , apparently in percentage points. That's internally possible, but then the reported standard deviation calculation is wrong in its interpretation: meaning percentage points if rates are measured in percentage points? Also, the Hull–White equation that I derived isn't actually the standard Hull–White specification we're subsequently describing, as derivation starts from where is constant. That's essentially the Vasicek model, but the standard one-factor Hull–White is with a time-dependent drift chosen to fit today's initial yield curve?

