Crank-Nicolson Method - python

I need to write the following pseudocode into Python code:
enter image description here
And here is my code:
import math
def f(x):
v = math.sin(math.pi/2*x)
return v
def zero_matrix(i, j, start_from=1):
matrix = [[-1] * (j+start_from)]
for x in range(i):
line = [-1] * start_from + [0] * j
matrix.append(line)
return matrix
def zero_vector(i, start_from=1):
return [-1] * start_from + [0] * i
def algo_12_3(l, T, alpha, m, N):
"""Crank-Nicolson Method.
Args:
l: endpoint
T: maximum time
alpha: constant
m:
N:
Return:
approximations wi,j to u(xi, tj) for each i=i,...,m-1 and j=1,...,N.
"""
w = zero_matrix(m, N)
z = zero_vector(m-1)
ll = zero_vector(m-1)
u = zero_vector(m-1)
h = l / m
k = T / N
lambda_ = alpha * alpha * k / (h * h)
for i in range(1, m):
w[i][0] = f(i * h)
ll[1] = 1 + lambda_
u[1] = -lambda_/(2*ll[1])
for i in range(2, m-1):
ll[i] = 1 + lambda_ + lambda_ * u[i-1]/2
u[i] = -lambda_/(2 * ll[i])
ll[m-1] = 1 + lambda_ + lambda_ * u[m-2]/2
for j in range(1, N + 1):
t = j * k
z[1] = ((1 - lambda_) * w[1][j-1] + lambda_ / 2 * w[2][j-1]) / ll[1]
for i in range(2, m):
z[i] = ((1 - lambda_) * w[i][j-1] + lambda_ / 2 * (w[i+1][j-1] + w[i-1][j-1] + z[i-1])) / ll[i]
w[m-1][j] = z[m-1]
for i in range(m-2, 0, -1):
w[i][j] = z[i] - u[i] * w[i+1][j]
print('t={}: '.format(t))
for i in range(1, m):
print('({}, {})'.format(i*h, w[i][j]))
algo_12_3(2, 0.1, 1, 4, 2)
My outputs are:
t=0.05:
(0.5, 0.6282614874855517)
(1.0, 0.8822836003342388)
(1.5, 0.5449281541522184)
t=0.1:
(0.5, 0.55687611895338)
(1.0, 0.7741379272219071)
(1.5, 0.5013205633978245)
However, the correct outputs should be:
t=0.05:
(0.5, 0.62884835)
(1.0, 0.88932586)
(1.5, 0.62884835)
t=0.1:
(0.5, 0.59404972)
(1.0, 0.84011317)
(1.5, 0.59404972)
I don't know if it's with the range or with the initial matrix formation. Can anyone help me with it? Thanks a lot!! Appreciate it!

Related

Plotting Monte Carlo Simulations for option pricing in Python

