예제 #1
0
def _blsimpv(price, spot, strike, risk_free_rate, time, option_type, dividend):

    spot = SimpleQuote(spot)
    daycounter = ActualActual(ISMA)
    risk_free_ts = FlatForward(today(), risk_free_rate, daycounter)
    dividend_ts = FlatForward(today(), dividend, daycounter)
    volatility_ts = BlackConstantVol(today(), NullCalendar(), .3, daycounter)

    process = BlackScholesMertonProcess(spot, dividend_ts, risk_free_ts,
                                        volatility_ts)

    exercise_date = today() + Period(time * 365, Days)
    exercise = EuropeanExercise(exercise_date)

    payoff = PlainVanillaPayoff(option_type, strike)

    option = EuropeanOption(payoff, exercise)
    engine = AnalyticEuropeanEngine(process)
    option.set_pricing_engine(engine)

    accuracy = 0.001
    max_evaluations = 1000
    min_vol = 0.01
    max_vol = 2

    vol = option.implied_volatility(price, process, accuracy, max_evaluations,
                                    min_vol, max_vol)

    return vol
예제 #2
0
def _blsprice(spot,
              strike,
              risk_free_rate,
              time,
              volatility,
              option_type='Call',
              dividend=0.0,
              calc='price'):
    """
    Black-Scholes option pricing model + greeks.
    """
    _spot = SimpleQuote(spot)

    daycounter = ActualActual(ISMA)
    risk_free_ts = FlatForward(today(), risk_free_rate, daycounter)
    dividend_ts = FlatForward(today(), dividend, daycounter)
    volatility_ts = BlackConstantVol(today(), NullCalendar(), volatility,
                                     daycounter)

    process = BlackScholesMertonProcess(_spot, dividend_ts, risk_free_ts,
                                        volatility_ts)

    exercise_date = today() + Period(time * 365, Days)
    exercise = EuropeanExercise(exercise_date)

    payoff = PlainVanillaPayoff(option_type, strike)

    option = EuropeanOption(payoff, exercise)
    engine = AnalyticEuropeanEngine(process)
    option.set_pricing_engine(engine)

    if calc == 'price':
        res = option.npv
    elif calc == 'delta':
        res = option.delta
    elif calc == 'gamma':
        res = option.gamma
    elif calc == 'theta':
        res = option.theta
    elif calc == 'rho':
        res = option.rho
    elif calc == 'vega':
        res = option.vega
    elif calc == 'lambda':
        res = option.delta * spot / option.npv
    else:
        raise ValueError('calc type %s is unknown' % calc)

    return res
예제 #3
0
    def test_mc_variance_swap(self):
        """ test mc variance engine vs expected result
        """

        vols = []
        dates = []

        interm_date = self.today + int(0.1 * 365 + 0.5)
        exercise = EuropeanExercise(self.ex_date)

        dates.append(interm_date)
        dates.append(self.ex_date)

        vols.append(0.1)
        vols.append(self.values['v'])

        # Exercising code using BlackVarianceCurve because BlackVarianceSurface
        # is unreliable. Result should be v*v for arbitrary t1 and v1
        # (as long as 0<=t1<t and 0<=v1<v)

        vol_ts = BlackVarianceCurve(self.today, dates, vols, self.dc, True)

        stoch_process = BlackScholesMertonProcess(self.spot, self.q_ts,
                                                  self.r_ts, vol_ts)

        engine = MCVarianceSwapEngine(
            stoch_process,
            time_steps_per_year=250,
            required_samples=1023,
            seed=42,
        )

        variance_swap = VarianceSwap(
            self.values['type'],
            self.values['strike'],
            self.values['nominal'],
            self.today,
            self.ex_date,
        )

        variance_swap.set_pricing_engine(engine)

        calculated = variance_swap.variance
        expected = 0.04
        tol = 3.0e-4
        error = abs(calculated - expected)
        self.assertTrue(error < tol)
    def setUp(self):

        self.settings = Settings()

        self.calendar = NullCalendar()

        self.todays_date = Date(15, May, 1998)
        self.settlement_date = Date(17, May, 1998)

        self.settings.evaluation_date = self.todays_date

        # options parameters
        self.dividend_yield = 0.00
        self.risk_free_rate = 0.06
        self.volatility = 0.25
        self.spot = SimpleQuote(100)
        self.maturity = Date(17, May, 1999)
        self.daycounter = Actual365Fixed()
        self.tol = 1e-2

        # bootstrap the yield/dividend/vol curves
        dates = [self.settlement_date] + \
                [self.settlement_date + Period(i + 1, Years)
                 for i in range(40)]
        rates = [0.01] + \
            [0.01 + 0.0002 * np.exp(np.sin(i / 4.0)) for i in range(40)]
        divRates = [0.02] + \
                   [0.02 + 0.0001 * np.exp(np.sin(i / 5.0)) for i in range(40)]

        self.r_ts = ZeroCurve(dates, rates, self.daycounter)
        self.q_ts = ZeroCurve(dates, divRates, self.daycounter)

        self.vol_ts = BlackConstantVol(
            self.settlement_date,
            self.calendar,
            self.volatility,
            self.daycounter
        )

        self.black_scholes_merton_process = BlackScholesMertonProcess(
            self.spot,
            self.q_ts,
            self.r_ts,
            self.vol_ts
        )

        self.dates = dates
