Skip to content

Commit

Permalink
fixed
Browse files Browse the repository at this point in the history
finally
  • Loading branch information
jong0077 committed Nov 27, 2024
1 parent f7f0a47 commit f1183a5
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 73 deletions.
102 changes: 42 additions & 60 deletions Testing.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "code",
"execution_count": 15,
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -12,84 +12,57 @@
},
{
"cell_type": "code",
"execution_count": 16,
"execution_count": 30,
"metadata": {},
"outputs": [],
"source": [
"test1 = AmericanOptionPricing(100, 0.025, 0.025, 0.25, 1, 10, 15,option_type=OptionType.Put,eta=0.5)"
"test1 = AmericanOptionPricing(100, 0.04, 0.04, 0.20, 3, 10, 3, 7, 200, option_type=OptionType.Put,eta=0.8)"
]
},
{
"cell_type": "code",
"execution_count": 17,
"execution_count": 31,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Jacobi-Newton iterations completed.\n",
"[ 61.49983948 61.90202814 63.12973443 65.23842875 68.29350105\n",
" 72.33045221 77.30132575 83.03118849 89.25971427 95.73561161\n",
" 100. ]\n"
]
}
],
"source": [
"test1.run_once()"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Starting iteration 1/10\n",
"Iteration 1/10 completed.\n",
"Starting iteration 2/10\n",
"Iteration 2/10 completed.\n",
"Starting iteration 3/10\n",
"Iteration 3/10 completed.\n",
"Starting iteration 4/10\n",
"Iteration 4/10 completed.\n",
"Starting iteration 5/10\n",
"Iteration 5/10 completed.\n",
"Starting iteration 6/10\n",
"Iteration 6/10 completed.\n",
"Starting iteration 7/10\n",
"Iteration 7/10 completed.\n",
"Starting iteration 8/10\n",
"Iteration 8/10 completed.\n",
"Starting iteration 9/10\n",
"Iteration 9/10 completed.\n",
"Starting iteration 10/10\n",
"Iteration 10/10 completed.\n",
"Starting iteration 1/3\n",
"Iteration 1/3 completed.\n",
"Starting iteration 2/3\n",
"Iteration 2/3 completed.\n",
"Starting iteration 3/3\n",
"Iteration 3/3 completed.\n",
"Jacobi-Newton iterations completed.\n"
]
}
],
"source": [
"test1.run_full_algorithm()"
"test1.run_full_algorithm()\n",
"#test1.run_once()"
]
},
{
"cell_type": "code",
"execution_count": 19,
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([ 61.2075653 , 61.52668244, 62.53737023, 64.38499353,\n",
" 67.27802552, 71.40766386, 76.87154055, 83.45660361,\n",
" 90.38381286, 94.43989948, 100. ])"
"array([ 61.24225892, 61.27712165, 61.38204477, 61.55803 ,\n",
" 61.80673573, 62.13045962, 62.53211128, 63.01517446,\n",
" 63.58365337, 64.24200295, 64.995034 , 65.84779433,\n",
" 66.80541202, 67.87290423, 69.05493176, 70.35550743,\n",
" 71.77763053, 73.32286494, 74.99082224, 76.77858653,\n",
" 78.68002539, 80.68506055, 82.77881187, 84.940758 ,\n",
" 87.14375634, 89.35320157, 91.52597224, 93.60973108,\n",
" 95.54162409, 97.24761131, 98.63915229, 99.60889207,\n",
" 100. ])"
]
},
"execution_count": 19,
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
Expand All @@ -100,22 +73,31 @@
},
{
"cell_type": "code",
"execution_count": 14,
"execution_count": 32,
"metadata": {},
"outputs": [],
"source": [
"test1.compute_pricing_points()"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Jacobi-Newton iterations completed.\n",
"[ 61.20951883 61.52816165 62.53772039 64.3837907 67.27601203\n",
" 71.40508714 76.87015086 83.45701518 90.37601681 94.42164035\n",
" 100. ]\n"
]
"data": {
"text/plain": [
"(12.196022514072425, 0.40929466849989227)"
]
},
"execution_count": 33,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"test1.manual_update()"
"test1.compute_option_pricing(100)"
]
}
],
Expand Down
33 changes: 20 additions & 13 deletions src/dq_plus.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from scipy.interpolate import BarycentricInterpolator
from scipy.integrate import quad
from src.chebyshev_interpolator import ChebyshevInterpolator
from src.Option import OptionType
from src.Option import OptionType, EuropeanOption
from src.quadrature_nodes import QuadratureNodes
from src.utils import QDplus

