diff options
Diffstat (limited to 'python/exploration')
| -rw-r--r-- | python/exploration/tranches.py | 151 |
1 files changed, 54 insertions, 97 deletions
diff --git a/python/exploration/tranches.py b/python/exploration/tranches.py index 028d41b1..7b475821 100644 --- a/python/exploration/tranches.py +++ b/python/exploration/tranches.py @@ -8,7 +8,7 @@ import numpy as np import pandas as pd from analytics import Swaption, BlackSwaption, Index, BlackSwaptionVolSurface, Portfolio -from analytics.scenarios import run_swaption_scenarios, run_index_scenarios, run_portfolio_scenarios +from analytics.scenarios import run_swaption_scenarios, run_index_scenarios, run_portfolio_scenarios, run_tranche_scenarios import exploration.swaption_calendar_spread as spread from scipy.interpolate import interp1d @@ -59,10 +59,10 @@ def rv_calc1(): pv = tranche.tranche_pvs(shortened=4).bond_price pv_prev_index.append(pv) - temp1 = pd.DataFrame(rho_tlp, index=df.date, columns=['3_rho_tlp','7_rho_tlp','15_rho_tlp']) - temp2 = pd.DataFrame(pv_tlp, index=df.date, columns=['03_pv_tlp','37_pv_tlp','715_pv_tlp','15100_pv_tlp']) - temp3 = pd.DataFrame(rho_prev_index, index=df.date, columns=['3_rho_ig27','7_rho_ig27','15_rho_ig27']) - temp4 = pd.DataFrame(pv_prev_index, index=df.date, columns=['03_pv_ig27','37_pv_ig27','715_pv_ig27','15100_pv_ig27']) + temp1 = pd.DataFrame(rho_tlp, index=df.date, columns=['3_rho_tlp', '7_rho_tlp', '15_rho_tlp']) + temp2 = pd.DataFrame(pv_tlp, index=df.date, columns=['03_pv_tlp', '37_pv_tlp', '715_pv_tlp', '15100_pv_tlp']) + temp3 = pd.DataFrame(rho_prev_index, index=df.date, columns=['3_rho_ig27', '7_rho_ig27', '15_rho_ig27']) + temp4 = pd.DataFrame(pv_prev_index, index=df.date, columns=['03_pv_ig27', '37_pv_ig27', '715_pv_ig27', '15100_pv_ig27']) results = results.append(pd.concat([temp1, temp2, temp3, temp4], axis=1)) @@ -96,113 +96,70 @@ def dispersion(): curve_df.groupby(['series', 'maturity']).mean() curve_df.groupby(['series', 'maturity']).std() -def scenarios(tranche, shock_range=None, roll_corr=False): +def run_scen(portf, tranche, spread_shock): - from copy import deepcopy - - tranche.build_skew() - orig_tranche_cl, _, orig_tranche_pv = tranche.tranche_pvs() + #Start with swaptions + earliest_expiry = min(portf.swaptions, key=lambda x: x.exercise_date).exercise_date + date_range = pd.bdate_range(portf.indices[0].trade_date, + earliest_expiry - pd.offsets.BDay(), freq='5B') + vs = BlackSwaptionVolSurface(portf.indices[0].index_type, + portf.indices[0].series, trade_date=portf.indices[0].trade_date) + vol_surface = vs[vs.list(option_type='payer')[-1]] + df = run_portfolio_scenarios(portf, date_range, spread_shock, np.array([0]), + vol_surface, params=["pnl", "delta"]) - if shock_range is None: - shock, step = 1, 10 - shock_range = (1 + np.linspace(-.3, shock, step)) * tranche.tranche_quotes.indexrefspread[0] + #now do the tranches + spread_range = (1+ spread_shock) * portf.indices[0].spread + results = run_tranche_scenarios(tranche, spread_range, date_range) + results.date = pd.to_datetime(results.date) + notional = 10000000 + results['delta_tranche'] = -notional * (results['0-3_delta'] - 6* results['7-15_delta']) + results['pnl_tranche'] = notional * (results['0-3_pnl'] + results['0-3_carry'] - + 6* (results['7-15_pnl'] + results['7-15_carry'])) + results.index.name = 'spread' - #create empty lists - shock_index_pv_calc = np.empty(len(shock_range)) - shock_tranche_pv = np.empty((len(shock_range), tranche.K.size - 1)) - shock_tranche_delta = np.empty((len(shock_range), tranche.K.size - 1)) - shock_tranche_cl = np.empty((len(shock_range), tranche.K.size - 1)) - shock_tranche_carry = np.empty((len(shock_range), tranche.K.size - 1)) - results = pd.DataFrame() + #combine + df = df.reset_index().merge(results.reset_index(), on=['date', 'spread']) + df['final_pnl'] = df.pnl_tranche + df.pnl + df['final_delta'] = df.delta_tranche + df.delta - for shortened in [0,1,2]: - temp_tranche = deepcopy(tranche) - if shortened > 0: - temp_tranche.cs = temp_tranche.cs[:-shortened] - for i, shock in enumerate(shock_range): - temp_tranche.tweak(shock) - if roll_corr is True: - temp_tranche.rho = tranche.map_skew(temp_tranche, 'TLP') - shock_index_pv_calc[i] = temp_tranche._snacpv(shock * 1e-4, temp_tranche.coupon(temp_tranche.maturity), temp_tranche.recovery) - shock_tranche_cl[i], _, shock_tranche_pv[i] = temp_tranche.tranche_pvs() - shock_tranche_delta[i] = temp_tranche.tranche_deltas()['delta'] - shock_tranche_carry[i] = temp_tranche.tranche_quotes.running - temp1 = pd.DataFrame(shock_tranche_pv, index=shock_range, columns=[s + "_pv" for s in tranche._row_names]) - temp2 = pd.DataFrame(shock_tranche_delta, index=shock_range, columns=[s + "_delta" for s in tranche._row_names]) - temp3 = pd.DataFrame(np.subtract(shock_tranche_pv, orig_tranche_pv), index=shock_range, columns=[s + "_pnl" for s in tranche._row_names]) - temp4 = pd.DataFrame(shock_index_pv_calc, index=shock_range, columns=['index_price_snacpv']) - temp5 = pd.DataFrame(shock_tranche_carry, index=shock_range, columns=[s + "_carry" for s in tranche._row_names]) - #temp5 = pd.DataFrame(np.subtract(shock_tranche_cl, orig_tranche_cl), index=shock_range, columns=[s + "_coupon_pnl" for s in tranche._row_names]) - df = pd.concat([temp1, temp2, temp3, temp4, temp5], axis=1) - if shortened > 0: - df['days'] = ((tranche.cs.index[-1] - tranche.cs.index[-shortened-1])/ np.timedelta64(1, 'D')).astype(int) - else: - df['days'] = 0 - for column in [s + "_carry" for s in tranche._row_names]: - df[column] *= df['days']/365 + return df - results = results.append(df) +def set_port(): - return results + #Construct Portfolio + option_delta = Index.from_name('IG', 30, '5yr') + option_delta.spread = 59 -def run_scen(trade_date = pd.Timestamp.today().normalize()- pd.offsets.BDay()): + option1 = BlackSwaption(option_delta, date(2018, 6, 20), 80, option_type="payer") + option1.sigma = .621 + option1.direction = 'Short' - option_delta = Index.from_tradeid(910) - option1 = BlackSwaption.from_tradeid(13, option_delta) - option2 = BlackSwaption.from_tradeid(12, option_delta) - portf = Portfolio([option1, option2, option_delta]) + option1.notional = 150_000_000 + option_delta.notional = 1 - #Start with swaptions + portf = Portfolio([option1, option_delta]) portf.reset_pv() - portf.mark() - earliest_date = min(portf.swaptions, key=lambda x: x.exercise_date).exercise_date - #date_range = pd.bdate_range(portf.indices[0].trade_date, earliest_date - BDay(), freq = '3B') - date_range = pd.date_range(trade_date, periods=4, freq = '5B') - vol_shock = np.arange(-0.01, 0.01, 0.01) - shock_min=-.3 - shock_max=.8 - spread_shock = np.arange(shock_min, shock_max, 0.05) - index = portf.indices[0].name.split()[1] - series = portf.indices[0].name.split()[3][1:] - vs = BlackSwaptionVolaSurface(index, series, trade_date=trade_date) - vol_surface = vs[vs.list(option_type='payer')[-1]] - - df = run_portfolio_scenarios(portf, date_range, spread_shock, vol_shock, vol_surface, - params=["pnl","delta"]) - df = df[df.vol_shock == 0] - df['days'] = ((df.index - trade_date)/ np.timedelta64(1, 'D')).astype(int) - - #now do the tranches + trade_date = (pd.datetime.today() - pd.offsets.BDay(1)).normalize() tranche = bkt.TrancheBasket('IG', 29, '5yr', trade_date=trade_date) - shock_range = (1 + spread_shock) * portf.indices[0].spread - results = scenarios(tranche, shock_range, date_range) - results.set_index('days', append=True) + return portf, tranche - notional = 10000000 - results['delta'] = -notional * (results['0-3_delta'] - 6* results['7-15_delta']) - results['pnl'] = notional* (results['0-3_pnl'] + results['0-3_carry'] - 6* (results['7-15_pnl'] + results['7-15_carry'])) - results['date'] = tranche.trade_date + results.days * pd.offsets.Day() - results.index.name = 'spread' +def set_df(): - #now combine the results - f = {} - for i, g in results.groupby('spread'): - f[i] = interp1d(g.days, g.pnl) + portf, tranche = set_port() - df['total_pnl'] = df.apply(lambda df: f[df.spread](df.days), axis = 1) - df.total_pnl = df.total_pnl.astype(float) + shock_min = -.3 + shock_max = .8 + spread_shock = np.arange(shock_min, shock_max, 0.05) + shock_range = (1+ spread_shock) * portf.indices[0].spread - return results, df, shock_range + results = run_scen(portf, tranche, spread_shock) + results = results.set_index('date') + return results, shock_range -def plot_pnl(): +def plot_scenarios(): - a, b, shock_range = run_scen() - a.reset_index(inplace=True) - a.set_index('date', inplace=True) - #plot Tranche only PNL - plot_time_color_map(a, shock_range, attr="pnl") - #plot swaption only PNL - plot_time_color_map(b, shock_range, attr="pnl") - #plot Tranche and Swaption PNL - plot_time_color_map(b, shock_range, attr="total_pnl") + df, shock_range = set_df() + plot_time_color_map(df, shock_range, attr="final_pnl") + plot_time_color_map(df, shock_range, attr="final_delta", color_map= 'rainbow', centered = False) |