예제 #5
0
def blsprice(spot, strike, risk_free_rate, time, volatility, option_type='Call', dividend=0.0):
    """ """
    spot = SimpleQuote(spot)

    daycounter = Actual360()
    risk_free_ts = FlatForward(today(), risk_free_rate, daycounter)
    dividend_ts = FlatForward(today(), dividend, daycounter)
    volatility_ts = BlackConstantVol(today(), NullCalendar(), volatility, daycounter)

    process = BlackScholesMertonProcess(spot, dividend_ts, risk_free_ts, volatility_ts)

    exercise_date = today() + 90
    exercise = EuropeanExercise(exercise_date)

    payoff = PlainVanillaPayoff(option_type, strike)

    option = EuropeanOption(payoff, exercise)
    engine = AnalyticEuropeanEngine(process)
    option.set_pricing_engine(engine)
    return option.npv
예제 #6
0
    def test_bsm_hw(self):
        print("Testing European option pricing for a BSM process" +
              " with one-factor Hull-White model...")

        dc = Actual365Fixed()
        todays_date = today()
        maturity_date = todays_date + Period(20, Years)

        settings = Settings()
        settings.evaluation_date = todays_date

        spot = SimpleQuote(100)

        q_ts = flat_rate(todays_date, 0.04, dc)
        r_ts = flat_rate(todays_date, 0.0525, dc)
        vol_ts = BlackConstantVol(todays_date, NullCalendar(), 0.25, dc)

        hullWhiteModel = HullWhite(r_ts, 0.00883, 0.00526)

        bsm_process = BlackScholesMertonProcess(spot, q_ts, r_ts, vol_ts)

        exercise = EuropeanExercise(maturity_date)

        fwd = spot.value * q_ts.discount(maturity_date) / \
            r_ts.discount(maturity_date)

        payoff = PlainVanillaPayoff(Call, fwd)

        option = VanillaOption(payoff, exercise)

        tol = 1e-8
        corr = [-0.75, -0.25, 0.0, 0.25, 0.75]
        expectedVol = [
            0.217064577, 0.243995801, 0.256402830, 0.268236596, 0.290461343
        ]

        for c, v in zip(corr, expectedVol):
            bsm_hw_engine = AnalyticBSMHullWhiteEngine(c, bsm_process,
                                                       hullWhiteModel)

            option = VanillaOption(payoff, exercise)
            option.set_pricing_engine(bsm_hw_engine)
            npv = option.npv

            compVolTS = BlackConstantVol(todays_date, NullCalendar(), v, dc)

            bs_process = BlackScholesMertonProcess(spot, q_ts, r_ts, compVolTS)
            bsEngine = AnalyticEuropeanEngine(bs_process)

            comp = VanillaOption(payoff, exercise)
            comp.set_pricing_engine(bsEngine)

            impliedVol = comp.implied_volatility(npv,
                                                 bs_process,
                                                 1e-10,
                                                 500,
                                                 min_vol=0.1,
                                                 max_vol=0.4)

            if (abs(impliedVol - v) > tol):
                print("Failed to reproduce implied volatility cor: %f" % c)
                print("calculated: %f" % impliedVol)
                print("expected  : %f" % v)

            if abs((comp.npv - npv) / npv) > tol:
                print("Failed to reproduce NPV")
                print("calculated: %f" % comp.npv)
                print("expected  : %f" % npv)

            self.assertAlmostEqual(impliedVol, v, delta=tol)
            self.assertAlmostEqual(comp.npv / npv, 1, delta=tol)
