diff options
Diffstat (limited to 'python/option_trades_et.py')
| -rw-r--r-- | python/option_trades_et.py | 95 |
1 files changed, 64 insertions, 31 deletions
diff --git a/python/option_trades_et.py b/python/option_trades_et.py index 9f27e4b3..8b64e7b7 100644 --- a/python/option_trades_et.py +++ b/python/option_trades_et.py @@ -59,27 +59,21 @@ def beta_calc(): ltvar = lr_var(resHY) graphit = compute_allocation(all_tenors) -def build_swaption(index = 'IG', series = 27, expiry = datetime.date(2017, 4, 19), strike = 65, ref = 62, trade_date = datetime.date(2017, 2, 23), t_range = None): +def build_swaption(index, series, expiry, strike, ref, trade_date, t_range= None, spread_range = None): index_obj = Index.from_name(index, series, '5yr', trade_date) swap_obj = opt.Swaption(index_obj, expiry, strike, option_type="payer") swap_obj.notional = 100000000 if t_range is None: t_range = pd.bdate_range(trade_date, expiry- BDay(), freq = '5B') + if spread_range is None: + spread_range = pd.Series(np.arange(ref - 10, ref +19, 5)) + vol_range = pd.Series(np.arange(25, 60, 5)) #not inclusive of end point - spread_range = pd.Series(np.arange(ref - 10, ref +19, 5)) df = pd.DataFrame(index = pd.MultiIndex.from_product([t_range, spread_range, vol_range], names = ['date', 'spread', 'vol']), columns = ['pv']) df = df.reset_index() - def manual_index_update(index, date): - index._yc = index._yc.expected_forward_curve(date) - index._trade_date = date - index._step_in_date = index.trade_date + datetime.timedelta(days=1) - index._accrued = index._fee_leg.accrued(index._step_in_date) - index._value_date = (pd.Timestamp(index._trade_date) + 3* BDay()).date() - index._update() - def aux(row, index, swap): index.spread = row.spread manual_index_update(index, row.date.date()) @@ -91,7 +85,7 @@ def build_swaption(index = 'IG', series = 27, expiry = datetime.date(2017, 4, 19 #calculate mapped vol df['moneyness'] = (strike- df.spread)/df.spread - df['days_to_expiry'] = (expiry - df.date) / np.timedelta64(1,'D') + df['days_to_expiry'] = (expiry - df.date).dt.days vol_surface = build_vol_surface_functions(trade_date, index, series) df['mapped_vol'] = df.apply(vol_from_surface, axis = 1, args=(vol_surface[0], vol_surface[1])) df['mapping_shift'] = pd.to_numeric(df.vol/100 - df.mapped_vol, errors = 'ignore') @@ -99,12 +93,37 @@ def build_swaption(index = 'IG', series = 27, expiry = datetime.date(2017, 4, 19 return df +def calc_delta_pnl(index, series, ref, trade_date, notional, t_range, spread_range): + + index_obj = Index.from_name(index, series, '5yr', trade_date) + index_obj.spread = ref + index_obj.notional = notional + startingpv = -index_obj.clean_pv + + index_pv = {} + for date in t_range: + for spread in spread_range: + index_obj.spread = spread + manual_index_update(index_obj, date) + #import pdb; pdb.set_trace() + index_pv[(date, spread)] = -index_obj.clean_pv + notional* (date.date()-trade_date).days/360* index_obj.fixed_rate/10000 + + df = pd.DataFrame.from_dict(index_pv, orient = 'index').reset_index() + df['date'] = df['index'].apply(lambda x: x[0]) + df['spread'] = df['index'].apply(lambda x: x[1]) + del df['index'] + df = df.set_index(['date','spread']).sort_index() + df = (df - startingpv).unstack(-1) + df.columns = df.columns.droplevel() + + return df + def find_mapped_pv(bought, sold, date): sold = sold.xs(date).reset_index() bought = bought.xs(date).reset_index() - #Bivariate B-Spline, instead of interp2d. Interp2d doesn't behave well.... + #Bivariate B-Spline, instead of interp2d. Interp2d doesn't behave well and complains a lot. annoying x = bought.spread.unique() y = sorted(bought.mapping_shift.unique()) grid = np.meshgrid(x,y) @@ -112,7 +131,6 @@ def find_mapped_pv(bought, sold, date): f_sold = SmoothBivariateSpline(sold.spread, sold.mapping_shift, sold.pv, kx = 4, ky = 4) intp_buy = f_buy.ev(grid[0],grid[1]) intp_sold = f_sold.ev(grid[0],grid[1]) - #import pdb; pdb.set_trace() df = pd.DataFrame(intp_buy, index = grid[1][0:,0], columns = grid[0][0]) df1 = pd.DataFrame(intp_sold, index = grid[1][0:,0], columns = grid[0][0]) @@ -151,8 +169,6 @@ def plot_color_map(df, val_date): #rows are spread, columns are volatility surface shift fig, ax = plt.subplots() - #import pdb; pdb.set_trace() - #Different ways to do a colormap: imshow and pcolormesh. using imshow here midpoint = 1 - df.max().max()/(df.max().max() + abs(df.min().min())) shifted_cmap = shiftedColorMap(cm.RdYlGn, midpoint=midpoint, name='shifted') @@ -166,8 +182,6 @@ def plot_color_map(df, val_date): fig.colorbar(chart, shrink = .8) - #import pdb; pdb.set_trace() - fig.savefig("/home/serenitas/edwin/PythonGraphs/payer_swap_" + str(val_date.date()) + ".png") def build_vol_surface_functions(date = datetime.date(2017, 2, 23), index = 'IG', series = '27'): @@ -187,7 +201,7 @@ def build_vol_surface_functions(date = datetime.date(2017, 2, 23), index = 'IG', df1 = df1.groupby(df1.index).filter(lambda x: len(x) >= 2) df1 = df1.reset_index() #once the dates are in the columns you need the use .dt to access dates functions - df1['days_to_expiry'] = (df1.expiry - df1.quotedate.dt.normalize().dt.tz_localize(None)) / np.timedelta64(1,'D') + df1['days_to_expiry'] = (df1.expiry - df1.quotedate.dt.normalize().dt.tz_localize(None)).dt.days df1['moneyness'] = (df1.strike - df1.ref)/df1.ref df1 = df1.groupby(['days_to_expiry','moneyness']).nth(-1).vol df1 = df1.reset_index() @@ -201,6 +215,21 @@ def vol_from_surface(row, f, g): vol = g(row.days_to_expiry, row.moneyness) return vol +def calc_and_plot(bought, sold, traded_price, week, lowerbound, upperbound, deltaPNL=None): + + if week > len(bought.index.get_level_values(0).unique()): + week = len(bought.index.get_level_values(0).unique())-1 + + date = bought.index.get_level_values(0).unique()[week] + + PNL = find_mapped_pv(bought, sold, date) - traded_price + deltaPNL.loc[date.date()] + + PNL = PNL[lowerbound:upperbound].sort_index(ascending = False) + + plot_color_map(PNL, date) + + return PNL + def full_analysis(): index = 'IG' series = 27, @@ -210,37 +239,41 @@ def full_analysis(): sell_strike = 72 ref = 62 trade_date = datetime.date(2017, 2, 23) + delta_notional = 13000000 t_range = pd.bdate_range(trade_date, buy_expiry- BDay(), freq = '5B') + spread_range = pd.Series(np.arange(ref - 10, ref +19, 5)) - bought = build_swaption(index, series, buy_expiry, buy_strike, ref, trade_date, t_range) - sold = build_swaption(index, series, sell_expiry, sell_strike, ref, trade_date, t_range) + bought = build_swaption(index, series, buy_expiry, buy_strike, ref, trade_date, t_range, spread_range) + sold = build_swaption(index, series, sell_expiry, sell_strike, ref, trade_date, t_range, spread_range) + + delta_PNL = calc_delta_pnl(index, series, ref, trade_date, delta_notional, t_range, spread_range) #Calc PNL and Plot: traded_price = 5000 lowerbound = -.05 #parallel shift down 5% vol upperbound = .1 #parallel shift up 10% vol - week = -3 #negative to count backwards + week = 1 #negative to count backwards - PNL = calc_and_plot(bought, sold, traded_price, week, lowerbound, upperbound) + PNL = calc_and_plot(bought, sold, traded_price, week, lowerbound, upperbound, delta_PNL) + + return (bought, sold, PNL, delta_PNL) - return (bought, sold, PNL) -def calc_and_plot(bought, sold, traded_price, week, lowerbound, upperbound): - if week > len(bought.index.get_level_values(0).unique()): - week = len(bought.index.get_level_values(0).unique())-1 - date = bought.index.get_level_values(0).unique()[week] - PNL = find_mapped_pv(bought, sold, date) - traded_price - PNL = PNL[lowerbound:upperbound].sort_index(ascending = False) - plot_color_map(PNL, date) - return PNL +def manual_index_update(index, date): #index as Index Object + index._yc = index._yc.expected_forward_curve(date) + index._trade_date = date + index._step_in_date = index.trade_date + datetime.timedelta(days=1) + index._accrued = index._fee_leg.accrued(index._step_in_date) + index._value_date = (pd.Timestamp(index._trade_date) + 3* BDay()).date() + index._update() import numpy as np |
