pu = PlotUtil()
start_date = datetime.date(2018, 9, 12)
end_date = datetime.date(2018, 9, 13)
nbr_maturity = 0
min_holding = 8
df_daily = get_data.get_comoption_mktdata(start_date, end_date, Util.STR_SR)
optionset = BaseOptionSet(df_data=df_daily, rf=0.015)
optionset.init()
# optionset.go_to(end_date)

maturity = optionset.select_maturity_date(nbr_maturity,
                                          min_holding=min_holding)
iv_htr = optionset.get_atm_iv_by_htbr(maturity)
iv_avg = get_atm_iv_average(optionset, maturity)

htbr = optionset.get_htb_rate(maturity)
print('iv_htr : ', iv_htr)
print('iv_avg : ', iv_avg)
print('htb rate : ', htbr)

# curve = optionset.get_implied_vol_curves(maturity)

# curve_htbr = optionset.get_implied_vol_curves_htbr(maturity)
curve_otm = optionset.get_otm_implied_vol_curve(maturity)
# curve_htbr[Util.PCT_IV_CALL_BY_HTBR] = curve_htbr[Util.PCT_IV_CALL_BY_HTBR].apply(lambda x: None if x<0.05 else x)
# curve_htbr[Util.PCT_IV_PUT_BY_HTBR] = curve_htbr[Util.PCT_IV_PUT_BY_HTBR].apply(lambda x: None if x<0.05 else x)
curve_otm[Util.PCT_IV_OTM_BY_HTBR] = curve_otm[Util.PCT_IV_OTM_BY_HTBR].apply(
    lambda x: None if x < 0.05 else x)

