Skip to content

Commit b3352e7

Browse files
committed
Various minor bug fixes
1 parent 88fc227 commit b3352e7

File tree

64 files changed

+4822
-4931
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+4822
-4931
lines changed

financepy/__init__.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
cr = "\n"
1+
if 1==1:
2+
cr = "\n"
23

3-
s = "####################################################################" + cr
4-
s += "# FINANCEPY BETA Version " + str('1.01') + " - This build: 12 Aug 2025 at 13:34 #" + cr
5-
s += "# This software is distributed FREE AND WITHOUT ANY WARRANTY #" + cr
6-
s += "# Report bugs as issues at https://github.com/domokane/FinancePy #" + cr
7-
s += "####################################################################"
8-
s += cr
4+
s = "####################################################################" + cr
5+
s += "# FINANCEPY Version " + str('1.1') + " - This build: 15 Aug 2025 at 13:36 #" + cr
6+
s += "# This software is distributed FREE AND WITHOUT ANY WARRANTY #" + cr
7+
s += "# Report bugs as issues at https://github.com/domokane/FinancePy #" + cr
8+
s += "####################################################################"
9+
s += cr
910

10-
print(s)
11+
print(s)

financepy/__init__.template

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
cr = "\n"
1+
if 1==1:
2+
cr = "\n"
23

3-
s = "####################################################################" + cr
4-
s += "# FINANCEPY BETA Version " + str(__version__) + " - This build: __dateandtime__ #" + cr
5-
s += "# This software is distributed FREE AND WITHOUT ANY WARRANTY #" + cr
6-
s += "# Report bugs as issues at https://github.com/domokane/FinancePy #" + cr
7-
s += "####################################################################"
8-
s += cr
4+
s = "####################################################################" + cr
5+
s += "# FINANCEPY Version " + str(__version__) + " - This build: __dateandtime__ #" + cr
6+
s += "# This software is distributed FREE AND WITHOUT ANY WARRANTY #" + cr
7+
s += "# Report bugs as issues at https://github.com/domokane/FinancePy #" + cr
8+
s += "####################################################################"
9+
s += cr
910

10-
print(s)
11+
print(s)

financepy/market/curves/composite_discount_curve.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,14 @@ def __init__(self, child_curves: List[DiscountCurve]):
2828
"""
2929

3030
check_argument_types(self.__init__, locals())
31-
assert (
32-
len(child_curves) > 0
33-
), "Empty list of child curves is not supported"
31+
assert len(child_curves) > 0, "Empty list of child curves is not supported"
3432

3533
self._children = child_curves
3634

3735
self.value_dt = self._children[0].value_dt
3836
assert all(
3937
c.value_dt == self.value_dt for c in self._children
40-
), "Child curves must all have the same vlauation date"
38+
), "Child curves must all have the same valuation date"
4139

4240
# Read off the first child
4341
self.dc_type = self._children[0].dc_type

financepy/market/curves/discount_curve_pwf_onf.py

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222

2323

2424
class DiscountCurvePWFONF(DiscountCurve):
25-
"""Curve with piece-wise flat instantaneous (ON) fwd rates. Curve is made up of a series of sections with each having
25+
"""Curve with piece-wise flat instantaneous (ON) fwd rates.
26+
Curve is made up of a series of sections with each having
2627
a flat instantaneous forward rate. The default compounding assumption is
2728
continuous. The class inherits methods from DiscountCurve."""
2829

@@ -34,7 +35,8 @@ def __init__(
3435
):
3536
"""
3637
Creates a discount curve using a vector of times and ON fwd rates
37-
The fwd rate is right-continuous i.e. a given value in the input is applied to the left of that date until the previous date exclusive
38+
The fwd rate is right-continuous i.e. a given value in the
39+
input is applied to the left of that date until the previous date exclusive
3840
The last fwd rate is extrapolated into the future
3941
"""
4042

