# 自定义利率模拟函数的输出结果不符合预期

``````def vasicek_sim(initial, final_time, sim_path_len, num_paths=None, *,
a, b, sigma, allow_neg=True):
"""

Parameters
----------
inital : float
the initial value of interest rate, i.e. r(0).
final_time : int
the time when the simulation stops.
sim_path_len : int
the number of points generated after the initial data.
num_paths : int, optional
the number of paths simulated. The default is None.
a : float
the parameter used in corresponding interest rate model.
b : float
the parameter used in corresponding interest rate model.
sigma : float
the parameter used in corresponding interest rate model.
allow_neg : bool, optional
when it equals to True, a negative interest rate is allowable
in the simulation. The default is True.

Returns
-------
None.

"""
import math, random
""""Create a list to store a path of interest rate(IR)"""
if type(initial) == list:
path_initial = initial
else:
path_initial = [initial]
delta = final_time / sim_path_len
"""" Generate a original path_box which has num_paths identical initial."""
if num_paths == None:
num_paths = 1
path_box = [path_initial for i in range(num_paths)]
y = [] # Used to store the paths of IR that have negative IR.
exp = math.exp(-a*delta)
"""" When num_paths is default value, there is only one path."""
for i in path_box:
for j in range(sim_path_len):
#print(i[-1])
r_old = i[-1]
W_1 = random.gauss(0, 1)
W_2 = random.gauss(0, 1)
#print(f'{W_1 = }\n{W_2 = }')
r_new = (exp*r_old
+ b*(1-exp)
+ sigma*((1-exp**2)/(2*a))**0.5*(W_2-W_1))
if allow_neg == False and r_new < 0:
print(r_new)
break
#print(r_new)
#print(i)
i.append(r_new)
# The paths removed before are appended to path_box again.
if y != []:
path_box.append(y)
return path_box``````

``````if __name__ == '__main__':
z = vasicek_sim([0.25, 0.3, 0.4], 2, 3, 2, a=0.5, b=0.6, sigma=0.2)
print(f'The path of interest rate is\n {z}')``````

``````The path of interest rate is
[[0.25, 0.3, 0.4, 0.3479323841038564, 0.2375140125192349, 0.40864261608808583, 0.5588591529202444, 0.3464802076221359, 0.2132402884958335], [0.25, 0.3, 0.4, 0.3479323841038564, 0.2375140125192349, 0.40864261608808583, 0.5588591529202444, 0.3464802076221359, 0.2132402884958335]]``````

If nothing wrong, it is caused by following statement.

``path_box = [path_initial for i in range(num_paths)]``

The items in list, `path_box`, will be all referenced to same variable `path_initial`, needed to be done shallow copy, like

``path_box = [path_initial.copy() for i in range(num_paths)]``

then you will get the expected result

``````[
[0.25, 0.3, 0.4, 0.7714668192797642, 0.4566794244275462, 0.6019010230728543],
[0.25, 0.3, 0.4, 0.41725434747677215, 0.3613226425994896, 0.5180695456476787],
]``````
3周前 评论
Ivanharry （楼主） 3周前
``````a = [1, 2, 3]
b = a
c = a.copy()``````

``````a[0] = 0
print(a)
print(b)
print(c)``````
``````[0, 2, 3]
[0, 2, 3]
[1, 2, 3]``````

3周前 评论

python import math
import random

def vasicek_sim(initial, final_time, sim_path_len, num_paths=1, a=None, b=None, sigma=None, *, allow_neg=True):
"""
Simulate paths using the Vasicek interest rate model.

``````Parameters
----------
initial : float or list of float
The initial value(s) of the interest rate.
final_time : float
The time when the simulation stops.
sim_path_len : int
The number of time steps in each simulation path.
num_paths : int, optional
The number of paths to simulate. Default is 1.
a, b, sigma : float, required
The parameters of the Vasicek model. These should not be optional.
allow_neg : bool, optional
Whether to allow negative interest rates in the simulation. Default is True.

Returns
-------
list of list of float
A list containing the simulated paths.
"""
if a is None or b is None or sigma is None:
raise ValueError("Parameters a, b, and sigma are required for the Vasicek model.")

if isinstance(initial, list):
path_initial = initial
else:
path_initial = [initial] * num_paths

delta = final_time / sim_path_len
exp = math.exp(-a * delta)
path_box = [path_initial]  # Start with a list of initial values for each path

for _ in range(sim_path_len):
new_rates = []
for r_old in path_box[-1]:  # Take the latest rates from the path_box
W = random.gauss(0, 1)  # Generate a single Gaussian random variable
r_new = (exp * r_old
+ b * (1 - exp)
+ sigma * ((1 - exp**2) / (2 * a))**0.5 * W)
if allow_neg or r_new >= 0:
new_rates.append(r_new)
else:
# Handle negative rates based on the allow_neg flag
if allow_neg:
new_rates.append(r_new)  # Keep the negative rate if allowed
else:
new_rates.append(0)  # Replace with zero or handle this case differently
path_box.append(new_rates)

return path_box``````

3周前 评论