예제 #1
0
 def __init__(self, sigma, vov=0, rho=0.0, beta=1.0, intr=0, divr=0):
     self.sigma = sigma
     self.vov = vov
     self.rho = rho
     self.intr = intr
     self.divr = divr
     self.bsm_model = pf.Bsm(sigma, intr=intr, divr=divr)
예제 #2
0
    def test_BsmBasket1Bm(self):
        ### Check the BsmBasket1Bm price should be same as that of the Bsm price if sigma components are same.
        for k in range(100):
            n = np.random.randint(1, 8)
            spot = np.random.uniform(80, 120, size=n)
            strike = np.random.uniform(80, 120, size=10)
            sigma = np.random.uniform(0.01, 1) * np.ones(n)
            texp = np.random.uniform(0.1, 10)
            intr = np.random.uniform(0, 0.1)
            divr = np.random.uniform(0, 0.1)
            weight = np.random.rand(n)
            weight /= np.sum(weight)

            cp = np.where(np.random.rand(10) > 0.5, 1, -1)
            is_fwd = (np.random.rand() > 0.5)

            m = pf.BsmBasket1Bm(sigma,
                                weight=weight,
                                intr=intr,
                                divr=divr,
                                is_fwd=is_fwd)
            p = m.price(strike, spot, texp, cp)

            m2 = pf.Bsm(sigma[0], intr=intr, divr=divr, is_fwd=is_fwd)
            p2 = m2.price(strike, np.sum(spot * weight), texp, cp)
            np.testing.assert_almost_equal(p, p2)
예제 #3
0
 def test_bsm_price(self):
     bsm = pf.Bsm(sigma=0.2, intr=0.05, divr=0.1)
     result = bsm.price(strike=np.arange(80, 126, 5), spot=100, texp=1.2)
     expect_result = np.array([
         15.71361973, 12.46799006, 9.69250803, 7.38869609, 5.52948546,
         4.06773495, 2.94558338, 2.10255008, 1.48139131, 1.03159130
     ])
     np.testing.assert_almost_equal(result, expect_result)
예제 #4
0
    def test_BsmDisp(self):
        strike = np.arange(80, 126, 5)
        dbs = pf.BsmDisp(sigma=0.2, beta=1, pivot=125, intr=0.05, divr=0.1)

        # DBS = BSM if beta=1
        bsm = pf.Bsm(sigma=dbs.sigma_disp, intr=0.05, divr=0.1)
        r1 = bsm.price(strike, 100, 2.5, cp=-1)
        r2 = dbs.price(strike, 100, 2.5, cp=-1)
        np.testing.assert_almost_equal(r1, r2)

        # DBS = Norm if beta=0
        dbs.beta = 0.0001
        dbs.is_fwd = True
        norm = pf.Norm(sigma=dbs.sigma_disp * dbs.pivot,
                       intr=0.05,
                       divr=0.1,
                       is_fwd=True)
        r1 = norm.price(strike, 100, 2.5, cp=-1)
        r2 = dbs.price(strike, 100, 2.5, cp=-1)
        np.testing.assert_almost_equal(r1 / r2, 1, decimal=4)
        dbs.is_fwd = False

        # Approximate BSM vol
        dbs.beta = 0.2
        v1 = dbs.vol_smile(strike, 100, 2.5, model='bsm')
        v2 = dbs.vol_smile(strike, 100, 2.5, model='bsm-approx')
        np.testing.assert_almost_equal(v1 / v2, 1, decimal=4)

        p1 = dbs.price(strike, 100, 2.5)
        p2 = pf.Bsm(v1, intr=0.05, divr=0.1).price(strike, 100, 2.5)
        np.testing.assert_almost_equal(p1, p2)

        # Approximate Bachelier vol
        dbs.beta = 0.8
        v1 = dbs.vol_smile(strike, 100, 2.5, model='norm')
        v2 = dbs.vol_smile(strike, 100, 2.5, model='norm-approx')
        np.testing.assert_almost_equal(v1 / v2, 1, decimal=4)

        p1 = dbs.price(strike, 100, 2.5)
        p2 = pf.Norm(v1, intr=0.05, divr=0.1).price(strike, 100, 2.5)
        np.testing.assert_almost_equal(p1, p2)