I am trying to show the monte carlo barrier prices for different number of simultations in the x axis. This is what i tried so far but i'm getting the error -> ValueError: x and y must have same first dimension, but have shapes (10,) and (5,).
I am new to python and as hard as i try i cannot find the error
import numpy as np
import numpy.random as npr
import matplotlib.pyplot as plt
def mc_single_barrier_do(S0, K, T, H, r, vol, N, M):
# Constants
dt = T / N # change in time
nudt = (r - 0.5 * vol ** 2) * dt # deterministic component
volsdt = vol * np.sqrt(dt) # diffusion coefficient
erdt = np.exp(r * dt) # discount factor
# Standard Error Placeholders
sum_CT = 0
sum_CT2 = 0
# Monte Carlo Method
for i in range(M):
# Barrier Crossed Flag
BARRIER = False
St = S0
for j in range(N):
epsilon = np.random.normal()
Stn = St * np.exp(nudt + volsdt * epsilon)
St = Stn
Ptn = np.exp(-2. * (H - St) * (H - Stn) / (St ** 2. * volsdt ** 2.))
Pt = Ptn
if Pt >= npr.uniform():
BARRIER = True
if np.amin(St) > H and BARRIER == False:
CT = np.maximum(St - K, 0)
else:
CT = 0.
sum_CT = sum_CT + CT
sum_CT2 = sum_CT2 + CT * CT
C0_MC = np.exp(-r * T) * sum_CT / M
return C0_MC
def sim_iterator(max_sample, N, S0, T, r, vol, K, H, method):
assert (method in ['MC', 'AV', 'CV'])
mean_payoffs = np.zeros(int(np.ceil(max_sample / 10)))
if method == 'MC':
for n_sample in range(10, max_sample + 1, 10):
payoffs = mc_single_barrier_do(n_sample, S0, K, T, H, r, vol, N)
mean_payoffs[int(n_sample / 10 - 1)] = np.mean(payoffs)
return mean_payoffs
r = 0.1
vol = 0.2
T = 2
N = 20
dt = T / N
S0 = 50
K = 50
H = 45
max_sample = 100
MC_price_estimates = sim_iterator(S0, T, r, vol, K, H, max_sample, N, method='MC')
x_axis1 = range(10, max_sample + 1, 10)
plt.plot(x_axis1, MC_price_estimates)
plt.xlabel("No. of Simulations")
plt.ylabel("Estimated option price")
plt.title("Ordinary Monte Carlo Method")
plt.legend()
plt.show()
in your function definition you used:
def sim_iterator(max_sample, N, S0, T, r, vol, K, H, method):
while when using the function you used:
MC_price_estimates = sim_iterator(S0, T, r, vol, K, H, max_sample, N, method='MC')
python has positional arguments, which means the arguments are mapped according to their position, not their name, so in the first position is mapped to the first argument, which means S0 in the second line was mapped to max_sample in the first line, just fix the arguments arrangement, or use keyword arguments S0=S0.
MC_price_estimates = sim_iterator(S0=S0, T=T, r=r, vol=vol, K=K, H=H, max_sample=max_sample, N=N, method='MC')
this is what your code will look like when you fix all arguments to be keyword arguments.
def mc_single_barrier_do(S0, K, T, H, r, vol, N, M):
# Constants
dt = T / N # change in time
nudt = (r - 0.5 * vol ** 2) * dt # deterministic component
volsdt = vol * np.sqrt(dt) # diffusion coefficient
erdt = np.exp(r * dt) # discount factor
# Standard Error Placeholders
sum_CT = 0
sum_CT2 = 0
# Monte Carlo Method
for i in range(M):
# Barrier Crossed Flag
BARRIER = False
St = S0
for j in range(N):
epsilon = np.random.normal()
Stn = St * np.exp(nudt + volsdt * epsilon)
St = Stn
Ptn = np.exp(-2. * (H - St) * (H - Stn) / (St ** 2. * volsdt ** 2.))
Pt = Ptn
if Pt >= npr.uniform():
BARRIER = True
if np.amin(St) > H and BARRIER == False:
CT = np.maximum(St - K, 0)
else:
CT = 0.
sum_CT = sum_CT + CT
sum_CT2 = sum_CT2 + CT * CT
C0_MC = np.exp(-r * T) * sum_CT / M
return C0_MC
def sim_iterator(max_sample, N, S0, T, r, vol, K, H, method):
assert (method in ['MC', 'AV', 'CV'])
mean_payoffs = np.zeros(int(np.ceil(max_sample / 10)))
if method == 'MC':
for n_sample in range(10, max_sample + 1, 10):
payoffs = mc_single_barrier_do(M=n_sample,S0= S0, K=K, T=T, H=H, r=r, vol=vol, N=N)
mean_payoffs[int(n_sample / 10 - 1)] = np.mean(payoffs)
return mean_payoffs
r = 0.1
vol = 0.2
T = 2
N = 20
dt = T / N
S0 = 50
K = 50
H = 45
max_sample = 100
MC_price_estimates = sim_iterator(S0=S0, T=T, r=r, vol=vol, K=K, H=H, max_sample=max_sample, N=N, method='MC')
x_axis1 = range(10, max_sample + 1, 10)
plt.plot(x_axis1, MC_price_estimates)
plt.xlabel("No. of Simulations")
plt.ylabel("Estimated option price")
plt.title("Ordinary Monte Carlo Method")
plt.legend()
plt.show()

Scipy linear-constrained optimisation out of bounds

