Exemplo n.º 1
0
    def load_data(self,
                  tickers=None,
                  start_date=history_default_start_date,
                  end_date=dt.datetime.today()):

        data_1 = get_equity_implied_volatility(tickers=tickers,
                                               fields=self.ivol_fields,
                                               start_date=start_date,
                                               end_date=end_date)

        self.data = self.data.append(data_1).drop_duplicates()

        dates = self.data.index.get_level_values('date')
        for i in range(1, 5):
            col1 = 'maturity_date_' + str(i) + 'mc'
            col2 = 'days_to_maturity_' + str(i) + 'mc'
            self.data[col1] = \
                utils.calendarday(date=dates, num_days=self.data[col2])

        self.data = self.data.sort_index().drop_duplicates()
        self.data = self.get_maturity_dates(tickers=tickers)

        # enforced cleaning
        self.data['curvature'] = utils.numeric_cap_floor(
            x=self.data['curvature'], cap=1.0)
        self.data['curvature_inf'] = utils.numeric_cap_floor(
            x=self.data['curvature_inf'], cap=1.0)
Exemplo n.º 2
0
def black_scholes_d1(spot=None,
                     strike=None,
                     tenor_in_days=None,
                     risk_free=None,
                     ivol=None,
                     div=None,
                     div_type='yield'):

    eps = 1e-7
    t = utils.numeric_cap_floor(x=tenor_in_days /
                                constants.trading_days_per_year,
                                floor=eps)
    pv_div, adj_spot = _handle_dividend(div=div,
                                        div_type=div_type,
                                        risk_free=risk_free,
                                        spot=spot,
                                        tenor_in_days=tenor_in_days)

    d1 = (np.log(adj_spot / strike) + (risk_free + ivol ** 2.0 / 2.0) * t) \
         / (ivol * t ** 0.5)

    d2 = d1 - ivol * t**0.5

    d1 = pd.to_numeric(d1)
    d2 = pd.to_numeric(d2)

    return d1, d2
Exemplo n.º 3
0
def black_scholes_vega(spot=None,
                       strike=None,
                       tenor_in_days=None,
                       risk_free=None,
                       ivol=None,
                       div=0.0,
                       div_type='yield',
                       d1=None,
                       option_type=None):

    eps = 1e-7
    t = utils.numeric_cap_floor(x=tenor_in_days /
                                constants.trading_days_per_year,
                                floor=eps)
    if div_type == 'yield':
        div_yield = div
    elif div_type == 'amount':
        div_yield = div / spot / t

    if d1 is None:
        d1, d2 = black_scholes_d1(spot=spot,
                                  strike=strike,
                                  tenor_in_days=tenor_in_days,
                                  risk_free=risk_free,
                                  ivol=ivol,
                                  div=div,
                                  div_type=div_type)

    vega = spot * np.exp(-div_yield * t) * norm.pdf(d1) * np.sqrt(t) / 100.0
    return vega
Exemplo n.º 4
0
def put_call_parity(input_price=None,
                    option_type='c',
                    spot=None,
                    strike=None,
                    div=0.0,
                    div_type='yield',
                    risk_free=None,
                    tenor_in_days=None):

    eps = 1e-7
    t = utils.numeric_cap_floor(x=tenor_in_days /
                                constants.trading_days_per_year,
                                floor=eps)
    pv_div, adj_spot = _handle_dividend(div=div,
                                        div_type=div_type,
                                        risk_free=risk_free,
                                        spot=spot,
                                        tenor_in_days=tenor_in_days)

    # cash plus call plus divs equals put plus stock
    if option_type.upper() in (['C', 'CALL']):
        other_price = input_price + spot \
                      - np.exp(risk_free * t) * strike - pv_div
    elif option_type.upper() in (['P', 'PUT']):
        other_price = np.exp(risk_free * t) * strike + pv_div - spot
    return other_price
Exemplo n.º 5
0
def black_scholes_price(spot=None,
                        strike=None,
                        tenor_in_days=None,
                        risk_free=None,
                        ivol=None,
                        div=0.0,
                        div_type='yield',
                        d1=None,
                        option_type='c'):

    eps = 1e-7
    t = utils.numeric_cap_floor(x=tenor_in_days /
                                constants.trading_days_per_year,
                                floor=eps)
    pv_div, adj_spot = _handle_dividend(div=div,
                                        div_type=div_type,
                                        risk_free=risk_free,
                                        spot=spot,
                                        tenor_in_days=tenor_in_days)

    if d1 is None:
        d1, d2 = black_scholes_d1(spot=spot,
                                  strike=strike,
                                  tenor_in_days=tenor_in_days,
                                  risk_free=risk_free,
                                  ivol=ivol,
                                  div=div,
                                  div_type=div_type)

    if isinstance(option_type, pd.Series):

        price = pd.Series(index=option_type.index)
        option_type = option_type.str.upper()

        d1 = pd.to_numeric(d1)
        d2 = pd.to_numeric(d2)

        call_ind = option_type.index[option_type.isin(['C', 'CALL'])]
        price.loc[call_ind] = adj_spot.loc[call_ind] \
            * norm.cdf(d1.loc[call_ind]) \
            - np.exp(-risk_free.loc[call_ind] * t.loc[call_ind])\
              * strike.loc[call_ind] * norm.cdf(d2.loc[call_ind])

        put_ind = option_type.index[option_type.isin(['P', 'PUT'])]
        price.loc[put_ind] = strike.loc[put_ind] \
            * np.exp(-risk_free.loc[put_ind]
            * t.loc[put_ind]) * norm.cdf(-d2.loc[put_ind]) \
            - spot.loc[put_ind] * norm.cdf(-d1.loc[put_ind])

    else:
        if option_type.upper() in (['C', 'CALL']):
            price = adj_spot * norm.cdf(d1) \
                    - np.exp(-risk_free * t) * strike * norm.cdf(d2)
        elif option_type.upper() in (['P', 'PUT']):
            price = strike * np.exp(-risk_free * t) * norm.cdf(-d2) \
                    - spot * norm.cdf(-d1)

    return price
