import sys #don't do this at home sys.path.append("..") from analytics import Swaption, BlackSwaption, Index, VolatilitySurface, Portfolio from analytics.scenarios import run_swaption_scenarios, run_index_scenarios, run_portfolio_scenarios from pandas.tseries.offsets import BDay import datetime import numpy as np import pandas as pd from scipy.interpolate import SmoothBivariateSpline from matplotlib import cm from mpl_toolkits.mplot3d import Axes3D import matplotlib.pyplot as plt import os import numpy as np import matplotlib import matplotlib.pyplot as plt from mpl_toolkits.axes_grid1 import AxesGrid import re from db import dbengine engine = dbengine('serenitasdb') 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 def plot_df(df, spread_shock, vol_shock, attr="pnl"): val_date = df.index[0].date() fig = plt.figure() ax = fig.gca(projection='3d') ## use smoothing spline on a finer grid series = df[attr] f = SmoothBivariateSpline(df.vol_shock.values, df.spread_shock.values, series.values) xx, yy = np.meshgrid(vol_shock, spread_shock) surf = ax.plot_surface(xx, yy, f(vol_shock, spread_shock).T, cmap=cm.viridis) ax.set_xlabel("Volatility shock") ax.set_ylabel("Spread") 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="."): 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_shock','vol_shock'], ascending = [True,False], 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') chart = ax.imshow(series.values.reshape(spread_shock.size, vol_shock.size).T, extent=(spread_shock.min(), spread_shock.max(), vol_shock.min(), vol_shock.max()), aspect='auto', interpolation='bilinear', cmap=shifted_cmap) 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): val_date = df.index[0].date() df = df.reset_index() df['days'] = (df['date'] - val_date).dt.days df.sort_values(by=['date','spread_shock'], ascending = [True,False], inplace = True) date_range = df.days.unique() fig, ax = plt.subplots() series = df[attr] midpoint = 1 - series.max() / (series.max() + abs(series.min())) shifted_cmap = shiftedColorMap(color_map, midpoint=midpoint, name='shifted') chart = ax.imshow(series.values.reshape(date_range.size, spread_shock.size).T, extent=(date_range.min(), date_range.max(), spread_shock.min(), spread_shock.max()), aspect='auto', interpolation='bilinear', cmap=shifted_cmap) ax.set_xlabel('Days') 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 = max([t for t in vs.list() if t[1] == 'BAML' and t[2] == 'payer' and t[3] == 'black']) 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(): 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 = max([t for t in vs.list() if t[1] == 'BAML' and t[2] == 'payer' and t[3] == 'black']) 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(): 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 = max([t for t in vs.list() if t[1] == 'BAML' and t[2] == 'payer' and t[3] == 'black']) 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 may_june_2017_trade(): option_delta = Index.from_tradeid(874) option1 = BlackSwaption.from_tradeid(7, option_delta) option2 = BlackSwaption.from_tradeid(8, option_delta) portf = Portfolio([option1, option2, option_delta]) 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 = max([t for t in vs.list() if t[1] == 'BAML' and t[2] == 'payer' and t[3] == 'black']) 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 portfolio_scenario_2(): #Manually Load trades option_delta = Index.from_name('ig', 28, '5yr') option_delta.spread = 67 option1 = BlackSwaption(option_delta, datetime.date(2017, 6, 21), 65, option_type="receiver") option2 = BlackSwaption(option_delta, datetime.date(2017, 5, 17), 65, option_type="receiver") option1.sigma = .39 option2.sigma = .424 option1.notional = 100_000_000 option2.notional = -100_000_000 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) #setting original pvs for pnl calc option1._original_pv = option1.pv option2._original_pv = option2.pv option_delta._original_clean_pv = option_delta._clean_pv option_delta._original_trade_date = option_delta._trade_date portf = Portfolio([option1, option2, option_delta]) 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 = max([t for t in vs.list() if t[1] == 'BAML' and t[2] == 'payer' and t[3] == 'black']) 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') #Delta in protection terms: Blue = going short, red = going long plot_time_color_map(df[round(df.vol_shock,2)==0], ref * (1 + spread_shock), 'delta', color_map = cm.coolwarm_r) def portfolio(): option_delta = Index.from_tradeid(874) option1 = BlackSwaption.from_tradeid(7, option_delta) option2 = BlackSwaption.from_tradeid(8, option_delta) 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 = max([t for t in vs.list() if t[1] == 'BAML' and t[2] == 'payer' and t[3] == 'black']) 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 portfolio_today(): option_deltas = {} options = {} for trade_id in [870,872,873]: option_deltas[trade_id] = Index.from_tradeid(trade_id) option_deltas[trade_id].trade_date = datetime.date.today() index_type = re.search('CDX (\w+) ', option_deltas[trade_id].name).group(1) series = re.search('\d+', option_deltas[trade_id].name).group(0) spread = pd.read_sql_query( "SELECT closespread FROM index_quotes " \ "WHERE date <= %s and index= %s and series = %s and tenor = '5yr'" \ "ORDER BY date DESC limit 1", engine, params=(option_deltas[trade_id].trade_date, index_type, series)) option_deltas[trade_id].spread = spread.iloc[0][0] option_deltas[trade_id].set_original_pv() for trade_id in [6]: options[trade_id] = BlackSwaption.from_tradeid(trade_id, option_deltas[870]) #options[trade_id].trade_date = datetime.date.today() options[trade_id].sigma = .5 options[trade_id].set_original_pv() #index_type = re.search('CDX (\w+) ', options[trade_id].index.name).group(1) #series = re.search('\d+', options[trade_id].index.name).group(0) #import pdb; pdb.set_trace() portf = Portfolio([*option_deltas, *options]) 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 = max([t for t in vs.list() if t[1] == 'BAML' and t[2] == 'payer' and t[3] == 'black']) 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 plot_time_color_map(df[round(df.vol_shock,2)==0], option_delta.spread * (1 + spread_shock), 'pnl') 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 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))