I am trying to maximize certain logLikelihood function, given trajectory T and parameter tMax, with respect to set o 2d + 2d^2 parameters X, where d is fixed integer.
Each parameter valid range is (0, 10), with exception to parameters with indexes 2*i+1 for i in range(d) (using Python convention). For those, the valid range is (-10, 10). Additionally, I create linear constraints, that for each i in range(d) X[2 * i] + X[2 * i + 1] * (tMax + 1.0) >=0
Here is implementation:
# T given
tMax = 500.0
_d = 2
# part of gradient for constraint X[2 * i] + X[2 * i + 1] * (tMax + 1.0) for i fixed in range(_d)
def grad_for_i(i, d, t_max):
g = np.zeros(2 * d + 2 * d**2)
g[2 * i] = 1.0
g[2 * i + 1] = t_max + 1.0
return g
# array of zeros of lenght l with 1 on index j
def one_on_jth(j, l):
r = [0.0 for _ in range(l)]
r[j] = 1.0
return r
new_lin_const = {
'type': 'ineq',
'fun' : lambda x: np.array(
[x[2 * i] + x[2 * i + 1] * (tMax+ 1.0) for i in range(_d)]
+ [x[j] for j in range(2*_d + 2*_d**2) if j not in [2 * i + 1 for i in range(_d)]]
),
'jac' : lambda x: np.array(
[grad_for_i(i, _d, tMax) for i in range(_d)]
+ [one_on_jth(j, 2*_d + 2*_d**2) for j in range(2*_d + 2*_d**2) if j not in [2 * i + 1 for i in range(_d)]]
)
}
X0 = [1.0 for _ in range(2 * (_d ** 2) + 2 * _d)]
bds = [(0.0, 10.0) for _ in range(2 * (_d ** 2) + 2 * _d)]
for i in range(_d):
bds[2*i + 1] = (-10.0, 10.0)
res = optimize.minimize(lambda x, args: -logLikelihood (x, args[0], args[1]),
constraints=new_lin_const, x0 = X0, args=([T, tMax]), method='SLSQP', options={'disp': True}, bounds=bds)
Procedures converges, but result given is out of linear constraints defined bounds:
print(res.x)
#array([ 1.38771114, -0.72145294, 1.3960635 , -0.22399423, 1.49987397,
# 1.45837707, 1.49958886, 1.45772475, 5.88312636, 5.83211339,
# 5.81175866, 5.67393651])
How is it possible, result is out of bounds?

Plot the multiple values returned by a function

My function returns 2 different values which I want to utilise in 2 different graphs using Matplotlib. How can I achieve it?
def option_value_european_put(T, m, r, sigma, mu, E):
cost_value_at_initial_t_put = []
portfolio_payoff_put = []
for e in E:
delta_t = T / m
u = (1 + (sigma * math.sqrt(delta_t)) * (math.sqrt(1 + ((mu ** 2) * delta_t) / math.pow(sigma, 2))))
v = 2 - u
option_stock_price_matrix_put = np.zeros((m + 1, m + 1))
sum = 0
k = m
start = m
for i in range(m + 1):
option_stock_price_matrix_put[i][start] = max(
(e - stock_price_binomial_model(
mu, sigma, T, m,
S
)[i][start], 0)
)
for j in range(m - 1, -1, -1):
for i in range(0, j + 1):
v_plus = option_stock_price_matrix_put[i][j + 1]
v_minus = option_stock_price_matrix_put[i + 1][j + 1]
v_t = ((((v_plus - v_minus) / (u - v)) * (1 + r * delta_t)) + (u * v_minus - v * v_plus) / (u - v)) / (
1 + r * delta_t)
option_stock_price_matrix_put[i][j] = v_t
cost_value_at_initial_t_put.append(option_stock_price_matrix_put[0][0])
for i in range(0, m+1):
sum = sum + option_stock_price_matrix_put[k][i]
portfolio_return_average = math.average(sum)
portfolio_payoff_put.append(portfolio_return_average-option_stock_price_matrix_put[0][0] )
return cost_value_at_initial_t_put, portfolio_payoff_put
I want to use cost_value_at_initial_t_put in 1 Matplotlib plot and the other value in another plot. How can I use it?
Supposing that cost_value_at_initial_t_put and portfolio_payoff_cut are both lists you can create subplots:
import matplotlib.pyplot as plt
fig, (ax_cost, ax_payoff) = plt.subplots(nrows=2)
ax_cost.plot(cost_value_at_initial_t_put)
ax_payoff.plot(portfolio_payoff_cut)

Error with list index out of range

It's uncomfortable code, I know, and sorry. Especially, if it's a stupid question.
Here is an error with list, and I don't know why (I'm beginner). Can someone, please, tell me, how to fix it?
This is the output:
Traceback (most recent call last):
File "C:/Users/milom/PycharmProjects/ChislM/method.py", line 77, in <module>
vx, vy = rk3(diff1, 0, U0, 10, 100)
File "C:/Users/milom/PycharmProjects/ChislM/method.py", line 39, in rk3
x,v=step(f, h, i, x0, U0)
File "C:/Users/milom/PycharmProjects/ChislM/method.py", line 11, in step
k2 = f(x[i] + (1 / 3) * h[i], v[i] + (1 / 3) * k1)
IndexError: list index out of range
Code:
import matplotlib.pyplot as plt
import math as m
import pandas as pd
x =[0]*101
v =[0]*101
def step(f, h, i, x0, U0):
x[0] = x0
v[0] = U0
k1 = f(x[i], v[i])
k2 = f(x[i] + (1 / 3) * h[i], v[i] + (1 / 3) * k1)
k3 = f(x[i] + (2 / 3) * h[i], v[i] + (2 / 3) * h[i] * k2)
x[i] = x[i - 1] + h[i]
v[i] = v[i - 1] + (h[i]) * ((1 / 4) * k1 + (3 / 4) * k3)
return x, v
def rk3(f, x0, U0, x1, n):
h = [(x1 - x0) / float(n)]
for i in range(1, n+1):
x,v=step(f, h, i, x0, U0)
###h= control(f, h[i], i, v[i], x0, U0)
return x, v
def diff1(x, U):
return 0.1
def diff(x, U):
return -(m.cos(10 * x) + ((m.log(1 + x ** 2)) / (1 + x)) * (U ** 2) + U)
def exact_path():
plt.grid()
plt.plot(vx, vy)
plt.show()
def table():
mytable = pd.DataFrame({
'Xn': vx,
'Vn': vy,
}, index=[i for i in range(0, 101)])
mytable.index.name = 'number'
pd.set_option('display.max_rows', None)
print(mytable)
task = int(input("Task:"))
U0 = float(input("First value- U0:"))
if task == 2:
vx, vy = rk3(diff, 0, U0, 10, 100)
table()
exact_path()
if task == 1:
vx, vy = rk3(diff1, 0, U0, 10, 100)
table()
exact_path()
P.S. It's a simple 3th order Runge-Kutta method, but mostly problem with synthax. I tried to implement method with Python.
In the rk3() function you have h = [(x1 - x0) / float(n)] which creates an list with only a single element in it. This means that the only valid non-negative index that can be used with it would be h[0]—and an attempt to use any other index value, as is likely in the step() function in the for loop, will cause an IndexError.

