def recalib_calendar(param): norm = sum( (w(log_moneyness_t, parameters[:, t]) - w(log_moneyness_t, param))**2 ) + 0.0001 * sum_negatives( np.array(svi_raw(k, param, maturities[t]) - slice_after)) + +0.00001 * g(param)[1] return norm
def fitness(indv): a, b, m, rho, sigma = indv.solution model_total_implied_variance=svi_raw(self.k,np.array([a, b, m, rho, sigma]),self.tau) value = norm(self.total_implied_variance - model_total_implied_variance,ord=2) # if bool(len(self.slice_before)) and np.array(model_total_implied_variance < self.slice_before).any(): # value +=(np.count_nonzero(~np.array(model_total_implied_variance < self.slice_before))*100) # # value = 1e6 # # if bool(len(self.slice_after)) and np.array(model_total_implied_variance > self.slice_after).any(): # value += float(np.count_nonzero(~np.array(model_total_implied_variance > self.slice_after)) * 100) # # value = 1e6 # if np.isnan(value): # value = 1e6 value = float(value) return value
def svi_interpolation(spot, log_moneyness, tau_interp, interest_interp, parameters, theta, maturities): # forward_theta, interest_rate_theta # close = forward_interp*np.exp(-interest_interp * tau_interp) if np.isin(tau_interp, maturities): total_implied_variance = svi_raw( log_moneyness, parameters[:, maturities == tau_interp], tau_interp) implied_volatility = np.sqrt(total_implied_variance / tau_interp) elif min(maturities) < tau_interp and tau_interp < max(maturities): theta_interp = interp1d(maturities, theta)(tau_interp) idx = np.argmin(abs(maturities - tau_interp)) if maturities[idx] < tau_interp: idx = idx + 1 alpha_t = (np.sqrt(theta[idx]) - np.sqrt(theta_interp)) / ( np.sqrt(theta[idx]) - np.sqrt(theta[idx - 1])) parameters_jw_fromer = svi_convertparameters(parameters[:, idx - 1], 'raw', 'jumpwing', maturities[idx - 1]) parameters_jw_after = svi_convertparameters(parameters[:, idx], 'raw', 'jumpwing', maturities[idx]) param_interp_jw = alpha_t * parameters_jw_fromer + ( 1 - alpha_t) * parameters_jw_after param_interp = svi_convertparameters(param_interp_jw, 'jumpwing', 'raw', tau_interp) total_implied_variance = svi_raw(log_moneyness, param_interp, tau_interp) implied_volatility = np.sqrt(total_implied_variance / tau_interp) elif tau_interp < maturities[0]: # extrapolation for small maturities theta_interp = interp1d(maturities, theta, fill_value='extrapolate')(tau_interp) strike_1 = spot * np.exp(log_moneyness) call_price_1 = np.array( [x if x >= 0 else 0 for x in (spot - strike_1)]) idx = 0 total_implied_variance_2 = svi_raw(log_moneyness, parameters[:, idx], maturities[idx]) implied_volatility_2 = np.sqrt(total_implied_variance_2 / maturities[idx]) strike_2 = spot * np.exp( interest_interp * maturities[0]) * np.exp(log_moneyness) call_price_2 = eurocall(implied_volatility_2, spot, strike_2, interest_interp, maturities[idx], 0) forward_interp = interp1d( np.array([0, maturities[0]]), [spot, spot * np.exp(interest_interp * maturities[0])])(tau_interp) alpha_t = (np.sqrt(theta[idx]) - np.sqrt(theta_interp)) / np.sqrt( theta[idx]) K_t = forward_interp * np.exp(log_moneyness) call_price = K_t * (alpha_t * call_price_1 / strike_1 + (1 - alpha_t) * call_price_2 / strike_2) implied_volatility = calcvol(spot, K_t, interest_interp, tau_interp, call_price, '0') total_implied_variance = np.array(implied_volatility)**2 * tau_interp # extrapolation for large maturities else: theta_interp = interp1d(maturities, theta, fill_value='extrapolate')(tau_interp) total_implied_variance = svi_raw(log_moneyness, parameters[:, -1], maturities[-1]) total_implied_variance = total_implied_variance + theta_interp - theta[ -1] implied_volatility = np.sqrt(total_implied_variance / tau_interp) return total_implied_variance
def fit_svi_surface(implied_volatility, log_moneyness, maturity): total_implied_variance = np.array(implied_volatility**2 * maturity) maturities = np.array(sorted(list(set(maturity)))) T = len(maturities) theta = np.zeros(T) parameters = np.zeros([5, T]) for t in np.arange(T - 1, -1, -1): pos = maturity == maturities[t] log_moneyness_t = np.array(log_moneyness[pos]) k = np.arange(-1, 1, 0.005) total_implied_variance_t = total_implied_variance[pos] if t == T - 1: # slice_before = [] slice_after = [] else: # slice_before=[] param_after = parameters[:, t + 1] slice_after = svi_raw(k, param_after, maturities[t + 1]) print( '================================starting fitting================================================' ) # parameters[:, t] = get_svi_optimal_params_non_calendar(slice_after,[list(log_moneyness_t), # total_implied_variance_t],maturities[t]) parameters[:, t] = svi_calibration_util( slice_after, [log_moneyness_t, total_implied_variance_t], maturities[t]) # penalize butterfly arbitrage # a, b, rho, m, sigma shunxu params_old = parameters[:, t] if (g(params_old)[0] < 0).any(): parameters_bnd = svi_convertparameters(params_old, 'raw', 'jumpwing', maturities[t]) parameters_bnd[3] = parameters_bnd[2] + 2 * parameters_bnd[1] parameters_bnd[4] = parameters_bnd[0] * 4 * parameters_bnd[ 2] * parameters_bnd[3] / (parameters_bnd[2] + parameters_bnd[3])**2 parameters_bnd_raw = svi_convertparameters(parameters_bnd, 'jumpwing', 'raw', maturities[t]) def recalib(param): norm = sum( (w(log_moneyness_t, params_old) - w(log_moneyness_t, param))**2) + 0.00001 * g(param)[1] return norm a, b, rho, m, sigma = params_old a_bnds, b_bnds, rho_bnds, m_bnds, sigma_bnds = parameters_bnd bnds = ((min(a, a_bnds), max(a, a_bnds)), (min(b, b_bnds), max(b, b_bnds)), (min(rho, rho_bnds), max(rho, rho_bnds)), (min(m, m_bnds), max(m, m_bnds)), (min(sigma, sigma_bnds), max(sigma, sigma_bnds))) res = minimize( recalib, (np.array(parameters_bnd_raw) + np.array(params_old)) / 2, bounds=bnds, method='SLSQP', tol=1e-9) param_new = res.x parameters[:, t] = param_new #penalize calendar arbitrage and butterfly arbitrage if slice_after != [] and np.array( (svi_raw(k, parameters[:, t], maturities[t]) - slice_after) > 0).any(): print( np.array((svi_raw(k, parameters[:, t], maturities[t]) - slice_after) > 0)) print('eliminating calendar arb') param_no_calendar_arb = parameters[:, t] # a:param_no_calendar_arb[0] # param_no_calendar_arb[0] = param_no_calendar_arb[0] + 0.5 # while np.array((svi_raw(k, param_no_calendar_arb, maturities[t]) - slice_after) > 0).any(): # param_no_calendar_arb[0] = param_no_calendar_arb[0] - 0.5 def recalib_calendar(param): norm = sum( (w(log_moneyness_t, parameters[:, t]) - w(log_moneyness_t, param))**2 ) + 0.0001 * sum_negatives( np.array(svi_raw(k, param, maturities[t]) - slice_after)) + +0.00001 * g(param)[1] return norm res2 = minimize(recalib_calendar, param_no_calendar_arb, method='SLSQP', tol=1e-9) parameters[:, t] = res2.x print(parameters[:, t]) theta[t] = svi_raw(0, parameters[:, t], maturities[t]) plt.plot(g(parameters[:, t])[0], 'r--') plt.plot([0] * 600, 'b') plt.show() a, b, rho, m, sigma = parameters[:, t] x_range = np.arange( min(log_moneyness_t) - 0.005, max(log_moneyness_t) + 0.02, 0.1 / 100) tv_svi2 = a + b * (rho * (x_range - m) + np.sqrt( (x_range - m)**2 + sigma**2)) plt.figure() plt.plot(np.exp(log_moneyness_t), implied_volatility[pos], 'ro') plt.plot(np.exp(x_range), np.sqrt(tv_svi2 / maturities[t]), 'b--') plt.show() return parameters, theta
strikes = d['exe_price'].values impliedVols = d['impvol'].values ttm = d['ttm'].values logMoneynesses = np.log(strikes / spot * np.exp(rf * ttm)) maturities = np.array(sorted(list(set(ttm)))) params = np.array( [[-6.12602361e-04, -7.68306690e-03, -1.41268209e-03, 1.27275581e-02], [3.28095217e-02, 7.23893507e-02, 1.00896003e-01, 1.13173980e-01], [-3.81018899e-01, -4.26001565e-01, -5.45357904e-01, -7.19617321e-01], [-2.32187306e-02, -4.54770989e-02, -2.26383083e-02, 1.24983464e-02], [3.77894587e-02, 1.33798429e-01, 8.35171426e-02, 1.07997580e-01]]) k = np.arange(-1, 1, 0.005) theta = np.zeros(4) for i in range(4): theta[i] = svi_raw(0, params[:, i], maturities[i]) #log_moneyness, tau_interp, interest_interp, parameters, theta,maturities, forward_theta, interest_rate_theta tau_interp = 0.04 plt.plot(k, svi_interpolation(spot, k, tau_interp, 0.03, params, theta, maturities), 'orange', label=str(tau_interp)) plt.plot(k, svi_raw(k, params[:, 0], maturities[0]), 'blue', label='0.090') plt.plot(k, svi_raw(k, params[:, 1], maturities[1]), 'green', label='0.167') # plt.plot(k,svi_raw(k,params[:,2],maturities[2]),'blue',label='0.416') # plt.plot(k,svi_raw(k,params[:,3],maturities[3]),'purple',label='0.665')
strikes = d['exe_price'].values impliedVols = d['impvol'].values ttm = d['ttm'].values logMoneynesses=np.log(strikes / spot * np.exp(rf * ttm)) maturities = np.array(sorted(list(set(ttm)))) k=np.arange(-1,1,0.005) # params=np.array([[ -6.12602361e-04 ,-7.68306690e-03 , -1.41268209e-03 , 1.27275581e-02], # [ 3.28095217e-02 , 7.23893507e-02 , 1.00896003e-01 , 1.13173980e-01], # [ -3.81018899e-01 ,-4.26001565e-01 , -5.45357904e-01 ,-7.19617321e-01], # [ -2.32187306e-02 , -4.54770989e-02 ,-2.26383083e-02 , 1.24983464e-02], # [ 3.77894587e-02 , 1.33798429e-01 , 8.35171426e-02 , 1.07997580e-01]]) params,theta= fit_svi_surface(impliedVols,logMoneynesses,ttm) implied_vols = ql.Matrix(len(k), len(maturities)) volset=[] for i in range(4): volset.append(np.sqrt(svi_raw(k,params[:,i],maturities[i])/maturities[i])) for i in range(implied_vols.rows()): for j in range(implied_vols.columns()): implied_vols[i][j] = volset[j][i] black_var_surface = ql.BlackVarianceSurface(evalDate, calendar, [ql.Date(28,2,2018),ql.Date(28,3,2018),ql.Date(27,6,2018),ql.Date(26,9,2018)], k, implied_vols, daycounter) # # plt.figure(figsize=(16,9)) # for i in np.arange(0.01,0.5,0.01): # tau_interp=i # plt.legend() # plt.plot(k,np.array([black_var_surface.blackVol(tau_interp,i) for i in k])**2*tau_interp ,label=str(tau_interp)) # # plt.plot(k,svi_raw(k,params[:,0],maturities[0]),'black',label=0.090)