예제 #7
0
    def test_compare_BsmHW_HestonHW(self):
        """
        From Quantlib test suite
        """

        print("Comparing European option pricing for a BSM " +
              "process with one-factor Hull-White model...")

        dc = Actual365Fixed()

        todays_date = today()
        settings = Settings()
        settings.evaluation_date = todays_date
        tol = 1.e-2

        spot = SimpleQuote(100)

        dates = [todays_date + Period(i, Years) for i in range(40)]

        rates = [0.01 + 0.0002 * np.exp(np.sin(i / 4.0)) for i in range(40)]
        divRates = [0.02 + 0.0001 * np.exp(np.sin(i / 5.0)) for i in range(40)]

        s0 = SimpleQuote(100)

        r_ts = ZeroCurve(dates, rates, dc)
        q_ts = ZeroCurve(dates, divRates, dc)

        vol = SimpleQuote(0.25)
        vol_ts = BlackConstantVol(todays_date, NullCalendar(), vol.value, dc)

        bsm_process = BlackScholesMertonProcess(spot, q_ts, r_ts, vol_ts)

        variance = vol.value * vol.value
        hestonProcess = HestonProcess(risk_free_rate_ts=r_ts,
                                      dividend_ts=q_ts,
                                      s0=s0,
                                      v0=variance,
                                      kappa=5.0,
                                      theta=variance,
                                      sigma=1e-4,
                                      rho=0.0)

        hestonModel = HestonModel(hestonProcess)

        hullWhiteModel = HullWhite(r_ts, a=0.01, sigma=0.01)

        bsmhwEngine = AnalyticBSMHullWhiteEngine(0.0, bsm_process,
                                                 hullWhiteModel)

        hestonHwEngine = AnalyticHestonHullWhiteEngine(hestonModel,
                                                       hullWhiteModel, 128)

        tol = 1e-5
        strikes = [0.25, 0.5, 0.75, 0.8, 0.9, 1.0, 1.1, 1.2, 1.5, 2.0, 4.0]
        maturities = [1, 2, 3, 5, 10, 15, 20, 25, 30]
        types = [Put, Call]

        for type in types:
            for strike in strikes:
                for maturity in maturities:
                    maturity_date = todays_date + Period(maturity, Years)

                    exercise = EuropeanExercise(maturity_date)

                    fwd = strike * s0.value * \
                        q_ts.discount(maturity_date) / \
                        r_ts.discount(maturity_date)

                    payoff = PlainVanillaPayoff(type, fwd)

                    option = VanillaOption(payoff, exercise)

                    option.set_pricing_engine(bsmhwEngine)
                    calculated = option.npv

                    option.set_pricing_engine(hestonHwEngine)
                    expected = option.npv

                    if ((np.abs(expected - calculated) > calculated * tol)
                            and (np.abs(expected - calculated) > tol)):

                        cp = PAYOFF_TO_STR[type]
                        print("Failed to reproduce npv")
                        print("strike    : %f" % strike)
                        print("maturity  : %d" % maturity)
                        print("type      : %s" % cp)

                    self.assertAlmostEqual(expected, calculated, delta=tol)
예제 #8
0
    def test_compare_bsm_bsmhw_hestonhw(self):

        dc = Actual365Fixed()

        todays_date = today()
        settings = Settings()
        settings.evaluation_date = todays_date
        tol = 1.e-2

        spot = SimpleQuote(100)

        dates = [todays_date + Period(i, Years) for i in range(40)]

        rates = [0.01 + 0.0002 * np.exp(np.sin(i / 4.0)) for i in range(40)]
        divRates = [0.02 + 0.0001 * np.exp(np.sin(i / 5.0)) for i in range(40)]

        s0 = SimpleQuote(100)

        r_ts = ZeroCurve(dates, rates, dc)
        q_ts = ZeroCurve(dates, divRates, dc)

        vol = SimpleQuote(0.25)
        vol_ts = BlackConstantVol(todays_date, NullCalendar(), vol.value, dc)

        bsm_process = BlackScholesMertonProcess(spot, q_ts, r_ts, vol_ts)

        payoff = PlainVanillaPayoff(Call, 100)
        exercise = EuropeanExercise(dates[1])

        option = VanillaOption(payoff, exercise)

        analytic_european_engine = AnalyticEuropeanEngine(bsm_process)

        option.set_pricing_engine(analytic_european_engine)
        npv_bsm = option.npv

        variance = vol.value * vol.value
        hestonProcess = HestonProcess(risk_free_rate_ts=r_ts,
                                      dividend_ts=q_ts,
                                      s0=s0,
                                      v0=variance,
                                      kappa=5.0,
                                      theta=variance,
                                      sigma=1e-4,
                                      rho=0.0)

        hestonModel = HestonModel(hestonProcess)

        hullWhiteModel = HullWhite(r_ts, a=0.01, sigma=0.01)

        bsmhwEngine = AnalyticBSMHullWhiteEngine(0.0, bsm_process,
                                                 hullWhiteModel)

        hestonHwEngine = AnalyticHestonHullWhiteEngine(hestonModel,
                                                       hullWhiteModel, 128)

        hestonEngine = AnalyticHestonEngine(hestonModel, 144)
        option.set_pricing_engine(hestonEngine)

        npv_heston = option.npv

        option.set_pricing_engine(bsmhwEngine)
        npv_bsmhw = option.npv

        option.set_pricing_engine(hestonHwEngine)
        npv_hestonhw = option.npv

        print("calculated with BSM: %f" % npv_bsm)
        print("BSM-HW: %f" % npv_bsmhw)
        print("Heston: %f" % npv_heston)
        print("Heston-HW: %f" % npv_hestonhw)

        self.assertAlmostEqual(npv_bsm, npv_bsmhw, delta=tol)
        self.assertAlmostEqual(npv_bsm, npv_hestonhw, delta=tol)
