Skip to content

Commit ffbf3f0

Browse files
committed
Added test, improved
1 parent f74f064 commit ffbf3f0

File tree

2 files changed

+30
-2
lines changed

2 files changed

+30
-2
lines changed

pyfeng/multiasset.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ def price(self, strike, spot, texp, cp=1):
288288

289289
class BsmBasket1Bm(opt.OptABC):
290290
"""
291-
Basket/Spread option when all asset prices are driven by a single
291+
Multiasset BSM model for pricing basket/Spread options when all asset prices are driven by a single Brownian motion (BM).
292292
293293
"""
294294

@@ -351,12 +351,16 @@ def root(fac, std, strike):
351351
x[y_max <= 0] = np.inf
352352
ind = ~((y_min >= 0) | (y_max <= 0))
353353

354+
if np.all(~ind):
355+
return x[0] if scalar_output else x
356+
354357
for k in range(32):
355358
y_vec = fac * np.exp(std * x[ind, None])
356359
y = np.log(np.sum(y_vec, axis=-1)) - log_k[ind] if log else np.sum(y_vec, axis=-1) - strike[ind]
357360
dy = np.sum(std * y_vec, axis=-1) / np.sum(y_vec, axis=-1) if log else np.sum(std * y_vec, axis=-1)
358361
x[ind] -= y / dy
359-
362+
if len(y) == 0:
363+
print(ind, y_vec, y)
360364
y_err_max = np.amax(np.abs(y))
361365
if y_err_max < BsmBasket1Bm.IMPVOL_TOL:
362366
break

tests/test_multiasset.py

+24
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,30 @@ def test_BsmNormNdMc(self):
129129
p2 = np.array([39.42304794, 33.60383167, 28.32667559, 23.60383167, 19.42304794])
130130
np.testing.assert_almost_equal(p, p2)
131131

132+
def test_BsmBasket1Bm(self):
133+
### Check the BsmBasket1Bm price should be same as that of the Bsm price if sigma components are same.
134+
for k in range(100):
135+
n = np.random.randint(1, 8)
136+
spot = np.random.uniform(80, 120, size=n)
137+
strike = np.random.uniform(80, 120, size=10)
138+
sigma = np.random.uniform(0.01, 1)*np.ones(n)
139+
texp = np.random.uniform(0.1, 10)
140+
intr = np.random.uniform(0, 0.1)
141+
divr = np.random.uniform(0, 0.1)
142+
weight = np.random.rand(n)
143+
weight /= np.sum(weight)
144+
145+
cp = np.where(np.random.rand(10) > 0.5, 1, -1)
146+
is_fwd = (np.random.rand() > 0.5)
147+
148+
m = pf.BsmBasket1Bm(sigma, weight=weight, intr=intr, divr=divr, is_fwd=is_fwd)
149+
p = m.price(strike, spot, texp, cp)
150+
151+
m2 = pf.Bsm(sigma[0], intr=intr, divr=divr, is_fwd=is_fwd)
152+
p2 = m2.price(strike, np.sum(spot*weight), texp, cp)
153+
np.testing.assert_almost_equal(p, p2)
154+
155+
132156

133157
if __name__ == '__main__':
134158
print(f'Pyfeng loaded from {pf.__path__}')

0 commit comments

Comments
 (0)