aboutsummaryrefslogtreecommitdiffstats
path: root/python/exploration/beta_trade.py
blob: fe6e5c5cec2e8237f83df261f1738dfa6152a261 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import sys
sys.path.append("..")
import math
import os
import pandas as pd
try:
    import feather
except ImportError:
    pass
from analytics.index_data import index_returns, get_index_quotes
from arch import arch_model
from math import log, exp, sqrt
import numpy as np
from scipy.optimize import minimize_scalar
from statsmodels.tsa.ar_model import AR

import matplotlib.pyplot as plt

def calc_returns(index_list=['HY', 'IG'], save_feather=False):
    returns = (index_returns(index=index_list, tenor='5yr', years=None).
               reset_index(['tenor'], drop=True).
               swaplevel(1, 0))
    returns = returns.groupby(level=['date','index']).nth(-1)['price_return']
    returns = returns.unstack().dropna()
    #if save_feather:
    #    feather.write_dataframe(returns.reset_index(),
    #                            os.path.join(os.environ["DATA_DIR"], "index_returns.fth"))
    return returns

def calc_betas(returns=None, spans=[5, 20], index_list=['HY', 'IG']):
    if returns is None:
        returns = calc_returns(index_list=index_list)

    return pd.concat([(returns.
                       ewm(span=span).
                       cov().
                       groupby(level='date').
                       apply(lambda df: df / np.diag(df))) for span in spans], axis=1, keys=spans)

def plot_betas(betas=None):
    spans = [5, 20]
    if betas is None:
        betas = calc_betas(spans=spans)
    for beta, span in zip(betas, spans):
        plt.plot(beta, label='EWMA' + str(span))
    plt.xlabel('date')
    plt.ylabel('beta')
    plt.legend()

def calc_realized_vol(returns=None):

    # three ways of computing the volatility
    # 1) 20 days simple moving average
    # 2) exponentially weighted moving average
    # 3) GARCH(1,1), we scale returns by 10 to help with the fitting
    if returns is None:
        returns = calc_returns()

    vol_sma = returns.rolling(20).std() * math.sqrt(252)
    vol_ewma = returns.ewm(span=20).std() * math.sqrt(252)
    scale = 10
    vol_garch = pd.DataFrame()
    for index in returns:
        am = arch_model(scale * returns[index].dropna())
        res = am.fit()
        vol_garch[index] = res.conditional_volatility * math.sqrt(252)/scale

    vol = pd.concat([vol_sma, vol_ewma, vol_garch], axis=1, keys=['sma', 'ewma', 'garch'])
    return vol
    #feather.write_dataframe(beta_ewma.to_frame('beta'),
    #                        os.path.join(os.environ['DATA_DIR'], "beta.fth"))

def spreads_ratio(series=list(range(22, 29)), index=['IG', 'HY'], tenor='5yr'):
    df = get_index_quotes(series=series, index=index, tenor=tenor)
    df = df['modelspread'].groupby(['date', 'index']).last().unstack()
    df['ratio'] = df.HY / df.IG
    return df

def loglik(beta, returns):
    x = (returns.HY - beta*returns.IG)
    model = AR(x, missing='drop')
    fit = model.fit(maxlag=2)
    return - fit.llf

if __name__ == "__main__":
    returns = calc_returns()
    betas = calc_betas(returns)
    plot_betas(betas)
    vol = calc_realized_vol(returns)
    ratios = spreads_ratio()
    prog = minimize_scalar(loglik, bracket=(3, 5), args=(returns,))