strikes = curve_otm[Util.AMT_APPLICABLE_STRIKE]
# pu.plot_line_chart(strikes,[list(curve[Util.PCT_IV_CALL]),list(curve[Util.PCT_IV_PUT])],['CALL IV','PUT iv'])
Example #2
0
class Indexing():
    def __init__(self, start_date, end_date):
        df_metrics = option_data(start_date, end_date)
        self.optionset = BaseOptionSet(df_metrics, rf=0.03)
        self.optionset.init()

    def fun_otm_quote(self, df):
        if df[Util.AMT_APPLICABLE_STRIKE] > df['mid_k']:
            quote = df['amt_call_quote']
        elif df[Util.AMT_APPLICABLE_STRIKE] < df['mid_k']:
            quote = df['amt_put_quote']
        else:
            quote = (df['amt_call_quote'] + df['amt_put_quote']) / 2.0
        return quote

    def fun_for_p1(self, df):
        DK = df['amt_delta_k']
        Q = df['amt_otm_quote']
        K = df[Util.AMT_APPLICABLE_STRIKE]
        res = Q * DK / K**2
        return Q * DK / K**2

    def fun_for_p2(self, df):
        DK = df['amt_delta_k']
        Q = df['amt_otm_quote']
        K = df[Util.AMT_APPLICABLE_STRIKE]
        F = df['F']
        return 2 * (1 - math.log(K / F, math.e)) * Q * DK / K**2

    def fun_for_p3(self, df):
        DK = df['amt_delta_k']
        Q = df['amt_otm_quote']
        K = df[Util.AMT_APPLICABLE_STRIKE]
        F = df['F']
        return 3 * (2 * math.log(K / F, math.e) -
                    math.log(K / F, math.e)**2) * Q * DK / K**2

    def fun_for_sigma(self, df):
        DK = df['amt_delta_k']
        Q = df['amt_otm_quote']
        K = df[Util.AMT_APPLICABLE_STRIKE]
        return Q * DK / K**2

    def get_e1(self, F, K):
        return -(1 + math.log(F / K, math.e) - F / K)

    def get_e2(self, F, K):
        return 2 * math.log(K / F, math.e) * (F / K - 1) + 0.5 * math.log(
            K / F, math.e)**2

    def get_e3(self, F, K):
        return 3 * (math.log(K / F, math.e)**2) * (
            (1.0 / 3.0) * math.log(K / F, math.e) + F / K - 1)

    def get_S(self, p1, p2, p3):
        res = (p3 - 3 * p1 * p2 + 2 * p1**3) / (p2 - p1**2)**1.5
        return res

    def get_T_quotes(self, df_mdt, eval_date):
        df_call = df_mdt[df_mdt[Util.CD_OPTION_TYPE] == Util.STR_CALL].rename(
            columns={Util.AMT_CLOSE: 'amt_call_quote'})
        df_put = df_mdt[df_mdt[Util.CD_OPTION_TYPE] == Util.STR_PUT].rename(
            columns={Util.AMT_CLOSE: 'amt_put_quote'})
        df_call = df_call.drop_duplicates(
            Util.AMT_APPLICABLE_STRIKE).reset_index(drop=True)
        df_put = df_put.drop_duplicates(
            Util.AMT_APPLICABLE_STRIKE).reset_index(drop=True)

        df = pd.merge(df_call[[
            'amt_call_quote', Util.AMT_APPLICABLE_STRIKE, Util.AMT_STRIKE
        ]],
                      df_put[['amt_put_quote', Util.AMT_APPLICABLE_STRIKE]],
                      how='inner',
                      on=Util.AMT_APPLICABLE_STRIKE)
        # df = pd.concat([df_call[['amt_call_quote']], df_put[['amt_put_quote']]], axis=1, join='inner', verify_integrity=True)
        df[Util.AMT_UNDERLYING_CLOSE] = df_put[
            Util.AMT_UNDERLYING_CLOSE].values[0]
        df['amt_cp_diff'] = abs(df['amt_call_quote'] - df['amt_put_quote'])
        maturitydt = df_put[Util.DT_MATURITY].values[0]
        df[Util.DT_MATURITY] = maturitydt
        ttm = (
            (maturitydt - eval_date).total_seconds() / 60.0) / (365.0 * 1440)
        df['amt_ttm'] = ttm
        df['amt_fv'] = math.exp(self.optionset.rf * (ttm))
        df = df.sort_values(by=Util.AMT_APPLICABLE_STRIKE).reset_index(
            drop=True)
        dk = df[Util.AMT_APPLICABLE_STRIKE].diff(periods=2).dropna() / 2.0
        dk.loc[1] = df.loc[1, Util.AMT_APPLICABLE_STRIKE] - df.loc[
            0, Util.AMT_APPLICABLE_STRIKE]
        dk.loc[len(df)] = df.loc[len(df) - 1,
                                 Util.AMT_APPLICABLE_STRIKE] - df.loc[
                                     len(df) - 2, Util.AMT_APPLICABLE_STRIKE]
        dk = dk.sort_index()
        dk = dk.reset_index(drop=True)
        df['amt_delta_k'] = dk
        return df

    def forward_cboe(self, t_quotes, eval_date):
        # ATM strike k0 -- First strike below the forward index level, F
        # Forward price F -- F, by identifying the strike price at which the absolute difference
        # between the call and put prices is smallest.
        df = t_quotes.set_index(Util.AMT_APPLICABLE_STRIKE)
        mid_k = df.sort_values(by='amt_cp_diff', ascending=True).index[0]
        p_call = df.loc[mid_k, 'amt_call_quote']
        p_put = df.loc[mid_k, 'amt_put_quote']
        F = df.loc[mid_k, 'amt_fv'] * (p_call - p_put) + mid_k
        df['k-f'] = df.index - F
        if len(df[df['k-f'] < 0]) > 0:
            K0 = df[df['k-f'] < 0].sort_values(by='amt_cp_diff',
                                               ascending=True).index[0]
        else:
            K0 = df.sort_values(by='amt_cp_diff', ascending=True).index[0]
        return mid_k, K0, F

    """ K0 is the 1st strike below F0 """

    def for_calculation(self, df, eval_date):
        mid_k, k0, F = self.forward_cboe(df, eval_date)
        ttm = df.loc[0, 'amt_ttm']
        S = df.loc[0, 'amt_underlying_close']
        implied_r = math.log(F / S, math.e) / ttm
        self.implied_rf = implied_r
        df['k0'] = k0
        df['mid_k'] = mid_k
        df['F'] = F
        df['amt_otm_quote'] = df.apply(self.fun_otm_quote, axis=1)
        return df

    def calculate_S_for_skew(self, df):
        k0 = df.loc[0, 'k0']
        F = df.loc[0, 'F']
        e1 = self.get_e1(F, k0)
        e2 = self.get_e2(F, k0)
        e3 = self.get_e3(F, k0)
        df['for_p1'] = df.apply(self.fun_for_p1, axis=1)
        df['for_p2'] = df.apply(self.fun_for_p2, axis=1)
        df['for_p3'] = df.apply(self.fun_for_p3, axis=1)
        fv = df.loc[0, 'amt_fv']
        p1 = -fv * df['for_p1'].sum() + e1
        p2 = fv * df['for_p2'].sum() + e2
        p3 = fv * df['for_p3'].sum() + e3
        S = self.get_S(p1, p2, p3)
        SKEW = 100 - 10 * S
        # S_r = self.get_S(-0.00173,0.003606,-0.00049)
        # SKEW_r = 100-10*S_r
        return S

    def calculate_sigma_for_vix(self, df):
        df['for_sigma'] = df.apply(self.fun_for_sigma, axis=1)
        k0 = df.loc[0, 'k0']
        F = df.loc[0, 'F']
        T = df.loc[0, 'amt_ttm']
        fv = df.loc[0, 'amt_fv']
        v1 = (1.0 / T) * (F / k0 - 1)**2
        # v1 = (F / K - 1) ** 2
        sum = df['for_sigma'].sum()
        sigma = (2.0 / T) * fv * sum - v1
        # sigma = 2.0 * fv * sum - v1
        return sigma

    def calculate(self, eval_date):
        df_daily_state = self.optionset.get_current_state()
        mdt = self.optionset.get_maturities_list()[0]
        if (mdt - self.optionset.eval_date).days <= 5:
            mdt1 = self.optionset.get_maturities_list()[1]
            mdt2 = self.optionset.get_maturities_list()[2]
        else:
            mdt1 = self.optionset.get_maturities_list()[0]
            mdt2 = self.optionset.get_maturities_list()[1]
        df_mdt1 = OptionUtil.get_df_by_mdt(df_daily_state, mdt1)
        df_mdt2 = OptionUtil.get_df_by_mdt(df_daily_state, mdt2)
        t_quotes1 = self.get_T_quotes(df_mdt1, eval_date)
        t_quotes2 = self.get_T_quotes(df_mdt2, eval_date)
        # t_quotes1.to_csv('t_quotes1.csv')
        # t_quotes2.to_csv('t_quotes2.csv')
        calculate1 = self.for_calculation(t_quotes1, eval_date)
        calculate2 = self.for_calculation(t_quotes2, eval_date)
        S1 = self.calculate_S_for_skew(calculate1)
        S2 = self.calculate_S_for_skew(calculate2)

        sigma1 = self.calculate_sigma_for_vix(calculate1)
        sigma2 = self.calculate_sigma_for_vix(calculate2)
        T1 = calculate1.loc[0, 'amt_ttm']
        T2 = calculate2.loc[0, 'amt_ttm']
        NT1 = (mdt1 - eval_date).total_seconds() / 60.0
        NT2 = (mdt2 - eval_date).total_seconds() / 60.0
        N30 = 30 * 1440.0
        N365 = 365 * 1440.0
        w = (NT2 - N30) / (NT2 - NT1)
        skew = 100 - 10 * (w * S1 + (1 - w) * S2)
        vix = 100 * math.sqrt(
            (T1 * sigma1 * w + T2 * sigma2 * (1 - w)) * N365 / N30)
        return vix, skew

    def get_atm_options(self, maturity):
        list_atm_call, list_atm_put = self.optionset.get_options_list_by_moneyness_mthd1(
            moneyness_rank=0, maturity=maturity)
        atm_call = self.optionset.select_higher_volume(list_atm_call)
        atm_put = self.optionset.select_higher_volume(list_atm_put)
        return atm_call, atm_put

    def get_atm_iv_average(self, maturity):
        atm_call, atm_put = self.get_atm_options(maturity)
        iv_call = atm_call.get_implied_vol()
        iv_put = atm_put.get_implied_vol()
        iv_avg = (iv_call + iv_put) / 2
        return iv_avg

    def run(self):
        self.df_res = pd.DataFrame()
        print('=' * 120)
        print("%10s %20s %20s %20s %20s %20s" %
              ('eval_date', 'vix', 'skew', 'iv_htr', 'iv_avg', 'htbr'))
        print('-' * 120)
        while self.optionset.current_index < self.optionset.nbr_index:
            eval_date = self.optionset.eval_date
            try:
                maturity = self.optionset.select_maturity_date(
                    nbr_maturity, min_holding=min_holding)
                iv_htr = self.optionset.get_atm_iv_by_htbr(maturity)
                iv_avg = self.get_atm_iv_average(maturity)
                htbr = self.optionset.get_htb_rate(maturity)
                vix, skew = self.calculate(eval_date)
                self.df_res.loc[eval_date, 'skew'] = skew
                self.df_res.loc[eval_date, 'vix'] = vix
                self.df_res.loc[
                    eval_date,
                    '50ETF'] = self.optionset.get_underlying_close()
                self.df_res.loc[eval_date, 'htb_rate'] = htbr
                self.df_res.loc[eval_date, 'iv_atm_htr'] = iv_htr
                self.df_res.loc[eval_date, 'iv_atm_avg'] = iv_avg
                print("%10s %20s %20s %20s %20s %20s" %
                      (eval_date, vix, skew, iv_htr, iv_avg, htbr))

            except:
                pass
            if not self.optionset.has_next(): break
            self.optionset.next()
