Пример #1
0
    def test_black_scholes_formula(self):
        S, K, r, q, sig, T = 100, 100, 0.02, 0.03, 0.2, 0.5
        F = S * np.exp((r - q) * T)
        df = np.exp(-r * T)
        ans = get_european_call_bs(S, K, r, q, sig, T)
        self.assertAlmostEqual(ans, 5.323767401196562, 11)

        ans = get_european_put_bs(S, K, r, q, sig, T)
        self.assertAlmostEqual(ans, 5.817556815807109, 11)
Пример #2
0
    def test_douglas_scheme(self):

        s1, q1, sig1 = 90, 0, 0.3
        s2, q2, sig2 = 110, 0, 0.4
        r = 0.01
        t = 0.4

        eq1 = EquityFactor('AAPL', s1, q1, sig1)
        eq2 = EquityFactor('MSFT', s2, q2, sig2)
        sec = ExchangeOption(eq1, eq2, t)

        # positive correlation
        rho = 0.4
        pde = BlackScholesPDE2D(eq1, eq2, r, rho)
        engine = FiniteDifferenceEngine(sec, pde, DouglasScheme())
        vals, states = engine.price({
            't': 50,
            'AAPL': 200,
            'MSFT': 210
        },
                                    scale=5)
        f = interp2d(states['MSFT'], states['AAPL'], vals)
        ans = f(s2, s1)[0]
        expected = get_european_call_bs(
            s1, s2, 0, 0, np.sqrt(sig1**2 + sig2**2 - 2 * rho * sig1 * sig2),
            t)
        assert_allclose(ans, expected, atol=0, rtol=0.0005)

        # negative correlation
        rho = -0.4
        pde = BlackScholesPDE2D(eq1, eq2, r, rho)
        engine = FiniteDifferenceEngine(sec, pde, DouglasScheme())
        vals, states = engine.price({
            't': 50,
            'AAPL': 200,
            'MSFT': 210
        },
                                    scale=5)
        f = interp2d(states['MSFT'], states['AAPL'], vals)
        ans = f(s2, s1)[0]
        expected = get_european_call_bs(
            s1, s2, 0, 0, np.sqrt(sig1**2 + sig2**2 - 2 * rho * sig1 * sig2),
            t)
        assert_allclose(ans, expected, atol=0, rtol=0.002)
Пример #3
0
    def test_black_scholes(self):
        m = 100  # time steps
        n = 600

        asset = 'AAPL'
        s, k = 248, 300
        r, q, sig, t = 254 / s - 1, 0, 0.72, 0.25

        sec = EuropeanCall(asset=asset, strike=k, tenor=t)
        pde = BlackScholesPDE1D(asset=asset, spot=s, r=r, q=q, sig=sig)
        engine = FiniteDifferenceEngine(sec, pde, CrankNicolsonScheme())
        ans, states = engine.price({'t': m, asset: n}, scale=5)
        xs = states[asset]
        mask = (xs > k * 0.8) & (xs < k * 1.2)
        ans = ans[mask]
        xs = xs[mask]
        expected = [get_european_call_bs(x, k, r, q, sig, t) for x in xs]
        assert_allclose(ans, expected, atol=0, rtol=0.0005)
Пример #4
0
    def test_european(self):
        s = 100
        k = 100
        r = 0.02
        q = 0.05
        sig = 0.3
        t = 1
        m = 1
        n = int(1E7)

        # test call and put
        secs = [EuropeanCall('stock', k, t), EuropeanPut('stock', k, t)]
        bs = BlackScholes(spot=s, interest=r, dividend=q, volatility=sig)
        engine = MonteCarloEngine(secs, model=bs)
        price = engine.price(m, n)
        actual = [
            get_european_call_bs(s, k, r, q, sig, t),
            get_european_put_bs(s, k, r, q, sig, t)
        ]
        assert_allclose(actual, price, rtol=1e-4,
                        atol=1e-2)  # test both relative diff and absolute diff
Пример #5
0
    def test_american_to_bs(self):
        """
        American call and put without interest and dividend should equal Black Scholes prices
        """
        s = 100
        k = 100
        r = 0
        q = 0
        sig = 0.3
        t = 1
        m = 50
        n = int(1E5)

        # American options without interest and dividend should equal Black Scholes prices
        secs = [AmericanCall('stock', k, t), AmericanPut('stock', k, t)]
        bs = BlackScholes(spot=s, interest=r, dividend=q, volatility=sig)
        lasso = LASSOFitter()
        engine = MonteCarloEngine(secs, model=bs, fitter=lasso)
        price = engine.price(m, n)
        actual = [
            get_european_call_bs(s, k, r, q, sig, t),
            get_european_put_bs(s, k, r, q, sig, t)
        ]
        assert_allclose(actual, price, rtol=0.01, atol=0.1)
Пример #6
0
    a22 = build_a22(r, q1, sig1, q2, sig2, xs, ys)
    a2 = a21 + a22

    a0 = build_a_mixed(rho, r, q1, sig1, q2, sig2, xs, ys)
    bounds = build_boundaries(r, q1, sig1, q2, sig2, xs, ys)

    start = time.time()
    for i in range(n_steps):
        curr = step(prev, dt, a0, a1, a2)
        prev = curr
        print(i)
    curr = curr.reshape(m, n)
    print(f'{time.time() - start:.2f}s')

    f = interp2d(ys, xs, curr)
    diff = []

    for x in np.linspace(s1 / np.exp(2 * sig1 * np.sqrt(t)),
                         s1 * np.exp(2 * sig1 * np.sqrt(t)), 10):
        for y in np.linspace(s2 / np.exp(2 * sig2 * np.sqrt(t)),
                             s2 * np.exp(2 * sig2 * np.sqrt(t)), 10):
            ans = f(y, x)[0]
            expected = get_european_call_bs(
                x, y, 0, 0, np.sqrt(sig1**2 + sig2**2 - 2 * rho * sig1 * sig2),
                t)
            diff.append(ans - expected)

    diff = np.array(diff)
    # print(diff)
    print(np.sqrt(np.sum(diff**2)))
Пример #7
0
    def _setup_boundary_conditions_(self):
        super(CNEu, self)._setup_boundary_conditions_()
        self.coeffs_[0, 0] -= 2 * self.alpha[0]
        self.coeffs_[0, 1] += self.alpha[0]
        self.coeffs_[-1, -1] -= 2 * self.gamma[-1]
        self.coeffs_[-1, -2] += self.gamma[-1]

    def _traverse_grid_(self):
        P, L, U = linalg.lu(self.coeffs_)
        for j in reversed(self.jValues):
            Ux = linalg.solve(L, np.dot(self.coeffs, self.grid[1:-1, j + 1]))
            self.grid[1:-1, j] = linalg.solve(U, Ux)
            self.grid[0, j] = 2 * self.grid[1, j] - self.grid[2, j]
            self.grid[-1, j] = 2 * self.grid[-2, j] - self.grid[-3, j]


S0 = 248
K = 300
r = 254 / S0 - 1
T = 0.25
sigma = 0.72
Smax = 1000
M = 100  # S
N = 1000  # t
is_call = True

option = CNEu(S0, K, r, T, sigma, Smax, M, N, is_call)
print(option.price())
print(get_european_call_bs(S0, K, r, 0, sigma, T))