Exemplo n.º 6
0
def black_scholes_delta(spot=None,
                        strike=None,
                        tenor_in_days=None,
                        risk_free=None,
                        ivol=None,
                        div=0.0,
                        div_type='yield',
                        d1=None,
                        option_type=None):

    eps = 1e-7
    t = utils.numeric_cap_floor(x=tenor_in_days /
                                constants.trading_days_per_year,
                                floor=eps)
    pv_div, adj_spot = _handle_dividend(div=div,
                                        div_type=div_type,
                                        risk_free=risk_free,
                                        spot=spot,
                                        tenor_in_days=tenor_in_days)
    div_yield = pv_div / spot / t

    if d1 is None:
        d1, d2 = black_scholes_d1(spot=spot,
                                  strike=strike,
                                  tenor_in_days=tenor_in_days,
                                  risk_free=risk_free,
                                  ivol=ivol,
                                  div=div,
                                  div_type=div_type)

    if isinstance(option_type, pd.Series):

        delta = pd.Series(index=option_type.index)
        option_type = option_type.str.upper()

        call_ind = option_type.index[option_type.isin(['C', 'CALL'])]
        delta.loc[call_ind] = np.exp(
            -div_yield.loc[call_ind] * t.loc[call_ind]) * norm.cdf(
                d1.loc[call_ind])

        put_ind = option_type.index[option_type.isin(['P', 'PUT'])]
        delta.loc[put_ind] = -np.exp(-div_yield.loc[put_ind] * t.loc[put_ind]
                                     ) * norm.cdf(-d1.loc[put_ind])

    else:
        if option_type.upper() in (['C', 'CALL']):
            delta = np.exp(-div_yield * t) * norm.cdf(d1)
        elif option_type.upper() in (['P', 'PUT']):
            delta = -np.exp(-div_yield * t) * norm.cdf(-d1)

    return delta
Exemplo n.º 7
0
def _handle_dividend(div=0.0,
                     div_type='yield',
                     risk_free=0.0,
                     spot=None,
                     tenor_in_days=None):
    eps = 1e-7
    t = utils.numeric_cap_floor(x=tenor_in_days /
                                constants.trading_days_per_year,
                                floor=eps)

    if div_type == 'yield':
        pv_div = (1.0 - np.exp(-risk_free * t)) / (eps + risk_free) * div * t
    elif div_type == 'amount':
        pv_div = np.exp(-t * risk_free) * div
    else:
        pv_div = 0.0
    adj_spot = spot - pv_div

    return pv_div, adj_spot
Exemplo n.º 8
0
def black_scholes_moneyness_from_delta(call_delta=None,
                                       tenor_in_days=None,
                                       ivol=None,
                                       risk_free=None,
                                       div_yield=None):
    """
    :param call_delta: this can be a scalar or an array-like. If the latter,
    ivol needs to have call delta as its columns
    :param tenor_in_days: this can be an integer or a Series with index that
    matches ivol's index
    :param ivol: this can be a scalar, a series, or a DataFrame indexed on
    date and/or ticker, with columns = call delta
    :param risk_free: can be scalar or series
    :param div_yield: can be scalar or series
    :return: scalar, series or DataFrame depending on inputs
    """

    if isinstance(call_delta, list):
        call_delta = np.array(call_delta)

    put_delta = 1.0 - call_delta
    eps = 1e-7
    t = utils.numeric_cap_floor(x=tenor_in_days /
                                constants.trading_days_per_year,
                                floor=eps)

    if isinstance(tenor_in_days, pd.Series) and isinstance(ivol, pd.DataFrame):
        m = pd.DataFrame(index=ivol.index, columns=ivol.columns)
        for col in ivol.columns:
            m[col] = np.exp(ivol[col] * t**0.5 *
                            norm.ppf((1 - col) * np.exp(div_yield * t)) -
                            (risk_free - div_yield - ivol[col]**2.0 / 2.0) * t)
    else:
        m = np.exp(ivol * t**0.5 *
                   norm.ppf(put_delta * np.exp(div_yield * t)) -
                   (risk_free - div_yield - ivol**2.0 / 2.0) * t)
    return m