22# Copyright (C) 2018, 2019, 2020 Dominic O'Kane, Saeed Amen
33##############################################################################
44
5+ import matplotlib .pyplot as plt
6+
57from typing import Union
68
79import numpy as np
810from scipy .optimize import minimize
911
10- import matplotlib .pyplot as plt
1112from numba import njit , float64 , int64
1213
1314from ...utils .error import FinError
@@ -340,9 +341,7 @@ def delta_fit(K, *args):
340341
341342 f = s * np .exp ((r_d - r_f ) * t )
342343 v = vol_function (vol_type_value , params , f , K , t )
343- delta_out = fast_delta (
344- s , t , K , r_d , r_f , v , delta_type_value , opt_type_value
345- )
344+ delta_out = fast_delta (s , t , K , r_d , r_f , v , delta_type_value , opt_type_value )
346345 inverse_delta_out = norminvcdf (np .abs (delta_out ))
347346 inv_obj_fn = inverse_delta_target - inverse_delta_out
348347
@@ -399,9 +398,7 @@ def solver_for_smile_strike_fast(
399398 parameters ,
400399 )
401400
402- K = newton_secant (
403- delta_fit , x0 = initial_guess , args = argtuple , tol = 1e-8 , maxiter = 50
404- )
401+ K = newton_secant (delta_fit , x0 = initial_guess , args = argtuple , tol = 1e-8 , maxiter = 50 )
405402
406403 return K
407404
@@ -411,9 +408,7 @@ def solver_for_smile_strike_fast(
411408
412409
413410@njit (
414- float64 (
415- float64 , float64 , float64 , float64 , int64 , float64 , int64 , float64
416- ),
411+ float64 (float64 , float64 , float64 , float64 , int64 , float64 , int64 , float64 ),
417412 fastmath = True ,
418413)
419414def solve_for_strike (
@@ -455,9 +450,7 @@ def solve_for_strike(
455450 vsqrtt = volatility * np .sqrt (t_del )
456451 arg = delta_target * phi / for_df # CHECK THIS !!!
457452 norm_inv_delta = norminvcdf (arg )
458- K = fwd_fx_rate * np .exp (
459- - vsqrtt * (phi * norm_inv_delta - vsqrtt / 2.0 )
460- )
453+ K = fwd_fx_rate * np .exp (- vsqrtt * (phi * norm_inv_delta - vsqrtt / 2.0 ))
461454 return K
462455
463456 elif delta_method_value == FinFXDeltaMethod .FORWARD_DELTA .value :
@@ -474,9 +467,7 @@ def solve_for_strike(
474467 vsqrtt = volatility * np .sqrt (t_del )
475468 arg = delta_target * phi # CHECK THIS!!!!!!!!
476469 norm_inv_delta = norminvcdf (arg )
477- K = fwd_fx_rate * np .exp (
478- - vsqrtt * (phi * norm_inv_delta - vsqrtt / 2.0 )
479- )
470+ K = fwd_fx_rate * np .exp (- vsqrtt * (phi * norm_inv_delta - vsqrtt / 2.0 ))
480471 return K
481472
482473 elif delta_method_value == FinFXDeltaMethod .SPOT_DELTA_PREM_ADJ .value :
@@ -492,9 +483,7 @@ def solve_for_strike(
492483 delta_target ,
493484 )
494485
495- K = newton_secant (
496- g , x0 = spot_fx_rate , args = argtuple , tol = 1e-7 , maxiter = 50
497- )
486+ K = newton_secant (g , x0 = spot_fx_rate , args = argtuple , tol = 1e-7 , maxiter = 50 )
498487
499488 return K
500489
@@ -511,9 +500,7 @@ def solve_for_strike(
511500 delta_target ,
512501 )
513502
514- K = newton_secant (
515- g , x0 = spot_fx_rate , args = argtuple , tol = 1e-7 , maxiter = 50
516- )
503+ K = newton_secant (g , x0 = spot_fx_rate , args = argtuple , tol = 1e-7 , maxiter = 50 )
517504
518505 return K
519506
@@ -642,29 +629,23 @@ def volatility(self, K, expiry_dt):
642629 # The volatility term structure is flat if there is only one expiry
643630 fwd = self .fwd [0 ]
644631 t_exp = self .t_exp [0 ]
645- vol = vol_function (
646- vol_type_value , self .parameters [0 ], fwd , K , t_exp
647- )
632+ vol = vol_function (vol_type_value , self .parameters [0 ], fwd , K , t_exp )
648633 return vol
649634
650635 # If the time is below first time then assume a flat vol
651636 if t <= self .t_exp [0 ]:
652637
653638 fwd = self .fwd [0 ]
654639 t_exp = self .t_exp [0 ]
655- vol = vol_function (
656- vol_type_value , self .parameters [0 ], fwd , K , t_exp
657- )
640+ vol = vol_function (vol_type_value , self .parameters [0 ], fwd , K , t_exp )
658641 return vol
659642
660643 # If the time is beyond the last time then extrapolate with a flat vol
661644 if t > self .t_exp [- 1 ]:
662645
663646 fwd = self .fwd [- 1 ]
664647 t_exp = self .t_exp [- 1 ]
665- vol = vol_function (
666- vol_type_value , self .parameters [- 1 ], fwd , K , t_exp
667- )
648+ vol = vol_function (vol_type_value , self .parameters [- 1 ], fwd , K , t_exp )
668649 return vol
669650
670651 for i in range (1 , num_curves ):
@@ -676,15 +657,11 @@ def volatility(self, K, expiry_dt):
676657
677658 fwd0 = self .fwd [index0 ]
678659 t0 = self .t_exp [index0 ]
679- vol0 = vol_function (
680- vol_type_value , self .parameters [index0 ], fwd0 , K , t0
681- )
660+ vol0 = vol_function (vol_type_value , self .parameters [index0 ], fwd0 , K , t0 )
682661
683662 fwd1 = self .fwd [index1 ]
684663 t1 = self .t_exp [index1 ]
685- vol1 = vol_function (
686- vol_type_value , self .parameters [index1 ], fwd1 , K , t1
687- )
664+ vol1 = vol_function (vol_type_value , self .parameters [index1 ], fwd1 , K , t1 )
688665
689666 vart0 = vol0 * vol0 * t0
690667 vart1 = vol1 * vol1 * t1
@@ -1047,8 +1024,7 @@ def check_calibration(self, verbose: bool, tol: float = 1e-6):
10471024
10481025 print ("======================================================" )
10491026 print (
1050- "MKT STRANGLE VOL IN: %9.6f %%"
1051- % (100.0 * self .ms_25_delta_vols [i ])
1027+ "MKT STRANGLE VOL IN: %9.6f %%" % (100.0 * self .ms_25_delta_vols [i ])
10521028 )
10531029
10541030 call .strike_fx_rate = self .k_25d_c_ms [i ]
@@ -1254,16 +1230,12 @@ def check_calibration(self, verbose: bool, tol: float = 1e-6):
12541230 sigma_rr = sigma_k_25d_c - sigma_k_25d_p
12551231
12561232 if verbose :
1257- print (
1258- "========================================================="
1259- )
1233+ print ("=========================================================" )
12601234 print (
12611235 "RR = VOL_K_25_C - VOL_K_25_P => RR_IN: %9.6f %% RR_OUT: %9.6f %%"
12621236 % (100.0 * self .rr_25_delta_vols [i ], 100.0 * sigma_rr )
12631237 )
1264- print (
1265- "========================================================="
1266- )
1238+ print ("=========================================================" )
12671239
12681240 diff = sigma_rr - self .rr_25_delta_vols [i ]
12691241
@@ -1319,9 +1291,7 @@ def implied_dbns(self, low_fx, high_fx, num_intervals):
13191291 k_s = np .array (k_s )
13201292 vols = np .array (vols )
13211293
1322- density = option_implied_dbn (
1323- self .spot_fx_rate , t_exp , r_d , r_f , k_s , vols
1324- )
1294+ density = option_implied_dbn (self .spot_fx_rate , t_exp , r_d , r_f , k_s , vols )
13251295
13261296 dbn = FinDistribution (k_s , density )
13271297 dbns .append (dbn )
@@ -1369,9 +1339,7 @@ def plot_vol_curves(self):
13691339 plt .xlabel ("Strike" )
13701340 plt .ylabel ("Volatility" )
13711341
1372- title = (
1373- "25d FIT:" + self .currency_pair + " " + str (self .vol_func_type )
1374- )
1342+ title = "25d FIT:" + self .currency_pair + " " + str (self .vol_func_type )
13751343
13761344 key_strikes = []
13771345 key_strikes .append (self .k_atm [tenor_index ])
0 commit comments