@@ -51,19 +53,15 @@ def __init__(
5153
self._knot_dates = [max(d, value_dt) for d in knot_dates]
5254
self._onfwd_rates = np.atleast_1d(onfwd_rates)
5355

54-
self._freq_type = FrequencyTypes.CONTINUOUS
55-
self._day_count_type = DayCountTypes.SIMPLE
56+
self.freq_type = FrequencyTypes.CONTINUOUS
57+
self.dc_type = DayCountTypes.SIMPLE
5658

57-
dc_times = times_from_dates(
58-
self._knot_dates, self.value_dt, self._day_count_type
59-
)
59+
dc_times = times_from_dates(self._knot_dates, self.value_dt, self.dc_type)
6060

6161
self._times = np.atleast_1d(dc_times)
6262

6363
# it is easier to deal in log(dfs), log(df[Ti]) = -\int_0^T_i f(u) du
64-
self._logdfs = -np.cumsum(
65-
np.diff(self._times, prepend=0.0) * self._onfwd_rates
66-
)
64+
self._logdfs = -np.cumsum(np.diff(self._times, prepend=0.0) * self._onfwd_rates)
6765
self._logdfs_interp = interpolate.interp1d(
6866
np.concatenate(([0.0], self._times)),
6967
np.concatenate(([0.0], self._logdfs)),
@@ -103,9 +101,7 @@ def brick_wall_curve(
103101
###############################################################################
104102

105103
@classmethod
106-
def flat_curve(
107-
cls, valuation_date: Date, level: float = 1.0 * g_basis_point
108-
):
104+
def flat_curve(cls, valuation_date: Date, level: float = 1.0 * g_basis_point):
109105
knot_dates = [valuation_date.add_tenor("1Y")]
110106
onfwd_rates = [level]
111107
return cls(valuation_date, knot_dates, onfwd_rates)
@@ -139,7 +135,7 @@ def df_t(self, t: Union[float, np.ndarray]):
139135
zero_rates = self._zero_rate(t)
140136

141137
df = self._zero_to_df(
142-
self.value_dt, zero_rates, t, self._freq_type, self._day_count_type
138+
self.value_dt, zero_rates, t, self.freq_type, self.dc_type
143139
)
144140

145141
return df
@@ -152,7 +148,7 @@ def __repr__(self):
152148
s += label_to_string("DATE", "ONWD RATE")
153149
for i in range(0, len(self._knot_dates)):
154150
s += label_to_string(self._knot_dates[i], self._onfwd_rates[i])
155-
s += label_to_string("FREQUENCY", (self._freq_type))
151+
s += label_to_string("FREQUENCY", (self.freq_type))
156152
return s
157153

158154
###############################################################################

financepy/market/volatility/fx_vol_surface.py

Lines changed: 19 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,6 @@ def obj_fast(params, *args):
165165

166166
# sum up the errors
167167
err = term1 + term2 + term3
168-
169168
return err
170169

171170

@@ -339,9 +338,7 @@ def delta_fit(K, *args):
339338

340339
f = s * np.exp((r_d - r_f) * t)
341340
v = vol_function(vol_type_value, params, f, K, t)
342-
delta_out = fast_delta(
343-
s, t, K, r_d, r_f, v, delta_type_value, option_type_value
344-
)
341+
delta_out = fast_delta(s, t, K, r_d, r_f, v, delta_type_value, option_type_value)
345342
inverse_delta_out = norminvcdf(np.abs(delta_out))
346343
inv_obj_fn = inverse_delta_target - inverse_delta_out
347344

@@ -398,9 +395,7 @@ def solver_for_smile_strike_fast(
398395
parameters,
399396
)
400397

401-
K = newton_secant(
402-
delta_fit, x0=initial_guess, args=argtuple, tol=1e-8, maxiter=50
403-
)
398+
K = newton_secant(delta_fit, x0=initial_guess, args=argtuple, tol=1e-8, maxiter=50)
404399

405400
return K
406401

@@ -410,9 +405,7 @@ def solver_for_smile_strike_fast(
410405

411406

412407
@njit(
413-
float64(
414-
float64, float64, float64, float64, int64, float64, int64, float64
415-
),
408+
float64(float64, float64, float64, float64, int64, float64, int64, float64),
416409
fastmath=True,
417410
)
418411
def solve_for_strike(
@@ -454,9 +447,7 @@ def solve_for_strike(
454447
vsqrtt = volatility * np.sqrt(t_del)
455448
arg = delta_target * phi / for_df # CHECK THIS !!!
456449
norm_inv_delta = norminvcdf(arg)
457-
K = fwd_fx_rate * np.exp(
458-
-vsqrtt * (phi * norm_inv_delta - vsqrtt / 2.0)
459-
)
450+
K = fwd_fx_rate * np.exp(-vsqrtt * (phi * norm_inv_delta - vsqrtt / 2.0))
460451
return K
461452

462453
elif delta_method_value == FinFXDeltaMethod.FORWARD_DELTA.value:
@@ -473,9 +464,7 @@ def solve_for_strike(
473464
vsqrtt = volatility * np.sqrt(t_del)
474465
arg = delta_target * phi # CHECK THIS!!!!!!!!
475466
norm_inv_delta = norminvcdf(arg)
476-
K = fwd_fx_rate * np.exp(
477-
-vsqrtt * (phi * norm_inv_delta - vsqrtt / 2.0)
478-
)
467+
K = fwd_fx_rate * np.exp(-vsqrtt * (phi * norm_inv_delta - vsqrtt / 2.0))
479468
return K
480469

481470
elif delta_method_value == FinFXDeltaMethod.SPOT_DELTA_PREM_ADJ.value:
@@ -491,9 +480,7 @@ def solve_for_strike(
491480
delta_target,
492481
)
493482

494-
K = newton_secant(
495-
g, x0=spot_fx_rate, args=argtuple, tol=1e-7, maxiter=50
496-
)
483+
K = newton_secant(g, x0=spot_fx_rate, args=argtuple, tol=1e-7, maxiter=50)
497484

498485
return K
499486

@@ -510,9 +497,7 @@ def solve_for_strike(
510497
delta_target,
511498
)
512499

513-
K = newton_secant(
514-
g, x0=spot_fx_rate, args=argtuple, tol=1e-7, maxiter=50
515-
)
500+
K = newton_secant(g, x0=spot_fx_rate, args=argtuple, tol=1e-7, maxiter=50)
516501

517502
return K
518503

@@ -540,7 +525,7 @@ def __init__(
540525
domestic_curve: DiscountCurve,
541526
foreign_curve: DiscountCurve,
542527
tenors: list,
543-
atm_vols: (list, np.ndarray),
528+
atm_vols: [list, np.ndarray],
544529
ms_25_delta_vols: (list, np.ndarray),
545530
rr_25_delta_vols: (list, np.ndarray),
546531
atm_method: FinFXATMMethod = FinFXATMMethod.FWD_DELTA_NEUTRAL,
@@ -641,29 +626,23 @@ def volatility(self, K, expiry_dt):
641626
# The volatility term structure is flat if there is only one expiry
642627
fwd = self.fwd[0]
643628
t_exp = self.t_exp[0]
644-
vol = vol_function(
645-
vol_type_value, self.parameters[0], fwd, K, t_exp
646-
)
629+
vol = vol_function(vol_type_value, self.parameters[0], fwd, K, t_exp)
647630
return vol
648631

649632
# If the time is below first time then assume a flat vol
650633
if t <= self.t_exp[0]:
651634

652635
fwd = self.fwd[0]
653636
t_exp = self.t_exp[0]
654-
vol = vol_function(
655-
vol_type_value, self.parameters[0], fwd, K, t_exp
656-
)
637+
vol = vol_function(vol_type_value, self.parameters[0], fwd, K, t_exp)
657638
return vol
658639

659640
# If the time is beyond the last time then extrapolate with a flat vol
660641
if t > self.t_exp[-1]:
661642

662643
fwd = self.fwd[-1]
663644
t_exp = self.t_exp[-1]
664-
vol = vol_function(
665-
vol_type_value, self.parameters[-1], fwd, K, t_exp
666-
)
645+
vol = vol_function(vol_type_value, self.parameters[-1], fwd, K, t_exp)
667646
return vol
668647

669648
for i in range(1, num_curves):
@@ -675,15 +654,11 @@ def volatility(self, K, expiry_dt):
675654

676655
fwd0 = self.fwd[index0]
677656
t0 = self.t_exp[index0]
678-
vol0 = vol_function(
679-
vol_type_value, self.parameters[index0], fwd0, K, t0
680-
)
657+
vol0 = vol_function(vol_type_value, self.parameters[index0], fwd0, K, t0)
681658

682659
fwd1 = self.fwd[index1]
683660
t1 = self.t_exp[index1]
684-
vol1 = vol_function(
685-
vol_type_value, self.parameters[index1], fwd1, K, t1
686-
)
661+
vol1 = vol_function(vol_type_value, self.parameters[index1], fwd1, K, t1)
687662

688663
vart0 = vol0 * vol0 * t0
689664
vart1 = vol1 * vol1 * t1
@@ -1046,8 +1021,7 @@ def check_calibration(self, verbose: bool, tol: float = 1e-6):
10461021

10471022
print("======================================================")
10481023
print(
1049-
"MKT STRANGLE VOL IN: %9.6f %%"
1050-
% (100.0 * self.ms_25_delta_vols[i])
1024+
"MKT STRANGLE VOL IN: %9.6f %%" % (100.0 * self.ms_25_delta_vols[i])
10511025
)
10521026

10531027
call.strike_fx_rate = self.k_25d_c_ms[i]
@@ -1253,16 +1227,12 @@ def check_calibration(self, verbose: bool, tol: float = 1e-6):
12531227
sigma_RR = sigma_k_25d_c - sigma_k_25d_p
12541228

12551229
if verbose:
1256-
print(
1257-
"========================================================="
1258-
)
1230+
print("=========================================================")
12591231
print(
12601232
"RR = VOL_K_25_C - VOL_K_25_P => RR_IN: %9.6f %% RR_OUT: %9.6f %%"
12611233
% (100.0 * self.rr_25_delta_vols[i], 100.0 * sigma_RR)
12621234
)
1263-
print(
1264-
"========================================================="
1265-
)
1235+
print("=========================================================")
12661236

12671237
diff = sigma_RR - self.rr_25_delta_vols[i]
12681238

@@ -1318,9 +1288,7 @@ def implied_dbns(self, low_fx, high_fx, num_intervals):
13181288
Ks = np.array(Ks)
13191289
vols = np.array(vols)
13201290

1321-
density = option_implied_dbn(
1322-
self.spot_fx_rate, t_exp, r_d, r_f, Ks, vols
1323-
)
1291+
density = option_implied_dbn(self.spot_fx_rate, t_exp, r_d, r_f, Ks, vols)
13241292

13251293
dbn = FinDistribution(Ks, density)
13261294
dbns.append(dbn)
@@ -1368,9 +1336,7 @@ def plot_vol_curves(self):
13681336
plt.xlabel("Strike")
13691337
plt.ylabel("Volatility")
13701338

1371-
title = (
1372-
"25d FIT:" + self.currency_pair + " " + str(self.vol_func_type)
1373-
)
1339+
title = "25d FIT:" + self.currency_pair + " " + str(self.vol_func_type)
13741340

13751341
key_strikes = []
13761342
key_strikes.append(self.k_atm[tenor_index])
@@ -1403,7 +1369,7 @@ def plot_vol_curves(self):
14031369
###########################################################################
14041370

14051371
def __repr__(self):
1406-
s = label_to_string("OBJECT TYPE", type(self)._name__)
1372+
s = label_to_string("OBJECT TYPE", type(self).__name__)
14071373
s += label_to_string("VALUE DATE", self.value_dt)
14081374
s += label_to_string("FX RATE", self.spot_fx_rate)
14091375
s += label_to_string("CCY PAIR", self.currency_pair)

0 commit comments

Comments
 (0)