Value Error, Shapes do Not Align Python

Yeah, so this is my code in multiclass logistic regression, but when I run it it gives the error of Value Error, Shapes not aligned or whatever.
import numpy
import matplotlib.pyplot as plt
import math as mt
#normalized and feature scaled
Just loading the data set
def load():
data = numpy.loadtxt(open("housing.data.txt", "rb"), dtype="float")
m, n = data.shape
first_col = numpy.ones((m, 1))
#create new array using new parameters
data = numpy.hstack((first_col, data))
#divide each X with the max in the column
#subtract the mean of X to each element
for l in range(1, n):
max = 0.0
sum = 0.0
for j in range(0, m):
if max < data[j, l]:
max = data[j, l]
sum += data[j, l]
avg = sum / m
for j in range(0, m):
data[j, l] -= avg
data[j, l] /= max
return data
def logistic(z):
z = z[0,0]
z = z * -1
return (1.0 / (1.0 + mt.exp(z)))
def hyp(theta, x):
x = numpy.mat(x)
theta = numpy.mat(theta)
return logistic(theta * x.T)
#cost and derivative functions: TO REWRITE
#regularize using "-1000/m (hyp(theta, data[x, :-1]))"
def derv(theta, data, j):
sum = 0.0
last = data.shape[1] - 1
m = data.shape[0]
for x in range(0, m):
sum += (hyp(theta, data[x, :-1]) - numpy.mat(data[x, last])) +
numpy.mat(data[x, j])
return (sum[0,0] / m)
#regularize using " + 1000/2m(hyp(theta, data[x, :-1]))"
def cost(theta, data):
sum = 0.0
last = data.shape[1] - 1
m = data.shape[0]
for x in range(0, m):
y = data[x, last]
sum += y * mt.log(hyp(theta, data[x, :-1])) + (1 - y) * mt.log(1
- hyp(theta, data[x, :-1]))
return -1 * (sum / m)
data = load()
data1 = data[:, [10]]
data2 = data[:, [13]]
d12 = numpy.hstack((data1, data2))
data3 = data[:, [14]]
pdata = numpy.hstack((d12, data3))
print(pdata)
alpha = 0.01
theta = [10,10,10,10]
ntheta = [0,0,0,0]
delta = 50
x = 0
for l in range(0, 1000):
old_cost = cost(theta, pdata)
for y in range(0, data.shape[1] - 1):
ntheta[y] = theta[y] - alpha * derv(theta, data1, y)
for k in range(0, data.shape[1] - 1):
theta[k] = ntheta[k]
new_cost = cost(theta, data1)
delta = new_cost - old_cost
print("Cost: " + str(new_cost))
print("Delta: " + str(delta))
for r in range(0, data.shape[1]):
if hyp(theta, data1[r, :-1]) >= 0.5:
print("Predicted: 1 Actual: " + str(data1[r, data1.shape[1] - 1]))
else:
print("Predicted: 0 Actual: " + str(data1[r, data1.shape[1] - 1]))
plt.scatter(data1[:, 1], data1[:, 2])
x1 = (-1 * theta[0]) / theta[1]
x2 = (-1 * theta[0]) / theta[1]
x = range(-2, 2)
y = [((-1 * theta[0]) - (theta[1] * z) ) for z in x]
plt.plot(x, y)
plt.show()
I'm guessing it cant be plotted like this or idk

Categories

Resources