Example #3
0
atm_put = optionset.select_higher_volume(put_list)
print('atm call iv: ', atm_call.get_implied_vol())
print('atm put iv: ', atm_put.get_implied_vol())
print('atm strike: ', atm_put.strike())

t_quote = optionset.get_T_quotes(dt_maturity)
ivs_c1 = optionset.get_call_implied_vol_curve(dt_maturity)
ivs_p1 = optionset.get_put_implied_vol_curve(dt_maturity)
ivs_c2 = optionset.get_call_implied_vol_curve_htbr(dt_maturity)
ivs_p2 = optionset.get_put_implied_vol_curve_htbr(dt_maturity)

iv_curve = optionset.get_implied_vol_curves(dt_maturity)
iv_curve_htbr = optionset.get_implied_vol_curves_htbr(dt_maturity)
iv_volume_weighted = optionset.get_volume_weighted_iv(dt_maturity)
iv_volume_weighted_htbr = optionset.get_volume_weighted_iv_htbr(dt_maturity)
htbr = optionset.get_htb_rate(dt_maturity)
print(iv_volume_weighted)
print(iv_volume_weighted_htbr)
print(htbr)
print(iv_curve_htbr)
""" Quantlib """
# global data
# todaysDate = QuantlibUtil.to_ql_date(end_date)
# Settings.instance().evaluationDate = todaysDate
# settlementDate = todaysDate
# maturityDate = QuantlibUtil.to_ql_date(datetime.date(2018,12,7))
# dt_settlement = QuantlibUtil.to_dt_date(settlementDate)
# dt_maturity = QuantlibUtil.to_dt_date(maturityDate)
# rf = 0.0
# spot = 3120.0
# strike = 3650.0