Aquí hay un intento de codificarla sin usar la clase de pago, pero estoy seguro de que hay una manera más eficiente:
import QuantLib as ql
import numpy as np
# global data
todaysDate = ql.Date(31, ql.August, 2018);
ql.Settings.instance().evaluationDate = todaysDate
settlementDate = ql.Date(2, ql.September, 2018)
# Setup the yield termstructure
rate = ql.SimpleQuote(0.03)
rate_handle = ql.QuoteHandle(rate)
dc = ql.Actual365Fixed()
yieldCurve = ql.FlatForward(todaysDate, rate_handle, dc)
yieldCurve.enableExtrapolation()
yieldCurveHandle = ql.YieldTermStructureHandle(yieldCurve)
# HW1F Fixed Params
sigma = 0.003
a = 0.03
timestep = 17
length = 4.25 # in years
forward_rate = -0.0026
day_count = ql.Thirty360()
hw_process = ql.HullWhiteProcess(yieldCurveHandle, a, sigma)
rng = ql.GaussianRandomSequenceGenerator(ql.UniformRandomSequenceGenerator(timestep, ql.UniformRandomGenerator()))
seq = ql.GaussianPathGenerator(hw_process, length, timestep, rng, False)
# Generate Paths
def generate_paths(num_paths, timestep):
arr = np.zeros((num_paths, timestep+1))
for i in range(num_paths):
sample_path = seq.next()
path = sample_path.value()
time = [path.time(j) for j in range(len(path))]
value = [path[j] for j in range(len(path))]
arr[i, :] = np.array(value)
return np.array(time), arr
num_paths = 2000
time, paths = generate_paths(num_paths, timestep)
# Derivative Details
effective_date = ql.Date(13, 6, 2018)
termination_date = ql.Date(13, 12, 2022)
notionals = np.array([100])
tenor = ql.Period(ql.Quarterly)
calendar = ql.TARGET()
business_convention = ql.ModifiedFollowing
termination_business_convention = ql.Following
date_generation = ql.DateGeneration.Forward
end_of_month = False
schedule = ql.Schedule(effective_date,
termination_date,
tenor,
calendar,
business_convention,
termination_business_convention,
date_generation,
end_of_month)
days = schedule.__len__()
dcf = np.array([ql.Actual360().yearFraction(schedule[x], schedule[x+1]) for x in range(days-1) ])
last_rate = 124.574 / 100
multi = 2
floor_strike = 0.02
snowball_rate = np.empty([num_paths, 18])
for i in range(18):
if i == 0:
snowball_rate[:, 0] = last_rate
else:
snowball_rate[:, i] = snowball_rate[:, i - 1] + multi * np.maximum((floor_strike - paths[:, i]), 0)
discountDates = [ (d - settlementDate)/365 for d in schedule]
discountRates = np.array([yieldCurve.discount(d) for d in discountDates[1:]])
cf = notionals * dcf * snowball_rate * discountRates
cf.mean(0).sum()