├── LV_2SIR
└── FX_LocalVol_Calibration.ipynb
├── README.md
├── SLV_2DIR
├── Calibrate_SLV_2DIR.ipynb
└── Reprice_SLV_2DIR.ipynb
├── SLV_2SIR
├── Calibrate_SLV_2SIR.ipynb
└── Reprice_SLV_2SIR.ipynb
├── lib
├── bsanalytic.py
├── calibrator.py
├── fxivolinterpolator.py
├── interpolator.py
└── surfaces.py
├── marketdata_JSON_asof_04_30_2020
├── EUR.json
├── EURUSD.json
├── EURUSD_Heston.json
├── USD.json
└── correlations.json
└── sim_lib
├── StochasticSim_Multiprocessing.py
└── sim_params.py
/README.md:
--------------------------------------------------------------------------------
1 | Calibration and Simulation Engine for Local Volatility Models
2 | -------------------------------------------------------------
3 |
4 | This repository contains calibration and simulation routines for deterministic/stochastic local volatility models with deterministic/stochastic interest rates, implemented in Python.
5 |
6 | The manuscript that gives the details of the calibration algorithms can be accessed at https://arxiv.org/abs/2009.14764. This repository provides a sample implementation of these algorithms.
7 |
8 | The repository contains implementation of calibration of local volaility surface for EUR/USD currency pair though the example is easily adapted to other currency pairs with appropriately calibrated G1pp parameters and discount curves.
9 |
10 | The repository contains notebooks detailing:
11 | - The calibration procedure
12 | - Visualization of local volatility surface
13 | - Repricing with the calibrated local volality surface
14 | - Comparing repriced vs market implied volatility
15 |
16 | For three different cases:
17 | - Local volatility surface with 2 (Domestic and Foreign) stochastic interest rates (LV2SR)
18 | - Stochastic Local volatility with 2 (Domestic and Foreign) deterministic interest rates (SLV2DR)
19 | - Stochastic Local volatility with 2 (Domestic and Foreign) stochastic interest rates (SLV2SR)
20 |
21 | # Files:
22 | - **marketdata_JSON_asof_04_30_2020/**: Market data in JSON format containing EUR and USD discount curves. Risk-Reversal and Butterfly calibrated market prices and implied volatility for EUR/USD.
23 | - **EURUSD_Heston.json**: Heston parameterization of Stochastic Local Volatility for EUR/USD.
24 |
25 | - **lib/**: library and utilities for reading and interpolating market data as well as calibration routines.
26 | - **bsanalytic.py**: Black-Scholes analytic formulas for relevant market instruments
27 | - **calibrator.py**: Main utilities for calibrating local volatility surface. Classes include local volatility calibration under Call surface or Total implied variance (TIV) formulation
28 | - **fxivolinterpolator.py**: Utilities for interpolating time-discretized and strike-discretized market data for implied volatility.
29 | - **surfaces.py**: Classes and utilities for constructing Call surface and TIV surface needed for calibration.
30 | - **interpolator.py**: Classes and utilities for interpolating constructed TIV and Call surface needed for calibration.
31 |
32 | - **sim_lib/StochasticSim_Multiprocessing.py**: Numpy based local volality and stochastic local volatility simulator. This simulates assets, interest rates, and volatility under the given local or stochastic local volatility and interest rates.
33 | - **Assets'** time-evolution described as GBM.
34 | - **Stochastic Interest rates** parametrized and described as Hull-White/G1pp processes
35 | - **Stochastic Local Volatility** described by Heston Model.
36 |
37 | - **LV_2SIR/FX_LocalVol_Calibration.ipynb**: Notebook demonstrating calibration of LV_2SIR and Repricing under Local Volatility.
38 |
39 | - **/SLV_2DIR/**:
40 | - **Calibrate_SLV_2DIR.ipynb**: Notebook demonstrating calibration of Leverage surface of the Stochastic Local volatility under deterministic rates.
41 | - **Reprice_SLV_2DIR.ipynb**: Reprice under the calibrated stochastic local volatility model under determistic rates.
42 |
43 | - **/SLV_2SIR/**:
44 | - **Calibrate_SLV_2DIR.ipynb**: Notebook demonstrating calibration of Leverage surface of the Stochastic Local volatility under stochastic rates.
45 | - **Reprice_SLV_2DIR.ipynb**: Reprice under the calibrated stochastic local volatility model under stochastic rates.
46 |
47 | ## Usage:
48 | Clone the repository. With an installation of Jupyter with Python kernel >=3.6, run notebooks in folders **/LV_2SIR, /SLV_2DIR and /SLV_2SIR** for the Local Volatility with stochastic rates, Stochastic Local volatlity with deterministic rates and Stochastic Local volatility with Stochastic rates respectively.
49 |
50 | # Overview of the model and Summary of Results
51 |
52 | ## The model (LV2SR)
53 | This corresponding model for the underlying FX process with 2 (domestic and foreign) rate is assumed to be:
54 |
55 |
56 |
57 | where the domestic and foreign rates are parametrized using the G1pp model. The domestic rate evolves in the domestic risk neutral measure as
58 |
59 | 
60 | }}_t})
61 |
62 | whereas the foreign short rate evolves in foreign risk neutral measure,
63 |
64 | 
65 | }}_t})
66 |
67 | ## Calibration of local volatility surface (LV2SR)
68 | The local volality surface or state dependent diffusion coefficient
is calibrated in the domestic **T-Forward measure**. The procedure is as follows:
69 |
70 | - The calibration is performed in a time slice-by-slice basis.
71 | - The underling FX model and the domestic and foreign rates are first simulated in the T-Fwd measure with the local volatility until current time slice.
72 | - The expectation
is gathered from the T-Fwd simulation of the interest rates and underliers.
73 | - The following extension to Dupire's formula for stochastic rates is used to compute the local volatility at the current time slice.
74 |
75 |
76 |
77 | - The procedure is repeated for all time slices starting from 0 to maturity.
78 |
79 | where:
80 |
: Time to maturity
81 |
82 |
: The Black-Scholes call price
83 |
84 |
: Total implied variance
85 |
86 |
: Value of Underlier at time.
87 |
88 |
: Strike
89 |
90 |
: Log-moneyness
91 |
92 | Local volatility surface obtained via different number of monte-carlo paths.
93 | 
94 |
95 | Call Option price and implied volatility Recovery:
96 | 
97 |
98 |
99 | ## Stochastic Local Volatility with 2 Deterministic Rates (SLV2DR)
100 | ## The model.
101 |
102 | The model of stochastic local volatility is modeled as a CIR(Cox-Ingersoll-Ross) process.
103 |
104 |
105 |
106 |
107 |
108 | where:
109 |
: Underlier's value at time
110 |
111 |
: The corresponding domestic and foreign rates (deterministic)
112 |
113 |
: State dependent leverage function
114 |
115 |
: The variance process
116 |
117 |
: The corresponding mean reversion, long-term variance and vol-of-vol parameters of the Heston process.
118 |
119 |
: Browninan drivers of the underlier and variance processes in Domestic Risk neutral measure
120 |
121 |
122 | ## Calibration of the Leverage Surface
123 |
124 | The leverage function is related to the local volatility calibrated with deterministic rates via the Dupire's formula and the expectation of variance process as:
125 |
126 |
127 |
128 | - The conditional expectation
can be computed by binning the underlier values at time from the simulation sample paths as a function of
.
129 | - Alternatively, the expectation can also obtained by regressing on the risk-factor, (here
) as described in the paper.
130 | - The value of
is computed from deterministic Dupire's formula.
131 | - Finally the value of leverage function
on the grid is obtained by dividing
by
132 |
133 |
134 | The leverage function calibrated with deterministic rates with different number of monte-carlo calibration paths.
135 | 
136 |
137 | The repriced call function at maturity and the corresponding implied vol recovered within +-2 Monte Carlo errors.
138 | 
139 |
140 | ## Stochastic Local Volatility with 2 Stochastic Rates (SLV2SR)
141 | ## The model.
142 | The model which is a mixture of stochastic local volatility with stochastic rates can be written as:
143 |
144 | The underlier modeled as CIR dynamics:
145 | \sqrt{U_t} S_t dW_t^{S\text{(DRN)}}})
146 |  dt %2B \xi_t \sqrt{U_t} dW_t^{U\text{(DRN)}}})
147 |
148 | Domestic rates modeled as a G1pp process:
149 | 
150 | }}})
151 |
152 | Foreign rates modeled as a second G1pp process:
153 | 
154 |  \sqrt{U_t}\right] dt %2B \sigma^f_t dW_t^{f\text{(DRN)}}})
155 |
156 | ## Calibration of the leverage surface
157 |
158 | The calibrated leverage function is related to the local volatility (LV2SR) and the variance process by:
159 |
160 |
161 | - The conditional expectation
can be computed by binning the underlier values at time from the simulation sample paths as a function of
in **T-Fwd measure**.
162 | - Alternatively, the expectation can also obtained by regressing on the risk-factor, (here
) as described in the paper.
163 | - The value of
is computed as in the LV2SIR method.
164 | - Finally the value of leverage function
on the grid is obtained by dividing
by
165 |
166 |
167 | The repriced Call option prices and the implied volatility recovered with the repriced options fall within +- 2 MC errors.
168 | 
169 |
--------------------------------------------------------------------------------
/lib/bsanalytic.py:
--------------------------------------------------------------------------------
1 | import scipy.optimize as opt
2 | import numpy as np
3 | from scipy.stats import norm
4 |
5 |
6 | def Call(S, K, T, r, q, sig):
7 | d1 = (np.log(S/K) + (r-q+sig**2/2)*T)/(sig*np.sqrt(T))
8 | d2 = d1 - sig*np.sqrt(T)
9 | return S*np.exp(-q*T)*norm.cdf(d1) - K*np.exp(-r*T)*norm.cdf(d2)
10 |
11 |
12 | def Put(S, K, T, r, q, sig):
13 | d1 = (np.log(S/K) + (r-q+sig**2/2)*T)/(sig*np.sqrt(T))
14 | d2 = d1 - sig*np.sqrt(T)
15 | return K * np.exp(-r * T) * norm.cdf(-d2) - S * np.exp(-q * T) * norm.cdf(-d1)
16 |
17 | def CallDelta(S, K, T, r, q, sig):
18 | d1 = (np.log(S/K) + (r-q+sig**2/2)*T)/(sig*np.sqrt(T))
19 | return np.exp(-q*T)*norm.cdf(d1)
20 |
21 | def Gamma(S, K, T, r, q, sig):
22 | d1 = (np.log(S/K) + (r-q+sig**2/2)*T)/(sig*np.sqrt(T))
23 | return np.exp(-q*T)*np.exp(-0.5*d1*d1)/(S*sig*np.sqrt(T)*np.sqrt(2.0*math.pi))
24 |
25 | def impliedvol_call(S,K,T,r,q,price,xtol=1e-10, guess=0.2):
26 | callfun=lambda iv:Call(S,K,T,r,q,iv)-price
27 | return float(opt.fsolve(callfun,guess))
28 |
29 | def impliedvol_put(S,K,T,r,q,price,guess=0.2):
30 | putfun=lambda iv:Put(S,K,T,r,q,iv)-price
31 | return float(opt.fsolve(putfun,guess))
32 |
--------------------------------------------------------------------------------
/lib/calibrator.py:
--------------------------------------------------------------------------------
1 | """Local volatility calibration utilities under stochastic interest rates and/or
2 | stochastic volatility"""
3 | import inspect
4 | import math
5 | import os
6 | import pickle
7 | import statistics
8 |
9 | import numpy as np
10 | import interpolator
11 |
12 | def split_seq(seq, size):
13 | """
14 | Splits a given list evenly to sublists of roughly the same size
15 |
16 | Parameters
17 | ----------
18 | seq : list
19 | Original sequence
20 | size : int
21 | Number of sublists
22 |
23 | Returns
24 | -------
25 | newseq : list of lists
26 |
27 | """
28 | newseq = []
29 | splitsize = 1.0/size*len(seq)
30 | for i in range(size):
31 | newseq.append(seq[int(round(i*splitsize)):int(round((i+1)*splitsize))])
32 | return newseq
33 |
34 | class LocalVolIRCalibration:
35 |
36 | def __init__(self, surface, simulator, filename=None):
37 | self.surface = surface
38 | self.simulator = simulator
39 | self.filename = filename
40 |
41 | def save_lv_surface(self, all_strikes, times, surfacevalues, surface_errs=None):
42 | """
43 | Save the local vol surface data
44 |
45 | Parameters
46 | ----------
47 | all_strikes : list of floats
48 | List of strikes
49 | times : list of floats
50 | List of times
51 | surfacevalues : list of lists of floats
52 | Vol surface data
53 | surface_errs : list of lists of floats
54 | Vol surface errors
55 |
56 | """
57 | if self.filename:
58 | dirname = os.path.dirname(self.filename)
59 | if not os.path.exists(dirname):
60 | os.makedirs(dirname)
61 | lvol_output = { 'spots': all_strikes,
62 | 'times': times,
63 | 'surfacevalues': surfacevalues,
64 | }
65 | if surface_errs:
66 | lvol_output['errors'] = surface_errs
67 | with open(self.filename, 'wb') as f:
68 | pickle.dump(lvol_output, f)
69 | print("Written: %s" % (self.filename))
70 |
71 | class DeterministicLocalVolDeterministicIRCalibration(LocalVolIRCalibration):
72 |
73 |
74 | def __init__(self, surface, simulator, filename=None):
75 | super(DeterministicLocalVolDeterministicIRCalibration, self).__init__(surface, simulator,
76 | filename=filename,
77 | )
78 |
79 | def calibrate_localvol(self, Ks, ts):
80 | """
81 | Do the calibration
82 |
83 | Parameters
84 | ----------
85 | Ks : list of lists of floats
86 | 2D strike grid
87 | ts : list of floats
88 | Time grid
89 |
90 | Returns
91 | -------
92 | locvols : list of lists of floats
93 | The local volatility surface
94 |
95 | """
96 | if len(Ks) != len(ts):
97 | raise Exception("Strike grid length does not match times grid length")
98 | locvols = []
99 | all_strikes = Ks
100 | for idx, t, in enumerate(ts):
101 | print("Processing time: %f" % t)
102 | strikes = all_strikes[idx]
103 | locvol_slice = self.surface.evaluate_localvol_slice_det_ir(strikes, t)
104 | locvols.append(locvol_slice)
105 | self.save_lv_surface(all_strikes[:idx+1], ts[:idx+1], locvols)
106 |
107 | return locvols
108 |
109 |
110 | class DeterministicLocalVolStochasticIRCalibration(LocalVolIRCalibration):
111 |
112 |
113 | def __init__(self, surface, simulator, filename=None):
114 | super(DeterministicLocalVolStochasticIRCalibration, self).__init__(surface, simulator,
115 | filename=filename,
116 | )
117 | self.deterministic_ir_calibration = DeterministicLocalVolDeterministicIRCalibration(surface, simulator,
118 | filename=filename,
119 | )
120 |
121 | def calibrate_localvol(self, Ks, ts):
122 | """
123 | Do the calibration
124 |
125 | Parameters
126 | ----------
127 | Ks : list of lists of floats
128 | 2D strike grid
129 | ts : list of floats
130 | Time grid
131 |
132 | Returns
133 | -------
134 | locvols : list of lists of floats
135 | The local volatility surface
136 |
137 | """
138 | if len(Ks) != len(ts):
139 | raise excp.InvalidLengthException("Strike grid length does not match times grid length")
140 | locvols = []
141 | locvol_errs = []
142 | all_strikes = Ks
143 | for idx, t, in enumerate(ts):
144 | print("Processing time: %f" % t)
145 | strikes = all_strikes[idx]
146 | if idx == 0:
147 | locvol_slice = self.deterministic_ir_calibration.surface.evaluate_localvol_slice_det_ir(strikes, t)
148 | locvol_err_slice = [0.0] * len(locvol_slice)
149 | else:
150 | self.simulator.set_contracts_for_calibration(strikes, t)
151 | self.simulator.update_localvol(all_strikes[:idx], ts[:idx], locvols)
152 | self.simulator.update_domestic_bfactors(t)
153 | self.simulator.update_base_bfactors(t)
154 | self.simulator.run()
155 | expectations = self.simulator.get_means_from_output()
156 | stderrs = self.simulator.get_stderrs_from_output()
157 | locvol_slice, locvol_err_slice = self.surface.evaluate_localvol_slice_stoc_ir(strikes, t, expectations, stderrs)
158 | locvols.append(locvol_slice)
159 | locvol_errs.append(locvol_err_slice)
160 | self.save_lv_surface(all_strikes[:idx+1], ts[:idx+1], locvols, locvol_errs)
161 |
162 | return locvols
163 |
164 | class StochasticLocalVolDeterministicIRCalibration(LocalVolIRCalibration):
165 |
166 |
167 | def __init__(self, surface, simulator, filename=None, var_method='curve_fit'):
168 | super(StochasticLocalVolDeterministicIRCalibration, self).__init__(surface, simulator,
169 | filename=filename,
170 | )
171 | self.var_method = var_method # curve_fit binning
172 |
173 | def calibrate_localvol(self, Ks, ts):
174 | """
175 | Do the calibration
176 |
177 | Parameters
178 | ----------
179 | Ks : list of lists of floats
180 | 2D strike grid
181 | ts : list of floats
182 | Time grid
183 |
184 | Returns
185 | -------
186 | all_Ls : list of lists of floats
187 | The leverage surface
188 |
189 | """
190 | if len(Ks) != len(ts):
191 | raise excp.InvalidLengthException("Strike grid length does not match times grid length")
192 | all_strikes = Ks
193 | #all_locvols = []
194 | all_Ls = []
195 | for idx, t, in enumerate(ts):
196 | print("Processing time: %f" % t)
197 | strikes = all_strikes[idx]
198 | locvol_slice = self.surface.evaluate_localvol_slice_det_ir(strikes, t)
199 | if idx == 0:
200 | locvol_S0 = interpolator.getLinearInterpEx(self.simulator.spot_FX, strikes, locvol_slice)
201 | L0 = locvol_S0 / math.sqrt(self.simulator.cir_v0)
202 | Ls = [L0] * len(strikes)
203 | #all_locvols.append(locvol_slice)
204 | all_Ls.append(Ls)
205 | if self.var_method in ('curve_fit', 'binning'):
206 | self.simulator.update_localvol([all_strikes[0]] + all_strikes[:idx], [0.0] + ts[:idx], all_Ls)
207 | self.simulator.set_simulation_times(ts[:idx + 1])
208 | self.simulator.set_observation_times([t])
209 | self.simulator.set_vanilla_contract('spot', t, None)
210 | self.simulator.run()
211 |
212 | cspots, cvars = self.simulator._get_X_and_U()
213 |
214 | if self.var_method == 'curve_fit':
215 | Ls = self.compute_L_curve_fit(cspots, cvars, strikes, t)
216 | else: # elif self.var_method == 'binning':
217 | Ls = self.compute_L_simple_bin_average(cspots, cvars, strikes, t)
218 | else:
219 | raise Exception("Method "+self.var_method+" is not implemented!")
220 |
221 | all_Ls.append(Ls)
222 |
223 | self.save_lv_surface([all_strikes[0]] + all_strikes[:idx+1],
224 | [0.0] + ts[:idx+1],
225 | all_Ls)
226 |
227 | return all_Ls
228 |
229 | def compute_L_curve_fit(self, spots, variances, strikes, time):
230 | """
231 | Compute the leverage function by estimating the conditional expectation
232 | on variance by least squares regression
233 |
234 | Parameters
235 | ----------
236 | spots : list of floats
237 | List of underlier values
238 | variances : list of floats
239 | List of variance process values. Must be of the same length
240 | as *spots*
241 | strikes : list of floats
242 | Strikes grid to compute the leverage grid at
243 | time : float
244 | Time for the calibration slice
245 |
246 | Returns
247 | -------
248 | Ls : list of floats
249 | The leverage surface slice for the given time
250 |
251 | """
252 | import numpy as np
253 | import scipy.optimize as scopt
254 | # Monomial
255 | #ls_eqn = lambda x, a, b, c: a * x**2 + b * x + c
256 | # Laguerre
257 | ls_eqn = lambda x, a, b, c: a * 0.5 * (x**2 - 4 * x + 2) + b * (1 - x) + c
258 | popt, pcov = scopt.curve_fit(ls_eqn, spots, variances)
259 | cstrikes = np.linspace(min(spots), max(spots), len(strikes))
260 |
261 | vars = np.array([max(ls_eqn(strike, popt[0], popt[1], popt[2]), 1e-6) for strike in cstrikes])
262 | locvol = np.array(self.surface.evaluate_localvol_slice_det_ir(cstrikes, time))
263 | cLs = locvol/np.sqrt(vars)
264 |
265 | Ls = [interpolator.getLinearInterpEx(strike, cstrikes, cLs) for strike in strikes]
266 | return Ls
267 |
268 | def compute_L_simple_bin_average(self, spots, variances, strikes, time):
269 | """
270 | Compute the leverage function by estimating the conditional expectation
271 | on variance by binning
272 |
273 | Parameters
274 | ----------
275 | spots : list of floats
276 | List of underlier values
277 | variances : list of floats
278 | List of variance process values. Must be of the same length
279 | as *spots*
280 | strikes : list of floats
281 | Strikes grid to compute the leverage grid at
282 | time : float
283 | Time for the calibration slice
284 |
285 | Returns
286 | -------
287 | Ls : list of floats
288 | The leverage surface slice for the given time
289 |
290 | """
291 | fpairs = sorted(zip(spots, variances))
292 | chunked_fpairs = split_seq(fpairs, len(strikes))
293 |
294 |
295 | cstrikes_and_vars = [[np.mean(x) for x in zip(*C)] for C in chunked_fpairs ]
296 | cstrikes, cvars = zip(*cstrikes_and_vars)
297 | locvol = np.array(self.surface.evaluate_localvol_slice_det_ir(cstrikes, time))
298 | cLs = locvol/np.sqrt(cvars)
299 |
300 | Ls = [interpolator.getLinearInterpEx(strike, cstrikes, cLs) for strike in strikes]
301 | return Ls
302 |
303 |
304 | class StochasticLocalVolStochasticIRCalibration(StochasticLocalVolDeterministicIRCalibration):
305 |
306 |
307 | def __init__(self, surface, simulator, filename=None, var_method='curve_fit'):
308 | super(StochasticLocalVolStochasticIRCalibration, self).__init__(surface, simulator,
309 | filename=filename,
310 | var_method=var_method,
311 | )
312 |
313 | def calibrate_localvol(self, Ks, ts, localvols=None):
314 | """
315 | Do the calibration
316 |
317 | Parameters
318 | ----------
319 | Ks : list of lists of floats
320 | 2D strike grid
321 | ts : list of floats
322 | Time grid
323 | localvols : list of lists of floats
324 | Given precalibrated deterministic local volatilities, e.g. with
325 | :class:`DeterministicLocalVolStochasticIRCalibration`.
326 |
327 | Returns
328 | -------
329 | all_Ls : list of lists of floats
330 | The leverage surface
331 |
332 | """
333 | if len(Ks) != len(ts):
334 | raise excp.InvalidLengthException("Strike grid length does not match times grid length")
335 | all_strikes = Ks
336 | all_Ls = []
337 | for idx, t, in enumerate(ts):
338 | print("Processing time: %f" % t)
339 | strikes = all_strikes[idx]
340 | if localvols:
341 | locvol_slice = localvols[idx]
342 | else:
343 | locvol_slice = self.surface.evaluate_localvol_slice_det_ir(strikes, t)
344 | if idx == 0:
345 | locvol_S0 = interpolator.getLinearInterpEx(self.simulator.spot_FX, strikes, locvol_slice)
346 | L0 = locvol_S0 / math.sqrt(self.simulator.cir_v0)
347 | Ls = [L0] * len(strikes)
348 | all_Ls.append(Ls)
349 | self.simulator.update_localvol([all_strikes[0]] + all_strikes[:idx], [0.0] + ts[:idx], all_Ls) # nonuniform
350 | self.simulator.update_domestic_bfactors(t)
351 | self.simulator.update_base_bfactors(t)
352 | self.simulator.set_simulation_times(ts[:idx + 1])
353 | self.simulator.set_observation_times([t])
354 | self.simulator.set_vanilla_contract('spot', t, None)
355 | self.simulator.run()
356 |
357 | obs_result = self.simulator.outputMC['MCResults']['SimulationObservations']
358 | cspots = [path[self.simulator.fx_prefix + 'FXrate'][0] for path in obs_result["Samples"]]
359 | cvars = [path[self.simulator.fx_prefix + 'FXStochVariance'][0] for path in obs_result["Samples"]]
360 |
361 | if self.var_method == 'curve_fit':
362 | Ls = self.compute_L_curve_fit(cspots, cvars, strikes, t)
363 | else: # binning
364 | Ls = self.compute_L_simple_bin_average(cspots, cvars, strikes, t)
365 | all_Ls.append(Ls)
366 |
367 | self.save_lv_surface([all_strikes[0]] + all_strikes[:idx+1],
368 | [0.0] + ts[:idx+1],
369 | all_Ls)
370 |
371 | return all_Ls
372 |
373 |
374 | class StochasticLocalVolStochasticIRCalibrationMultiRegression(StochasticLocalVolDeterministicIRCalibration):
375 |
376 |
377 | def __init__(self, surface, simulator, filename=None, var_method='curve_fit'):
378 | super(StochasticLocalVolStochasticIRCalibrationMultiRegression, self).__init__(surface, simulator,
379 | filename=filename,
380 | var_method=var_method,
381 | )
382 |
383 | def calibrate_localvol(self):
384 | """
385 | Do the calibration. Uses the same grid as the given localvol surface.
386 |
387 | Returns
388 | -------
389 | regcoeffs, rsq : list of lists of floats, list of floats
390 | Regression coefficients and R-squares from regression for each time
391 | slice
392 |
393 | """
394 | all_popt = []
395 | all_rsq = []
396 | Ks = self.surface.surface_interpolator.xs
397 | ts = self.surface.surface_interpolator.ts
398 | locvols = self.surface.surface_interpolator.vols
399 | self.simulator.update_localvol(Ks, ts, locvols)
400 | for idx, t, in enumerate(self.surface.surface_interpolator.ts):
401 | print("Processing time: %f" % t)
402 | strikes = Ks[idx]
403 | if idx == 0:
404 | locvol_slice = self.surface.surface_interpolator.vols[idx]
405 | locvol_S0 = interpolator.getLinearInterpEx(self.simulator.spot_FX, strikes, locvol_slice)
406 | L0 = self.simulator.cir_v0
407 | all_popt.append([L0] + [0.0] * (len(inspect.signature(self.simulator.regression_equation).parameters) - 2)) # the length must match the total number of basis functions
408 | all_rsq.append(1.0)
409 | self.simulator.update_regression_coefficients(ts[:idx + 1], all_popt, all_rsq, self.simulator.nrmcruns)
410 | self.simulator.update_domestic_bfactors(t)
411 | self.simulator.update_base_bfactors(t)
412 | self.simulator.set_simulation_times(ts[:idx + 1])
413 | self.simulator.set_observation_times([t])
414 | self.simulator.set_vanilla_contract('spot', t, None)
415 | self.simulator.run()
416 |
417 | obs_result = self.simulator.outputMC['MCResults']['SimulationObservations']
418 | cspots = [path[self.simulator.fx_prefix + 'FXrate'][0] for path in obs_result["Samples"]]
419 | cvars = [path[self.simulator.fx_prefix + 'FXStochVariance'][0] for path in obs_result["Samples"]]
420 | cdomxs = [path[self.simulator.domestic_currency_prefix + 'Domestic_XFactor'][0] for path in obs_result["Samples"]]
421 | cbasxs = [path[self.simulator.base_currency_prefix + 'Base_XFactor'][0] for path in obs_result["Samples"]]
422 |
423 | if self.var_method == 'curve_fit':
424 | popt, rsq = self.compute_L_curve_fit(cspots, cdomxs, cbasxs, cvars, len(strikes), t)
425 | else:
426 | raise excp.NotImplementedException("Method %s not implemented" % (self.var_method))
427 | all_popt.append(popt)
428 | all_rsq.append(rsq)
429 |
430 | self.save_regression_coefficients([0.0] + ts[:idx+1], all_popt, all_rsq)
431 |
432 | return all_popt, all_rsq
433 |
434 | def save_regression_coefficients(self, times, regcoeffs, rsq):
435 | """
436 | Save regression coefficients in a pickle file. The file name is given in
437 | the constructor.
438 |
439 | Parameters
440 | ----------
441 | times : list of floats
442 | Time slices
443 | regcoeffs : list of lists of floats
444 | Regression coefficients for each time slice
445 | rsq : list of floats
446 | R-squares from regression results for each time slice
447 |
448 | """
449 | if self.filename:
450 | dirname = os.path.dirname(self.filename)
451 | if not os.path.exists(dirname):
452 | os.makedirs(dirname)
453 |
454 | l_output = {'times': times,
455 | 'regcoeffs': regcoeffs,
456 | 'R2': rsq,
457 | 'nrdatapoints': self.simulator.nrmcruns,
458 | }
459 |
460 | with open(self.filename, 'wb') as f:
461 | pickle.dump(l_output, f)
462 | print("Written: %s" % (self.filename))
463 |
464 | def compute_L_curve_fit(self, spots, domxs, basxs, variances, nr_chunks, time):
465 | """
466 | Compute the leverage function by estimating the conditional expectation
467 | on variance by least squares regression. Returns the regression results.
468 |
469 | Parameters
470 | ----------
471 | spots : list of floats
472 | List of underlier values
473 | variances : list of floats
474 | List of variance process values. Must be of the same length
475 | as *spots*
476 | nr_chunks : int
477 | Number of bins. Corresponds to the size of the output strikes grid
478 | time : float
479 | Time for the calibration slice
480 |
481 | Returns
482 | -------
483 | reg, rsq : List of floats, float
484 | Regression coefficients and R-square from regression
485 |
486 | """
487 | import numpy as np
488 | import scipy.optimize as scopt
489 |
490 | ls_eqn = self.simulator.regression_equation
491 | popt, pcov = scopt.curve_fit(ls_eqn, (spots, domxs, basxs), variances)
492 | residuals = np.asarray(variances) - ls_eqn((np.asarray(spots), np.asarray(domxs), np.asarray(basxs)), *popt)
493 | ss_res = np.sum(residuals**2)
494 | ss_tot = np.sum((np.asarray(variances) - np.mean(variances))**2)
495 | rsq = 1.0 - (ss_res / ss_tot)
496 | return popt.tolist(), rsq
497 |
--------------------------------------------------------------------------------
/lib/fxivolinterpolator.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import scipy
3 |
4 | class FXIVolInterpolator:
5 |
6 | def __init__(self, ivoljsondata, spot_FX, dfcurve, base_dfcurve):
7 |
8 | self.strikes = [ivol_at_t['strikes'] for ivol_at_t in ivoljsondata]
9 | self.times = [ivol_at_t['time'] for ivol_at_t in ivoljsondata]
10 | self.ivolvals = [ivol_at_t['vols'] for ivol_at_t in ivoljsondata]
11 | self.dfcurve = dfcurve
12 | self.base_dfcurve = base_dfcurve
13 | self.spot_FX = spot_FX
14 | self.interps = [scipy.interpolate.CubicSpline(Ks, ivols, bc_type='natural') for Ks, ivols in zip(self.strikes, self.ivolvals)]
15 | self.fwds = self.spot_FX * np.array(self.base_dfcurve(self.times))/np.array(self.dfcurve(self.times))
16 | ref_impvolvals = [interp(fwd) for interp, fwd in zip(self.interps, self.fwds)]
17 |
18 | self.ref_impvols = scipy.interpolate.CubicSpline(self.times, ref_impvolvals, bc_type='clamped')
19 |
20 |
21 | def impliedvol_lkf(self, tval, lkf):
22 |
23 | ref_impvol = self.ref_impvols(tval) ## reference implied vols
24 | nr_stddev = lkf/(ref_impvol*np.sqrt(tval)) ## number of standard deviations for current lkf
25 | Ks = [np.exp(nr_stddev * self.ref_impvols(t1) * np.sqrt(t1))*fwd for t1,fwd in zip(self.times, self.fwds)]
26 |
27 | tinterp = scipy.interpolate.InterpolatedUnivariateSpline(self.times, [interp(K) for interp, K in zip(self.interps, Ks)])
28 |
29 | self.tinterp = tinterp
30 | self.lastKs = Ks
31 | return tinterp(tval)
32 |
33 | def impliedvol_K(self, tval, strike):
34 |
35 | forward = self.spot_FX * self.base_dfcurve(tval)/self.dfcurve(tval)
36 | lkf = np.log(strike/forward)
37 |
38 | ivol = self.impliedvol_lkf(tval, lkf)
39 |
40 | return ivol
41 |
--------------------------------------------------------------------------------
/lib/interpolator.py:
--------------------------------------------------------------------------------
1 | "Uniform and nonuniform surface interpolators"
2 | import scipy.interpolate
3 | import math
4 |
5 | import numpy as np
6 | import bsanalytic as bsan
7 | import scipy
8 | import bisect
9 | import datetime
10 |
11 |
12 | class InterpolatedCurve:
13 | def __init__(self, times, values, interpolation_fnc=None):
14 | self.times = times
15 | self.values = values
16 | ASOFDATE=datetime.datetime(2020, 4, 30)
17 | self.dates = [ASOFDATE+datetime.timedelta(days=timeval * 365) for timeval in times]
18 | if (interpolation_fnc is None):
19 | self.interpolation_fnc = getLinearInterpEx
20 | elif interpolation_fnc.lower() == 'pwc_left_cts':
21 | self.interpolation_fnc = getLeftConstantInterpEx
22 | elif interpolation_fnc.lower() == 'loglinear':
23 | self.interpolation_fnc = getLogLinearInterpEx
24 | return
25 |
26 | def __call__(self, dateortimes):
27 | if isinstance(dateortimes, list) or isinstance(dateortimes, np.ndarray):
28 | return [self.interpolation_fnc(tval, self.times, self.values) for tval in dateortimes]
29 | else:
30 | return self.interpolation_fnc(dateortimes, self.times, self.values)
31 |
32 |
33 | class SurfaceInterpolator:
34 | """
35 | Nonuniform surface interpolator based on scipy implementation.
36 | x values are interpolated with the splines of the given degree.
37 | t values are interpolated linearly.
38 |
39 | Parameters
40 | ----------
41 | xs : list of lists of floats
42 | Nonuniform grid of x values (e.g. strikes)
43 | ts : list of floats
44 | Grid of t values (e.g. times).
45 | vols : list of lists of floats
46 | Nonuniform grid of values to be interpolated (e.g. volatilities).
47 | Must be of the same shape with *xs*
48 | k : int
49 | Degree of spline to interpolate the x values
50 |
51 | """
52 | def __init__(self, xs, ts, vols, k=3):
53 | self.xs = xs
54 | self.ts = ts
55 | self.vols = vols
56 | if len(ts) != len(xs):
57 | raise Exception("ts length must match xs length")
58 | if len(ts) != len(vols):
59 | raise Exception("ts length must match vols length")
60 | self.interp = []
61 | for idx, t in enumerate(ts):
62 | slice_interp = scipy.interpolate.CubicSpline(xs[idx], vols[idx], bc_type='natural') ## 'clamped'
63 | self.interp.append(slice_interp)
64 |
65 | def eval(self, x, t, dx=0, dt=0):
66 | """
67 | Interpolate the surface at the given point
68 |
69 | Parameters
70 | ----------
71 | x : float
72 | t : float
73 | dx : int
74 | Degree of derivative in the x direction
75 | dt : int
76 | Degree of derivative in the y direction
77 |
78 | Returns
79 | -------
80 | out : float
81 | Interpolated value
82 |
83 | """
84 | if t < self.ts[0]:
85 | return self.interp[0](x, nu=dx) if dt == 0 else 0.0
86 | elif self.ts[-1] < t:
87 | return self.interp[-1](x, nu=dx) if dt == 0 else 0.0
88 | else:
89 | interp_vols = [self.interp[idx](x, nu=dx) for idx in range(len(self.ts))]
90 | times_interp = scipy.interpolate.InterpolatedUnivariateSpline(self.ts, interp_vols, k=1)
91 | return times_interp(t, nu=dt).tolist() # tolist needs to be used to convert it to float for some reason
92 |
93 | class SurfaceInterpolatorInterp2D:
94 | """
95 | Uniform surface interpolator based on scipy implementation.
96 |
97 | Parameters
98 | ----------
99 | xs : list of floats
100 | Grid of x values (e.g. strikes)
101 | ts : list of floats
102 | Grid of t values (e.g. times).
103 | vols : list of lists of floats
104 | Uniform grid of values to be interpolated (e.g. volatilities)
105 | kind : str
106 | Interpolation type. See :func:`scipy.interpolate.interp2d` documentation
107 |
108 | """
109 | def __init__(self, xs, ts, vols, kind='cubic'):
110 | self.xs = xs
111 | self.ts = ts
112 | self.vols = vols
113 | self.interp = scipy.interpolate.interp2d(xs, ts, vols, kind=kind, copy=False)
114 |
115 | def eval(self, x, t, dx=0, dt=0):
116 | """
117 | Interpolate the surface at the given point
118 |
119 | Parameters
120 | ----------
121 | x : float
122 | t : float
123 | dx : int
124 | Degree of derivative in the x direction
125 | dt : int
126 | Degree of derivative in the y direction
127 |
128 | Returns
129 | -------
130 | out : float
131 | Interpolated value
132 |
133 | """
134 | return self.interp(x, t, dx, dt)[0]
135 |
136 | def generate_call_price_interpolator(impvolobj, strikes,
137 | times, domestic_dfcurve, base_dfcurve, spot):
138 | """
139 | Generate a uniform call price surface
140 |
141 | Parameters
142 | ----------
143 | impvolobj :
144 | Implied vol surface
145 | strikes : list of floats
146 | Grid of strikes
147 | times : list of floats
148 | Grid of times
149 | domestic_dfcurve :
150 | (domestic) discount curve
151 | base_dfcurve :
152 | base discount curve or dividend yield curve
153 | spot : float
154 | Time zero value of the underlier
155 |
156 | Returns
157 | -------
158 | interp : :class:`SurfaceInterpolatorInterp2D`
159 | Interpolator object
160 |
161 | """
162 | print("Creating call price interpolator")
163 | allcalls = []
164 | for T in times:
165 | callslice = []
166 | domestic_df = domestic_dfcurve(T)
167 | base_df = base_dfcurve(T)
168 | rd = - math.log(domestic_df) / T
169 | rf = - math.log(base_df) / T
170 | for strike in strikes:
171 | impvol = impvolobj.impliedvol_K(T, strike)
172 | call = max(0.0, bsan.Call(spot, strike, T, rd, rf, impvol))
173 | callslice.append(call)
174 | allcalls.append(callslice)
175 | call_interp = SurfaceInterpolatorInterp2D(strikes, times, allcalls)
176 | print("Created call price interpolator")
177 | return call_interp
178 |
179 | def generate_call_price_interpolator_nonuniform(impvolobj, nrstrikes,
180 | times, domestic_dfcurve, base_dfcurve, spot,
181 | width_nr_stdev=3.5):
182 | """
183 | Generate a nonuniform call price surface
184 |
185 | Parameters
186 | ----------
187 | impvolobj :
188 | Implied vol surface
189 | nrstrikes : int
190 | Number of strikes
191 | times : list of floats
192 | Grid of times
193 | domestic_dfcurve :
194 | (domestic) discount curve
195 | base_dfcurve :
196 | base discount curve or dividend yield curve
197 | spot : float
198 | Time zero value of the underlier
199 | width_nr_stdev : float
200 | Width of the generated grid in terms of standard deviations from ATMF
201 |
202 | Returns
203 | -------
204 | interp : :class:`SurfaceInterpolator`
205 | Interpolator object
206 |
207 | """
208 | print("Creating call price interpolator")
209 | allcalls = []
210 | allstrikes = []
211 | for T in times:
212 | domestic_df = domestic_dfcurve(T)
213 | base_df = base_dfcurve(T)
214 | rd = - math.log(domestic_df) / T
215 | rf = - math.log(base_df) / T
216 | fwd = spot * base_df / domestic_df
217 | ref_impvol = impvolobj.impliedvol_K(T, fwd)
218 | ymin = -width_nr_stdev * ref_impvol * math.sqrt(T)
219 | ymax = +width_nr_stdev * ref_impvol * math.sqrt(T)
220 | Kmin = math.exp(ymin) * fwd
221 | Kmax = math.exp(ymax) * fwd
222 | Ks = list(np.arange(Kmin, Kmax, (Kmax - Kmin) / nrstrikes))[:nrstrikes]
223 | allstrikes.append(Ks)
224 | callslice = []
225 | for K in Ks:
226 | impvol = impvolobj.impliedvol_K(T, K)
227 | call = max(0.0, bsan.Call(spot, K, T, rd, rf, impvol))
228 | callslice.append(call)
229 | allcalls.append(callslice)
230 | all_times = times
231 | impvars = SurfaceInterpolator(allstrikes, all_times, allcalls)
232 | print("Created Call surface interpolator")
233 | return impvars
234 |
235 | def generate_implied_totalvariance_interpolator(impvolobj, ys, times):
236 | """
237 | Generate a uniform total implied variance surface
238 |
239 | Parameters
240 | ----------
241 | impvolobj :
242 | Implied vol surface
243 | ys : list of floats
244 | Grid of log-moneynesses
245 | times : list of floats
246 | Grid of times
247 |
248 | Returns
249 | -------
250 | interp :
251 | Interpolator object
252 |
253 | """
254 | print("Creating implied total variance interpolator")
255 | totalvariance = []
256 | for T in times:
257 | w_slice = []
258 | for y in ys:
259 | impvol = impvolobj.impliedvol_lkf(T, y)
260 | w_slice.append(impvol * impvol * T)
261 | totalvariance.append(w_slice)
262 | impvars = SurfaceInterpolatorInterp2D(ys, times, totalvariance)
263 | print("Created implied total variance interpolator")
264 | return impvars
265 |
266 | def generate_implied_totalvariance_interpolator_nonuniform(impvolobj, nrys, times,
267 | width_nr_stdev=3.5):
268 | """
269 | Generate a nonuniform total implied variance surface
270 |
271 | Parameters
272 | ----------
273 | impvolobj :
274 | Implied vol surface
275 | nrys : int
276 | Number of log-moneynesses
277 | times : list of floats
278 | Grid of times
279 | width_nr_stdev : float
280 | Width of the generated grid in terms of standard deviations from ATMF
281 |
282 | Returns
283 | -------
284 | interp : :class:`SurfaceInterpolator`
285 | Interpolator object
286 |
287 | """
288 | print("Creating implied total variance interpolator")
289 | totalvariance = []
290 | all_ys = []
291 | for T in times:
292 | ref_impvol = impvolobj.impliedvol_lkf(T, 0.0)
293 | ymin = -width_nr_stdev * ref_impvol * math.sqrt(T)
294 | ymax = +width_nr_stdev * ref_impvol * math.sqrt(T)
295 | ys = list(np.arange(ymin, ymax, (ymax - ymin) / nrys))[:nrys]
296 | all_ys.append(ys)
297 | w_slice = []
298 | for y in ys:
299 | impvol = impvolobj.impliedvol_lkf(T, y)
300 | w_slice.append(impvol * impvol * T)
301 | totalvariance.append(w_slice)
302 | all_times = times
303 | impvars = SurfaceInterpolator(all_ys, all_times, totalvariance)
304 | print("Created implied total variance interpolator")
305 | return impvars
306 |
307 |
308 | def constructShortRateCurve(dfcurve, name=None):
309 | """
310 | Construct short rate curve from given discount factors
311 |
312 | Parameters
313 | ----------
314 | dfcurve :
315 | Discount factor curve
316 | name : str
317 | Name of the curve
318 |
319 | Returns
320 | -------
321 | ratecurve :
322 | Short rate curve
323 |
324 | """
325 | if name is None:
326 | name = 'shortRate'
327 | logdfs = [np.log(df) for df in dfcurve.values]
328 |
329 | srcurve = {'values': [(logdf1-logdf2)/(t2-t1) for logdf1,logdf2,t1,t2 in zip(logdfs,logdfs[1:],
330 | dfcurve.times,dfcurve.times[1:])], 'times':dfcurve.times[:-1]}
331 |
332 | shortratecurve = InterpolatedCurve(srcurve['times'], srcurve['values'], interpolation_fnc='pwc_left_cts')
333 |
334 | return shortratecurve
335 |
336 |
337 | def constructDiscountcurve(times, vals):
338 | crv = InterpolatedCurve(times, vals, interpolation_fnc='loglinear')
339 | return crv
340 |
341 | def getLinearInterpEx(t,tlist,xlist,diffun=lambda x,y:x-y):
342 | """
343 | getLinearInterpEx(t,tlist,xlist,diffun=lambda x,y:x-y)
344 | Linear interpolation. Constant extrapolation.
345 |
346 | Parameters
347 | ----------
348 | t : float
349 | point to be interpolated
350 | tlist : list
351 | independent variables
352 | xlist : list of floats
353 | dependent variables
354 | diffun : function
355 | difference function for two *tlist* values
356 |
357 | Returns
358 | -------
359 | out : float
360 | Linear interpolation at point *t*
361 |
362 | """
363 | ts,xs=getBracketingPoints(t,tlist,xlist)
364 | if len(ts)==1:
365 | # extrapolating outside range of tlist by constant
366 | return xs[0]
367 | else:
368 | w=diffun(t,ts[0])/diffun(ts[1],ts[0])
369 | return w*xs[1]+(1.0-w)*xs[0]
370 |
371 | def getLeftConstantInterpEx(t,tlist,xlist,diffun=None):
372 | """
373 | Left constant interpolation. Constant extrapolation.
374 |
375 | Parameters
376 | ----------
377 | t : float
378 | point to be interpolated
379 | tlist : list of floats
380 | independent variables
381 | xlist : list of floats
382 | dependent variables
383 |
384 | Returns
385 | -------
386 | out : float
387 | Left constant interpolation at point *t*
388 |
389 | """
390 | ts,xs=getBracketingPoints(t,tlist,xlist)
391 | return xs[0]
392 |
393 |
394 | def getLogLinearInterpEx(t,tlist,xlist,diffun=lambda x,y:x-y):
395 | """
396 | getLogLinearInterpEx(t,tlist,xlist,diffun=lambda x,y:x-y)
397 | Log-linear interpolation. Constant extrapolation.
398 |
399 | Parameters
400 | ----------
401 | t : float
402 | point to be interpolated
403 | tlist : list
404 | independent variables
405 | xlist : list of floats
406 | dependent variables
407 | diffun : function
408 | difference function for two *tlist* values
409 |
410 | Returns
411 | -------
412 | out : float
413 | Log-linear interpolation at point *t*
414 |
415 | """
416 | ts,xs=getBracketingPoints(t,tlist,xlist)
417 | if len(ts) == 1:
418 | return xs[0]
419 | lxlist=[math.log(x) for x in xs]
420 | w=diffun(t,ts[0])/diffun(ts[1],ts[0])
421 | lxi = w*lxlist[1]+(1.0-w)*lxlist[0]
422 | return math.exp(lxi)
423 |
424 |
425 | def getBracketingPoints(t,tlist,xlist,left_continuous=True):
426 | """
427 | Points bracketing *t*
428 |
429 | Parameters
430 | ----------
431 | t : float
432 | point to be bracketed
433 | tlist : list of floats
434 | independent variables
435 | xlist : list of floats
436 | dependent variables
437 |
438 | Returns
439 | -------
440 | out : list of lists
441 | Bracketing points
442 |
443 | """
444 | #print(t,tlist,xlist)
445 | if left_continuous:
446 | if (t>=tlist[-1]):
447 | return [[tlist[-1]],[xlist[-1]]]
448 | elif (ttlist[-1]):
455 | return [[tlist[-1]],[xlist[-1]]]
456 | elif (t<=tlist[0]):
457 | return [[tlist[0]],[xlist[0]]]
458 | else:
459 | idx = bisect.bisect_left(tlist, t)
460 | return [[tlist[idx - 1], tlist[idx]], [xlist[idx - 1], xlist[idx]]]
461 |
--------------------------------------------------------------------------------
/lib/surfaces.py:
--------------------------------------------------------------------------------
1 | "Surface classes used in local volatility calibration"
2 | import scipy.stats
3 | import math
4 | import bsanalytic as bsan
5 | import interpolator
6 |
7 | import numpy as np
8 |
9 | class Surface:
10 | """
11 | Parent level surface class
12 |
13 | """
14 | def __init__(self, surface_interpolator, domestic_dfcurve, base_dfcurve, spot_FX, impvolobj=None, localvol_cap=1e20):
15 | self.surface_interpolator = surface_interpolator
16 | self.domestic_dfcurve = domestic_dfcurve
17 | self.base_dfcurve = base_dfcurve
18 | self.spot_FX = spot_FX
19 | self.localvol_cap = localvol_cap
20 | self.delta_t = 5e-4
21 |
22 | def get_fwd(self, t):
23 | """
24 | Returns the forward value of the underlier at the given time
25 |
26 | Parameters
27 | ----------
28 | t : float
29 | time
30 |
31 | Returns
32 | -------
33 | fwd : float
34 | Forward
35 |
36 | """
37 | domestic_df = self.domestic_dfcurve(t)
38 | base_df = self.base_dfcurve(t)
39 | rd = - math.log(domestic_df) / t
40 | rf = - math.log(base_df) / t
41 | erdt = base_df / domestic_df
42 | return self.spot_FX * erdt
43 |
44 | def get_atmf_vol(self, t):
45 | """
46 | Returns at the money forward implied volatility at the given time
47 |
48 | """
49 | raise Exception
50 |
51 | def create_strike_grid(self, t, nrstrikes, gridtype='uniform_in_y', width_nr_stdev=3.0):
52 | """
53 | Compute 1D strike grid for a given time using the ATMF vol
54 |
55 | Parameters
56 | ----------
57 | t : float
58 | Time
59 | nrstrikes : int
60 | Number of strikes in the grid
61 | gridtype : {'uniform_in_y'}
62 | Grid type
63 | width_nr_stdev : float
64 | Width of the generated grid in terms of standard deviations from ATMF.
65 |
66 | Returns
67 | -------
68 | strikes : list of floats
69 | 1D strike grid
70 |
71 | """
72 | if gridtype == 'uniform_in_y':
73 | fwd = self.get_fwd(t)
74 | ref_impvol = self.get_atmf_vol(t)
75 | ymin = -width_nr_stdev * ref_impvol * math.sqrt(t)
76 | ymax = +width_nr_stdev * ref_impvol * math.sqrt(t)
77 | ys = list(np.arange(ymin, ymax, (ymax - ymin) / nrstrikes))[:nrstrikes]
78 | strikes = [fwd * math.exp(y) for y in ys]
79 | else:
80 | raise Exception('Gridtype %s not implemented' % gridtype)
81 | return strikes
82 |
83 |
84 | class CallSurface(Surface):
85 | """
86 | Call price surface class
87 |
88 | """
89 | def __init__(self, surface_interpolator, domestic_dfcurve, base_dfcurve, spot_FX, localvol_cap=1e20):
90 | super(CallSurface, self).__init__(surface_interpolator, domestic_dfcurve, base_dfcurve, spot_FX, localvol_cap)
91 |
92 | def evaluate_localvol_slice_det_ir(self, strikes, t):
93 | return [self.evaluate_localvol_deterministic_ir(K, t) for K in strikes]
94 |
95 | def evaluate_localvol_deterministic_ir(self, K, t):
96 | """
97 | Evaluate local volatility using standard Dupire's formula
98 |
99 | Parameters
100 | ----------
101 | K : float
102 | strike
103 | t : float
104 | time
105 |
106 | Returns
107 | -------
108 | localvol : float
109 | Local volatility
110 |
111 | """
112 | domestic_df = self.domestic_dfcurve(t)
113 | base_df = self.base_dfcurve(t)
114 | rd = -math.log(domestic_df) / t
115 | rf = -math.log(base_df) / t
116 | c = self.surface_interpolator.eval(K, t)
117 | d_c_d_t = self.surface_interpolator.eval(K, t, dt=1)
118 | d_c_d_K = self.surface_interpolator.eval(K, t, dx=1)
119 | d2_c_d_K2 = self.surface_interpolator.eval(K, t, dx=2)
120 | nom = d_c_d_t + (rd - rf) * K * d_c_d_K + rf * c
121 | denom = 0.5 * K * K * d2_c_d_K2
122 | return math.sqrt(min(self.localvol_cap, max(0.0, nom / denom)))
123 |
124 | def evaluate_localvol_slice_stoc_ir(self, strikes, t, expectations, stderrs):
125 | """
126 | Evaluate local volatility using Dupire's formula for stochastic rates
127 | for various strikes on a given time slice
128 |
129 | Parameters
130 | ----------
131 | strikes : list of floats
132 | strikes
133 | t : float
134 | time
135 | expectations : list of floats
136 | Values of the expectations in Dupire's formula
137 | stderrs : list of floats
138 | Standard error for the expectations
139 |
140 | Returns
141 | -------
142 | localvols, localvol_errs : list of floats, list of floats
143 | Local volatilities, Errors in local volatility
144 |
145 | """
146 | locvols = []
147 | locvol_errs = []
148 | for K,expect,stderr in zip(strikes, expectations, stderrs):
149 | locvol, locvol_err = self.evaluate_localvol_stochastic_ir(K, t, expect, stderr)
150 | locvols.append(locvol)
151 | locvol_errs.append(locvol_err)
152 | return locvols, locvol_errs
153 | #return [self.evaluate_localvol_stochastic_ir(K, t, expect) for K,expect in zip(strikes, expectations)]
154 |
155 | def evaluate_localvol_stochastic_ir(self, K, t, expectation, stderr):
156 | """
157 | Evaluate local volatility using Dupire's formula for stochastic rates
158 |
159 | Parameters
160 | ----------
161 | K : float
162 | strike
163 | t : float
164 | time
165 | expectation : float
166 | Value of the expectation in Dupire's formula
167 | stderr : float
168 | Standard error for the expectation
169 |
170 | Returns
171 | -------
172 | localvol, localvol_err : float, float
173 | Local volatility, Error in local volatility
174 |
175 | """
176 | domestic_df = self.domestic_dfcurve(t)
177 | base_df = self.base_dfcurve(t)
178 | rd = -math.log(domestic_df) / t
179 | rf = -math.log(base_df) / t
180 | c = self.surface_interpolator.eval(K, t)
181 | d_c_d_t = self.surface_interpolator.eval(K, t, dt=1)
182 | d_c_d_K = self.surface_interpolator.eval(K, t, dx=1)
183 | d2_c_d_K2 = self.surface_interpolator.eval(K, t, dx=2)
184 | nom = d_c_d_t - domestic_df * expectation
185 | nom_err = domestic_df * stderr
186 | denom = 0.5 * K * K * d2_c_d_K2
187 | locvol = math.sqrt(min(self.localvol_cap, max(0.0, nom / denom)))
188 | locvol_err = 0.5 * (nom_err / denom) / math.sqrt(locvol) if locvol > 0.0 else 0.0
189 | return locvol, locvol_err
190 |
191 | def get_atmf_vol(self, t):
192 | """
193 | Returns at the money forward implied volatility at the given time
194 |
195 | Parameters
196 | ----------
197 | t : float
198 |
199 | Returns
200 | -------
201 | atmfvol : float
202 |
203 | """
204 | domestic_df = self.domestic_dfcurve(t)
205 | base_df = self.base_dfcurve(t)
206 | rd = - math.log(domestic_df) / t
207 | rf = - math.log(base_df) / t
208 | erdt = base_df / domestic_df
209 | fwd = self.spot_FX * erdt
210 | ref_call = self.surface_interpolator.eval(fwd, t)
211 | return bsan.impliedvol_call(self.spot_FX, fwd, t, rd, rf, ref_call, 0.1)
212 |
213 |
214 | class TIVSurface(Surface):
215 | """
216 | Total implied variance surface class
217 |
218 | """
219 | def __init__(self, surface_interpolator, impvolobj, domestic_dfcurve, base_dfcurve, spot_FX, localvol_cap=1e20):
220 | super(TIVSurface, self).__init__(surface_interpolator, domestic_dfcurve, base_dfcurve, spot_FX, localvol_cap)
221 | self.fxvolsurf = impvolobj
222 |
223 | def evaluate_localvol_slice_det_ir(self, strikes, t):
224 | return [self.evaluate_localvol_deterministic_ir(K, t) for K in strikes]
225 |
226 | def evaluate_localvol_deterministic_ir(self, K, t):
227 | """
228 | Evaluate local volatility using standard Dupire's formula
229 |
230 | Parameters
231 | ----------
232 | K : float
233 | strike
234 | t : float
235 | time
236 |
237 | Returns
238 | -------
239 | localvol : float
240 | Local volatility
241 |
242 | """
243 | domestic_df = self.domestic_dfcurve(t)
244 | base_df = self.base_dfcurve(t)
245 | erdt = base_df / domestic_df
246 | fwd = self.spot_FX * erdt
247 | y = math.log(K / fwd)
248 | w = self.surface_interpolator.eval(y, t)
249 | d_w_d_t = self.surface_interpolator.eval(y, t, dt=1)
250 | d_w_d_y = self.surface_interpolator.eval(y, t, dx=1)
251 | d2_w_d_y2 = self.surface_interpolator.eval(y, t, dx=2)
252 | nom = d_w_d_t
253 | denom = 1.0 - d_w_d_y * y / w + 0.5 * d2_w_d_y2 + 0.25 * (-0.25 - 1.0 / w + y ** 2 / w ** 2) * d_w_d_y ** 2
254 | return math.sqrt(min(self.localvol_cap, max(0.0, nom / denom)))
255 |
256 |
257 | def evaluate_localvol_slice_stoc_ir(self, strikes, t, expectations, stderrs):
258 | """
259 | Evaluate local volatility using Dupire's formula for stochastic rates
260 | for various strikes on a given time slice
261 |
262 | Parameters
263 | ----------
264 | strikes : list of floats
265 | strikes
266 | t : float
267 | time
268 | expectations : list of floats
269 | Values of the expectations in Dupire's formula
270 | stderrs : list of floats
271 | Standard error for the expectations
272 |
273 | Returns
274 | -------
275 | localvols, localvol_errs : list of floats, list of floats
276 | Local volatilities, Errors in local volatility
277 |
278 | """
279 | locvols = []
280 | locvol_errs = []
281 | for K,expect,stderr in zip(strikes, expectations, stderrs):
282 | locvol, locvol_err = self.evaluate_localvol_stochastic_ir(K, t, expect, stderr)
283 | locvols.append(locvol)
284 | locvol_errs.append(locvol_err)
285 | return locvols, locvol_errs
286 |
287 |
288 | def evaluate_localvol_stochastic_ir(self, K, t, expectation, stderr):
289 | """
290 | Evaluate local volatility using Dupire's formula for stochastic rates
291 |
292 | Parameters
293 | ----------
294 | K : float
295 | strike
296 | t : float
297 | time
298 | expectation : float
299 | Value of the expectation in Dupire's formula
300 | stderr : float
301 | Standard error for the expectation
302 |
303 | Returns
304 | -------
305 | localvol, localvol_err : float, float
306 | Local volatility, Error in local volatility
307 |
308 | """
309 | domestic_df = self.domestic_dfcurve(t)
310 | base_df = self.base_dfcurve(t)
311 | domestic_shortrate = interpolator.constructShortRateCurve(self.domestic_dfcurve)
312 | rd = domestic_shortrate(t)
313 | base_shortrate = interpolator.constructShortRateCurve(self.base_dfcurve)
314 | rf = base_shortrate(t)
315 | mu_T = rd - rf
316 | erdt = base_df / domestic_df
317 | fwd = self.spot_FX * erdt
318 | y = math.log(K / fwd)
319 | e_y = math.exp(y)
320 | w = self.surface_interpolator.eval(y, t)
321 | d_w_d_t = self.surface_interpolator.eval(y, t, dt=1)
322 | d_w_d_y = self.surface_interpolator.eval(y, t, dx=1)
323 | d2_w_d_y2 = self.surface_interpolator.eval(y, t, dx=2)
324 | d_1 = -y / math.sqrt(w) + 0.5 * math.sqrt(w)
325 | d_2 = d_1 - math.sqrt(w)
326 | call = fwd * (scipy.stats.norm.cdf(d_1) - e_y * scipy.stats.norm.cdf(d_2))
327 | d_call_d_w = 0.5 * fwd * e_y * scipy.stats.norm.pdf(d_2) / math.sqrt(w)
328 | d_call_d_y = -fwd * e_y * scipy.stats.norm.cdf(d_2)
329 |
330 | nom = -mu_T * (d_call_d_y + d_call_d_w * d_w_d_y) - rf * call + d_call_d_w * d_w_d_t - expectation
331 | nom_err = stderr
332 | denom = d_call_d_w * (1.0 - d_w_d_y * y / w + 0.5 * d2_w_d_y2 + 0.25 * (-0.25 - 1.0 / w + y ** 2 / w ** 2) * d_w_d_y ** 2)
333 |
334 | locvol = math.sqrt(min(self.localvol_cap, max(0.0, nom / denom)))
335 | locvol_err = 0.5 * (nom_err / denom) / math.sqrt(locvol) if locvol > 0.0 else 0.0
336 | return locvol, locvol_err
337 |
338 | def get_atmf_vol(self, t):
339 | """
340 | Returns at the money forward implied volatility at the given time
341 |
342 | Parameters
343 | ----------
344 | t : float
345 |
346 | Returns
347 | -------
348 | atmfvol : float
349 |
350 | """
351 | ref_totimpvar = self.surface_interpolator.eval(0.0, t)
352 | return math.sqrt(ref_totimpvar / t)
353 |
354 |
355 | class LVSurface(Surface):
356 | """
357 | Wrapper to evaluate a given local volatility surface through interpolation
358 |
359 | """
360 | def __init__(self, surface_interpolator, domestic_dfcurve, base_dfcurve, spot_FX, localvol_cap=1e20):
361 | super(LVSurface, self).__init__(surface_interpolator, domestic_dfcurve, base_dfcurve, spot_FX, localvol_cap)
362 |
363 | def evaluate_localvol_deterministic_ir(self, K, t):
364 | """
365 | Evaluate local volatility at the given strike and time
366 |
367 | Parameters
368 | ----------
369 | K : float
370 | strike
371 | t : float
372 | time
373 |
374 | Returns
375 | -------
376 | localvol : float
377 | Local volatility
378 |
379 | """
380 | return max(0.0, self.surface_interpolator.eval(K, t)) # localvol_cap is ignored for now
381 |
382 | def evaluate_localvol_slice_det_ir(self, strikes, t):
383 | return [self.evaluate_localvol_deterministic_ir(K, t) for K in strikes]
384 |
385 | def evaluate_localvol_stochastic_ir(self, K, t, expectation, stderr):
386 | """
387 | Evaluate local volatility at the given strike and time
388 |
389 | Parameters
390 | ----------
391 | K : float
392 | strike
393 | t : float
394 | time
395 | expectation : ignored
396 | stderr : ignored
397 |
398 | Returns
399 | -------
400 | localvol, 0.0 : float, float
401 | Local volatility, 0.0
402 |
403 | """
404 | return max(0.0, self.surface_interpolator.eval(K, t)), 0.0 # localvol_cap is ignored for now
405 |
406 | def get_atmf_vol(self, t): # not really the ATMF implied vol but should do for our purposes
407 | """
408 | Returns at the money forward local volatility at the given time
409 |
410 | Parameters
411 | ----------
412 | t : float
413 |
414 | Returns
415 | -------
416 | vol : float
417 |
418 | """
419 | fwd = self.get_fwd(t)
420 | return self.evaluate_localvol_deterministic_ir(fwd, t)
421 |
422 |
423 | def generate_call_price_surface(impvolobj, strikes, times, domestic_dfcurve, base_dfcurve, spot, localvol_cap=1e20):
424 | """
425 | Generates a uniform call price surface for local volatility evaluation
426 |
427 | Parameters
428 | ----------
429 | impvolobj :
430 | Implied vol surface
431 | strikes : list of floats
432 | Grid of strikes
433 | times : list of floats
434 | Grid of times
435 | domestic_dfcurve :
436 | (domestic) discount curve
437 | base_dfcurve :
438 | base discount curve or dividend yield curve
439 | spot : float
440 | Time zero value of the underlier
441 | localvol_cap : float
442 | Cap for local volatility
443 |
444 | Returns
445 | -------
446 | calls : :class:`CallSurface`
447 | Surface for local volatility evaluation
448 |
449 | """
450 | interp = interpolator.generate_call_price_interpolator(impvolobj, strikes, times, domestic_dfcurve, base_dfcurve, spot)
451 | return CallSurface(interp, domestic_dfcurve, base_dfcurve, spot, localvol_cap)
452 |
453 | def generate_call_price_surface_nonuniform(impvolobj, nrstrikes, times, domestic_dfcurve,
454 | base_dfcurve, spot, localvol_cap=1e20,
455 | width_nr_stdev=3.5):
456 | """
457 | Generates a nonuniform call price surface for local volatility evaluation
458 |
459 | Parameters
460 | ----------
461 | impvolobj :
462 | Implied vol surface
463 | nrstrikes : list of floats
464 | Number of strikes
465 | times : list of floats
466 | Grid of times
467 | domestic_dfcurve :
468 | (domestic) discount curve
469 | base_dfcurve :
470 | base discount curve or dividend yield curve
471 | spot : float
472 | Time zero value of the underlier
473 | localvol_cap : float
474 | Cap for local volatility
475 | width_nr_stdev : float
476 | Width of the generated grid in terms of standard deviations from ATMF
477 |
478 | Returns
479 | -------
480 | calls : :class:`CallSurface`
481 | Surface for local volatility evaluation
482 |
483 | """
484 | interp = interpolator.generate_call_price_interpolator_nonuniform(impvolobj, nrstrikes, times, domestic_dfcurve, base_dfcurve, spot, width_nr_stdev)
485 | return CallSurface(interp, domestic_dfcurve, base_dfcurve, spot, localvol_cap)
486 |
487 | def generate_tiv_surface(impvolobj, ys, times, domestic_dfcurve, base_dfcurve, spot, localvol_cap=1e20):
488 | """
489 | Generates a uniform total implied variance surface for local volatility
490 | evaluation
491 |
492 | Parameters
493 | ----------
494 | impvolobj :
495 | Implied vol surface
496 | ys : list of floats
497 | Grid of log-moneynesses
498 | times : list of floats
499 | Grid of times
500 | domestic_dfcurve :
501 | (domestic) discount curve
502 | base_dfcurve :
503 | base discount curve or dividend yield curve
504 | spot : float
505 | Time zero value of the underlier
506 | localvol_cap : float
507 | Cap for local volatility
508 |
509 | Returns
510 | -------
511 | calls : :class:`TIVSurface`
512 | Surface for local volatility evaluation
513 |
514 | """
515 | interp = interpolator.generate_implied_totalvariance_interpolator(impvolobj, ys, times)
516 | return TIVSurface(interp, domestic_dfcurve, base_dfcurve, spot, localvol_cap)
517 |
518 | def generate_tiv_surface_nonuniform(impvolobj, nrys, times, domestic_dfcurve, base_dfcurve, spot, localvol_cap=1e20,
519 | width_nr_stdev=3.5):
520 | """
521 | Generates a nonuniform total implied volatility surface for local volatility evaluation
522 |
523 | Parameters
524 | ----------
525 | impvolobj :
526 | Implied vol surface
527 | nrstrikes : list of floats
528 | Number of log-moneynesses
529 | times : list of floats
530 | Grid of times
531 | domestic_dfcurve :
532 | (domestic) discount curve
533 | base_dfcurve :
534 | base discount curve or dividend yield curve
535 | spot : float
536 | Time zero value of the underlier
537 | localvol_cap : float
538 | Cap for local volatility
539 | width_nr_stdev : float
540 | Width of the generated grid in terms of standard deviations from ATMF
541 |
542 | Returns
543 | -------
544 | calls : :class:`TIVSurface`
545 | Surface for local volatility evaluation
546 |
547 | """
548 | interp = interpolator.generate_implied_totalvariance_interpolator_nonuniform(impvolobj, nrys, times, width_nr_stdev)
549 | return TIVSurface(interp, impvolobj, domestic_dfcurve, base_dfcurve, spot, localvol_cap)
550 |
551 | def generate_lv_surface_from_values_nonuniform(strikes, times, localvols, domestic_dfcurve, base_dfcurve, spot, localvol_cap=1e20):
552 | """
553 | Generates a nonuniform local volatility surface for direct evaluation
554 |
555 | Parameters
556 | ----------
557 | strikes : list of lists of floats
558 | Grid of strikes
559 | times : list of floats
560 | Grid of times
561 | localvols : list of lists of floats
562 | Grid of local volatilities. Must be of the same shape with *strikes*
563 | domestic_dfcurve :
564 | (domestic) discount curve
565 | base_dfcurve :
566 | base discount curve or dividend yield curve
567 | spot : float
568 | Time zero value of the underlier
569 | localvol_cap : float
570 | Cap for local volatility
571 |
572 | Returns
573 | -------
574 | calls : :class:`LVSurface`
575 | Surface for local volatility evaluation
576 |
577 | """
578 | interp = interpolator.SurfaceInterpolator(strikes, times, localvols)
579 | return LVSurface(interp, domestic_dfcurve, base_dfcurve, spot, localvol_cap)
580 |
581 | def generate_2d_strike_grid(surface, nrstrikes, times, rectangular, width_nr_stdev=3.5):
582 | """
583 | Compute 2D strike grid for given times and number of strikes
584 |
585 | Parameters
586 | ----------
587 | surface : :class:`Surface`
588 | Surface to query for the 1D subgrids
589 | nrstrikes : int
590 | Number of strikes in the 1D subgrids
591 | times : list of floats
592 | Times
593 | rectangular : bool
594 | The shape of the output grid
595 | width_nr_stdev : float
596 | Width of the generated grid in terms of standard deviations from ATMF.
597 |
598 | Returns
599 | -------
600 | strikes : list of lists of floats
601 | 2D strike grid
602 |
603 | """
604 | strike_matrix = []
605 | if rectangular:
606 | finaltime = times[-1]
607 | strike_grid = surface.create_strike_grid(finaltime, nrstrikes, width_nr_stdev=width_nr_stdev)
608 | for t in times:
609 | strike_matrix.append(strike_grid[:])
610 | else:
611 | for t in times:
612 | strike_grid = surface.create_strike_grid(t, nrstrikes, width_nr_stdev=width_nr_stdev)
613 | strike_matrix.append(strike_grid)
614 | return strike_matrix
615 |
--------------------------------------------------------------------------------
/marketdata_JSON_asof_04_30_2020/EUR.json:
--------------------------------------------------------------------------------
1 | {
2 | "g1++": {
3 | "meanrev": {
4 | "times": [
5 | 0.0
6 | ],
7 | "values": [
8 | 0.02
9 | ]
10 | },
11 | "vol": {
12 | "times": [
13 | 0.0,
14 | 0.243668720054757,
15 | 0.49555099247091033,
16 | 0.9938398357289527,
17 | 1.9931553730321698,
18 | 2.9897330595482545,
19 | 4.993839835728953,
20 | 9.987679671457906,
21 | 14.986995208761122
22 | ],
23 | "values": [
24 | 0.008201872637889726,
25 | 0.007770983137783938,
26 | 0.007542689160940279,
27 | 0.007253759705537655,
28 | 0.0071294284340146985,
29 | 0.007467517723482615,
30 | 0.00740128888965986,
31 | 0.007713492209067195,
32 | 0.007713492209067195
33 | ]
34 | },
35 | "shift": {
36 | "times": [
37 | 0.0,
38 | 0.010958904109589041,
39 | 0.0136986301369863,
40 | 0.01643835616438356,
41 | 0.03287671232876712,
42 | 0.08767123287671233,
43 | 0.09863013698630137,
44 | 0.16986301369863013,
45 | 0.26575342465753427,
46 | 0.42191780821917807,
47 | 0.5178082191780822,
48 | 0.6821917808219178,
49 | 0.7698630136986301,
50 | 0.9205479452054794,
51 | 1.010958904109589,
52 | 1.0136986301369864,
53 | 1.16986301369863,
54 | 1.2657534246575342,
55 | 1.4219178082191781,
56 | 1.5178082191780822,
57 | 1.6794520547945206,
58 | 1.7753424657534247,
59 | 2.0136986301369864,
60 | 2.265753424657534,
61 | 2.5232876712328767,
62 | 2.7726027397260276,
63 | 3.0136986301369864,
64 | 3.271232876712329,
65 | 3.5205479452054793,
66 | 3.76986301369863,
67 | 4.019178082191781,
68 | 4.021917808219178,
69 | 4.2684931506849315,
70 | 4.52054794520548,
71 | 4.772602739726027,
72 | 5.016438356164383,
73 | 5.019178082191781,
74 | 5.2684931506849315,
75 | 5.52054794520548,
76 | 5.772602739726027,
77 | 6.016438356164383,
78 | 6.2684931506849315,
79 | 6.52054794520548,
80 | 6.772602739726027,
81 | 7.013698630136986,
82 | 7.016438356164383,
83 | 7.2684931506849315,
84 | 7.52054794520548,
85 | 7.778082191780822,
86 | 8.01917808219178,
87 | 8.276712328767124,
88 | 8.526027397260274,
89 | 8.775342465753425,
90 | 9.024657534246575,
91 | 9.027397260273972,
92 | 9.273972602739725,
93 | 9.523287671232877,
94 | 9.775342465753425,
95 | 10.021917808219179,
96 | 10.024657534246575,
97 | 10.271232876712329,
98 | 10.523287671232877,
99 | 10.775342465753425,
100 | 11.01917808219178,
101 | 11.021917808219179,
102 | 11.271232876712329,
103 | 11.523287671232877,
104 | 11.775342465753425,
105 | 12.01917808219178,
106 | 12.021917808219179,
107 | 12.273972602739725,
108 | 12.526027397260274,
109 | 12.783561643835617,
110 | 13.021917808219179,
111 | 13.273972602739725,
112 | 13.531506849315068,
113 | 13.780821917808218,
114 | 14.021917808219179,
115 | 14.27945205479452,
116 | 14.528767123287672,
117 | 14.778082191780822,
118 | 15.027397260273972,
119 | 15.03013698630137,
120 | 15.276712328767124,
121 | 15.526027397260274,
122 | 15.778082191780822,
123 | 16.024657534246575,
124 | 16.027397260273972,
125 | 16.276712328767122,
126 | 16.528767123287672,
127 | 16.78082191780822,
128 | 17.024657534246575,
129 | 17.276712328767122,
130 | 17.528767123287672,
131 | 17.78082191780822,
132 | 18.02191780821918,
133 | 18.024657534246575,
134 | 18.276712328767122,
135 | 18.528767123287672,
136 | 18.786301369863015,
137 | 19.024657534246575,
138 | 19.276712328767122,
139 | 19.534246575342465,
140 | 19.783561643835615,
141 | 20.03287671232877,
142 | 20.035616438356165,
143 | 20.28219178082192,
144 | 20.53150684931507,
145 | 20.783561643835615,
146 | 21.03013698630137,
147 | 21.03287671232877,
148 | 21.279452054794522,
149 | 21.53150684931507,
150 | 21.783561643835615,
151 | 22.027397260273972,
152 | 22.03013698630137,
153 | 22.279452054794522,
154 | 22.53150684931507,
155 | 22.783561643835615,
156 | 23.027397260273972,
157 | 23.279452054794522,
158 | 23.53150684931507,
159 | 23.783561643835615,
160 | 24.03013698630137,
161 | 24.28219178082192,
162 | 24.53972602739726,
163 | 24.78904109589041,
164 | 25.03013698630137,
165 | 25.28767123287671,
166 | 25.53698630136986,
167 | 25.786301369863015,
168 | 26.035616438356165,
169 | 26.03835616438356,
170 | 26.284931506849315,
171 | 26.534246575342465,
172 | 26.786301369863015,
173 | 27.03287671232877,
174 | 27.28219178082192,
175 | 27.534246575342465,
176 | 27.786301369863015,
177 | 28.03287671232877,
178 | 28.284931506849315,
179 | 28.53698630136986,
180 | 28.78904109589041,
181 | 29.03013698630137,
182 | 29.03287671232877,
183 | 29.284931506849315,
184 | 29.53698630136986,
185 | 29.794520547945204,
186 | 30.03287671232877,
187 | 30.284931506849315,
188 | 30.542465753424658,
189 | 30.791780821917808,
190 | 31.03287671232877,
191 | 31.29041095890411,
192 | 31.53972602739726,
193 | 31.78904109589041,
194 | 32.04109589041096,
195 | 32.28767123287671,
196 | 32.53972602739726,
197 | 32.79178082191781,
198 | 33.038356164383565,
199 | 33.28767123287671,
200 | 33.53972602739726,
201 | 33.79178082191781,
202 | 34.035616438356165,
203 | 34.038356164383565,
204 | 34.28767123287671,
205 | 34.53972602739726,
206 | 34.79178082191781,
207 | 35.035616438356165,
208 | 35.28767123287671,
209 | 35.53972602739726,
210 | 35.797260273972604,
211 | 36.038356164383565,
212 | 36.295890410958904,
213 | 36.54520547945206,
214 | 36.794520547945204,
215 | 37.04657534246575,
216 | 37.293150684931504,
217 | 37.54246575342466,
218 | 37.794520547945204,
219 | 38.04383561643836,
220 | 38.29041095890411,
221 | 38.54246575342466,
222 | 38.794520547945204,
223 | 39.04109589041096,
224 | 39.29041095890411,
225 | 39.54246575342466,
226 | 39.794520547945204,
227 | 40.04109589041096,
228 | 40.293150684931504,
229 | 40.54520547945206,
230 | 40.8027397260274,
231 | 41.04109589041096,
232 | 41.293150684931504,
233 | 41.55068493150685,
234 | 41.8,
235 | 42.04109589041096,
236 | 42.298630136986304,
237 | 42.54794520547945,
238 | 42.797260273972604,
239 | 43.04931506849315,
240 | 43.295890410958904,
241 | 43.54520547945206,
242 | 43.797260273972604,
243 | 44.04383561643836,
244 | 44.295890410958904,
245 | 44.54794520547945,
246 | 44.8,
247 | 45.04383561643836,
248 | 45.295890410958904,
249 | 45.54794520547945,
250 | 45.8,
251 | 46.04109589041096,
252 | 46.04383561643836,
253 | 46.295890410958904,
254 | 46.54794520547945,
255 | 46.8054794520548,
256 | 47.04383561643836,
257 | 47.295890410958904,
258 | 47.553424657534244,
259 | 47.8027397260274,
260 | 48.05205479452055,
261 | 48.3013698630137,
262 | 48.55068493150685,
263 | 48.8027397260274,
264 | 49.04931506849315,
265 | 49.298630136986304,
266 | 49.55068493150685,
267 | 49.8027397260274,
268 | 50.04657534246575,
269 | 50.298630136986304,
270 | 50.55068493150685,
271 | 50.8027397260274,
272 | 51.04657534246575,
273 | 51.298630136986304,
274 | 51.55068493150685,
275 | 51.8027397260274,
276 | 52.04931506849315,
277 | 52.3013698630137,
278 | 52.558904109589044,
279 | 52.80821917808219,
280 | 53.04931506849315,
281 | 53.30684931506849,
282 | 53.556164383561644,
283 | 53.8054794520548,
284 | 54.054794520547944,
285 | 54.3041095890411,
286 | 54.553424657534244,
287 | 54.8054794520548,
288 | 55.05205479452055,
289 | 55.3013698630137,
290 | 55.553424657534244,
291 | 55.8054794520548,
292 | 56.05205479452055,
293 | 56.3041095890411,
294 | 56.556164383561644,
295 | 56.80821917808219,
296 | 57.05205479452055,
297 | 57.3041095890411,
298 | 57.556164383561644,
299 | 57.81369863013698,
300 | 58.05205479452055,
301 | 58.3041095890411,
302 | 58.56164383561644,
303 | 58.81095890410959,
304 | 59.05205479452055,
305 | 59.30958904109589,
306 | 59.558904109589044,
307 | 59.80821917808219
308 | ],
309 | "values": [
310 | -0.005506720962915683,
311 | -0.005832459346381448,
312 | -0.005950379440551133,
313 | -0.005849401393492587,
314 | -0.006738074712492744,
315 | -0.006833345882557904,
316 | -0.0072916428195209555,
317 | -0.00757531878057988,
318 | -0.00798875554236345,
319 | -0.007595407360737167,
320 | -0.010352229376659083,
321 | -0.008494303462344322,
322 | -0.00889886303711125,
323 | -0.008822921170490005,
324 | -0.008846419392324795,
325 | -0.009166544313699707,
326 | -0.008976374937912491,
327 | -0.009191165502434208,
328 | -0.00888608762417948,
329 | -0.010201621776258834,
330 | -0.008677535938484377,
331 | -0.008642260995791066,
332 | -0.00856757610684166,
333 | -0.008618418017291627,
334 | -0.00870626209099597,
335 | -0.008575460266011543,
336 | -0.008422030412555594,
337 | -0.008413246231271286,
338 | -0.008351721185226018,
339 | -0.008312552762843217,
340 | -0.008173118981064518,
341 | -0.008062178645317438,
342 | -0.007840322615045801,
343 | -0.007590373202140859,
344 | -0.007295799729405175,
345 | -0.007139840369505385,
346 | -0.006998231406799201,
347 | -0.006823027759407777,
348 | -0.006560523986302729,
349 | -0.006153411645732721,
350 | -0.0057603649355974975,
351 | -0.005313359191398726,
352 | -0.004783387675100494,
353 | -0.00417614034675932,
354 | -0.004009565308209881,
355 | -0.0038705504645974516,
356 | -0.003500449856587225,
357 | -0.003168250319312599,
358 | -0.002759723527105311,
359 | -0.0024849995381045777,
360 | -0.002153572451009954,
361 | -0.0015798432399131033,
362 | -0.0010491844851165763,
363 | -0.0008599521523687192,
364 | -0.0009207495881844551,
365 | -0.0005352559289873011,
366 | -0.00030045390073651424,
367 | -0.00011179314606980848,
368 | -5.514585853110534e-06,
369 | 0.00018411432759704103,
370 | 0.00038365377591770077,
371 | 0.0006233996571405677,
372 | 0.000927971549963165,
373 | 0.0010525734404670116,
374 | 0.0012398657283275434,
375 | 0.0014642747090630288,
376 | 0.0017829231326188396,
377 | 0.0021630685219876343,
378 | 0.002275362308500421,
379 | 0.002413943444648941,
380 | 0.002703769304061011,
381 | 0.0029771856661989916,
382 | 0.0033083585906178597,
383 | 0.003450803551939949,
384 | 0.0036822543831415413,
385 | 0.003840061889022348,
386 | 0.004199771951994939,
387 | 0.004227360412471199,
388 | 0.004338374865338152,
389 | 0.004526154859455587,
390 | 0.004700837302931522,
391 | 0.004713654821289909,
392 | 0.004659772265248805,
393 | 0.004833329369844098,
394 | 0.0049424940450711816,
395 | 0.005027676922292482,
396 | 0.005038409947960801,
397 | 0.005174197149422363,
398 | 0.005231560756047068,
399 | 0.005334202173249529,
400 | 0.005476956825853841,
401 | 0.005558418957175313,
402 | 0.005649657182861397,
403 | 0.0057638068792454766,
404 | 0.005937752438011853,
405 | 0.005944330254746669,
406 | 0.005989478478652711,
407 | 0.006107850550451556,
408 | 0.006231859118354319,
409 | 0.0064071461811533266,
410 | 0.006473219992565735,
411 | 0.006604698343484679,
412 | 0.006705533222384744,
413 | 0.006947654027333221,
414 | 0.0069529086397813215,
415 | 0.0069698602019210324,
416 | 0.007139764392906535,
417 | 0.007243991825458401,
418 | 0.0073281409434496165,
419 | 0.00732786995665816,
420 | 0.007453959263415496,
421 | 0.007524361610252075,
422 | 0.007587710239011731,
423 | 0.007676397864047087,
424 | 0.007678889886222121,
425 | 0.007754450480522547,
426 | 0.007780907977746078,
427 | 0.00783095404962634,
428 | 0.007901578011961261,
429 | 0.007917646115429368,
430 | 0.007927834012894602,
431 | 0.007943813796411903,
432 | 0.007976409437072465,
433 | 0.007946398801084054,
434 | 0.00793374528641874,
435 | 0.00789269544361266,
436 | 0.007947388463564808,
437 | 0.007862846806056487,
438 | 0.007836819793363033,
439 | 0.007871860224697555,
440 | 0.007910388325200177,
441 | 0.007955505868147902,
442 | 0.007874099814379304,
443 | 0.007931189984757997,
444 | 0.007968244259502348,
445 | 0.008006235667529678,
446 | 0.008078637249334556,
447 | 0.008142458409374331,
448 | 0.00821755407833753,
449 | 0.008314013726203382,
450 | 0.008418204090687994,
451 | 0.008534141160631717,
452 | 0.008667271202940837,
453 | 0.008818295417397549,
454 | 0.008891099628869132,
455 | 0.00896815258402749,
456 | 0.00914595068850089,
457 | 0.009340415195698917,
458 | 0.009542965466817824,
459 | 0.009745077232493135,
460 | 0.009955084226380237,
461 | 0.010165775048302331,
462 | 0.010341351435754837,
463 | 0.010556565276653607,
464 | 0.010772212834709,
465 | 0.010958571566744124,
466 | 0.011165135832796014,
467 | 0.011351186380377366,
468 | 0.011554709538469942,
469 | 0.011763290479243599,
470 | 0.011952997479446524,
471 | 0.012136372796112502,
472 | 0.012354258923728649,
473 | 0.01255524364458536,
474 | 0.012728291682865258,
475 | 0.012856083906431993,
476 | 0.012934602186773485,
477 | 0.013145878629358067,
478 | 0.013343116132840626,
479 | 0.01348890634876,
480 | 0.013727021271506212,
481 | 0.013921216210986267,
482 | 0.014113441200949185,
483 | 0.014267135946510327,
484 | 0.01448849519620808,
485 | 0.01471762077085748,
486 | 0.014836198623177102,
487 | 0.01494577648134296,
488 | 0.015261012126517703,
489 | 0.015362412352199225,
490 | 0.015532524380405283,
491 | 0.015729394862503254,
492 | 0.015839500289989452,
493 | 0.016027879403524067,
494 | 0.016218173119629763,
495 | 0.016347908143942946,
496 | 0.016468047354322,
497 | 0.016681933002674922,
498 | 0.01683100205508222,
499 | 0.016912475307102215,
500 | 0.017128038924806823,
501 | 0.017284055255487634,
502 | 0.017441126275271408,
503 | 0.017492606173907542,
504 | 0.01775724587272454,
505 | 0.01792220109516162,
506 | 0.018162241097775252,
507 | 0.018037366860851473,
508 | 0.018406549898835733,
509 | 0.01865164911127176,
510 | 0.018694812932383904,
511 | 0.018736822311666988,
512 | 0.019152544739931446,
513 | 0.019193673927541784,
514 | 0.019362715587552086,
515 | 0.019575611767227052,
516 | 0.019660027509046638,
517 | 0.019921475494652074,
518 | 0.02009620840743563,
519 | 0.020181344949560417,
520 | 0.02040192074933384,
521 | 0.020626121925388284,
522 | 0.020805558420291435,
523 | 0.020850320813149616,
524 | 0.020938444887161314,
525 | 0.021167223324615257,
526 | 0.021352546823152907,
527 | 0.021536319874250757,
528 | 0.021592169464166765,
529 | 0.02190654079069275,
530 | 0.022099716878704826,
531 | 0.022370356431383583,
532 | 0.022311148582839186,
533 | 0.022748483913132462,
534 | 0.022819912298760854,
535 | 0.023017357572840062,
536 | 0.023251430788728374,
537 | 0.02337009455374634,
538 | 0.02361317548909796,
539 | 0.023854275390142943,
540 | 0.02401694635512861,
541 | 0.0241811907870439,
542 | 0.02444762548456927,
543 | 0.024638420430434155,
544 | 0.024761855025369782,
545 | 0.024986116692134172,
546 | 0.025206894950493997,
547 | 0.025394960109928862,
548 | 0.025524717489583598,
549 | 0.02576777822651517,
550 | 0.025957850514722484,
551 | 0.026190347218009273,
552 | 0.026189516244971164,
553 | 0.026505387312512473,
554 | 0.026732024516124473,
555 | 0.026844363638828337,
556 | 0.02696185217811041,
557 | 0.02727112638562638,
558 | 0.02738595133216232,
559 | 0.027566185458888007,
560 | 0.027763153993143892,
561 | 0.027898501310941716,
562 | 0.028094579480935956,
563 | 0.02828730412004352,
564 | 0.02844228419022501,
565 | 0.028613491898178127,
566 | 0.02880160457030754,
567 | 0.028970804449607514,
568 | 0.029088316445098295,
569 | 0.02930234516786083,
570 | 0.029468134649707024,
571 | 0.0296330711529522,
572 | 0.029749345014339717,
573 | 0.02995239284829273,
574 | 0.030115598086507045,
575 | 0.030302740305085483,
576 | 0.030352026179016937,
577 | 0.03058291425474568,
578 | 0.03076423424510045,
579 | 0.03086656964467633,
580 | 0.031030520604899355
581 | ]
582 | },
583 | "x0": 0.0
584 | },
585 | "discount": {
586 | "times": [
587 | 0.0,
588 | 0.010958904109589041,
589 | 0.0136986301369863,
590 | 0.01643835616438356,
591 | 0.03287671232876712,
592 | 0.08767123287671233,
593 | 0.09863013698630137,
594 | 0.16986301369863013,
595 | 0.26575342465753427,
596 | 0.42191780821917807,
597 | 0.5178082191780822,
598 | 0.6821917808219178,
599 | 0.7698630136986301,
600 | 0.9205479452054794,
601 | 1.010958904109589,
602 | 1.0136986301369864,
603 | 1.16986301369863,
604 | 1.2657534246575342,
605 | 1.4219178082191781,
606 | 1.5178082191780822,
607 | 1.6794520547945206,
608 | 1.7753424657534247,
609 | 2.0136986301369864,
610 | 2.265753424657534,
611 | 2.5232876712328767,
612 | 2.7726027397260276,
613 | 3.0136986301369864,
614 | 3.271232876712329,
615 | 3.5205479452054793,
616 | 3.76986301369863,
617 | 4.019178082191781,
618 | 4.021917808219178,
619 | 4.2684931506849315,
620 | 4.52054794520548,
621 | 4.772602739726027,
622 | 5.016438356164383,
623 | 5.019178082191781,
624 | 5.2684931506849315,
625 | 5.52054794520548,
626 | 5.772602739726027,
627 | 6.016438356164383,
628 | 6.2684931506849315,
629 | 6.52054794520548,
630 | 6.772602739726027,
631 | 7.013698630136986,
632 | 7.016438356164383,
633 | 7.2684931506849315,
634 | 7.52054794520548,
635 | 7.778082191780822,
636 | 8.01917808219178,
637 | 8.276712328767124,
638 | 8.526027397260274,
639 | 8.775342465753425,
640 | 9.024657534246575,
641 | 9.027397260273972,
642 | 9.273972602739725,
643 | 9.523287671232877,
644 | 9.775342465753425,
645 | 10.021917808219179,
646 | 10.024657534246575,
647 | 10.271232876712329,
648 | 10.523287671232877,
649 | 10.775342465753425,
650 | 11.01917808219178,
651 | 11.021917808219179,
652 | 11.271232876712329,
653 | 11.523287671232877,
654 | 11.775342465753425,
655 | 12.01917808219178,
656 | 12.021917808219179,
657 | 12.273972602739725,
658 | 12.526027397260274,
659 | 12.783561643835617,
660 | 13.021917808219179,
661 | 13.273972602739725,
662 | 13.531506849315068,
663 | 13.780821917808218,
664 | 14.021917808219179,
665 | 14.27945205479452,
666 | 14.528767123287672,
667 | 14.778082191780822,
668 | 15.027397260273972,
669 | 15.03013698630137,
670 | 15.276712328767124,
671 | 15.526027397260274,
672 | 15.778082191780822,
673 | 16.024657534246575,
674 | 16.027397260273972,
675 | 16.276712328767122,
676 | 16.528767123287672,
677 | 16.78082191780822,
678 | 17.024657534246575,
679 | 17.276712328767122,
680 | 17.528767123287672,
681 | 17.78082191780822,
682 | 18.02191780821918,
683 | 18.024657534246575,
684 | 18.276712328767122,
685 | 18.528767123287672,
686 | 18.786301369863015,
687 | 19.024657534246575,
688 | 19.276712328767122,
689 | 19.534246575342465,
690 | 19.783561643835615,
691 | 20.03287671232877,
692 | 20.035616438356165,
693 | 20.28219178082192,
694 | 20.53150684931507,
695 | 20.783561643835615,
696 | 21.03013698630137,
697 | 21.03287671232877,
698 | 21.279452054794522,
699 | 21.53150684931507,
700 | 21.783561643835615,
701 | 22.027397260273972,
702 | 22.03013698630137,
703 | 22.279452054794522,
704 | 22.53150684931507,
705 | 22.783561643835615,
706 | 23.027397260273972,
707 | 23.279452054794522,
708 | 23.53150684931507,
709 | 23.783561643835615,
710 | 24.03013698630137,
711 | 24.28219178082192,
712 | 24.53972602739726,
713 | 24.78904109589041,
714 | 25.03013698630137,
715 | 25.28767123287671,
716 | 25.53698630136986,
717 | 25.786301369863015,
718 | 26.035616438356165,
719 | 26.03835616438356,
720 | 26.284931506849315,
721 | 26.534246575342465,
722 | 26.786301369863015,
723 | 27.03287671232877,
724 | 27.28219178082192,
725 | 27.534246575342465,
726 | 27.786301369863015,
727 | 28.03287671232877,
728 | 28.284931506849315,
729 | 28.53698630136986,
730 | 28.78904109589041,
731 | 29.03013698630137,
732 | 29.03287671232877,
733 | 29.284931506849315,
734 | 29.53698630136986,
735 | 29.794520547945204,
736 | 30.03287671232877,
737 | 30.284931506849315,
738 | 30.542465753424658,
739 | 30.791780821917808,
740 | 31.03287671232877,
741 | 31.29041095890411,
742 | 31.53972602739726,
743 | 31.78904109589041,
744 | 32.04109589041096,
745 | 32.28767123287671,
746 | 32.53972602739726,
747 | 32.79178082191781,
748 | 33.038356164383565,
749 | 33.28767123287671,
750 | 33.53972602739726,
751 | 33.79178082191781,
752 | 34.035616438356165,
753 | 34.038356164383565,
754 | 34.28767123287671,
755 | 34.53972602739726,
756 | 34.79178082191781,
757 | 35.035616438356165,
758 | 35.28767123287671,
759 | 35.53972602739726,
760 | 35.797260273972604,
761 | 36.038356164383565,
762 | 36.295890410958904,
763 | 36.54520547945206,
764 | 36.794520547945204,
765 | 37.04657534246575,
766 | 37.293150684931504,
767 | 37.54246575342466,
768 | 37.794520547945204,
769 | 38.04383561643836,
770 | 38.29041095890411,
771 | 38.54246575342466,
772 | 38.794520547945204,
773 | 39.04109589041096,
774 | 39.29041095890411,
775 | 39.54246575342466,
776 | 39.794520547945204,
777 | 40.04109589041096,
778 | 40.293150684931504,
779 | 40.54520547945206,
780 | 40.8027397260274,
781 | 41.04109589041096,
782 | 41.293150684931504,
783 | 41.55068493150685,
784 | 41.8,
785 | 42.04109589041096,
786 | 42.298630136986304,
787 | 42.54794520547945,
788 | 42.797260273972604,
789 | 43.04931506849315,
790 | 43.295890410958904,
791 | 43.54520547945206,
792 | 43.797260273972604,
793 | 44.04383561643836,
794 | 44.295890410958904,
795 | 44.54794520547945,
796 | 44.8,
797 | 45.04383561643836,
798 | 45.295890410958904,
799 | 45.54794520547945,
800 | 45.8,
801 | 46.04109589041096,
802 | 46.04383561643836,
803 | 46.295890410958904,
804 | 46.54794520547945,
805 | 46.8054794520548,
806 | 47.04383561643836,
807 | 47.295890410958904,
808 | 47.553424657534244,
809 | 47.8027397260274,
810 | 48.05205479452055,
811 | 48.3013698630137,
812 | 48.55068493150685,
813 | 48.8027397260274,
814 | 49.04931506849315,
815 | 49.298630136986304,
816 | 49.55068493150685,
817 | 49.8027397260274,
818 | 50.04657534246575,
819 | 50.298630136986304,
820 | 50.55068493150685,
821 | 50.8027397260274,
822 | 51.04657534246575,
823 | 51.298630136986304,
824 | 51.55068493150685,
825 | 51.8027397260274,
826 | 52.04931506849315,
827 | 52.3013698630137,
828 | 52.558904109589044,
829 | 52.80821917808219,
830 | 53.04931506849315,
831 | 53.30684931506849,
832 | 53.556164383561644,
833 | 53.8054794520548,
834 | 54.054794520547944,
835 | 54.3041095890411,
836 | 54.553424657534244,
837 | 54.8054794520548,
838 | 55.05205479452055,
839 | 55.3013698630137,
840 | 55.553424657534244,
841 | 55.8054794520548,
842 | 56.05205479452055,
843 | 56.3041095890411,
844 | 56.556164383561644,
845 | 56.80821917808219,
846 | 57.05205479452055,
847 | 57.3041095890411,
848 | 57.556164383561644,
849 | 57.81369863013698,
850 | 58.05205479452055,
851 | 58.3041095890411,
852 | 58.56164383561644,
853 | 58.81095890410959,
854 | 59.05205479452055,
855 | 59.30958904109589,
856 | 59.558904109589044,
857 | 59.80821917808219,
858 | 60.057534246575344
859 | ],
860 | "values": [
861 | 1.0,
862 | 1.0000603494627,
863 | 1.00007632990946,
864 | 1.00009263371712,
865 | 1.00018880213965,
866 | 1.00055815675065,
867 | 1.00063309053479,
868 | 1.00115300317843,
869 | 1.0018806604115,
870 | 1.00313196838415,
871 | 1.00386353574735,
872 | 1.00557521420974,
873 | 1.0063258161836,
874 | 1.00767950443314,
875 | 1.00848625094303,
876 | 1.00851078020898,
877 | 1.00996119581811,
878 | 1.0108352053466,
879 | 1.01229560711511,
880 | 1.01316470476399,
881 | 1.01484901143958,
882 | 1.0157021781382,
883 | 1.01782142336668,
884 | 1.02005480415715,
885 | 1.02236308686531,
886 | 1.02463345187068,
887 | 1.02680984399266,
888 | 1.02910898877504,
889 | 1.03134792623608,
890 | 1.03358699308581,
891 | 1.03583266128114,
892 | 1.03585703883124,
893 | 1.03803131640964,
894 | 1.04021392563663,
895 | 1.04234980389344,
896 | 1.0443595352277,
897 | 1.04438177479931,
898 | 1.0463785315247,
899 | 1.04837120150742,
900 | 1.05031533268808,
901 | 1.05211202310119,
902 | 1.05388628707272,
903 | 1.05556375240985,
904 | 1.05712246013396,
905 | 1.05847968215164,
906 | 1.05849474149989,
907 | 1.05985471220681,
908 | 1.06113908926271,
909 | 1.06238509663469,
910 | 1.06346977120187,
911 | 1.06457799334563,
912 | 1.06558777532985,
913 | 1.06647000575744,
914 | 1.06723634550196,
915 | 1.06724435502753,
916 | 1.06799396996186,
917 | 1.06867522581043,
918 | 1.06932769465518,
919 | 1.06994293853695,
920 | 1.06994961316987,
921 | 1.07051395761937,
922 | 1.0710652896818,
923 | 1.07158103119678,
924 | 1.07202858394215,
925 | 1.07203340609105,
926 | 1.07243714449568,
927 | 1.07281513361947,
928 | 1.07313809615868,
929 | 1.07338113933305,
930 | 1.07338370969725,
931 | 1.07359898669383,
932 | 1.07376840369169,
933 | 1.07390002531736,
934 | 1.07396824284412,
935 | 1.0740348592268,
936 | 1.07407444621877,
937 | 1.07410517998319,
938 | 1.07407459165626,
939 | 1.07407038473512,
940 | 1.07407252115672,
941 | 1.07406013250092,
942 | 1.07403711924331,
943 | 1.07403703089066,
944 | 1.07406147993609,
945 | 1.07407643884047,
946 | 1.07409991206748,
947 | 1.07413755194281,
948 | 1.07413814677827,
949 | 1.07417518618009,
950 | 1.07423609912203,
951 | 1.0743087865699,
952 | 1.07437968912514,
953 | 1.07447051561507,
954 | 1.07457721681887,
955 | 1.07469391565376,
956 | 1.0747990536059,
957 | 1.07480044686721,
958 | 1.07493744691769,
959 | 1.07508423370528,
960 | 1.07524342896375,
961 | 1.07538534389699,
962 | 1.07555909490785,
963 | 1.07574465651839,
964 | 1.07594033708755,
965 | 1.07611372233317,
966 | 1.07611585006545,
967 | 1.07632411394302,
968 | 1.07653203697587,
969 | 1.0767581075438,
970 | 1.07700011855349,
971 | 1.0770030492733,
972 | 1.07725508765468,
973 | 1.07753826106837,
974 | 1.07784961923171,
975 | 1.07817094189335,
976 | 1.07817478837968,
977 | 1.07852723272143,
978 | 1.0789222234042,
979 | 1.07934996558259,
980 | 1.07978951658664,
981 | 1.08028558469987,
982 | 1.08082596249608,
983 | 1.0814093201066,
984 | 1.08201734219219,
985 | 1.08269437152628,
986 | 1.08343932181209,
987 | 1.08421968535408,
988 | 1.08500527043719,
989 | 1.08591745250903,
990 | 1.08685647910735,
991 | 1.08783439154206,
992 | 1.08885048210264,
993 | 1.08886178439494,
994 | 1.08992507445579,
995 | 1.09103355340638,
996 | 1.09219424389903,
997 | 1.09336857917876,
998 | 1.09458584749492,
999 | 1.09584984236,
1000 | 1.09714457069871,
1001 | 1.09843508747293,
1002 | 1.09977679066511,
1003 | 1.10113848378271,
1004 | 1.10251555387324,
1005 | 1.10384174067752,
1006 | 1.10385686755539,
1007 | 1.10525374718027,
1008 | 1.10665393619336,
1009 | 1.10808386886644,
1010 | 1.10940323398009,
1011 | 1.11079370004576,
1012 | 1.11220942709519,
1013 | 1.11357472870773,
1014 | 1.11489775171066,
1015 | 1.1163034629294,
1016 | 1.11765780350157,
1017 | 1.11901296044751,
1018 | 1.12037846882671,
1019 | 1.12171525951441,
1020 | 1.12307783984239,
1021 | 1.1244356805465,
1022 | 1.12576404012592,
1023 | 1.12710871022057,
1024 | 1.12846053288086,
1025 | 1.1298098365153,
1026 | 1.13111955479483,
1027 | 1.13113416613558,
1028 | 1.1324687642813,
1029 | 1.13381230252089,
1030 | 1.13515442072358,
1031 | 1.13646479058958,
1032 | 1.13780532214207,
1033 | 1.13914530918109,
1034 | 1.14051505972368,
1035 | 1.14180742701803,
1036 | 1.14317875361388,
1037 | 1.14449608877045,
1038 | 1.14583383635527,
1039 | 1.14720988446867,
1040 | 1.14852063224608,
1041 | 1.14987102331642,
1042 | 1.15124234446724,
1043 | 1.1525970926317,
1044 | 1.15395936668797,
1045 | 1.15535238801018,
1046 | 1.15674590459129,
1047 | 1.15812627821828,
1048 | 1.15954183081818,
1049 | 1.16096621162107,
1050 | 1.16240309529506,
1051 | 1.16383977645788,
1052 | 1.16530079632492,
1053 | 1.16677227762978,
1054 | 1.16828673453683,
1055 | 1.16972655955829,
1056 | 1.17122603091477,
1057 | 1.17276665320158,
1058 | 1.17424407465727,
1059 | 1.17576078638633,
1060 | 1.17732635860567,
1061 | 1.17882626882537,
1062 | 1.18036886677302,
1063 | 1.18197232783669,
1064 | 1.18347462989472,
1065 | 1.18503662012615,
1066 | 1.18662170195788,
1067 | 1.18816492251165,
1068 | 1.18977329155015,
1069 | 1.19136001716073,
1070 | 1.19295100470715,
1071 | 1.19451937167296,
1072 | 1.19613005514424,
1073 | 1.19772989400223,
1074 | 1.19933228817437,
1075 | 1.20090519295281,
1076 | 1.20092307579286,
1077 | 1.20252769329779,
1078 | 1.20413282928997,
1079 | 1.2057744053765,
1080 | 1.2073304363733,
1081 | 1.20893536879348,
1082 | 1.21057351009487,
1083 | 1.21213392076468,
1084 | 1.21376757996924,
1085 | 1.21532422215497,
1086 | 1.21691445853081,
1087 | 1.21851776551926,
1088 | 1.22007046908191,
1089 | 1.2216591813133,
1090 | 1.22324653306564,
1091 | 1.22481580008905,
1092 | 1.22633879056757,
1093 | 1.22791759953792,
1094 | 1.22947004315148,
1095 | 1.23101937479616,
1096 | 1.23253441104678,
1097 | 1.23408587381833,
1098 | 1.23562452039597,
1099 | 1.23716038316188,
1100 | 1.23867722137781,
1101 | 1.24020696512642,
1102 | 1.24176668823085,
1103 | 1.24325987548213,
1104 | 1.24475574316202,
1105 | 1.2463084005466,
1106 | 1.2477961176324,
1107 | 1.24930297134262,
1108 | 1.25082729963968,
1109 | 1.25230915922215,
1110 | 1.25380905387312,
1111 | 1.25532320299249,
1112 | 1.25679664168853,
1113 | 1.25829744906805,
1114 | 1.25980708726474,
1115 | 1.26131026567746,
1116 | 1.26278546230081,
1117 | 1.26429295211413,
1118 | 1.26579501514152,
1119 | 1.26729753411092,
1120 | 1.26876649872933,
1121 | 1.27026995720689,
1122 | 1.27177455167525,
1123 | 1.27331375490146,
1124 | 1.27475336115652,
1125 | 1.27626300551558,
1126 | 1.2778075162986,
1127 | 1.27929665391349,
1128 | 1.28077154958855,
1129 | 1.28232514446065,
1130 | 1.28382450655148,
1131 | 1.28534350188693,
1132 | 1.28686228799129
1133 | ]
1134 | }
1135 | }
--------------------------------------------------------------------------------
/marketdata_JSON_asof_04_30_2020/EURUSD_Heston.json:
--------------------------------------------------------------------------------
1 | {"kappa": {"times": [0.0, 0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0, 3.25, 3.5, 3.75, 4.0, 4.25, 4.5, 4.75, 5.0, 5.25, 5.5, 5.75, 6.0, 6.25, 6.5, 6.75, 7.0, 7.25, 7.5, 7.75, 8.0, 8.25, 8.5, 8.75, 9.0, 9.25, 9.5, 9.75, 10.0, 10.25, 10.5], "values": [2.014763227215412, 2.1497376322555315, 1.5941433511540037, 2.346154102539426, 1.2714568025557331, 2.4610636783144817, 2.09257282751059, 2.560912872079869, 2.2687385019386435, 2.2997717287738193, 2.023289086252716, 2.177734582957916, 2.1055531373119214, 2.2928402197065965, 2.18293772736349, 2.2811586557509163, 1.384285529067584, 2.101415164052669, 1.3590201608737704, 1.9808395049140157, 1.2603231955195784, 2.0884480384571096, 1.6782901226419389, 2.3021958100298674, 1.1175354593665514, 4.52170818307358, 1.6701072745375476, 2.2379557914504495, 1.2096588980498888, 1.0552644559260862, 4.872203489364411, 2.0629458764255886, 2.575177824637888, 2.546372144042377, 2.1363181309169716, 1.2379303225936837, 2.1964295443057065, 2.0767380292283755, 2.0448190784884543, 1.9016140725907846, 1.7717418785476742, 1.7717418785476742, 2.357228808340786]}, "volofvar": {"times": [0.0, 0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0, 3.25, 3.5, 3.75, 4.0, 4.25, 4.5, 4.75, 5.0, 5.25, 5.5, 5.75, 6.0, 6.25, 6.5, 6.75, 7.0, 7.25, 7.5, 7.75, 8.0, 8.25, 8.5, 8.75, 9.0, 9.25, 9.5, 9.75, 10.0, 10.25, 10.5], "values": [0.11205809081254259, 0.10013246770239756, 0.17185036880066584, 0.12200369353238497, 0.09921396029172129, 0.12770567628155838, 0.10900817303544816, 0.14785794426985474, 0.0916322302509428, 0.14066007931642677, 0.11920367713454832, 0.1573220241717988, 0.13579022204681473, 0.1573365511311965, 0.1316886209758107, 0.14612907208110737, 0.11224744932047187, 0.12860854337271868, 0.09853577608423794, 0.1210411280591488, 0.08857005607798249, 0.08800647781650406, 0.05415532550135918, 0.09644782688274434, 0.05933313620449928, 0.12507258333410548, 0.06309502661161107, 0.11373046426234698, 0.07100116765006394, 0.24889278337902176, 0.09760014081541281, 0.08141353426866574, 0.056186773800976766, 0.20707779282778382, 0.1938025406994981, 0.16334990097265883, 0.19832869287469296, 0.1815595742804636, 0.20410675586289506, 0.21079102627248547, 0.20081428885002034, 0.20081428885002034, 0.12372309279040941]}, "theta": {"times": [0.0, 0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0, 3.25, 3.5, 3.75, 4.0, 4.25, 4.5, 4.75, 5.0, 5.25, 5.5, 5.75, 6.0, 6.25, 6.5, 6.75, 7.0, 7.25, 7.5, 7.75, 8.0, 8.25, 8.5, 8.75, 9.0, 9.25, 9.5, 9.75, 10.0, 10.25, 10.5], "values": [0.004509532260633167, 0.006847280940905134, 0.009275708319217929, 0.004191737905086856, 0.01348855628457387, 0.0034436733194370852, 0.012083534331797752, 0.0043530550279523164, 0.012641825554038436, 0.004773228229761113, 0.01109063744336827, 0.0058387994090694515, 0.011049114908759436, 0.00558226577337708, 0.011094157639976562, 0.005854251217283136, 0.014282468526215225, 0.004732738912757038, 0.013871388716831743, 0.00545975086727644, 0.01626074906400058, 0.004333897164047347, 0.016108019919473377, 0.002844334916007014, 0.021941609873870976, 0.005886723186246965, 0.015247736981947507, 0.0038573505781797158, 0.03861998811785348, 0.02940497212519592, 0.0009777611757016437, 0.011803651090240879, 0.020362041393412588, 0.008451375874011345, 0.00983948952058197, 0.019704153903621346, 0.009009275598127323, 0.013687204790474371, 0.011552214769863256, 0.012228992957091112, 0.013952849289415882, 0.014971020224842016, 0.023060451241239698]}, "initialvar": 0.004815512591220546, "rho": -0.3538237610667506}
--------------------------------------------------------------------------------
/marketdata_JSON_asof_04_30_2020/USD.json:
--------------------------------------------------------------------------------
1 | {
2 | "g1++": {
3 | "meanrev": {
4 | "times": [
5 | 0.0
6 | ],
7 | "values": [
8 | 0.02
9 | ]
10 | },
11 | "vol": {
12 | "times": [
13 | 0.0,
14 | 0.243668720054757,
15 | 0.49555099247091033,
16 | 0.9938398357289527,
17 | 1.9931553730321698,
18 | 2.9897330595482545,
19 | 4.993839835728953,
20 | 9.987679671457906,
21 | 14.986995208761122
22 | ],
23 | "values": [
24 | 0.009564621745688066,
25 | 0.008811806310273307,
26 | 0.008512898832317166,
27 | 0.008037199234425575,
28 | 0.008181982355896898,
29 | 0.00815909872398803,
30 | 0.008095340926479584,
31 | 0.008180814454803861,
32 | 0.008180814454803861
33 | ]
34 | },
35 | "shift": {
36 | "times": [
37 | 0.0,
38 | 0.0027397260273972603,
39 | 0.07945205479452055,
40 | 0.08767123287671233,
41 | 0.11506849315068493,
42 | 0.16712328767123288,
43 | 0.16986301369863013,
44 | 0.2493150684931507,
45 | 0.25205479452054796,
46 | 0.2547945205479452,
47 | 0.2602739726027397,
48 | 0.336986301369863,
49 | 0.33972602739726027,
50 | 0.3835616438356164,
51 | 0.4191780821917808,
52 | 0.42191780821917807,
53 | 0.5013698630136987,
54 | 0.5068493150684932,
55 | 0.5095890410958904,
56 | 0.5205479452054794,
57 | 0.5863013698630137,
58 | 0.589041095890411,
59 | 0.6328767123287671,
60 | 0.6712328767123288,
61 | 0.673972602739726,
62 | 0.6821917808219178,
63 | 0.7479452054794521,
64 | 0.7506849315068493,
65 | 0.7589041095890411,
66 | 0.8273972602739726,
67 | 0.8356164383561644,
68 | 0.8821917808219178,
69 | 0.9178082191780822,
70 | 0.9205479452054794,
71 | 0.9972602739726028,
72 | 1.0,
73 | 1.0027397260273974,
74 | 1.0082191780821919,
75 | 1.0876712328767124,
76 | 1.1123287671232878,
77 | 1.16986301369863,
78 | 1.2273972602739727,
79 | 1.2547945205479452,
80 | 1.3397260273972602,
81 | 1.3616438356164384,
82 | 1.4219178082191781,
83 | 1.4767123287671233,
84 | 1.5068493150684932,
85 | 1.5890410958904109,
86 | 1.5917808219178082,
87 | 1.673972602739726,
88 | 1.7068493150684931,
89 | 1.7589041095890412,
90 | 1.8356164383561644,
91 | 2.010958904109589,
92 | 2.263013698630137,
93 | 2.515068493150685,
94 | 2.7726027397260276,
95 | 3.010958904109589,
96 | 3.263013698630137,
97 | 3.5205479452054793,
98 | 3.76986301369863,
99 | 4.021917808219178,
100 | 4.2684931506849315,
101 | 4.517808219178082,
102 | 4.76986301369863,
103 | 5.019178082191781,
104 | 5.265753424657534,
105 | 5.517808219178082,
106 | 5.76986301369863,
107 | 6.016438356164383,
108 | 6.265753424657534,
109 | 6.517808219178082,
110 | 6.76986301369863,
111 | 7.013698630136986,
112 | 7.265753424657534,
113 | 7.517808219178082,
114 | 7.76986301369863,
115 | 8.016438356164384,
116 | 8.26849315068493,
117 | 8.526027397260274,
118 | 8.775342465753425,
119 | 9.016438356164384,
120 | 9.273972602739725,
121 | 9.523287671232877,
122 | 9.772602739726027,
123 | 10.024657534246575,
124 | 10.271232876712329,
125 | 10.520547945205479,
126 | 10.772602739726027,
127 | 11.021917808219179,
128 | 11.26849315068493,
129 | 11.520547945205479,
130 | 11.772602739726027,
131 | 12.01917808219178,
132 | 12.271232876712329,
133 | 12.523287671232877,
134 | 12.775342465753425,
135 | 13.01917808219178,
136 | 13.271232876712329,
137 | 13.523287671232877,
138 | 13.780821917808218,
139 | 14.01917808219178,
140 | 14.271232876712329,
141 | 14.528767123287672,
142 | 14.778082191780822,
143 | 15.01917808219178,
144 | 15.276712328767124,
145 | 15.526027397260274,
146 | 15.775342465753425,
147 | 16.027397260273972,
148 | 16.273972602739725,
149 | 16.526027397260275,
150 | 16.778082191780822,
151 | 17.024657534246575,
152 | 17.273972602739725,
153 | 17.526027397260275,
154 | 17.778082191780822,
155 | 18.02191780821918,
156 | 18.273972602739725,
157 | 18.526027397260275,
158 | 18.778082191780822,
159 | 19.02191780821918,
160 | 19.273972602739725,
161 | 19.526027397260275,
162 | 19.783561643835615,
163 | 20.024657534246575,
164 | 20.28219178082192,
165 | 20.53150684931507,
166 | 20.78082191780822,
167 | 21.03287671232877,
168 | 21.279452054794522,
169 | 21.528767123287672,
170 | 21.78082191780822,
171 | 22.03013698630137,
172 | 22.276712328767122,
173 | 22.528767123287672,
174 | 22.78082191780822,
175 | 23.027397260273972,
176 | 23.276712328767122,
177 | 23.528767123287672,
178 | 23.78082191780822,
179 | 24.027397260273972,
180 | 24.279452054794522,
181 | 24.53150684931507,
182 | 24.78904109589041,
183 | 25.027397260273972,
184 | 25.279452054794522,
185 | 25.53698630136986,
186 | 25.786301369863015,
187 | 26.027397260273972,
188 | 26.284931506849315,
189 | 26.534246575342465,
190 | 26.783561643835615,
191 | 27.035616438356165,
192 | 27.28219178082192,
193 | 27.53150684931507,
194 | 27.783561643835615,
195 | 28.03287671232877,
196 | 28.28219178082192,
197 | 28.534246575342465,
198 | 28.786301369863015,
199 | 29.03013698630137,
200 | 29.28219178082192,
201 | 29.534246575342465,
202 | 29.786301369863015,
203 | 30.03013698630137,
204 | 30.28219178082192,
205 | 30.534246575342465,
206 | 30.791780821917808,
207 | 31.03013698630137,
208 | 31.28219178082192,
209 | 31.53972602739726,
210 | 31.78904109589041,
211 | 32.04109589041096,
212 | 32.28767123287671,
213 | 32.536986301369865,
214 | 32.78904109589041,
215 | 33.038356164383565,
216 | 33.28493150684932,
217 | 33.536986301369865,
218 | 33.78904109589041,
219 | 34.035616438356165,
220 | 34.28493150684932,
221 | 34.536986301369865,
222 | 34.78904109589041,
223 | 35.032876712328765,
224 | 35.28493150684932,
225 | 35.536986301369865,
226 | 35.78904109589041,
227 | 36.035616438356165,
228 | 36.28767123287671,
229 | 36.54520547945206,
230 | 36.794520547945204,
231 | 37.035616438356165,
232 | 37.293150684931504,
233 | 37.54246575342466,
234 | 37.79178082191781,
235 | 38.04383561643836,
236 | 38.29041095890411,
237 | 38.53972602739726,
238 | 38.79178082191781,
239 | 39.04109589041096,
240 | 39.28767123287671,
241 | 39.53972602739726,
242 | 39.79178082191781,
243 | 40.038356164383565,
244 | 40.29041095890411,
245 | 40.54246575342466,
246 | 40.794520547945204,
247 | 41.038356164383565,
248 | 41.29041095890411,
249 | 41.54246575342466,
250 | 41.8,
251 | 42.038356164383565,
252 | 42.29041095890411,
253 | 42.54794520547945,
254 | 42.797260273972604,
255 | 43.038356164383565,
256 | 43.295890410958904,
257 | 43.54520547945206,
258 | 43.794520547945204,
259 | 44.04657534246575,
260 | 44.293150684931504,
261 | 44.54520547945206,
262 | 44.797260273972604,
263 | 45.04383561643836,
264 | 45.293150684931504,
265 | 45.54520547945206,
266 | 45.797260273972604,
267 | 46.04109589041096,
268 | 46.293150684931504,
269 | 46.54520547945206,
270 | 46.797260273972604,
271 | 47.04109589041096,
272 | 47.293150684931504,
273 | 47.54520547945206,
274 | 47.8027397260274,
275 | 48.04383561643836,
276 | 48.3013698630137,
277 | 48.55068493150685,
278 | 48.8,
279 | 49.05205479452055,
280 | 49.298630136986304,
281 | 49.54794520547945,
282 | 49.8,
283 | 50.04931506849315,
284 | 50.295890410958904,
285 | 50.54794520547945,
286 | 50.8,
287 | 51.04657534246575,
288 | 51.295890410958904,
289 | 51.54794520547945,
290 | 51.8,
291 | 52.04657534246575,
292 | 52.298630136986304,
293 | 52.55068493150685,
294 | 52.80821917808219,
295 | 53.04657534246575,
296 | 53.298630136986304,
297 | 53.556164383561644,
298 | 53.8054794520548,
299 | 54.04657534246575,
300 | 54.3041095890411,
301 | 54.553424657534244,
302 | 54.8027397260274,
303 | 55.054794520547944,
304 | 55.3013698630137,
305 | 55.55068493150685,
306 | 55.8027397260274,
307 | 56.05205479452055,
308 | 56.3013698630137,
309 | 56.553424657534244,
310 | 56.8054794520548,
311 | 57.04931506849315,
312 | 57.3013698630137,
313 | 57.553424657534244,
314 | 57.8054794520548,
315 | 58.04931506849315,
316 | 58.3013698630137,
317 | 58.553424657534244,
318 | 58.81095890410959,
319 | 59.04931506849315,
320 | 59.3013698630137,
321 | 59.558904109589044
322 | ],
323 | "values": [
324 | 0.0004055554447072937,
325 | 0.000431002086713193,
326 | 0.0004312216350670653,
327 | 0.00043137444293751847,
328 | 0.00046984160000399856,
329 | 0.0004702175546609572,
330 | 0.0004582743592720203,
331 | 0.00045910952682203855,
332 | 0.000459171907349015,
333 | 0.00045926662235902164,
334 | 0.000460302395721903,
335 | 0.00046138919506583256,
336 | 0.0004620989432762081,
337 | 0.00046339212399501697,
338 | 0.000464056162664479,
339 | 0.0004656008767392337,
340 | 0.00046729035958922594,
341 | 0.00046746268917665534,
342 | 0.00046775296644238146,
343 | 0.00040861620248697927,
344 | 0.0004101941977245107,
345 | 0.00042146682055299307,
346 | 0.0004235483642050012,
347 | 0.0004246294910056294,
348 | 0.000424924031418565,
349 | 0.0004354266454779482,
350 | 0.0003782451096509255,
351 | 0.0003785686819173376,
352 | 0.00038090360715855546,
353 | 0.0003833131736282694,
354 | 0.0003851115309546927,
355 | 0.0005001456820547846,
356 | 0.0005014811896651654,
357 | 0.0005433589834409877,
358 | 0.0005453527170730394,
359 | 0.0005455607437070982,
360 | 0.0005458736842811645,
361 | 0.0005491817643267246,
362 | 0.0005373340821095268,
363 | 0.0006037813287654711,
364 | 0.0005750848959068507,
365 | 0.0005631586204150833,
366 | 0.0006085488446191006,
367 | 0.0005924191463416588,
368 | 0.0006490568386003868,
369 | 0.0006230860667038821,
370 | 0.000495299488560759,
371 | 0.0005688290226050261,
372 | 0.0005530387246982449,
373 | 0.0006360500911842325,
374 | 0.0006162599433647485,
375 | 0.000551773484553788,
376 | 0.0006031883275791803,
377 | 0.0006297923894772499,
378 | 0.001111043271411978,
379 | 0.0012781355098113365,
380 | 0.0014689207133258644,
381 | 0.00177279202838637,
382 | 0.0020228692177923567,
383 | 0.0023329546865433638,
384 | 0.0027376613728791127,
385 | 0.003117960750110608,
386 | 0.0035816102079202525,
387 | 0.003997978545080569,
388 | 0.004416608241941467,
389 | 0.004887685954843123,
390 | 0.005358332064426993,
391 | 0.005725575680365629,
392 | 0.006146401195158535,
393 | 0.006624481533125774,
394 | 0.006968022180246059,
395 | 0.007286378024533147,
396 | 0.007615381136916492,
397 | 0.0080355690843699,
398 | 0.008163298862162919,
399 | 0.008409913306313502,
400 | 0.00864727918889253,
401 | 0.008959312441265408,
402 | 0.00908950819886495,
403 | 0.009219767577136917,
404 | 0.009546377322420732,
405 | 0.00986320351430016,
406 | 0.00979051652501535,
407 | 0.010087236441224369,
408 | 0.010249803894598225,
409 | 0.010365044566206459,
410 | 0.010590258413533709,
411 | 0.010688252669318353,
412 | 0.010785264003641618,
413 | 0.010951736247741746,
414 | 0.011109818495965228,
415 | 0.011156420244664478,
416 | 0.011273031026413543,
417 | 0.011449653593397275,
418 | 0.011490424744974933,
419 | 0.011600415172046429,
420 | 0.011712481012507216,
421 | 0.01191296992061847,
422 | 0.011939284073809682,
423 | 0.012062040331267013,
424 | 0.012140588977731908,
425 | 0.01245762034905073,
426 | 0.012457104165378936,
427 | 0.012558831235187952,
428 | 0.012787551533059176,
429 | 0.01302113498213265,
430 | 0.013046370051141728,
431 | 0.013290403634672446,
432 | 0.013461702808895028,
433 | 0.013611267494154634,
434 | 0.013828703185376894,
435 | 0.013954911660700772,
436 | 0.01412927228505157,
437 | 0.014345778026133564,
438 | 0.014495002925383674,
439 | 0.014647940177469829,
440 | 0.01482400151046112,
441 | 0.015060668319719346,
442 | 0.015171316238490743,
443 | 0.015349384665393567,
444 | 0.015528270668285991,
445 | 0.015764700283106694,
446 | 0.015882043677358723,
447 | 0.0160638084134265,
448 | 0.016212515645350832,
449 | 0.01650759407984557,
450 | 0.016577975968267288,
451 | 0.016817422146083304,
452 | 0.016998922698568526,
453 | 0.017163270156713727,
454 | 0.017378635908776856,
455 | 0.017539116757533304,
456 | 0.01770208800448511,
457 | 0.017897723344405116,
458 | 0.018089971168212832,
459 | 0.01823387466015313,
460 | 0.018411773130640716,
461 | 0.018616944828432246,
462 | 0.01877388256985915,
463 | 0.018933295182988225,
464 | 0.019107614308585943,
465 | 0.019305975256307513,
466 | 0.019448785801710146,
467 | 0.019620212872896323,
468 | 0.01976931059806423,
469 | 0.02002035048442587,
470 | 0.020121486328808218,
471 | 0.020270182703814706,
472 | 0.020468815077818135,
473 | 0.02065846803445034,
474 | 0.02076161360989614,
475 | 0.020952461432455965,
476 | 0.021111400594609524,
477 | 0.021262643701294513,
478 | 0.0214342033568414,
479 | 0.021581178677642004,
480 | 0.021730564836534034,
481 | 0.021890648976876075,
482 | 0.022042391123817943,
483 | 0.02218990048678193,
484 | 0.022342054597737384,
485 | 0.02249826606526746,
486 | 0.022635716867336,
487 | 0.022784047732565437,
488 | 0.02293107763910794,
489 | 0.02307385761896284,
490 | 0.023214446065573397,
491 | 0.0233578197120434,
492 | 0.023506261763786555,
493 | 0.023626142446774787,
494 | 0.023774999529997624,
495 | 0.023924626925696222,
496 | 0.02405089378377626,
497 | 0.02419192162344717,
498 | 0.024312762285780432,
499 | 0.024450427574887454,
500 | 0.024590712937556963,
501 | 0.024713906944571807,
502 | 0.0248320785943822,
503 | 0.02498044878487482,
504 | 0.025110564441123154,
505 | 0.025213114202316235,
506 | 0.02534945691147595,
507 | 0.025488383278679427,
508 | 0.02561454274509826,
509 | 0.0256892886171809,
510 | 0.0258574377566694,
511 | 0.025980692987953385,
512 | 0.026102986823103705,
513 | 0.026184155795005225,
514 | 0.02634044004001185,
515 | 0.02650182179281138,
516 | 0.026560190913162512,
517 | 0.02660163220338729,
518 | 0.02685341636380137,
519 | 0.02690124912348071,
520 | 0.02701314025567617,
521 | 0.027151085675456505,
522 | 0.027207932783068774,
523 | 0.027343553907704907,
524 | 0.02748162133351573,
525 | 0.02756160351853172,
526 | 0.027636178407301818,
527 | 0.027804586836800885,
528 | 0.02791264932006574,
529 | 0.027950669113671674,
530 | 0.028122839039129346,
531 | 0.028231867809573624,
532 | 0.028343550153811577,
533 | 0.028342278986292973,
534 | 0.02856921950879515,
535 | 0.028689403689420676,
536 | 0.028890073328818943,
537 | 0.028730428311588445,
538 | 0.02906236160754665,
539 | 0.029276215107254006,
540 | 0.029292623021590893,
541 | 0.029295097703318146,
542 | 0.02969176445443422,
543 | 0.029714335849795066,
544 | 0.029862237808445654,
545 | 0.03005847021613475,
546 | 0.030125678371144056,
547 | 0.030374132215017054,
548 | 0.03053985513202746,
549 | 0.030617870317000362,
550 | 0.030834243578559392,
551 | 0.031055987724875545,
552 | 0.03123848186198799,
553 | 0.03128590888446013,
554 | 0.0316109549798901,
555 | 0.031806862978938345,
556 | 0.03200739999162846,
557 | 0.032075421264487,
558 | 0.03241692923271268,
559 | 0.03263183507784814,
560 | 0.03293627027976458,
561 | 0.03290197256956321,
562 | 0.03338534853352644,
563 | 0.0334997328188718,
564 | 0.033738942519855084,
565 | 0.03402424337220457,
566 | 0.03419485427378212,
567 | 0.03448942208786462,
568 | 0.03478898974079585,
569 | 0.03501989669432983,
570 | 0.035254647019763316,
571 | 0.03559624539242859,
572 | 0.03586677978948645,
573 | 0.0360682868513303,
574 | 0.036366322401873936,
575 | 0.03666183052817768,
576 | 0.03692503096385871,
577 | 0.03712635375211521,
578 | 0.037441630778867384,
579 | 0.03769880299753852,
580 | 0.03800648173850212,
581 | 0.03807302939506379,
582 | 0.03845162790273969,
583 | 0.03874821407184643,
584 | 0.0389258810177802,
585 | 0.03909498766858297,
586 | 0.03946949005507201,
587 | 0.03964590798236095,
588 | 0.03988087398940286,
589 | 0.04013414506075856,
590 | 0.040324063751762444,
591 | 0.04056988539610105,
592 | 0.04081338119636452,
593 | 0.04101736311402372,
594 | 0.04123583685101576,
595 | 0.04146931019765863,
596 | 0.041683363556858075,
597 | 0.041841754081304375,
598 | 0.04209659466585885,
599 | 0.04230139754219744,
600 | 0.0425030006480894,
601 | 0.04265227011858477,
602 | 0.04289069628433939,
603 | 0.04308237004164714,
604 | 0.04330066080718525,
605 | 0.043378949797355126,
606 | 0.04363096428804863,
607 | 0.04383818609644412,
608 | 0.043971057536593555
609 | ]
610 | },
611 | "x0": 0.0
612 | },
613 | "discount": {
614 | "times": [
615 | 0.0,
616 | 0.0027397260273972603,
617 | 0.07945205479452055,
618 | 0.08767123287671233,
619 | 0.11506849315068493,
620 | 0.16712328767123288,
621 | 0.16986301369863013,
622 | 0.2493150684931507,
623 | 0.25205479452054796,
624 | 0.2547945205479452,
625 | 0.2602739726027397,
626 | 0.336986301369863,
627 | 0.33972602739726027,
628 | 0.3835616438356164,
629 | 0.4191780821917808,
630 | 0.42191780821917807,
631 | 0.5013698630136987,
632 | 0.5068493150684932,
633 | 0.5095890410958904,
634 | 0.5205479452054794,
635 | 0.5863013698630137,
636 | 0.589041095890411,
637 | 0.6328767123287671,
638 | 0.6712328767123288,
639 | 0.673972602739726,
640 | 0.6821917808219178,
641 | 0.7479452054794521,
642 | 0.7506849315068493,
643 | 0.7589041095890411,
644 | 0.8273972602739726,
645 | 0.8356164383561644,
646 | 0.8821917808219178,
647 | 0.9178082191780822,
648 | 0.9205479452054794,
649 | 0.9972602739726028,
650 | 1.0,
651 | 1.0027397260273974,
652 | 1.0082191780821919,
653 | 1.0876712328767124,
654 | 1.1123287671232878,
655 | 1.16986301369863,
656 | 1.2273972602739727,
657 | 1.2547945205479452,
658 | 1.3397260273972602,
659 | 1.3616438356164384,
660 | 1.4219178082191781,
661 | 1.4767123287671233,
662 | 1.5068493150684932,
663 | 1.5890410958904109,
664 | 1.5917808219178082,
665 | 1.673972602739726,
666 | 1.7068493150684931,
667 | 1.7589041095890412,
668 | 1.8356164383561644,
669 | 2.010958904109589,
670 | 2.263013698630137,
671 | 2.515068493150685,
672 | 2.7726027397260276,
673 | 3.010958904109589,
674 | 3.263013698630137,
675 | 3.5205479452054793,
676 | 3.76986301369863,
677 | 4.021917808219178,
678 | 4.2684931506849315,
679 | 4.517808219178082,
680 | 4.76986301369863,
681 | 5.019178082191781,
682 | 5.265753424657534,
683 | 5.517808219178082,
684 | 5.76986301369863,
685 | 6.016438356164383,
686 | 6.265753424657534,
687 | 6.517808219178082,
688 | 6.76986301369863,
689 | 7.013698630136986,
690 | 7.265753424657534,
691 | 7.517808219178082,
692 | 7.76986301369863,
693 | 8.016438356164384,
694 | 8.26849315068493,
695 | 8.526027397260274,
696 | 8.775342465753425,
697 | 9.016438356164384,
698 | 9.273972602739725,
699 | 9.523287671232877,
700 | 9.772602739726027,
701 | 10.024657534246575,
702 | 10.271232876712329,
703 | 10.520547945205479,
704 | 10.772602739726027,
705 | 11.021917808219179,
706 | 11.26849315068493,
707 | 11.520547945205479,
708 | 11.772602739726027,
709 | 12.01917808219178,
710 | 12.271232876712329,
711 | 12.523287671232877,
712 | 12.775342465753425,
713 | 13.01917808219178,
714 | 13.271232876712329,
715 | 13.523287671232877,
716 | 13.780821917808218,
717 | 14.01917808219178,
718 | 14.271232876712329,
719 | 14.528767123287672,
720 | 14.778082191780822,
721 | 15.01917808219178,
722 | 15.276712328767124,
723 | 15.526027397260274,
724 | 15.775342465753425,
725 | 16.027397260273972,
726 | 16.273972602739725,
727 | 16.526027397260275,
728 | 16.778082191780822,
729 | 17.024657534246575,
730 | 17.273972602739725,
731 | 17.526027397260275,
732 | 17.778082191780822,
733 | 18.02191780821918,
734 | 18.273972602739725,
735 | 18.526027397260275,
736 | 18.778082191780822,
737 | 19.02191780821918,
738 | 19.273972602739725,
739 | 19.526027397260275,
740 | 19.783561643835615,
741 | 20.024657534246575,
742 | 20.28219178082192,
743 | 20.53150684931507,
744 | 20.78082191780822,
745 | 21.03287671232877,
746 | 21.279452054794522,
747 | 21.528767123287672,
748 | 21.78082191780822,
749 | 22.03013698630137,
750 | 22.276712328767122,
751 | 22.528767123287672,
752 | 22.78082191780822,
753 | 23.027397260273972,
754 | 23.276712328767122,
755 | 23.528767123287672,
756 | 23.78082191780822,
757 | 24.027397260273972,
758 | 24.279452054794522,
759 | 24.53150684931507,
760 | 24.78904109589041,
761 | 25.027397260273972,
762 | 25.279452054794522,
763 | 25.53698630136986,
764 | 25.786301369863015,
765 | 26.027397260273972,
766 | 26.284931506849315,
767 | 26.534246575342465,
768 | 26.783561643835615,
769 | 27.035616438356165,
770 | 27.28219178082192,
771 | 27.53150684931507,
772 | 27.783561643835615,
773 | 28.03287671232877,
774 | 28.28219178082192,
775 | 28.534246575342465,
776 | 28.786301369863015,
777 | 29.03013698630137,
778 | 29.28219178082192,
779 | 29.534246575342465,
780 | 29.786301369863015,
781 | 30.03013698630137,
782 | 30.28219178082192,
783 | 30.534246575342465,
784 | 30.791780821917808,
785 | 31.03013698630137,
786 | 31.28219178082192,
787 | 31.53972602739726,
788 | 31.78904109589041,
789 | 32.04109589041096,
790 | 32.28767123287671,
791 | 32.536986301369865,
792 | 32.78904109589041,
793 | 33.038356164383565,
794 | 33.28493150684932,
795 | 33.536986301369865,
796 | 33.78904109589041,
797 | 34.035616438356165,
798 | 34.28493150684932,
799 | 34.536986301369865,
800 | 34.78904109589041,
801 | 35.032876712328765,
802 | 35.28493150684932,
803 | 35.536986301369865,
804 | 35.78904109589041,
805 | 36.035616438356165,
806 | 36.28767123287671,
807 | 36.54520547945206,
808 | 36.794520547945204,
809 | 37.035616438356165,
810 | 37.293150684931504,
811 | 37.54246575342466,
812 | 37.79178082191781,
813 | 38.04383561643836,
814 | 38.29041095890411,
815 | 38.53972602739726,
816 | 38.79178082191781,
817 | 39.04109589041096,
818 | 39.28767123287671,
819 | 39.53972602739726,
820 | 39.79178082191781,
821 | 40.038356164383565,
822 | 40.29041095890411,
823 | 40.54246575342466,
824 | 40.794520547945204,
825 | 41.038356164383565,
826 | 41.29041095890411,
827 | 41.54246575342466,
828 | 41.8,
829 | 42.038356164383565,
830 | 42.29041095890411,
831 | 42.54794520547945,
832 | 42.797260273972604,
833 | 43.038356164383565,
834 | 43.295890410958904,
835 | 43.54520547945206,
836 | 43.794520547945204,
837 | 44.04657534246575,
838 | 44.293150684931504,
839 | 44.54520547945206,
840 | 44.797260273972604,
841 | 45.04383561643836,
842 | 45.293150684931504,
843 | 45.54520547945206,
844 | 45.797260273972604,
845 | 46.04109589041096,
846 | 46.293150684931504,
847 | 46.54520547945206,
848 | 46.797260273972604,
849 | 47.04109589041096,
850 | 47.293150684931504,
851 | 47.54520547945206,
852 | 47.8027397260274,
853 | 48.04383561643836,
854 | 48.3013698630137,
855 | 48.55068493150685,
856 | 48.8,
857 | 49.05205479452055,
858 | 49.298630136986304,
859 | 49.54794520547945,
860 | 49.8,
861 | 50.04931506849315,
862 | 50.295890410958904,
863 | 50.54794520547945,
864 | 50.8,
865 | 51.04657534246575,
866 | 51.295890410958904,
867 | 51.54794520547945,
868 | 51.8,
869 | 52.04657534246575,
870 | 52.298630136986304,
871 | 52.55068493150685,
872 | 52.80821917808219,
873 | 53.04657534246575,
874 | 53.298630136986304,
875 | 53.556164383561644,
876 | 53.8054794520548,
877 | 54.04657534246575,
878 | 54.3041095890411,
879 | 54.553424657534244,
880 | 54.8027397260274,
881 | 55.054794520547944,
882 | 55.3013698630137,
883 | 55.55068493150685,
884 | 55.8027397260274,
885 | 56.05205479452055,
886 | 56.3013698630137,
887 | 56.553424657534244,
888 | 56.8054794520548,
889 | 57.04931506849315,
890 | 57.3013698630137,
891 | 57.553424657534244,
892 | 57.8054794520548,
893 | 58.04931506849315,
894 | 58.3013698630137,
895 | 58.553424657534244,
896 | 58.81095890410959,
897 | 59.04931506849315,
898 | 59.3013698630137,
899 | 59.558904109589044,
900 | 59.80821917808219
901 | ],
902 | "values": [
903 | 1.0,
904 | 0.999998888890123,
905 | 0.999965833937136,
906 | 0.999962292399836,
907 | 0.999950487366091,
908 | 0.999926079166038,
909 | 0.999924794540434,
910 | 0.999888547946261,
911 | 0.999887298087139,
912 | 0.999886048229578,
913 | 0.999883548519145,
914 | 0.999848553229241,
915 | 0.999847303420112,
916 | 0.99982730668651,
917 | 0.999811059634939,
918 | 0.999809809872677,
919 | 0.99977356744662,
920 | 0.999771068017388,
921 | 0.999769818305115,
922 | 0.999764819471645,
923 | 0.999738825938338,
924 | 0.999737742889117,
925 | 0.999719969941543,
926 | 0.999704418871603,
927 | 0.99970330809015,
928 | 0.999699975753195,
929 | 0.999672762084145,
930 | 0.999671790181015,
931 | 0.999668874477296,
932 | 0.99964457727702,
933 | 0.999641661652672,
934 | 0.999625139941995,
935 | 0.999608509422728,
936 | 0.999607230163475,
937 | 0.999568420498912,
938 | 0.999567037070367,
939 | 0.999565653643737,
940 | 0.999562886796221,
941 | 0.999522768367875,
942 | 0.999510712882395,
943 | 0.999478959827839,
944 | 0.999449142647011,
945 | 0.999435374220336,
946 | 0.999389280283683,
947 | 0.999377849745647,
948 | 0.999343247840189,
949 | 0.999313532292882,
950 | 0.999301170071375,
951 | 0.999261909670924,
952 | 0.999260656931892,
953 | 0.999216649750532,
954 | 0.999199914137017,
955 | 0.999177030923358,
956 | 0.999139965085234,
957 | 0.999053384637824,
958 | 0.998815108251438,
959 | 0.998544315166674,
960 | 0.998229408214553,
961 | 0.997876266825903,
962 | 0.997451926010708,
963 | 0.99695237561456,
964 | 0.996382259599378,
965 | 0.995725381403384,
966 | 0.994984451326323,
967 | 0.994148503469757,
968 | 0.993216256951538,
969 | 0.992196012608373,
970 | 0.991090863702649,
971 | 0.989889873454388,
972 | 0.988605458407187,
973 | 0.987254193629441,
974 | 0.985826114438651,
975 | 0.984327322043331,
976 | 0.98277193641856,
977 | 0.98119120161622,
978 | 0.979551789142612,
979 | 0.977878782833646,
980 | 0.976175270002297,
981 | 0.974461466883446,
982 | 0.972706650462861,
983 | 0.970911970234631,
984 | 0.969125906212524,
985 | 0.967353793621137,
986 | 0.965511077627946,
987 | 0.963687827858245,
988 | 0.96185765134825,
989 | 0.960012566345501,
990 | 0.95818700865701,
991 | 0.956351148093522,
992 | 0.954506279077781,
993 | 0.952676456962529,
994 | 0.950863903208359,
995 | 0.949035536890153,
996 | 0.947215661555251,
997 | 0.945429696879495,
998 | 0.943631076494148,
999 | 0.941843765567204,
1000 | 0.940067662803438,
1001 | 0.93833985239882,
1002 | 0.936585450222238,
1003 | 0.934840843740377,
1004 | 0.933079750373489,
1005 | 0.931415967242778,
1006 | 0.929695352650652,
1007 | 0.927954251216909,
1008 | 0.926255847020912,
1009 | 0.924599066921257,
1010 | 0.922864622472422,
1011 | 0.921170277274827,
1012 | 0.919477118990062,
1013 | 0.917772140792184,
1014 | 0.916095600736872,
1015 | 0.914394384955829,
1016 | 0.912695380178125,
1017 | 0.911025848162128,
1018 | 0.909345584788092,
1019 | 0.907654630039691,
1020 | 0.905966651716688,
1021 | 0.904322807327703,
1022 | 0.902641283543226,
1023 | 0.900963063183956,
1024 | 0.899288211095435,
1025 | 0.897658174527035,
1026 | 0.895990262755367,
1027 | 0.894325771833597,
1028 | 0.892636916780602,
1029 | 0.891034720808769,
1030 | 0.88935252680966,
1031 | 0.887715698957802,
1032 | 0.886082889417853,
1033 | 0.884440457253897,
1034 | 0.882830679293958,
1035 | 0.881211958232308,
1036 | 0.879584576393219,
1037 | 0.877976900492141,
1038 | 0.876389302298133,
1039 | 0.8747799610977,
1040 | 0.873177273136121,
1041 | 0.871609717544308,
1042 | 0.870035415316152,
1043 | 0.868454659062061,
1044 | 0.866881839427516,
1045 | 0.865345462738698,
1046 | 0.863789473513045,
1047 | 0.862242359112152,
1048 | 0.860676235821283,
1049 | 0.859218265605101,
1050 | 0.857699622717178,
1051 | 0.856162896494777,
1052 | 0.854678825856871,
1053 | 0.853247672140572,
1054 | 0.851743038601568,
1055 | 0.850291894028523,
1056 | 0.848852302778292,
1057 | 0.847410507016796,
1058 | 0.846008917156162,
1059 | 0.84460568967062,
1060 | 0.843201136978748,
1061 | 0.841823562767145,
1062 | 0.840459223784939,
1063 | 0.839094430176403,
1064 | 0.837743447768206,
1065 | 0.836448333559851,
1066 | 0.835125734295479,
1067 | 0.833817752980322,
1068 | 0.832524655695525,
1069 | 0.831288253950265,
1070 | 0.830025638656758,
1071 | 0.82877862818298,
1072 | 0.827519855843785,
1073 | 0.82637346519784,
1074 | 0.825174341085636,
1075 | 0.823964163819154,
1076 | 0.822811668130728,
1077 | 0.8216621806855,
1078 | 0.820556825727404,
1079 | 0.819454814785085,
1080 | 0.81835639999921,
1081 | 0.817288902891143,
1082 | 0.816252387725021,
1083 | 0.815206496816139,
1084 | 0.814178456974498,
1085 | 0.813195230002415,
1086 | 0.812216637140799,
1087 | 0.811242924072393,
1088 | 0.810287641503483,
1089 | 0.809390730687119,
1090 | 0.80847259695738,
1091 | 0.807573295727581,
1092 | 0.806692955870554,
1093 | 0.805857943625388,
1094 | 0.80501581335415,
1095 | 0.804166926843445,
1096 | 0.803376666589928,
1097 | 0.802644773644548,
1098 | 0.801854665346638,
1099 | 0.801123161287269,
1100 | 0.800411455145387,
1101 | 0.799706850018787,
1102 | 0.799047849147404,
1103 | 0.798396137687309,
1104 | 0.797751945826322,
1105 | 0.797140758021156,
1106 | 0.796562524195953,
1107 | 0.795979574906812,
1108 | 0.795417266850241,
1109 | 0.794900577654329,
1110 | 0.794379578085988,
1111 | 0.793878789118741,
1112 | 0.793397601322542,
1113 | 0.792972171877127,
1114 | 0.792528120667494,
1115 | 0.792101744711708,
1116 | 0.791668134277828,
1117 | 0.791335541722512,
1118 | 0.790957909341869,
1119 | 0.790571213601786,
1120 | 0.790234659268131,
1121 | 0.78994702672722,
1122 | 0.789600610850755,
1123 | 0.789301597787648,
1124 | 0.789013519178246,
1125 | 0.788723874158435,
1126 | 0.788466899093075,
1127 | 0.788195078396839,
1128 | 0.787930943401554,
1129 | 0.787696605109936,
1130 | 0.78745652064104,
1131 | 0.787209933952749,
1132 | 0.786967426404747,
1133 | 0.786761982388818,
1134 | 0.786524622662067,
1135 | 0.786288473893215,
1136 | 0.786052548311357,
1137 | 0.785849227309032,
1138 | 0.785610557078255,
1139 | 0.785369055160939,
1140 | 0.785101675198599,
1141 | 0.784895273897312,
1142 | 0.784616980141023,
1143 | 0.784364367704495,
1144 | 0.784103426440526,
1145 | 0.783822236754043,
1146 | 0.783552050057153,
1147 | 0.783259308041528,
1148 | 0.782942962283768,
1149 | 0.782623232643589,
1150 | 0.782299045731147,
1151 | 0.78193858863606,
1152 | 0.78156344345133,
1153 | 0.781194911365848,
1154 | 0.780801648918888,
1155 | 0.780384066022073,
1156 | 0.779952991481569,
1157 | 0.779529516450038,
1158 | 0.779072361083147,
1159 | 0.778602709250874,
1160 | 0.778100312992664,
1161 | 0.777658152639723,
1162 | 0.777153049422972,
1163 | 0.776616469282868,
1164 | 0.776099931164293,
1165 | 0.775603586865516,
1166 | 0.775036309931693,
1167 | 0.774490066914816,
1168 | 0.773934761868317,
1169 | 0.773360756212287,
1170 | 0.77279871961181,
1171 | 0.772218875204309,
1172 | 0.771621756453889,
1173 | 0.771027874569179,
1174 | 0.770427676759515,
1175 | 0.769811708710744,
1176 | 0.769190457474231,
1177 | 0.768594138546902,
1178 | 0.767963777915432,
1179 | 0.767329681202392,
1180 | 0.766692381689523,
1181 | 0.766081896087171,
1182 | 0.765439759111982,
1183 | 0.764796073579741,
1184 | 0.764131872423281,
1185 | 0.763535596611706,
1186 | 0.762890648802254,
1187 | 0.762227056131967,
1188 | 0.761594010590306
1189 | ]
1190 | }
1191 | }
--------------------------------------------------------------------------------
/marketdata_JSON_asof_04_30_2020/correlations.json:
--------------------------------------------------------------------------------
1 | {
2 | "USD_EUR": 0.161,
3 | "USD_EURUSD": 0.166,
4 | "EUR_EURUSD": 0.551,
5 | "USD_EURUSDstochvar": -0.2,
6 | "EUR_EURUSDstochvar": -0.2,
7 | "EURUSD_EURUSDstochvar": -0.3620005301106583
8 | }
--------------------------------------------------------------------------------
/sim_lib/StochasticSim_Multiprocessing.py:
--------------------------------------------------------------------------------
1 | import multiprocessing
2 | import multiprocessing as mp
3 | import ctypes as c
4 | import os, inspect, sys
5 | import pickle
6 | import StochasticSim_Multiprocessing as smp
7 | import sim_params
8 |
9 | ###################### Read the G1pp parameters ##########################
10 | import scipy.integrate as integrate
11 | from scipy.integrate import simps
12 | from scipy.integrate import cumtrapz
13 | from numpy.random import multivariate_normal as mvn
14 | from numpy.random import uniform
15 | from numpy.random import normal
16 | import numpy as np
17 | import copy
18 | import inspect
19 | import gc
20 |
21 | ### simulator api definition #######
22 | #locvol_sim = LocalVolStochasticIRSimulation(domestic_dfcurve, base_dfcurve, spot_FX,
23 | # domestic_ta, domestic_a, domestic_tvol, domestic_vols, domestic_x0,
24 | # base_ta, base_a, base_tvol, base_vols, base_x0,
25 | # rho_domestic_base, rho_domestic_fx, rho_base_fx,
26 | # nr_mcruns, LVOL_NUMMETHOD, SHORTRATE_NUMMETHOD,
27 | # antitheticpaths=ANTITHETIC,
28 | # in_forward_measure=True,
29 | # nrsubsim=NRSUBSIM,
30 | # )
31 | #---------------------------------------------------------------------------
32 | class LocalVolStochasticIRSimulation():
33 | def __init__(self, domestic_shifttimes, domestic_shiftvalues, base_shifttimes, base_shiftvalues, spot_FX,
34 | domestic_ta, domestic_a, domestic_tvol, domestic_vols, domestic_x0,
35 | base_ta, base_a, base_tvol, base_vols, base_x0,
36 | rho_domestic_base, rho_domestic_fx, rho_base_fx,
37 | nr_mcruns, LVOL_NUMMETHOD, SHORTRATE_NUMMETHOD,
38 | antitheticpaths=True,
39 | in_forward_measure=False,
40 | nrsubsim=2,
41 | observation_names = None,
42 | observe_at_given_times=True,
43 | domestic_currency_name='USD',
44 | base_currency_name='EUR',
45 | fx_name='EURUSD',
46 | maxtdisargs=None,
47 | save_output_flags=None):
48 |
49 | #self.sdedata = sdedata
50 | #self.g1pp_data = g1pp_data
51 |
52 | self.nrsubsim = nrsubsim
53 | self.nr_mcruns = nr_mcruns
54 | self.dtype_glob = 'float' #'float32'
55 | self.nsteps_peryear = 250
56 | self.in_forward_measure = in_forward_measure
57 | self.observation_names = observation_names if (observation_names is not None) else []
58 | self.antitheticpaths = antitheticpaths
59 | self.in_DRN = True
60 | self.det_DR = False
61 | self.det_FR = False
62 | self.DLV = True
63 | self.spot_FX = spot_FX
64 | self.fx_prefix=''
65 | self.domestic_currency_prefix=''
66 | self.base_currency_prefix=''
67 |
68 | self.g1pp_data = sim_params.g1pp_dataC(spot_FX, base_x0, domestic_x0, domestic_ta, domestic_shifttimes,
69 | domestic_tvol, domestic_a, domestic_vols, domestic_shiftvalues,
70 | base_ta, base_a, base_shifttimes, base_shiftvalues, base_tvol, base_vols)
71 |
72 | self.sdedata = sim_params.sdedataC(rho_domestic_base, rho_base_fx, rho_domestic_fx)
73 |
74 | self.heston_data = None
75 |
76 | if (maxtdisargs is None): ### for output shared memory allocation...
77 | self.maxT = 10.0
78 | maxtdisargs = {'maturity':self.maxT, 'time_steps': int(self.nsteps_peryear*self.maxT)}
79 |
80 | self.maxT = maxtdisargs['maturity']
81 | self.maxn_time = maxtdisargs['time_steps']
82 | maxn_time = self.maxn_time
83 | maxT = self.maxT
84 | self.dt = maxT/maxn_time
85 | self.n_paths_per_process = int(nr_mcruns/nrsubsim)
86 |
87 | self.updated_contracts_or_sim = False
88 | self.lvol_expectations = 0.0
89 | self.lvol_stderr = 0.0
90 |
91 | #mult = 1 if dtype_glob=='float32' else 2
92 |
93 | self.t_stamp_raw = []
94 | self.Xsamples_raw = []
95 | self.rd_raw = []
96 | self.rb_raw = []
97 | self.volsamples_raw = []
98 | self.Utsamples_raw = []
99 | self.dW_raw = []
100 | self.xd_raw = []
101 | self.xb_raw = []
102 |
103 | #mg = multiprocessing.Manager()
104 | self.contracts = {}
105 | self.lvol_data = {}
106 |
107 | self.save_output_flags = {'XS':True, 'RD':True, 'RB':True, 'XD':False, 'XB':False, 'DW':False, 'VOLTRAJ':False}
108 |
109 | ##### override save output flags ###
110 | save_keys = self.save_output_flags.keys()
111 | if save_output_flags is not None:
112 | for keyval in save_keys:
113 | if keyval in save_output_flags.keys():
114 | self.save_output_flags[keyval] = save_output_flags[keyval]
115 |
116 |
117 | self.mult = 1 if (self.dtype_glob=='float32') else 2
118 |
119 | if type(self) is LocalVolStochasticIRSimulation:
120 | print('in_forward_measure =%s, Antithetic=%s, in_DRN=%s, det_DR=%s, det_FR=%s, DLV=%s'%(self.in_forward_measure, self.antitheticpaths, self.in_DRN, self.det_DR, self.det_FR, self.DLV))
121 | self._allocate_shmem()
122 | print("Initializing pool for ...", type(self))
123 | self.simpool = multiprocessing.Pool(processes = self.nrsubsim, initializer=init_process, initargs=(self.t_stamp_raw,
124 | self.Xsamples_raw,
125 | self.rd_raw,
126 | self.rb_raw,
127 | self.xd_raw,
128 | self.xb_raw,
129 | self.dW_raw,
130 | self.volsamples_raw,
131 | self.Utsamples_raw,
132 | self.maxn_time, self.maxT))
133 |
134 | return
135 | #---------------------------------------------------------------------------
136 | def _allocate_shmem(self):
137 | mult = self.mult
138 | maxn_time = self.maxn_time
139 | n_paths_per_process = self.n_paths_per_process
140 |
141 | SAVE_XS = self.save_output_flags['XS']
142 | SAVE_RD = self.save_output_flags['RD']
143 | SAVE_RB = self.save_output_flags['RB']
144 | SAVE_XD = self.save_output_flags['XD']
145 | SAVE_XB = self.save_output_flags['XB']
146 | SAVE_DW = self.save_output_flags['DW']
147 | SAVE_VOLTRAJ = self.save_output_flags['VOLTRAJ']
148 |
149 | for _ in range(self.nrsubsim):
150 | print("Allocating shmem ...", end='')
151 | self.t_stamp_raw.append(mp.Array(c.c_float, mult*maxn_time, lock=False))
152 | if (SAVE_XS):
153 | self.Xsamples_raw.append(mp.Array(c.c_float, mult*n_paths_per_process*(maxn_time+1), lock=False))
154 | print('XS', end=' ')
155 | if (SAVE_RD):
156 | self.rd_raw.append(mp.Array(c.c_float, mult*n_paths_per_process*maxn_time, lock=False))
157 | print('RD', end=' ')
158 | if (SAVE_RB):
159 | self.rb_raw.append(mp.Array(c.c_float, mult*n_paths_per_process*maxn_time, lock=False))
160 | print('RB', end=' ')
161 | if (SAVE_XD):
162 | self.xd_raw.append(mp.Array(c.c_float, mult*n_paths_per_process*maxn_time, lock=False))
163 | print('XD', end=' ')
164 | if (SAVE_XB):
165 | self.xb_raw.append(mp.Array(c.c_float, mult*n_paths_per_process*maxn_time, lock=False))
166 | print('XB', end=' ')
167 | if (SAVE_DW):
168 | self.dW_raw.append(mp.Array(c.c_float, mult*n_paths_per_process*(maxn_time+1), lock=False))
169 | print('DW', end=' ')
170 | if (SAVE_VOLTRAJ):
171 | self.volsamples_raw.append(mp.Array(c.c_float, mult*n_paths_per_process*maxn_time, lock=False))
172 | print('VOLTRAJ', end=' ')
173 | print()
174 | return
175 | #---------------------------------------------------------------------------
176 | def delete_all(self):
177 | #---------------------------------------------------------------------------
178 | self.simpool.close()
179 |
180 | SAVE_XS = self.save_output_flags['XS']
181 | SAVE_XD = self.save_output_flags['XD']
182 | SAVE_XB = self.save_output_flags['XB']
183 | SAVE_RD = self.save_output_flags['RD']
184 | SAVE_RB = self.save_output_flags['RB']
185 | SAVE_DW = self.save_output_flags['DW']
186 | SAVE_VOLTRAJ = self.save_output_flags['VOLTRAJ']
187 | SAVE_HESTON = self.save_output_flags['HESTON'] if (self.DLV==False) else False
188 |
189 | for ts in self.t_stamp_raw: del(ts)
190 | if (SAVE_XS):
191 | for Xs in self.Xsamples_raw: del(Xs)
192 | print('Deleting Xs...')
193 | if (SAVE_RB):
194 | for rb in self.rb_raw: del(rb)
195 | print('Deleting RB...')
196 | if (SAVE_RD):
197 | for rd in self.rd_raw: del(rd)
198 | print('Deleting RD...')
199 | if (SAVE_XB):
200 | for xb in self.xb_raw: del(xb)
201 | print('Deleting XB...')
202 | if (SAVE_XD):
203 | for xd in self.xd_raw: del(xd)
204 | print('Deleting XD...')
205 | if (SAVE_DW):
206 | for dW in self.dW_raw: del(dW)
207 | print('Deleting DW...')
208 | if (SAVE_VOLTRAJ):
209 | for vol in self.volsamples_raw: del(vol)
210 | print('Deleting VOLTRAJ...')
211 | if (SAVE_HESTON):
212 | for ut in self.Utsamples_raw: del(ut)
213 | print('Deleting HESTON UT...')
214 |
215 | del(self.t_stamp_raw, self.Xsamples_raw, self.rd_raw, self.rb_raw, self.xb_raw, self.xd_raw, self.dW_raw, self.volsamples_raw, self.Utsamples_raw)
216 | mp.heap.BufferWrapper._heap = mp.heap.Heap ()
217 | gc.collect ()
218 |
219 | #----------------------------------------------------------------------------------------------------------
220 | def run(self, det_DR = None, det_FR = None, DLV = None):
221 | #----------------------------------------------------------------------------------------------------------
222 | pinputs = []
223 | tdisargs = self.tdisargs
224 | sdedata = self.sdedata
225 | g1pp_data = self.g1pp_data
226 | heston_data = self.heston_data
227 | lvol_data = self.lvol_data
228 | self.updated_contracts_or_sim = True
229 |
230 | if (det_DR is None): det_DR = self.det_DR
231 | if (det_FR is None): det_FR = self.det_FR
232 | if (DLV is None): DLV = self.DLV
233 |
234 | n_trials = self.n_paths_per_process
235 | for pid in range(self.nrsubsim):
236 | pinputs.append((pid, n_trials, tdisargs, sdedata, g1pp_data, heston_data, lvol_data, det_DR, det_FR, DLV, self.in_DRN, self.in_forward_measure, self.antitheticpaths, self.dtype_glob, self.save_output_flags))
237 | print('ProcessID:%d, n_trials:%d, '%(pinputs[-1][0], pinputs[-1][1])+'maturity:{maturity:.3f}, timesteps:{time_steps:d}'.format(**pinputs[-1][2]))
238 |
239 | self.simpool.starmap(smp.simulate_paths, pinputs)
240 |
241 | self._collect_simulation_results()
242 |
243 | return
244 |
245 | #---------------------------------------------------------------------------
246 | def _get_X_and_U(self):
247 | dtype_glob= self.dtype_glob
248 | n_timesteps = self.tdisargs['time_steps'] + 1
249 | n_trials = self.n_paths_per_process
250 | observation_idxs = -1
251 | print('Reading X and U at step ', n_timesteps)
252 | spots = np.concatenate([np.frombuffer(xs, dtype=dtype_glob).reshape((n_trials, -1))[:,:n_timesteps][:, observation_idxs] for xs in self.Xsamples_raw], axis=0)
253 | variances = np.concatenate([np.frombuffer(ut, dtype=dtype_glob).reshape((n_trials, -1))[:,:n_timesteps][:, observation_idxs] for ut in self.Utsamples_raw], axis=0)
254 | return spots, variances
255 |
256 | #---------------------------------------------------------------------------
257 | def _collect_simulation_results(self):
258 | self.outputMC = {}
259 | self.outputMC['MCResults'] = {}
260 | self.outputMC['MCResults']['SimulationObservations'] = {}
261 | self.outputMC['MCResults']['SimulationObservations']['Samples'] = []
262 | dtype_glob= self.dtype_glob
263 | n_timesteps = self.tdisargs['time_steps'] + 1
264 | n_trials = self.n_paths_per_process
265 | observation_idxs = [-1]
266 | observation_names = self.observation_names #['FXrate', 'FXStochvar']
267 | print('Collecting results for ', observation_names)
268 | self.MCobservations = []
269 |
270 | for obsname in observation_names:
271 | if (obsname.lower() == 'fxrate'):
272 | resout = np.concatenate([np.frombuffer(xs, dtype=dtype_glob).reshape((n_trials, -1))[:,:n_timesteps][:, observation_idxs] for xs in self.Xsamples_raw], axis=0)
273 | if (obsname.lower() == 'fxstochvariance'):
274 | resout = np.concatenate([np.frombuffer(ut, dtype=dtype_glob).reshape((n_trials, -1))[:,:n_timesteps][:, observation_idxs] for ut in self.Utsamples_raw], axis=0)
275 | if (obsname.lower() == 'rd'):
276 | resout = np.concatenate([np.frombuffer(rd, dtype=dtype_glob).reshape((n_trials, -1))[:,:n_timesteps][:, observation_idxs] for rd in self.rd_raw], axis=0)
277 | if (obsname.lower() == 'rb'):
278 | resout = np.concatenate([np.frombuffer(rb, dtype=dtype_glob).reshape((n_trials, -1))[:,:n_timesteps][:, observation_idxs] for rb in self.rb_raw], axis=0)
279 | if (obsname.lower() == 'domestic_xfactor'):
280 | resout = np.concatenate([np.frombuffer(xd, dtype=dtype_glob).reshape((n_trials, -1))[:,:n_timesteps][:, observation_idxs] for xd in self.xd_raw], axis=0)
281 | if (obsname.lower() == 'base_xfactor'):
282 | resout = np.concatenate([np.frombuffer(xb, dtype=dtype_glob).reshape((n_trials, -1))[:,:n_timesteps][:, observation_idxs] for xb in self.xb_raw], axis=0)
283 | #if (obsname.lower() == 'tstamp'):
284 | # #resout = np.concatenate([np.frombuffer(ts, dtype=dtype_glob).reshape((1, -1))[:,:n_timesteps] for ts in self.t_stamp_raw], axis=0)
285 | # resout = np.frombuffer(self.t_stamp_raw[0], dtype=dtype_glob).reshape(-1)[:n_timesteps][observation_idxs]
286 |
287 | self.MCobservations.append(list(resout))
288 |
289 | for t in zip(*self.MCobservations):
290 | self.outputMC['MCResults']['SimulationObservations']['Samples'].append({obsname: res for obsname,res in zip(observation_names, t)})
291 |
292 | return
293 |
294 | #---------------------------------------------------------------------------
295 | def update_base_bfactors(self, finaltime):
296 |
297 | print(finaltime, self.nsteps_peryear)
298 | self.tdisargs = {'maturity':finaltime, 'time_steps':int(self.nsteps_peryear*finaltime)}
299 | return
300 |
301 | #---------------------------------------------------------------------------
302 | def update_domestic_bfactors(self, finaltime):
303 |
304 | self.tdisargs = {'maturity':finaltime, 'time_steps':int(self.nsteps_peryear*finaltime)}
305 | return
306 |
307 | #---------------------------------------------------------------------------
308 |
309 | def set_simulation_times(self, finaltimes):
310 |
311 | self.tdisargs = {'maturity':finaltimes[-1], 'time_steps':int(self.nsteps_peryear*finaltimes[-1])}
312 | return
313 |
314 | def set_observation_times(self, obstimes):
315 |
316 | self.tdisargs = {'maturity':obstimes[-1], 'time_steps':int(self.nsteps_peryear*obstimes[-1])}
317 | return
318 |
319 | def set_vanilla_contract(self, contracttype, maturity, strike):
320 |
321 | return
322 | #---------------------------------------------------------------------------
323 | def update_localvol(self, strikes, ts, locvols):
324 |
325 | self.lvol_data['spots'] = strikes
326 | self.lvol_data['surfacevalues'] = locvols
327 | self.lvol_data['times'] = ts
328 | return
329 |
330 | #---------------------------------------------------------------------------
331 | def _compute_means_from_output(self):
332 |
333 | print('Recomputing localvol means and stderr from output...')
334 | n_trials_per_process = self.n_paths_per_process
335 | n_timesteps = self.tdisargs['time_steps']
336 | strikes = self.contracts['strikes']
337 | dtype_glob = self.dtype_glob
338 | Xsamples = np.concatenate([np.frombuffer(xs, dtype=dtype_glob).reshape((n_trials_per_process, -1))[:,:n_timesteps+1] for xs in self.Xsamples_raw], axis=0)
339 | rd = np.concatenate([np.frombuffer(rds, dtype=dtype_glob).reshape((n_trials_per_process, -1))[:,:n_timesteps] for rds in self.rd_raw], axis=0)
340 | rb = np.concatenate([np.frombuffer(rbs, dtype=dtype_glob).reshape((n_trials_per_process, -1))[:,:n_timesteps] for rbs in self.rb_raw], axis=0)
341 |
342 | self.lvol_expectations = np.array([np.mean((rd[:, n_timesteps-1]*K - rb[:, n_timesteps-1]*Xsamples[:, n_timesteps])*(Xsamples[:,n_timesteps]>K), axis=0) for K in strikes])
343 | self.lvol_stderr = [0.0]*len(strikes)
344 | self.updated_contracts_or_sim = False
345 |
346 | return
347 |
348 | #---------------------------------------------------------------------------
349 | def get_means_from_output(self):
350 |
351 | if (self.updated_contracts_or_sim==True):
352 | self._compute_means_from_output()
353 |
354 | return self.lvol_expectations
355 |
356 | #---------------------------------------------------------------------------
357 | def get_stderrs_from_output(self):
358 |
359 | if (self.updated_contracts_or_sim==True):
360 | self._compute_means_from_output()
361 |
362 | return self.lvol_stderr
363 |
364 | #---------------------------------------------------------------------------
365 | def set_contracts_for_calibration(self, Ks, expiry):
366 |
367 | self.contracts['strikes'] = Ks
368 | self.contracts['expiry'] = expiry
369 | self.updated_contracts_or_sim = True
370 | return
371 |
372 | #---------------------------------------------------------------------------
373 | class StochasticLocalVolSimulation(LocalVolStochasticIRSimulation):
374 | #---------------------------------------------------------------------------
375 | def __init__(self, domestic_shifttimes, domestic_shiftvalues, base_shifttimes, base_shiftvalues, spot_FX,
376 | initialvar, volofvar_dict, kappa_dict, theta_dict,
377 | domestic_ta, domestic_a, domestic_tvol, domestic_vols, domestic_x0,
378 | base_ta, base_a, base_tvol, base_vols, base_x0,
379 | rho_domestic_base, rho_domestic_fx, rho_base_fx,
380 | rho_fx_v, rho_domestic_v, rho_base_v,
381 | nr_mcruns, LVOL_NUMMETHOD, SHORTRATE_NUMMETHOD,
382 | antitheticpaths=True,
383 | in_forward_measure=False,
384 | nrsubsim=2,
385 | observation_names=['|FXrate', '|FXStochVariance'],
386 | observe_at_given_times=True,
387 | domestic_currency_name='USD',
388 | base_currency_name='EUR',
389 | fx_name='EURUSD',
390 | maxtdisargs=None,
391 | save_output_flags=None,
392 | ):
393 |
394 | super(StochasticLocalVolSimulation, self).__init__(domestic_shifttimes, domestic_shiftvalues, base_shifttimes, base_shiftvalues, spot_FX,
395 | domestic_ta, domestic_a, domestic_tvol, domestic_vols, domestic_x0,
396 | base_ta, base_a, base_tvol, base_vols, base_x0,
397 | rho_domestic_base, rho_domestic_fx, rho_base_fx,
398 | nr_mcruns, LVOL_NUMMETHOD, SHORTRATE_NUMMETHOD,
399 | antitheticpaths=antitheticpaths,
400 | in_forward_measure=in_forward_measure,
401 | nrsubsim=nrsubsim,
402 | observation_names = observation_names,
403 | observe_at_given_times=observe_at_given_times,
404 | domestic_currency_name='USD',
405 | base_currency_name='EUR',
406 | fx_name='EURUSD',
407 | maxtdisargs=maxtdisargs,
408 | save_output_flags=save_output_flags)
409 |
410 |
411 | self.nrmcruns = nr_mcruns
412 | self.DLV = False
413 | self.in_DRN = True
414 | self.det_DR = True
415 | self.det_FR = True
416 |
417 | save_dict = {'HESTON': True, 'XD': False, 'XB': False}
418 |
419 | ###### override default save_output_flags ###
420 | for key in save_dict.keys():
421 | self.save_output_flags[key] = save_output_flags[key] if (save_output_flags is not None) and (key in save_output_flags.keys()) else save_dict[key]
422 |
423 | self.cir_v0 = initialvar
424 | SAVE_HESTON = self.save_output_flags['HESTON']
425 |
426 | self.heston_data = sim_params.heston_dataC(kappa_dict, theta_dict, volofvar_dict, initialvar, rho_fx_v, rho_domestic_v, rho_base_v)
427 |
428 | for _ in range(self.nrsubsim):
429 | if (SAVE_HESTON):
430 | print("Allocating shmem ...", end='')
431 | self.Utsamples_raw.append(mp.Array(c.c_float, self.mult*self.n_paths_per_process*self.maxn_time, lock=False))
432 | print('HESTON UT', end=' ')
433 | print()
434 |
435 | if type(self) is StochasticLocalVolSimulation:
436 | self._allocate_shmem()
437 | print("Initializing pool for ...", type(self))
438 | self.simpool = multiprocessing.Pool(processes = self.nrsubsim, initializer=init_process, initargs=(self.t_stamp_raw,
439 | self.Xsamples_raw,
440 | self.rd_raw,
441 | self.rb_raw,
442 | self.xd_raw,
443 | self.xb_raw,
444 | self.dW_raw,
445 | self.volsamples_raw,
446 | self.Utsamples_raw,
447 | self.maxn_time, self.maxT))
448 |
449 |
450 | #---------------------------------------------------------------------------
451 | def init_process(t_stamp, Xsamples, rd, rb, xd, xb, dW, volsamples, Utsamples, maxn_time, maxT):
452 |
453 | smp.t_stamp_raw = t_stamp
454 | smp.Xsamples_raw = Xsamples
455 | smp.rd_raw = rd
456 | smp.rb_raw = rb
457 | smp.xd_raw = xd
458 | smp.xb_raw = xb
459 | smp.dW_raw = dW
460 | smp.volsamples_raw = volsamples
461 | smp.Utsamples_raw = Utsamples
462 | smp.maxn_time = maxn_time
463 | smp.maxT = maxT
464 |
465 | #---------------------------------------------------------------------------
466 | def simulate_paths(pid, n_trials, tdisargs, sdedata, g1pp_data, heston_data, lvol_data, det_DR = False, det_FR = True, DLV=True, in_DRN=True,
467 | in_forward_measure=False, antitheticpaths=True, dtype_glob='float32', save_output_flags=None):
468 |
469 | print("using passed and extracted g1pp_data for pid=%d"%pid)
470 |
471 | dim = 1
472 | T = tdisargs['maturity']
473 | maxn_time = smp.maxn_time
474 | dt = T/tdisargs['time_steps'] #smp.maxT/smp.maxn_time
475 |
476 | n_timesteps = tdisargs['time_steps']+1
477 |
478 | in_forward_measure = ((det_DR==False) and in_forward_measure)
479 |
480 | print('in_forward_measure =%s, Antithetic=%s, in_DRN=%s, det_DR=%s, det_FR=%s, DLV=%s'%(in_forward_measure, antitheticpaths, in_DRN, det_DR, det_FR, DLV))
481 |
482 | MILSTEIN_SDE = False #True #self.MILSTEIN_SDE
483 | EULER_SDE = True #False
484 |
485 | if (save_output_flags is not None):
486 | SAVE_XS = save_output_flags['XS']
487 | SAVE_XD = save_output_flags['XD']
488 | SAVE_XB = save_output_flags['XB']
489 | SAVE_RD = save_output_flags['RD']
490 | SAVE_RB = save_output_flags['RB']
491 | SAVE_DW = save_output_flags['DW']
492 | SAVE_VOLTRAJ = save_output_flags['VOLTRAJ']
493 | if (DLV==False): SAVE_HESTON = save_output_flags['HESTON']
494 | else:
495 | SAVE_DW, SAVE_XD, SAVE_XB, SAVE_XS, SAVE_RD, SAVE_RB, SAVE_VOLTRAJ, SAVE_HESTON = False, False, False, False, False, False, False, False
496 |
497 | x0_range = [g1pp_data.spot_FX]*2
498 |
499 | #######################################################################################################
500 | domestic_shifttimes, domestic_ta, domestic_tvol = g1pp_data.domestic_shifttimes, g1pp_data.domestic_ta, g1pp_data.domestic_tvol
501 | base_shifttimes, base_ta, base_tvol = g1pp_data.base_shifttimes, g1pp_data.base_ta, g1pp_data.base_tvol
502 |
503 | domestic_shiftvalues, domestic_a, domestic_vol = g1pp_data.domestic_shiftvalues, g1pp_data.domestic_a, g1pp_data.domestic_vol
504 | base_shiftvalues, base_a, base_vol = g1pp_data.base_shiftvalues, g1pp_data.base_a, g1pp_data.base_vol
505 | #######################################################################################################
506 |
507 | bdtT = lambda t:(1.0 - np.exp(-domestic_a[0]*(T-t)))/domestic_a[0]
508 | #######################################################################################################
509 |
510 | t_stamp = np.frombuffer(smp.t_stamp_raw[pid], dtype=dtype_glob)
511 | t_stamp[:n_timesteps] = dt*np.arange(n_timesteps)
512 |
513 | if (SAVE_VOLTRAJ):
514 | volsamples = np.frombuffer(smp.volsamples_raw[pid], dtype=dtype_glob).reshape((n_trials, maxn_time))
515 |
516 | if (SAVE_DW):
517 | dWs = np.frombuffer(smp.dW_raw[pid], dtype=dtype_glob).reshape((n_trials, maxn_time+1))
518 | dWs[:,0] = 0
519 |
520 | xds = np.ones(n_trials)*(g1pp_data.domestic_x0 if det_DR==False else 0.0)
521 | xbs = np.ones(n_trials)*(g1pp_data.base_x0 if det_FR==False else 0.0)
522 | if (SAVE_XD):
523 | xd = np.frombuffer(smp.xd_raw[pid], dtype=dtype_glob).reshape((n_trials, maxn_time))
524 | xd[:,0]= xds
525 | if (SAVE_XB):
526 | xb = np.frombuffer(smp.xb_raw[pid], dtype=dtype_glob).reshape((n_trials, maxn_time))
527 | xb[:,0]= xbs
528 |
529 | rds = xds + domestic_shiftvalues[0]
530 | rbs = xbs + base_shiftvalues[0]
531 | if (SAVE_RD):
532 | rd = np.frombuffer(smp.rd_raw[pid], dtype=dtype_glob).reshape((n_trials, maxn_time))
533 | rd[:,0] = rds
534 | if (SAVE_RB):
535 | rb = np.frombuffer(smp.rb_raw[pid], dtype=dtype_glob).reshape((n_trials, maxn_time))
536 | rb[:,0] = rbs
537 |
538 | ###################Asset Initialization###################
539 | Xs = np.random.uniform(low = x0_range[0], high=x0_range[1], size=n_trials) #spot_FX
540 | if (SAVE_XS):
541 | Xsamples = np.frombuffer(smp.Xsamples_raw[pid], dtype=dtype_glob).reshape((n_trials, maxn_time+1))
542 | Xsamples[:,0] = Xs
543 | lvol_spots, lvol_vols = np.array(lvol_data['spots']), np.array(lvol_data['surfacevalues'])
544 | tslices = np.array(lvol_data['times'])
545 |
546 | #####################################################
547 |
548 | if (DLV==False):
549 | Ut = np.ones(n_trials)*heston_data.initialvar
550 | kappa_times = np.array(heston_data.kappa_times)
551 | kappa_vals = heston_data.kappa_vals
552 | theta_times = np.array(heston_data.theta_times)
553 | theta_vals = heston_data.theta_vals
554 | volofvar_times = np.array(heston_data.volofvar_times)
555 | volofvar_vals = heston_data.volofvar_vals
556 | rho_fx_v = heston_data.rho_fx_v
557 | rho_domestic_v = heston_data.rho_domestic_v
558 | rho_base_v = heston_data.rho_base_v
559 | if (SAVE_HESTON):
560 | Utsamples = np.frombuffer(smp.Utsamples_raw[pid], dtype=dtype_glob).reshape((n_trials, maxn_time))
561 | Utsamples[:,0] = Ut
562 | else:
563 | rho_fx_v, rho_domestic_v, rho_base_v = 1, 1, 1
564 |
565 | covariances_mat = np.array([[1.0, sdedata.rho_domestic_fx, sdedata.rho_base_fx, rho_fx_v],
566 | [sdedata.rho_domestic_fx, 1.0, sdedata.rho_domestic_base, rho_domestic_v],
567 | [sdedata.rho_base_fx, sdedata.rho_domestic_base, 1.0, rho_base_v],
568 | [rho_fx_v, rho_domestic_v, rho_base_v, 1.0]])
569 |
570 | #aoidx, doidx, foidx, uoidx = 0, 1, 2, 3
571 | #xpos, dpos, fpos, upos = 0, 1, 2, 3
572 |
573 | det_X = False
574 |
575 | stochastic_components = np.logical_not([det_X, det_DR, det_FR, DLV])
576 | cov_mat = covariances_mat[stochastic_components, :][:,stochastic_components]
577 |
578 | xpos, dpos, fpos, upos = tuple(np.cumsum(stochastic_components) - 1)
579 | meanval = [0.0]*np.sum(stochastic_components)
580 |
581 | print('Using covariance matrix, ', cov_mat)
582 | print('xpos, dpos, fpos, upos:', xpos, dpos, fpos, upos)
583 | ################################### Start the simulation ####################################
584 | search_index = lambda array_vals, val: min(len(array_vals)-1, np.searchsorted(array_vals, val))
585 | search_index_closest = lambda array_vals, val: (np.abs(array_vals - val)).argmin()
586 |
587 | volvals = np.zeros(Xsamples.shape[0])
588 | sig_d = domestic_vol[0]
589 |
590 | print('PID, Time, idx, TsliceIdx, TsliceTime, Volvals[0], Shapes: ', end='')
591 | if (DLV==False): print('Ut ', end='')
592 | print('Incr, Xdrift, Xs, idxvals, volvals, rds, rbs, xds, xbs')
593 | for idx, (t, dt) in enumerate(zip(t_stamp[1:n_timesteps], np.diff(t_stamp[:n_timesteps])), 1):
594 |
595 | sqrtdt = np.sqrt(dt)
596 | if (antitheticpaths==True):
597 | samplevals = mvn(mean = meanval, cov=cov_mat, size=[int(0.5*n_trials),1])
598 | dW_sample = np.concatenate([samplevals, -1*samplevals], axis=0)
599 | else:
600 | dW_sample = mvn(mean = meanval, cov=cov_mat, size=[n_trials,1]) ###### generates random samples of size (n_trials x 1 x len(meanval))
601 | ####### save dWs to output
602 | if (SAVE_DW):
603 | dWs[:,idx] = dW_sample[:,0,xpos]
604 |
605 |
606 | ################# Local Volatility ################################
607 | dW = dW_sample[:,0, xpos]
608 | tidx = search_index(tslices, t) if (DLV==True) else search_index_closest(tslices, t) #search_index(tslices, t) #if (DLV==True) else np.searchsorted(tslices, t) - 1
609 | #print('LVOL search_index:', tidx)
610 | indexvals = np.argmin(np.abs(lvol_spots[tidx:tidx+1,:] - Xs.reshape(-1,1)), axis=1)
611 | volvals = lvol_vols[tidx, indexvals]
612 | if (DLV==False): ### SLV
613 | volvals = volvals*np.sqrt(Ut)
614 | ######### save localvol trajectory ###############################
615 | if (SAVE_VOLTRAJ):
616 | volsamples[:,idx-1] = volvals
617 | ###################################################################
618 |
619 | #print('pid %d, t %.3f, volvals_mean %.8f'%(pid, t, np.mean(volvals)))
620 | sig2o2 = volvals**2/2
621 | incr = volvals*dW*sqrtdt
622 | ####### save xsamples to output #####################
623 | Xdrift = rds - rbs
624 | if (in_forward_measure==True): Xdrift += -(sdedata.rho_domestic_fx*bdtT(t)*sig_d*volvals)
625 | if (MILSTEIN_SDE==True):
626 | Xs = Xs*(1.0 + (Xdrift + sig2o2*(dW**2-1))*dt + incr)
627 | elif (EULER_SDE==True):
628 | Xs = Xs*(1.0 + Xdrift*dt + incr)
629 |
630 | if (SAVE_XS):
631 | Xsamples[:,idx] = Xs
632 |
633 | if ((idx-1)%20==0):
634 | print(('{:2d}'+'{:8.3f}'+'{:5d}'*2+'{:8.3f}'*2).format(pid, t,idx, tidx, tslices[tidx], volvals[0]), end='')
635 |
636 | ################# SLV ###########################################
637 | if (DLV==False):
638 | uidx = search_index(kappa_times, t)
639 | kappa_u = 0.0 if (uidx==0) else kappa_vals[uidx-1] #kappa_vals[uidx] #
640 | uidx = search_index(theta_times, t)
641 | theta_u = 0.0 if (uidx==0) else theta_vals[uidx-1] #theta_vals[uidx] #
642 | uidx = search_index(volofvar_times, t)
643 | volofvar_u = 0.0 if (uidx==0) else volofvar_vals[uidx-1] #volofvar_vals[uidx] #
644 | Udrift = kappa_u*(theta_u - Ut)*dt
645 | Uincr = volofvar_u*np.sqrt(Ut)*dW_sample[:,0, upos]*sqrtdt
646 | if (in_forward_measure==True):
647 | #didx = search_index(domestic_tvol, t)
648 | #sig_d = 0.0 if (didx==0) else domestic_vol[didx-1]
649 | Udrift += -(rho_domestic_v*bdtT(t)*sig_d*volofvar_u*np.sqrt(Ut)*dt)
650 | Ut = Ut + Udrift + Uincr
651 | Ut[Ut<0] = 0 #Ut = np.abs(Ut) #-1*Ut[idxmask1]
652 | if ((idx-1)%20==0):
653 | print(Ut.shape, end='')
654 | if (SAVE_HESTON):
655 | Utsamples[:,idx] = Ut
656 | #################################################################
657 |
658 | ################## Domestic G1pp ####################################
659 | if (det_DR==False):
660 | didx = search_index(domestic_tvol, t)
661 | sig_d = 0.0 if (didx==0) else domestic_vol[didx-1]
662 | sigd2_2 = sig_d**2/2
663 | didx = search_index(domestic_ta, t)
664 | a_d = 0.0 if (didx==0) else domestic_a[didx-1]
665 | incrd = sig_d*dW_sample[:,0, dpos]*sqrtdt
666 | xddrift = (-a_d*xds*dt)
667 | ############# in T-Forward Measure ########################################
668 | if (in_forward_measure==True): xddrift += -(sig_d**2)*bdtT(t)*dt
669 | ###########################################################################
670 | xds = xds + xddrift + incrd
671 | if (SAVE_XD):
672 | xd[:, idx] = xds
673 |
674 | ################## Foreign G1pp ####################################
675 | if (det_FR==False):
676 | bidx = search_index(base_tvol, t)
677 | sig_b = 0.0 if (bidx==0) else base_vol[bidx-1]
678 | sigb2_2 = sig_b**2/2
679 | bidx = search_index(base_ta, t)
680 | a_b = 0.0 if (bidx==0) else base_a[bidx-1]
681 |
682 | incrb = sig_b*dW_sample[:,0, fpos]*sqrtdt
683 | xbdrift = (-a_b*xbs*dt)
684 |
685 | ############ in Domestic Risk-Neutral measure ###################################
686 | if (in_DRN==True): xbdrift += -sdedata.rho_base_fx*sig_b*volvals*dt
687 | ###############################################################################
688 | if (in_forward_measure==True): xbdrift += -sdedata.rho_domestic_base*bdtT(t)*sig_b*sig_d*dt
689 | xbs = xbs + xbdrift + incrb
690 | if (SAVE_XB):
691 | xb[:, idx] = xbs
692 | #################################################
693 |
694 | didx = search_index(domestic_shifttimes, t)
695 | phi_d = 0.0 if (didx==0) else domestic_shiftvalues[didx-1]
696 |
697 | bidx = search_index(base_shifttimes, t)
698 | phi_b = 0.0 if (bidx==0) else base_shiftvalues[bidx-1]
699 |
700 | rds = xds + phi_d
701 | rbs = xbs + phi_b
702 | if (SAVE_RD):
703 | rd[:,idx] = rds
704 | if (SAVE_RB):
705 | rb[:,idx] = rbs
706 |
707 | if ((idx-1)%20==0):
708 | print(incr.shape, Xdrift.shape, Xs.shape, indexvals.shape, volvals.shape, rds.shape, rbs.shape, xds.shape, xbs.shape)
709 |
710 |
711 |
712 | print('PiD:%d returned to caller'%pid)
713 | return
--------------------------------------------------------------------------------
/sim_lib/sim_params.py:
--------------------------------------------------------------------------------
1 |
2 | ##################################################################################
3 | class sdedataC():
4 | def __init__(self, rho_domestic_base, rho_base_fx, rho_domestic_fx):
5 |
6 | self.rho_domestic_base = rho_domestic_base
7 | self.rho_base_fx = rho_base_fx
8 | self.rho_domestic_fx = rho_domestic_fx
9 | return
10 | ##################################################################################
11 |
12 | ##################################################################################
13 | class g1pp_dataC():
14 | def __init__(self, spot_FX, base_x0, domestic_x0, g1ppTA, domestic_shifttimes, g1ppTVOL, g1ppA, g1ppVOL, domestic_shiftvalues,
15 | g1ppdivTA, g1ppdivMEANREV, base_shifttimes, base_shiftvalues, g1ppdivTVOL, g1ppdivVOL):
16 |
17 | self.spot_FX=spot_FX
18 | self.base_x0 = base_x0
19 | self.domestic_x0 = domestic_x0
20 |
21 | self.domestic_ta = g1ppTA
22 | self.domestic_shifttimes = domestic_shifttimes
23 | self.domestic_tvol = g1ppTVOL
24 |
25 | self.domestic_a = g1ppA
26 | self.domestic_vol = g1ppVOL
27 | self.domestic_shiftvalues = domestic_shiftvalues
28 |
29 | self.base_ta = g1ppdivTA
30 | self.base_a = g1ppdivMEANREV
31 | self.base_shifttimes = base_shifttimes
32 | self.base_shiftvalues = base_shiftvalues
33 | self.base_tvol = g1ppdivTVOL
34 | self.base_vol = g1ppdivVOL
35 | return
36 | ##################################################################################
37 |
38 |
39 | ##################################################################################
40 | class heston_dataC():
41 | def __init__(self, kappa_dict, theta_dict, volofvar_dict, initialvar, rho_fx_v, rho_domestic_v, rho_base_v):
42 | self.kappa_times = kappa_dict['times']
43 | self.kappa_vals = kappa_dict['values']
44 | self.theta_times = theta_dict['times']
45 | self.theta_vals = theta_dict['values']
46 | self.volofvar_times = volofvar_dict['times']
47 | self.volofvar_vals = volofvar_dict['values']
48 | self.initialvar = initialvar
49 | self.rho_fx_v = rho_fx_v
50 | self.rho_domestic_v = rho_domestic_v
51 | self.rho_base_v = rho_base_v
52 | return
53 | ##################################################################################
--------------------------------------------------------------------------------