diff options
| -rw-r--r-- | python/exploration/swaption_calendar_spread.py | 165 | ||||
| -rw-r--r-- | python/notebooks/Option Trades.ipynb | 142 | ||||
| -rw-r--r-- | python/option_trades_et.py | 336 |
3 files changed, 169 insertions, 474 deletions
diff --git a/python/exploration/swaption_calendar_spread.py b/python/exploration/swaption_calendar_spread.py index 3cf23b52..304e7be9 100644 --- a/python/exploration/swaption_calendar_spread.py +++ b/python/exploration/swaption_calendar_spread.py @@ -11,6 +11,7 @@ from scipy.interpolate import SmoothBivariateSpline from matplotlib import cm from mpl_toolkits.mplot3d import Axes3D import matplotlib.pyplot as plt +from operator import attrgetter import os import numpy as np @@ -88,16 +89,16 @@ def plot_df(df, spread_shock, vol_shock, attr="pnl"): ax.set_zlabel("PnL") ax.set_title('{} of Trade on {}'.format(attr.title(), val_date)) -def plot_color_map(df, spread_shock, vol_shock, attr="pnl", path="."): +def plot_color_map(df, spread_shock, vol_shock, attr="pnl", path=".", index ='IG'): val_date = df.index[0].date() #rows are spread, columns are volatility surface shift fig, ax = plt.subplots() #We are plotting an image, so we have to sort from high to low on the Y axis - df.sort_values(by=['spread','vol_shock'], ascending = [True,False], inplace = True) + ascending = [False,False] if index == 'HY' else [True,False] + df.sort_values(by=['spread','vol_shock'], ascending = ascending, inplace = True) series = df[attr] - #import pdb; pdb.set_trace() midpoint = 1 - series.max() / (series.max() + abs(series.min())) shifted_cmap = shiftedColorMap(cm.RdYlGn, midpoint=midpoint, name='shifted') @@ -106,21 +107,23 @@ def plot_color_map(df, spread_shock, vol_shock, attr="pnl", path="."): vol_shock.min(), vol_shock.max()), aspect='auto', interpolation='bilinear', cmap=shifted_cmap) - ax.set_xlabel('Spread') + ax.set_xlabel('Price') if index == 'HY' else ax.set_xlabel('Spread') ax.set_ylabel('Volatility shock') ax.set_title('{} of Trade on {}'.format(attr.title(), val_date)) fig.colorbar(chart, shrink=.8) #fig.savefig(os.path.join(path, "vol_spread_color_map"+ attr+ "_{}.png".format(val_date))) -def plot_time_color_map(df, spread_shock, attr="pnl", path=".", color_map = cm.RdYlGn): +def plot_time_color_map(df, spread_shock, attr="pnl", path=".", color_map = cm.RdYlGn, index ='IG'): val_date = df.index[0].date() df = df.reset_index() df['days'] = (df['date'] - val_date).dt.days - df.sort_values(by=['date','spread'], ascending = [True,False], inplace = True) + ascending = [True,True] if index == 'HY' else [True,False] + df.sort_values(by=['date','spread'], ascending = ascending, inplace = True) date_range = df.days.unique() + #plt.style.use('seaborn-whitegrid') fig, ax = plt.subplots() series = df[attr] midpoint = 1 - series.max() / (series.max() + abs(series.min())) @@ -131,152 +134,38 @@ def plot_time_color_map(df, spread_shock, attr="pnl", path=".", color_map = cm.R spread_shock.min(), spread_shock.max()), aspect='auto', interpolation='bilinear', cmap=shifted_cmap) + #chart = ax.contour(date_range, spread_shock, series.values.reshape(date_range.size, spread_shock.size).T) + ax.set_xlabel('Days') - ax.set_ylabel('Spread') + ax.set_ylabel('Price') if index == 'HY' else ax.set_ylabel('Spread') ax.set_title('{} of Trade'.format(attr.title())) fig.colorbar(chart, shrink=.8) #fig.savefig(os.path.join(path, "spread_time_color_map_"+ attr+ "_{}.png".format(val_date))) -def dec_jan_2017_trade(): - option_delta = Index.from_tradeid(864) - option1 = BlackSwaption.from_tradeid(3, option_delta) - option2 = BlackSwaption.from_tradeid(4, option_delta) - - portf = Portfolio([option1, option2, option_delta]) - date_range = pd.bdate_range(option_delta.trade_date, pd.Timestamp('2017-01-18') - BDay(), freq = '2B') - vol_shock = np.arange(-0.15, 0.3, 0.01) - spread_shock = np.arange(-0.2, 0.3, 0.01) - vs = VolatilitySurface("IG", 27, trade_date=option_delta.trade_date) - vol_select = vs.list('BAML', 'payer', 'black')[-1] - vol_surface = vs[vol_select] - - df = run_portfolio_scenarios(portf, date_range, spread_shock, vol_shock, - vol_surface, params=["pnl", "delta"], vol_time_roll=False) - plot_time_color_map(df[round(df.vol_shock,2)==0], option_delta.spread * (1 + spread_shock), 'pnl') - -def april_may_2017_trade(what='pnl'): - option_delta = Index.from_tradeid(870) - option1 = BlackSwaption.from_tradeid(5, option_delta) - option2 = BlackSwaption.from_tradeid(6, option_delta) - - portf = Portfolio([option1, option2, option_delta]) - date_range = pd.bdate_range(option_delta.trade_date, pd.Timestamp('2017-04-19') - BDay(), freq = '2B') - vol_shock = np.arange(-0.15, 0.3, 0.01) - spread_shock = np.arange(-0.2, 0.3, 0.01) - vs = VolatilitySurface("IG", 27, trade_date=option_delta.trade_date) - vol_select = vs.list('BAML', 'payer', 'black')[-1] - vol_surface = vs[vol_select] - - df = run_portfolio_scenarios(portf, date_range, spread_shock, vol_shock, - vol_surface, params=[what], vol_time_roll=False) - plot_time_color_map(df[abs(df.vol_shock)<1e-3], option_delta.spread * (1 + spread_shock), what) - - -def june_july_2017_trade(): - option_delta_pf = Index.from_tradeid(874) - option_delta2_pf = Index.from_tradeid(879) - - option1_pf = BlackSwaption.from_tradeid(7, option_delta_pf) - option2_pf = BlackSwaption.from_tradeid(9, option_delta_pf) - #option_delta.notional = option_delta.notional - option_delta2.notional - option_delta_pf.notional = 50_335_169 - - portf = Portfolio([option1_pf, option2_pf, option_delta_pf]) - portf.trade_date = datetime.date(2017, 5, 17) - portf.mark() - portf.reset_pv() - - date_range = pd.bdate_range(option_delta_pf.trade_date, pd.Timestamp('2017-06-21') - BDay(), freq = '2B') - vol_shock = np.arange(-0.15, 0.3, 0.01) - spread_shock = np.arange(-0.2, 0.3, 0.01) - vs = VolatilitySurface("IG", 28, trade_date=option_delta_pf.trade_date) - vol_select = vs.list('BAML', 'payer', 'black')[-1] - vol_surface = vs[vol_select] - - df = run_portfolio_scenarios(portf, date_range, spread_shock, vol_shock, vol_surface, - params=["pnl", "delta"], vol_time_roll=True) +def plot_trade_scenarios(portf): - #period = -4 - #plot_df(df.loc[date_range[period]], spread_plot_range, vol_shock_range) - #plot_color_map(df.loc[date_range[period]], option_delta.spread * (1 + spread_shock), vol_shock, 'pnl') - plot_time_color_map(df[round(df.vol_shock,2)==0], option_delta_pf.spread * (1 + spread_shock), 'pnl') - #plot_time_color_map(df[round(df.vol_shock,2)==0], ref * (1 + spread_shock), 'delta', color_map = cm.coolwarm_r) - return df - -def hy_trade_scenario(): - - #Manually Load trades - option_delta = Index.from_name('hy', 28, '5yr') - option_delta.price = 107.5 - option1 = BlackSwaption(option_delta, datetime.date(2017, 8, 16), 106, option_type="payer") - option2 = BlackSwaption(option_delta, datetime.date(2017, 8, 16), 104, option_type="payer") - option1.sigma = .331 - option2.sigma = .388 - option1.notional = 20_000_000 - option2.notional = 40_000_000 - option2.direction = 'Short' - option_delta.notional = -(option1.delta * option1.notional + option2.delta*option2.notional) - if option_delta.notional < 0: - option_delta.direction = 'Seller' - option_delta.notional = abs(option_delta.notional) - - portf = Portfolio([option1, option2, option_delta]) portf.reset_pv() - date_range = pd.bdate_range(option_delta.trade_date, pd.Timestamp('2017-08-16') - BDay(), freq = '5B') + earliest_date = min(portf.swaptions,key=attrgetter('exercise_date')).exercise_date + date_range = pd.bdate_range(portf.indices[0].trade_date, earliest_date - BDay(), freq = '5B') vol_shock = np.arange(-0.15, 0.3, 0.01) - spread_shock = np.arange(-0.1, 0.4, 0.01) - vs = VolatilitySurface("HY", 28, trade_date=option_delta.trade_date) - vol_select = vs.list('BAML', 'payer', 'black')[-1] + spread_shock = np.arange(-0.15, 0.35, 0.01) + index = portf.indices[0].name.split()[1] + series = portf.indices[0].name.split()[3][1:] + vs = VolatilitySurface(index, series, trade_date=portf.indices[0].trade_date) + vol_select = vs.list(option_type='payer', model='black')[-1] vol_surface = vs[vol_select] - df = run_portfolio_scenarios(portf, date_range, spread_shock, vol_shock, vol_surface, params=["pnl", "delta"], vol_time_roll=True) - - #period = -4 - #plot_df(df.loc[date_range[period]], spread_plot_range, vol_shock_range) - #plot_color_map(df.loc[date_range[period]], option_delta.spread * (1 + spread_shock), vol_shock, 'pnl') - #plot_time_color_map(df[round(df.vol_shock,2)==0], option_delta.spread * (1 + spread_shock), 'pnl') - hy_plot_range = 100 + (500- option_delta.spread * (1 + spread_shock))*option_delta.DV01/option_delta.notional*100 - plot_time_color_map(df[round(df.vol_shock,2)==0], hy_plot_range, 'pnl') - #Delta in protection terms: Blue = going short, red = going long - #plot_time_color_map(df[round(df.vol_shock,2)==0], option_delta.spread * (1 + spread_shock), 'delta', color_map = cm.coolwarm_r) + df = run_portfolio_scenarios(portf, date_range, spread_shock, vol_shock, vol_surface, params=["pnl","delta"], vol_time_roll=True) - return df + hy_plot_range = 100 - (500- portf.indices[0].spread * (1 + spread_shock))*portf.indices[0].DV01/portf.indices[0].notional*100 -def portfolio(): - option_delta = Index.from_tradeid(874) - option1 = BlackSwaption.from_tradeid(7, option_delta) - option2 = BlackSwaption.from_tradeid(8, option_delta) + shock = hy_plot_range if index == 'HY' else portf.indices[0].spread * (1 + spread_shock) - portf = Portfolio([option1, option2, option3, option_delta, option_delta1, option_delta2, option_delta3]) - date_range = pd.bdate_range(option_delta.trade_date, pd.Timestamp('2017-05-17') - BDay(), freq = '2B') - vol_shock = np.arange(-0.15, 0.3, 0.01) - spread_shock = np.arange(-0.2, 0.3, 0.01) - vs = VolatilitySurface("IG", 28, trade_date=option_delta.trade_date) - vol_select = vs.list('BAML', 'payer', 'black')[-1] - vol_surface = vs[vol_select] - - df = run_portfolio_scenarios(portf, date_range, spread_shock, vol_shock, vol_surface, params=["pnl", "delta"], vol_time_roll=False) - - #plot it period = -4 - #plot_df(df.loc[date_range[period]], spread_plot_range, vol_shock_range) - plot_color_map(df.loc[date_range[period]], option_delta.spread * (1 + spread_shock), vol_shock, 'pnl') - plot_time_color_map(df[round(df.vol_shock,2)==0], option_delta.spread * (1 + spread_shock), 'pnl') - plot_time_color_map(df[round(df.vol_shock,2)==0], ref * (1 + spread_shock), 'delta', color_map = cm.coolwarm_r) - -def probabilities(): - from scipy.stats import lognorm - - option_delta = Index.from_tradeid(874) - vs = VolatilitySurface("IG", 28, trade_date=option_delta.trade_date) - vol_select = max([t for t in vs.list() if t[1] == 'BAML' and t[2] == 'payer' and t[3] == 'black']) - vol_surface = vs[vol_select] - t = .1 - mon = 1 + plot_time_color_map(df[round(df.vol_shock,2)==0], shock, 'pnl', index=index) + plot_time_color_map(df[round(df.vol_shock,2)==0], shock, 'delta', color_map = cm.coolwarm_r, index=index) + plot_color_map(df.loc[date_range[period]], shock, vol_shock, 'pnl', index=index) + #plot_df(df.loc[date_range[period]], shock, vol_shock) - date_range = pd.bdate_range(option_delta.trade_date, pd.Timestamp('2017-05-17') - BDay(), freq = 'B') - curr_vols = np.maximum(vol_surface.ev(t, mon), 0) - dist = lognorm(curr_vols, scale) - lognorm.ppf(.5, curr_vols, scale = np.exp(64)) diff --git a/python/notebooks/Option Trades.ipynb b/python/notebooks/Option Trades.ipynb new file mode 100644 index 00000000..4440d5f2 --- /dev/null +++ b/python/notebooks/Option Trades.ipynb @@ -0,0 +1,142 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from analytics import Swaption, BlackSwaption, Index, VolatilitySurface, Portfolio\n", + "from analytics.scenarios import run_swaption_scenarios, run_index_scenarios, run_portfolio_scenarios\n", + "import datetime\n", + "\n", + "import swaption_calendar_spread as spread" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#Delta Chart: Red = Long Risk, Blue = Short Risk" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#Ad hoc\n", + "option_delta = Index.from_name('HY', 28, '5yr')\n", + "option_delta.price = 107.625\n", + "option1 = BlackSwaption(option_delta, datetime.date(2017, 9, 20), 107, option_type=\"payer\")\n", + "option2 = BlackSwaption(option_delta, datetime.date(2017, 9, 20), 105, option_type=\"payer\")\n", + "option1.sigma = .270\n", + "option2.sigma = .3625\n", + "option1.notional = 20_000_000\n", + "option2.notional = 40_000_000\n", + "option1.direction = 'Long'\n", + "option2.direction = 'Short'\n", + "option_delta.notional = -2000000\n", + "#option_delta.notional = option_delta.notional - option_delta2.notional\n", + "if option_delta.notional < 0:\n", + " option_delta.direction = 'Seller'\n", + " option_delta.notional = abs(option_delta.notional)\n", + "portf = Portfolio([option1, option2, option_delta])\n", + "spread.plot_trade_scenarios(portf)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#Dec Jan 2017 Trade\n", + "option_delta = Index.from_tradeid(864)\n", + "option1 = BlackSwaption.from_tradeid(3, option_delta)\n", + "option2 = BlackSwaption.from_tradeid(4, option_delta)\n", + "portf = Portfolio([option1, option2, option_delta])\n", + "spread.plot_trade_scenarios(portf)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#Feb 2017: Sell May Buy April Calendar Trade\n", + "option_delta = Index.from_tradeid(870)\n", + "option1 = BlackSwaption.from_tradeid(5, option_delta)\n", + "option2 = BlackSwaption.from_tradeid(6, option_delta)\n", + "portf = Portfolio([option1, option2, option_delta])\n", + "spread.plot_trade_scenarios(portf)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#April 2017: Sell May Buy June Calendar Trade\n", + "option_delta = Index.from_tradeid(874)\n", + "option1 = BlackSwaption.from_tradeid(7, option_delta)\n", + "option2 = BlackSwaption.from_tradeid(8, option_delta)\n", + "portf = Portfolio([option1, option2, option_delta])\n", + "spread.plot_trade_scenarios(portf)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#June July 2017 Calendar Trade\n", + "option_delta_pf = Index.from_tradeid(874)\n", + "option_delta2_pf = Index.from_tradeid(879)\n", + "\n", + "option1_pf = BlackSwaption.from_tradeid(7, option_delta_pf)\n", + "option2_pf = BlackSwaption.from_tradeid(9, option_delta_pf)\n", + "option_delta_pf.notional = 50_335_169\n", + "\n", + "portf = Portfolio([option1_pf, option2_pf, option_delta_pf])\n", + "portf.trade_date = datetime.date(2017, 5, 17)\n", + "portf.mark()\n", + "spread.plot_trade_scenarios(portf)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/python/option_trades_et.py b/python/option_trades_et.py deleted file mode 100644 index 8b64e7b7..00000000 --- a/python/option_trades_et.py +++ /dev/null @@ -1,336 +0,0 @@ -import analytics.option as opt -import pandas as pd -import numpy as np -import matplotlib.pyplot as plt -import numpy as np -import matplotlib.colors as colors -import math - -from matplotlib import cm -from exploration.option_trades import * -from pandas.tseries.offsets import * -from analytics import Index, ForwardIndex -from db import dbengine, dbconn -from scipy.interpolate import * - -serenitasdb = dbengine('serenitasdb') - -def get_dfs(index="IG"): - df0 = atm_vol(index, datetime.date(2014, 6, 11)) - df = rolling_vol(df0, 'atm_vol', term=[1,2,3,4,5,6]) - df1 = rolling_vol(df0, 'otm_vol', term=[1,2,3,4,5,6]) - return (df,df1) - -def calendar_spread(): - df = get_dfs()[0] - df['cal 3m-1m'] = df['3m']-df['1m'] - df['cal 5m-3m'] = df['5m']-df['3m'] - df = df.sort_index() - df = df.groupby(df.index.date).nth(-1) - df[['cal 3m-1m','cal 5m-3m']].plot() - #last 100,100-200,200-300 days - avg = pd.DataFrame([df[-100:].mean(),df[-200:-100].mean(),df[-300:-200].mean()]) - return (df[-1:], avg) - -def put_spread(index = "IG"): - dfs = get_dfs() - df = pd.concat([dfs[0], dfs[1]], axis = 1, keys=['atm','otm']) - steepness = df['otm'] - df['atm'] - steepness.plot() - #last 100,100-200,200-300 days - avg = pd.DataFrame([steepness[-100:].mean(),steepness[-200:-100].mean(),steepness[-300:-200].mean()]) - return (steepness[-1:], avg) - -def swaption_analysis(): - cal = calendar_spread() - cal_otm = calendar_spread(moneyness = "otm_vol") - vol_df = atm_vol('IG',27).groupby(level = 'quotedate').last().dropna() - -def beta_calc(): - am = arch_model(10000*index_price_returns(index='IG')) - res = am.fit(update_freq=0, disp='off') - - amIG = arch_model(100*index_returns()) - resIG = amIG.fit(update_freq=0, disp='off') - ltvar = lr_var(resIG) - - amHY = arch_model(1000*index_returns(index = 'HY')) - resHY = amHY.fit(update_freq=0, disp='off') - ltvar = lr_var(resHY) - graphit = compute_allocation(all_tenors) - -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 - - 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 aux(row, index, swap): - index.spread = row.spread - manual_index_update(index, row.date.date()) - swap.sigma = row.vol/100 - swap._update() - return swap.pv - - df['pv'] = df.apply(aux, axis=1, args=(index_obj, swap_obj)) - - #calculate mapped vol - df['moneyness'] = (strike- df.spread)/df.spread - 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') - df = df.set_index(['date', 'spread', 'vol']) - - 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 and complains a lot. annoying - x = bought.spread.unique() - y = sorted(bought.mapping_shift.unique()) - grid = np.meshgrid(x,y) - f_buy = SmoothBivariateSpline(bought.spread, bought.mapping_shift, bought.pv, kx = 4, ky = 4) - 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]) - 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]) - - #Use NDInterpolate - not copmplete - #f_buy = LinearNDInterpolator((bought.spread, bought.mapping_shift), bought.pv) - #f_sold = LinearNDInterpolator((sold.spread, sold.mapping_shift), sold.pv) - - #Use interp2d - #x = bought.spread.unique() - #y = sorted(bought.mapping_shift.unique()) - #f_buy = interp2d(bought.spread, bought.mapping_shift, bought.pv) - #f_sold = interp2d(sold.spread, sold.mapping_shift, sold.pv) - #intp_buy = f_buy(x,y) - #intp_sold = f_sold(x,y) - #df = pd.DataFrame(data = intp_buy, index = y, columns = x) - #df1 = pd.DataFrame(data = intp_sold, index = y, columns = x) - - PNL = df - df1 - - return PNL - -def result_fill(df, date): - - data = df.xs(date).reset_index() - #make df.vol a variable to make this function more general - f = interp2d(data.spread, data.vol, data.pv) - x = np.arange(data.spread.min(), data.spread.max(), .5) - y = np.arange(data.vol.min(), data.vol.max(), .5) - intp_result = f(x,y) - df1 = pd.DataFrame(data = intp_result, index = y, columns = x) - - return df1 - -def plot_color_map(df, val_date): - - #rows are spread, columns are volatility surface shift - fig, ax = plt.subplots() - - #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') - - chart = ax.imshow(df, extent=(df.columns.min(), df.columns.max(), df.index.min(), df.index.max()) \ - ,aspect= 'auto', interpolation='bilinear', cmap=shifted_cmap) - - ax.set_xlabel('Spread') - ax.set_ylabel('Parallel Shift of Volatility Surface') - ax.set_title('PV of Trade on ' + str(val_date.date())) - - fig.colorbar(chart, shrink = .8) - - 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'): - df1 = pd.read_sql_query('SELECT quotedate, expiry, series, strike, vol ' \ - 'FROM swaption_quotes ' \ - 'WHERE index = %s and series = %s and date(quotedate) = %s', - serenitasdb, - index_col=['quotedate', 'expiry', 'series'], - params=(index.upper(), series, date), parse_dates=['quotedate', 'expiry']) - index_data = pd.read_sql_query( - 'SELECT quotedate, expiry, series, ref, fwdspread FROM swaption_ref_quotes ' \ - 'WHERE index= %s and date(quotedate) = %s', - serenitasdb, index_col=['quotedate', 'expiry', 'series'], - params=(index.upper(), date), parse_dates=['quotedate', 'expiry']) - - df1 = df1.join(index_data) - 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)).dt.days - df1['moneyness'] = (df1.strike - df1.ref)/df1.ref - df1 = df1.groupby(['days_to_expiry','moneyness']).nth(-1).vol - df1 = df1.reset_index() - f = LinearNDInterpolator((df1.days_to_expiry, df1.moneyness), df1.vol) - g = NearestNDInterpolator((df1.days_to_expiry, df1.moneyness), df1.vol) - return (f,g) - -def vol_from_surface(row, f, g): - vol = f(row.days_to_expiry, row.moneyness) - if math.isnan(vol) is True: - 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, - buy_expiry = datetime.date(2017, 4, 19) - buy_strike = 65 - sell_expiry = datetime.date(2017, 5, 17) - 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, 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 = 1 #negative to count backwards - - PNL = calc_and_plot(bought, sold, traded_price, week, lowerbound, upperbound, delta_PNL) - - return (bought, sold, PNL, delta_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 -import matplotlib -import matplotlib.pyplot as plt -from mpl_toolkits.axes_grid1 import AxesGrid - -def shiftedColorMap(cmap, start=0, midpoint=0.5, stop=1.0, name='shiftedcmap'): - ''' - Function to offset the "center" of a colormap. Useful for - data with a negative min and positive max and you want the - middle of the colormap's dynamic range to be at zero - - Input - ----- - cmap : The matplotlib colormap to be altered - start : Offset from lowest point in the colormap's range. - Defaults to 0.0 (no lower ofset). Should be between - 0.0 and `midpoint`. - midpoint : The new center of the colormap. Defaults to - 0.5 (no shift). Should be between 0.0 and 1.0. In - general, this should be 1 - vmax/(vmax + abs(vmin)) - For example if your data range from -15.0 to +5.0 and - you want the center of the colormap at 0.0, `midpoint` - should be set to 1 - 5/(5 + 15)) or 0.75 - stop : Offset from highets point in the colormap's range. - Defaults to 1.0 (no upper ofset). Should be between - `midpoint` and 1.0. - ''' - cdict = { - 'red': [], - 'green': [], - 'blue': [], - 'alpha': [] - } - - # regular index to compute the colors - reg_index = np.linspace(start, stop, 257) - - # shifted index to match the data - shift_index = np.hstack([ - np.linspace(0.0, midpoint, 128, endpoint=False), - np.linspace(midpoint, 1.0, 129, endpoint=True) - ]) - - for ri, si in zip(reg_index, shift_index): - r, g, b, a = cmap(ri) - - cdict['red'].append((si, r, r)) - cdict['green'].append((si, g, g)) - cdict['blue'].append((si, b, b)) - cdict['alpha'].append((si, a, a)) - - newcmap = matplotlib.colors.LinearSegmentedColormap(name, cdict) - plt.register_cmap(cmap=newcmap) - - return newcmap - - - |
