├── 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 |
61 | 62 | whereas the foreign short rate evolves in foreign risk neutral measure, 63 | 64 |
65 |
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 | ![LV_2SR_Convergence](https://user-images.githubusercontent.com/12563351/141022625-c281469d-dd3e-4bf9-94cb-c31cd48ddac7.png) 94 | 95 | Call Option price and implied volatility Recovery: 96 | ![LV_2SR_maturity_diff_call_and_ivol](https://user-images.githubusercontent.com/12563351/141033827-4e3c9b81-1911-4a50-9c1e-77d73a61bc62.png) 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 | ![SLV_2DR_Convergence](https://user-images.githubusercontent.com/12563351/141051960-bcf55031-9cd1-419f-87b6-87a48d1588e2.png) 136 | 137 | The repriced call function at maturity and the corresponding implied vol recovered within +-2 Monte Carlo errors. 138 | ![SLV_2DR_maturity_diff_call_and_ivol](https://user-images.githubusercontent.com/12563351/141052061-d024c83f-deb1-4b1e-bc81-331684bdaa20.png) 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 |
146 |
147 | 148 | Domestic rates modeled as a G1pp process:
149 |
150 |
151 | 152 | Foreign rates modeled as a second G1pp process:
153 |
154 |
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 | ![SLV_2SR_maturity_diff_call_and_ivol](https://user-images.githubusercontent.com/12563351/141054532-cb876819-1bf7-4729-b88e-6bdfc7113c50.png) 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 | ################################################################################## --------------------------------------------------------------------------------