Jamshidian Trick¶
Background¶
Jamshidian's trick for handling E[max(sum, K)] as sum of E[max].
This code is purely educational and comes from the Financial Engineering course by L.A. Grzelak, based on the book "Mathematical Modeling and Computation in Finance: With Exercises and Python and MATLAB Computer Codes", by C.W. Oosterlee and L.A. Grzelak, World Scientific Publishing Europe Ltd, 2019.
@author: Lech A. Grzelak
Code¶
```python """ Jamshidian's trick for handling E[max(sum, K)] as sum of E[max].
This code is purely educational and comes from the Financial Engineering course by L.A. Grzelak, based on the book "Mathematical Modeling and Computation in Finance: With Exercises and Python and MATLAB Computer Codes", by C.W. Oosterlee and L.A. Grzelak, World Scientific Publishing Europe Ltd, 2019.
@author: Lech A. Grzelak """
import numpy as np import matplotlib.pyplot as plt import scipy.optimize as optimize
======================================================================¶
def psi_sum(psi, n, x): """Compute sum of psi_i.""" temp = 0 for i in range(0, n): temp = temp + psi(i, x) return temp
def jamshidian_trick(psi, n, k): """Compute optimal strike using Jamshidian's trick.""" a = lambda x: psi_sum(psi, n, x) - k result = optimize.newton(a, 0.1) return result
def main(): """Main computation.""" num_samples = 1000 x = np.random.normal(0.0, 1.0, (num_samples, 1)) psi_i = lambda i, x: np.exp(-i * np.abs(x))
# Number of terms
n = 15
a = 0
for i in range(0, n):
a = a + psi_i(i, x)
k = np.linspace(2, 10, 10)
result_mc = np.zeros(len(k))
for (i, ki) in enumerate(k):
result_mc[i] = np.mean(np.maximum(a - ki, 0))
# Jamshidian's trick
result_jams = np.zeros(len(k))
for i, ki in enumerate(k):
# Compute optimal K*
opt_x = jamshidian_trick(psi_i, n, ki)
a = 0
for j in range(0, n):
a = a + np.mean(np.maximum(psi_i(j, x) - psi_i(j, opt_x), 0))
result_jams[i] = a
plt.figure()
plt.plot(k, result_mc)
plt.plot(k, result_jams, '--r')
plt.grid()
plt.xlabel('K')
plt.ylabel('expectation')
plt.legend(['Monte Carlo', "Jamshidian's trick"])
if name == "main": main() ```
Exercises¶
Exercise 1. Jamshidian's trick converts a swaption (option on a sum of cash flows) into a portfolio of options on individual cash flows. Explain the key insight.
Solution to Exercise 1
A payer swaption payoff is \(\max\!\bigl(\sum_{i=1}^n c_i P(T, T_i) - 1, 0\bigr)\), where \(c_i\) are coupon payments. Directly pricing this requires handling the maximum of a sum. Jamshidian's trick exploits the fact that in a one-factor model, all bond prices are monotonic in the short rate \(r(T)\). There exists a unique \(r^*\) such that \(\sum_i c_i P(T, T_i; r^*) = 1\). For \(r > r^*\), the swaption is in the money. The swaption decomposes into:
where \(K_i = P(T, T_i; r^*)\) and ZBP is the zero-coupon bond put price.
Exercise 2. Find \(r^*\) for a 1-year swaption on a 2-year annual swap with coupon \(5\%\) if \(P(1, 2; r) = e^{-0.8r}\) and \(P(1, 3; r) = e^{-1.5r}\). The condition is \(0.05\,e^{-0.8r^*} + 1.05\,e^{-1.5r^*} = 1\).
Solution to Exercise 2
This is a nonlinear equation that requires numerical solution. Testing \(r^* = 0.05\):
This exceeds 1, so \(r^*\) must be higher. Testing \(r^* = 0.08\):
This is below 1, so \(r^* \in (0.05, 0.08)\). Bisection or Newton's method gives \(r^* \approx 0.065\).
Exercise 3. Explain why Jamshidian's trick only works for one-factor models and fails for multi-factor models.
Solution to Exercise 3
The trick relies on all bond prices being monotonically decreasing functions of a single state variable \(r(T)\). In a one-factor model, higher \(r\) means lower prices for all bonds, so there is a unique \(r^*\) where the exercise boundary is crossed. In a multi-factor model (e.g., 2F Hull-White), bond prices depend on multiple state variables \((r, u)\). The exercise boundary \(\sum c_i P(T, T_i; r, u) = 1\) is a curve in \((r, u)\) space, not a single point. Different bonds may respond differently to the two factors, so no single threshold decomposes the problem into individual bond options.
Exercise 4. After finding \(r^*\) and the individual strikes \(K_i = P(T, T_i; r^*)\), how do you aggregate the individual bond option prices to obtain the swaption price?
Solution to Exercise 4
The swaption price is simply the sum of the weighted bond put prices:
where \(c_i\) is the cash flow at \(T_i\) (\(c_i = K\tau\) for intermediate coupons, \(c_n = 1 + K\tau\) for the final coupon including principal), and \(\text{ZBP}(0, T, T_i, K_i)\) is the Hull-White analytical put price on a \(T_i\)-maturity bond with strike \(K_i\) and option expiry \(T\). No optimization is needed at this stage -- it is a simple linear combination of known analytical prices.