예제 #5
0
    def test_bsm_iv_greeks(self):
        for k in range(100):
            spot = np.random.uniform(80, 120)
            strike = np.random.uniform(80, 120)
            sigma = np.random.uniform(0.1, 10)
            texp = np.random.uniform(0.1, 10)
            intr = np.random.uniform(0, 0.3)
            divr = np.random.uniform(0, 0.3)
            cp = 1 if np.random.rand() > 0.5 else -1
            is_fwd = (np.random.rand() > 0.5)

            # print( spot, strike, vol, texp, intr, divr, cp)
            m_bsm = pf.Bsm(sigma, intr=intr, divr=divr, is_fwd=is_fwd)
            price = m_bsm.price(strike, spot, texp, cp),

            # get implied vol
            iv = m_bsm.impvol(price, strike, spot, texp=texp, cp=cp)

            # now price option with the obtained implied vol
            m_bsm2 = copy.copy(m_bsm)
            m_bsm2.sigma = iv
            price_imp = m_bsm2.price(strike, spot, texp, cp)

            # compare the two prices
            self.assertAlmostEqual(price,
                                   price_imp,
                                   delta=200 * m_bsm.IMPVOL_TOL)

            delta1 = m_bsm.delta(strike=strike, spot=spot, texp=texp, cp=cp)
            delta2 = m_bsm.delta_numeric(strike=strike,
                                         spot=spot,
                                         texp=texp,
                                         cp=cp)
            self.assertAlmostEqual(delta1, delta2, delta=1e-4)

            gamma1 = m_bsm.delta(strike=strike, spot=spot, texp=texp, cp=cp)
            gamma2 = m_bsm.delta_numeric(strike=strike,
                                         spot=spot,
                                         texp=texp,
                                         cp=cp)
            self.assertAlmostEqual(gamma1, gamma2, delta=1e-4)

            vega1 = m_bsm.vega(strike=strike, spot=spot, texp=texp, cp=cp)
            vega2 = m_bsm.vega_numeric(strike=strike,
                                       spot=spot,
                                       texp=texp,
                                       cp=cp)
            self.assertAlmostEqual(vega1, vega2, delta=1e-3)
예제 #6
0
파일: sabr.py 프로젝트: chenyingong/ASP
class ModelBsmMC:
    beta = 1.0   # fixed (not used)
    vov, rho = 0.0, 0.0
    sigma, intr, divr = None, None, None
    bsm_model = None
    '''
    You may define more members for MC: time step, etc
    '''
    
    def __init__(self, sigma, vov=0, rho=0.0, beta=1.0, intr=0, divr=0, time_steps=1_000, n_samples=10_000):
        self.sigma = sigma
        self.vov = vov
        self.rho = rho
        self.intr = intr
        self.divr = divr
        self.time_steps = time_steps
        self.n_samples = n_samples
        self.bsm_model = pf.Bsm(sigma, intr=intr, divr=divr)