예제 #9
0
    def test_replicating_variance_swap(self):
        """
            data from "A Guide to Volatility and Variance Swaps",
            Derman, Kamal & Zou, 1999
            with maturity t corrected from 0.25 to 0.246575
            corresponding to Jan 1, 1999 to Apr 1, 1999
        """

        replicating_option_data = [
            {
                'type': OptionType.Put,
                'strike': 50,
                'v': 0.30
            },
            {
                'type': OptionType.Put,
                'strike': 55,
                'v': 0.29
            },
            {
                'type': OptionType.Put,
                'strike': 60,
                'v': 0.28
            },
            {
                'type': OptionType.Put,
                'strike': 65,
                'v': 0.27
            },
            {
                'type': OptionType.Put,
                'strike': 70,
                'v': 0.26
            },
            {
                'type': OptionType.Put,
                'strike': 75,
                'v': 0.25
            },
            {
                'type': OptionType.Put,
                'strike': 80,
                'v': 0.24
            },
            {
                'type': OptionType.Put,
                'strike': 85,
                'v': 0.23
            },
            {
                'type': OptionType.Put,
                'strike': 90,
                'v': 0.22
            },
            {
                'type': OptionType.Put,
                'strike': 95,
                'v': 0.21
            },
            {
                'type': OptionType.Put,
                'strike': 100,
                'v': 0.20
            },
            {
                'type': OptionType.Call,
                'strike': 100,
                'v': 0.20
            },
            {
                'type': OptionType.Call,
                'strike': 105,
                'v': 0.19
            },
            {
                'type': OptionType.Call,
                'strike': 110,
                'v': 0.18
            },
            {
                'type': OptionType.Call,
                'strike': 115,
                'v': 0.17
            },
            {
                'type': OptionType.Call,
                'strike': 120,
                'v': 0.16
            },
            {
                'type': OptionType.Call,
                'strike': 125,
                'v': 0.15
            },
            {
                'type': OptionType.Call,
                'strike': 130,
                'v': 0.14
            },
            {
                'type': OptionType.Call,
                'strike': 135,
                'v': 0.13
            },
        ]

        dates = [self.ex_date]

        call_strikes, put_strikes, call_vols, put_vols = [], [], [], []

        # Assumes ascending strikes and same min call and max put strikes
        for data in replicating_option_data:
            if data['type'] == OptionType.Call:
                call_strikes.append(data['strike'])
                call_vols.append(data['v'])
            elif data['type'] == OptionType.Put:
                put_strikes.append(data['strike'])
                put_vols.append(data['v'])
            else:
                raise ValueError("unknown option type")

        vols = np.zeros((len(replicating_option_data) - 1, 1))
        strikes = []
        for j, v in enumerate(put_vols):
            vols[j][0] = v
            strikes.append(put_strikes[j])

        for k in range(1, len(call_vols)):
            j = len(put_vols) - 1
            vols[j + k][0] = call_vols[k]
            strikes.append(call_strikes[k])

        vols_mat = Matrix.from_ndarray(vols)

        vol_ts = BlackVarianceSurface(self.today, NullCalendar(), dates,
                                      strikes, vols_mat, self.dc)

        stoch_process = BlackScholesMertonProcess(self.spot, self.q_ts,
                                                  self.r_ts, vol_ts)

        engine = ReplicatingVarianceSwapEngine(stoch_process, call_strikes,
                                               put_strikes, 5.0)

        variance_swap = VarianceSwap(
            self.values['type'],
            self.values['strike'],
            self.values['nominal'],
            self.today,
            self.ex_date,
        )

        variance_swap.set_pricing_engine(engine)

        calculated = variance_swap.variance
        expected = self.values['result']

        self.assertAlmostEqual(calculated, expected, delta=self.values['tol'])