diff options
| -rw-r--r-- | python/analytics/portfolio.py | 4 | ||||
| -rw-r--r-- | python/exploration/swaption_calendar_spread.py | 89 | ||||
| -rw-r--r-- | python/graphics.py | 17 | ||||
| -rw-r--r-- | python/notebooks/Option Trades.ipynb | 150 |
4 files changed, 65 insertions, 195 deletions
diff --git a/python/analytics/portfolio.py b/python/analytics/portfolio.py index 809b49a2..43d9b5e7 100644 --- a/python/analytics/portfolio.py +++ b/python/analytics/portfolio.py @@ -88,11 +88,11 @@ class Portfolio: vs = BlackSwaptionVolSurface(index_type, series, tenor, index.value_date) if surface_id is None: for source in source_list: - if len(vs.list(source, option_type, model)) >=1: + if len(vs.list(source)) >=1: break else: raise ValueError("No market data available for this day") - self._vs[k] = vs[vs.list(source, option_type, model)[-1]] + self._vs[k] = vs[vs.list(source)[-1]] else: self._vs[k] = vs[surface_id] for swaption in self.swaptions: diff --git a/python/exploration/swaption_calendar_spread.py b/python/exploration/swaption_calendar_spread.py deleted file mode 100644 index e21ffd66..00000000 --- a/python/exploration/swaption_calendar_spread.py +++ /dev/null @@ -1,89 +0,0 @@ -import sys -#don't do this at home -sys.path.append("..") -from analytics import (Swaption, BlackSwaption, BlackSwaptionVolSurface, - Index, ProbSurface, 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 - -import os -import numpy as np -import matplotlib -import matplotlib.pyplot as plt -from graphics import plot_time_color_map, plot_color_map - -from db import dbengine -engine = dbengine('serenitasdb') - -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_trade_scenarios(portf, shock_min=-.15, shock_max=.2, period=-1, vol_time_roll=True): - portf.reset_pv() - 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') - vol_shock = np.arange(-0.15, 0.3, 0.01) - spread_shock = np.arange(shock_min, shock_max, 0.01) - index = portf.indices[0].name.split()[1] - series = portf.indices[0].name.split()[3][1:] - vs = BlackSwaptionVolSurface(index, 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, vol_shock, vol_surface, - params=["pnl","delta"]) - - hy_plot_range = 100 + (500 - portf.indices[0].spread * (1 + spread_shock)) * \ - abs(portf.indices[0].DV01) / portf.indices[0].notional * 100 - - shock = hy_plot_range if index == 'HY' else portf.indices[0].spread * (1 + spread_shock) - - 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)==.2], shock, 'pnl', index=index) - plot_color_map(df.loc[date_range[period]], shock, vol_shock, 'pnl', index=index) - return df - -def exercise_probability(): - engine = dbengine('serenitasdb') - #Ad hoc - option_delta = Index.from_name('HY', 29, '5yr') - option_delta.price = 107.875 - option1 = BlackSwaption(option_delta, datetime.date(2017, 12, 20), 107, option_type="payer") - option2 = BlackSwaption(option_delta, datetime.date(2017, 12, 20), 105, option_type="payer") - option1.sigma = .280 - option2.sigma = .371 - option1.notional = 20_000_000 - option2.notional = 40_000_000 - option1.direction = 'Long' - option2.direction = 'Short' - option_delta.notional = option1.notional * option1.delta + option2.notional * option2.delta - option_delta.direction = 'Seller' if option_delta.notional > 0 else 'Buyer' - option_delta.notional = abs(option_delta.notional) - portf = Portfolio([option1, option2, option_delta]) - - portf.reset_pv() - 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='5B') - vol_shock = np.arange(-0.15, 0.3, 0.01) - 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 = ProbSurface(index, series, trade_date=portf.indices[0].trade_date) - vs.plot(vs.list()[-1]) diff --git a/python/graphics.py b/python/graphics.py index cc538aa8..fc9764bb 100644 --- a/python/graphics.py +++ b/python/graphics.py @@ -141,4 +141,19 @@ def plot_prob_map(df, attr="pnl", path=".", color_map=cm.RdYlGn, index='IG'): ax.set_ylabel('Probability') ax.set_title('{} of Trade'.format(attr.title())) - fig.colorbar(chart, shrink=.8)
\ No newline at end of file + fig.colorbar(chart, shrink=.8) + +def plot_swaption_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))
\ No newline at end of file diff --git a/python/notebooks/Option Trades.ipynb b/python/notebooks/Option Trades.ipynb index f550923d..ff4c6525 100644 --- a/python/notebooks/Option Trades.ipynb +++ b/python/notebooks/Option Trades.ipynb @@ -6,11 +6,15 @@ "metadata": {}, "outputs": [], "source": [ + "import datetime\n", + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "from graphics import plot_time_color_map, plot_color_map\n", "from analytics import Swaption, BlackSwaption, BlackSwaptionVolSurface, Index, Portfolio\n", "from analytics.scenarios import run_swaption_scenarios, run_index_scenarios, run_portfolio_scenarios\n", - "import datetime\n", "\n", - "from exploration.swaption_calendar_spread import plot_trade_scenarios\n", + "#from exploration.swaption_calendar_spread import plot_trade_scenarios\n", "#import swaption_calendar_spread as spread" ] }, @@ -29,17 +33,48 @@ "metadata": {}, "outputs": [], "source": [ + "def plot_trade_scenarios(portf, shock_min=-.15, shock_max=.2, period=-1, vol_time_roll=True):\n", + " portf.reset_pv()\n", + " earliest_date = min(portf.swaptions, key=lambda x: x.exercise_date).exercise_date\n", + " date_range = pd.bdate_range(portf.indices[0].value_date,\n", + " earliest_date - pd.tseries.offsets.BDay(), freq='3B')\n", + " vol_shock = np.arange(-0.15, 0.3, 0.01)\n", + " spread_shock = np.arange(shock_min, shock_max, 0.01)\n", + " index = portf.indices[0].name.split()[1]\n", + " series = portf.indices[0].name.split()[3][1:]\n", + " vs = BlackSwaptionVolSurface(index, series, value_date=portf.indices[0].value_date)\n", + " vol_surface = vs[vs.list(option_type='payer')[-1]]\n", + "\n", + " df = run_portfolio_scenarios(portf, date_range, spread_shock, vol_shock, vol_surface,\n", + " params=[\"pnl\",\"delta\"])\n", + "\n", + " hy_plot_range = 100 + (500 - portf.indices[0].spread * (1 + spread_shock)) * \\\n", + " abs(portf.indices[0].DV01) / portf.indices[0].notional * 100\n", + "\n", + " shock = hy_plot_range if index == 'HY' else portf.indices[0].spread * (1 + spread_shock)\n", + "\n", + " plot_time_color_map(df[round(df.vol_shock,2)==0], shock, 'pnl', index=index)\n", + " plot_time_color_map(df[round(df.vol_shock,2)==.2], shock, 'pnl', index=index)\n", + " plot_color_map(df.loc[date_range[period]], shock, vol_shock, 'pnl', index=index)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ "#Ad hoc\n", - "option_delta = Index.from_name('IG', 29, '5yr', trade_date=datetime.date(2018, 1, 3))\n", - "option_delta.spread = 50\n", - "option1 = BlackSwaption(option_delta, datetime.date(2018, 2, 21), 55, option_type=\"payer\")\n", - "option2 = BlackSwaption(option_delta, datetime.date(2018, 2, 21), 67.5, option_type=\"payer\")\n", - "option3 = BlackSwaption(option_delta, datetime.date(2018, 2, 21), 80, option_type=\"payer\")\n", - "option1.sigma = .38\n", - "option2.sigma = .61\n", + "option_delta = Index.from_name('IG', 30, '5yr', value_date=datetime.date(2018, 5, 17))\n", + "option_delta.spread = 61\n", + "option1 = BlackSwaption(option_delta, datetime.date(2018, 8, 15), 60, option_type=\"payer\")\n", + "option2 = BlackSwaption(option_delta, datetime.date(2018, 8, 15), 80, option_type=\"payer\")\n", + "option3 = BlackSwaption(option_delta, datetime.date(2018, 8, 15), 80, option_type=\"payer\")\n", + "option1.sigma = .381\n", + "option2.sigma = .545\n", "option3.sigma = .69\n", "option1.notional = 100_000_000\n", - "option2.notional = 200_000_000\n", + "option2.notional = 300_000_000\n", "option3.notional = 1\n", "option1.direction = 'Long'\n", "option2.direction = 'Short'\n", @@ -68,34 +103,6 @@ "metadata": {}, "outputs": [], "source": [ - "portf.trade_date = datetime.date(2018,2,1)\n", - "portf.ref = 52\n", - "#portf.swaptions[0].sigma = .25\n", - "#portf.swaptions[1].sigma = .31\n", - "#portf.swaptions[2].sigma = .46\n", - "portf.swaptions[0].sigma = .38\n", - "portf.swaptions[1].sigma = .61\n", - "#portf.swaptions[2].sigma = .69\n", - "portf" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df.spread = df.spread.round(2)\n", - "df1= df.set_index('spread', append=True)\n", - "df1.xs(('2018-01-16', '66.0'))" - ] - }, - { - "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", @@ -147,7 +154,7 @@ "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.value_date = datetime.date(2017, 5, 17)\n", "portf.mark()\n", "plot_trade_scenarios(portf)" ] @@ -171,69 +178,6 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": [ - "#Ad hoc\n", - "option_delta = Index.from_name('IG', 29, '5yr')\n", - "option_delta.spread = 49.5\n", - "option1 = BlackSwaption(option_delta, datetime.date(2018, 2, 21), 55, option_type=\"payer\")\n", - "option2 = BlackSwaption(option_delta, datetime.date(2018, 2, 21), 67.5, option_type=\"payer\")\n", - "option3 = BlackSwaption(option_delta, datetime.date(2018, 1, 21), 52.5, option_type=\"payer\")\n", - "option4 = BlackSwaption(option_delta, datetime.date(2018, 1, 21), 60, option_type=\"payer\")\n", - "option1.sigma = .38\n", - "option2.sigma = .61\n", - "option3.sigma = .371\n", - "option4.sigma = .581\n", - "option1.notional = 100_000_000\n", - "option2.notional = 200_000_000\n", - "option3.notional = 100_000_000\n", - "option4.notional = 100_000_000\n", - "option1.direction = 'Long'\n", - "option2.direction = 'Short'\n", - "option3.direction = 'Short'\n", - "option4.direction = 'Long'\n", - "#option_delta.notional = 1\n", - "option_delta.notional = option1.notional * option1.delta + option2.notional * option2.delta \n", - "option_delta.direction = 'Seller' if option_delta.notional > 0 else 'Buyer'\n", - "option_delta.notional = abs(option_delta.notional)\n", - "portf = Portfolio([option1, option2, option3, option4, option_delta])\n", - "#Plot Scenarios Inputs: Portfolio, spread shock tightening%, spread shock widening%, snapshot period)\n", - "plot_trade_scenarios(portf, -.15, .8, -4, vol_time_roll=False)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "portf" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "portf.pv" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "portf.trade_date = datetime.date(2018,1,16)\n", - "portf.ref = 47\n", - "portf.pnl" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], "source": [] } ], @@ -253,7 +197,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.4" + "version": "3.6.5" } }, "nbformat": 4, |