예제 #7
0
파일: sv32_mc.py 프로젝트: daifengqi/PyFENG
    def price(
        self,
        strike,
        spot,
        texp,
        sigma,
        delta,
        intr=0,
        divr=0,
        psi_c=1.5,
        path=10000,
        scheme="QE",
        seed=None,
    ):
        """
        Conditional MC routine for 3/2 model
        Generate paths for vol only using QE discretization scheme.
        Compute integrated variance and get BSM prices vector for all strikes.

        Args:
            strike: strike price, in vector form
            spot: spot (or forward)
            texp: time to expiry
            sigma: initial volatility
            delta: length of each time step
            intr: interest rate (domestic interest rate)
            divr: dividend/convenience yield (foreign interest rate)
            psi_c: critical value for psi, lying in [1, 2]
            path: number of vol paths generated
            scheme: discretization scheme for vt, {'QE', 'TG', 'Euler', 'Milstein', 'KJ'}
            seed: random seed for rv generation

        Return:
            BSM price vector for all strikes
        """
        self.sigma = sigma
        self.bsm_model = pf.Bsm(self.sigma, intr=intr, divr=divr)
        self.delta = delta
        self.path = int(path)
        self.step = int(texp / self.delta)

        # xt = 1 / vt
        xt = 1 / self.sigma**2 * np.ones([self.path, self.step + 1])
        np.random.seed(seed)

        # equivalent kappa and theta for xt to follow a Heston model
        kappa_new = self.kappa * self.theta
        theta_new = (self.kappa + self.vov**2) / (self.kappa * self.theta)
        vov_new = -self.vov
        if scheme == "QE":
            u = np.random.uniform(size=(self.path, self.step))

            expo = np.exp(-kappa_new * self.delta)
            for i in range(self.step):
                # compute m, s_square, psi given xt(i)
                m = theta_new + (xt[:, i] - theta_new) * expo
                s2 = xt[:, i] * (vov_new**2) * expo * (
                    1 - expo) / kappa_new + theta_new * (vov_new**2) * (
                        (1 - expo)**2) / (2 * kappa_new)
                psi = s2 / m**2

                # compute xt(i+1) given psi
                below = np.where(psi <= psi_c)[0]
                ins = 2 * psi[below]**-1
                b2 = ins - 1 + np.sqrt(ins * (ins - 1))
                b = np.sqrt(b2)
                a = m[below] / (1 + b2)
                z = spst.norm.ppf(u[below, i])
                xt[below, i + 1] = a * (b + z)**2

                above = np.where(psi > psi_c)[0]
                p = (psi[above] - 1) / (psi[above] + 1)
                beta = (1 - p) / m[above]
                for k in range(len(above)):
                    if u[above[k], i] > p[k]:
                        xt[above[k], i + 1] = beta[k]**-1 * np.log(
                            (1 - p[k]) / (1 - u[above[k], i]))
                    else:
                        xt[above[k], i + 1] = 0

        elif scheme == "TG":
            if np.all(self.rx_results) == None:
                self.psi_points, self.rx_results = self.prepare_rx()

            expo = np.exp(-self.kappa * self.delta)
            for i in range(self.step):
                # compute m, s_square, psi given vt(i)
                m = theta_new + (xt[:, i] - theta_new) * expo
                s2 = xt[:, i] * (vov_new**2) * expo * (
                    1 - expo) / kappa_new + theta_new * (vov_new**2) * (
                        (1 - expo)**2) / (2 * kappa_new)
                psi = s2 / m**2

                rx = np.array([self.find_rx(j) for j in psi])

                z = np.random.normal(size=(self.path, self.step))
                mu_v = np.zeros_like(z)
                sigma_v = np.zeros_like(z)
                mu_v[:,
                     i] = rx * m / (spst.norm.pdf(rx) + rx * spst.norm.cdf(rx))
                sigma_v[:, i] = (np.sqrt(s2) * psi**(-0.5) /
                                 (spst.norm.pdf(rx) + rx * spst.norm.cdf(rx)))

                xt[:, i + 1] = np.fmax(mu_v[:, i] + sigma_v[:, i] * z[:, i], 0)

        elif scheme == "Euler":
            z = np.random.normal(size=(self.path, self.step))
            for i in range(self.step):
                xt[:, i +
                   1] = (xt[:, i] + kappa_new *
                         (theta_new - np.max(xt[:, i], 0)) * self.delta +
                         vov_new * np.sqrt(np.max(xt[:, i], 0) * self.delta) *
                         z[:, i])

        elif scheme == "Milstein":
            z = np.random.normal(size=(self.path, self.step))
            for i in range(self.step):
                xt[:, i +
                   1] = (xt[:, i] + kappa_new *
                         (theta_new - np.max(xt[:, i], 0)) * self.delta +
                         vov_new * np.sqrt(np.max(xt[:, i], 0) * self.delta) *
                         z[:, i] + vov_new**2 * 0.25 *
                         (z[:, i]**2 - 1) * self.delta)

        elif scheme == "KJ":
            z = np.random.normal(size=(self.path, self.step))
            for i in range(self.step):
                xt[:, i +
                   1] = (xt[:, i] + kappa_new * theta_new * self.delta +
                         vov_new * np.sqrt(np.max(xt[:, i], 0) * self.delta) *
                         z[:, i] + vov_new**2 * 0.25 *
                         (z[:, i]**2 - 1) * self.delta) / (
                             1 + kappa_new * self.delta)

        # compute integral of vt, equivalent spot and vol
        vt = 1 / xt
        below_0 = np.where(vt < 0)
        vt[below_0] = 0
        vt_int = spint.simps(vt, dx=self.delta)

        spot_cmc = spot * np.exp(self.rho / self.vov *
                                 (np.log(vt[:, -1] / vt[:, 0]) - self.kappa *
                                  (self.theta * texp - vt_int *
                                   (1 + self.vov**2 * 0.5 / self.kappa))) -
                                 self.rho**2 * vt_int / 2)
        vol_cmc = np.sqrt((1 - self.rho**2) * vt_int / texp)

        # compute bsm price vector for the given strike vector
        price_cmc = np.zeros_like(strike)
        for j in range(len(strike)):
            price_cmc[j] = np.mean(
                self.bsm_model.price_formula(strike[j],
                                             spot_cmc,
                                             vol_cmc,
                                             texp,
                                             intr=intr,
                                             divr=divr))

        return price_cmc