Expand All @@ -13,7 +13,7 @@ class AmericanOptionPricing:
This class handles initialization of exercise boundary, fixed-point iteration, and interpolation.
"""

def __init__(self, K, r, q, vol, tau_max, n, l,p, option_type=OptionType.Put, eta=0.5):
def __init__(self, K, r, q, vol, tau_max, l, m, n, p, option_type=OptionType.Put, eta=0.5):
"""
Initialize the DQPlus engine with option parameters and collocation nodes.
Expand All @@ -29,11 +29,13 @@ def __init__(self, K, r, q, vol, tau_max, n, l,p, option_type=OptionType.Put, et
self.q = q
self.vol = vol
self.n = n
self.m = m
self.l = l
self.eta = eta
self.option_type = option_type
self.X = self.K * min(1, self.r/self.q)
self.tau_max = tau_max
self.iteration_no = 0

self.initial_boundary = np.zeros(self.n+1)
self.updateded_boundary = np.zeros(self.n+1)
Expand Down Expand Up @@ -88,8 +90,8 @@ def compute_option_pricing(self,S):
# Step 1: Compute European option price
tau = self.tau_max

european_price = self.K * np.exp(-self.r * self.tau_max) * norm.cdf(self.d2(tau, S/self.K)) - S * np.exp(-self.q * tau) * norm.cdf(-self.d1(tau,S/self.K))
european_price = EuropeanOption.european_put_value(self.tau_max, S, self.r, self.q, self.vol, self.K)

integral1 = self.compute_pricing_integral_1(S)
integral2 = self.compute_pricing_integral_2(S)

Expand Down Expand Up @@ -216,7 +218,7 @@ def evaluate_boundary(self):

# Use the quadrature nodes obtained in the quadacture earlier
for k, y_k in enumerate(self.y_nodes):
adjusted_tau = tau - tau * (1 + y_k)**2 / 4 # Obtain the adjusted tau for each y_k, but the adjusted tau cannot be negative
adjusted_tau = tau - tau * (1 + y_k)**2 / 4 # Obtain the adjusted tau for each y_k, but the adjusted tau cannot be too small
z = 2 * np.sqrt(adjusted_tau / self.tau_max) - 1 # From the tau obtain the z value
qz_interpolated[k] = max(self.clenshaw_algorithm(z, self.chebyshev_coefficients),0) # Interpolate qz using the clenshaw algorithm

Expand All @@ -237,7 +239,7 @@ def K1_integrad (self, tau, B, yk_nodes, B_y):
K1integrads = np.zeros(k)

for i,yk in enumerate(yk_nodes):
term0 = 0.25 * tau * (1 + yk)**2
term0 = tau * (1 + yk)**2 / 4
term1 = np.exp(-self.q * term0)
term2 = (1 + yk)
term3 = norm.cdf(self.d1(term0, B / B_y[i]))
Expand Down Expand Up @@ -266,7 +268,7 @@ def K2(self):
for i in range(self.n):
tau = self.tau_nodes[i]
integrad = self.K2_integrad(tau, self.updateded_boundary[i], self.y_nodes, self.B_yk[i])
self.k2[i] = tau*np.exp(self.q*tau)*sum(integrad*self.w_weights)
self.k2[i] = np.sqrt(tau)*np.exp(self.q*tau)*sum(integrad*self.w_weights)

def K3_integrand(self, tau, B_tau, yk_nodes, B_y):
k = len(yk_nodes)
Expand All @@ -283,7 +285,7 @@ def K3(self):
for i in range(self.n):
tau = self.tau_nodes[i]
integrad = self.K3_integrand(tau, self.updateded_boundary[i], self.y_nodes, self.B_yk[i])
self.k3[i] = tau*np.exp(self.r*tau)*sum(integrad*self.w_weights)
self.k3[i] = np.sqrt(tau)*np.exp(self.r*tau)*sum(integrad*self.w_weights)

def compute_ND_values(self):
"""
Expand Down Expand Up @@ -318,7 +320,10 @@ def DPrime(self):
self.D_prime = -self.d2(self.tau_nodes[:-1], self.updateded_boundary[:-1]/self.K) * norm.pdf(self.d1(self.tau_nodes[:-1], self.updateded_boundary[:-1]/self.K)) / (self.updateded_boundary[:-1] * self.vol * self.vol * self.tau_nodes[:-1])

def fprime(self):
self.f_prime = self.K*np.exp(-(self.r-self.q)*self.tau_nodes[:-1])*(self.N_prime/self.D_values - self.D_prime*self.N_values/(np.square(self.D_values)))
if self.iteration_no == 0:
self.f_prime = self.K*np.exp(-(self.r-self.q)*self.tau_nodes[:-1])*(self.N_prime/self.D_values - self.D_prime*self.N_values/np.square(self.D_values) )
else:
self.f_prime = np.zeros(len(self.tau_nodes[:-1]))

def update_boundary(self):
"""
Expand Down Expand Up @@ -357,7 +362,7 @@ def update_boundary(self):
B_next[self.n] = self.updateded_boundary[self.n]
return B_next

def run_full_algorithm(self, m=2):
def run_full_algorithm(self):
"""
Run the complete Jacobi-Newton iterative scheme for pricing American options.
Expand All @@ -368,8 +373,8 @@ def run_full_algorithm(self, m=2):
- B_values (numpy array): The final boundary values after m iterations.
"""
self.initialize_boundary()
for j in range(1, m + 1):
print(f"Starting iteration {j}/{m}")
for j in range(1, self.m + 1):
print(f"Starting iteration {j}/{self.m}")

# Step 5: Compute H(sqrt(tau)) and initialize Chebyshev interpolation
H_values = self.compute_H()
Expand All @@ -391,7 +396,7 @@ def run_full_algorithm(self, m=2):
# Step 9: Update B_values using the Jacobi-Newton scheme
self.updateded_boundary = self.update_boundary()

print(f"Iteration {j}/{m} completed.")
print(f"Iteration {j}/{self.m} completed.")

print("Jacobi-Newton iterations completed.")

Expand Down Expand Up @@ -419,6 +424,7 @@ def run_once(self):
self.updateded_boundary = self.update_boundary()
print("Jacobi-Newton iterations completed.")
print(self.updateded_boundary)
self.iteration_no = 1


## Manually run once more for testing
Expand All @@ -444,6 +450,7 @@ def manual_update(self):
self.updateded_boundary = self.update_boundary()
print("Jacobi-Newton iterations completed.")
print(self.updateded_boundary)
self.iteration_no += 1



Expand Down
18 changes: 18 additions & 0 deletions src/quadrature_nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,21 @@ def get_nodes_and_weights(self):
raise ValueError("Nodes and weights have not been computed yet. Call compute_legendre_nodes() first.")

return self.y_nodes, self.w_weights

def compute_tanh_sinh_nodes(self):
"""
Compute the Tanh_sinh quadrature nodes and weights.
"""
n = self.l
nodes = np.zeros(n)
weights = np.zeros(n)

# Compute the nodes and weights
for k in range(n):
# Compute the k-th node
nodes[k] = np.tanh(np.pi * (k + 0.5) / n)

# Compute the weight for the k-th node
weights[k] = (np.pi / n) / (np.cosh(np.pi * (k + 0.5) / n) ** 2)

self.y_nodes, self.w_weights = nodes, weights

0 comments on commit f1183a5

Please sign in to comment.