{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "import pandas as pd\n", "import numpy as np\n", "import graphics as g\n", "import globeop_reports as go\n", "import serenitas.analytics.curve_trades as ct\n", "import datetime\n", "\n", "from ipywidgets import widgets\n", "from pandas.tseries.offsets import BDay\n", "from serenitas.analytics.scenarios import run_curve_scenarios\n", "from serenitas.analytics.curve_trades import curve_spread_diff, spreads_diff_table, theta_matrix_by_series\n", "from scipy.optimize import brentq\n", "from serenitas.utils.db import dbengine\n", "from serenitas.analytics import CreditIndex" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "w = widgets.Dropdown(\n", " options=['IG', 'EU'],\n", " value='IG',\n", " description='Index:',\n", " disabled=False,\n", ")\n", "w" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "index = w.value\n", "report_date = (datetime.date.today() - BDay(1)).date()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "index = 'EU'\n", "series = 36 if index == 'IG' else 35\n", "model = ct.curve_model('5yr', '10yr', index=index, max_series=series)\n", "model_results = ct.curve_model_results(model[0], model[1])" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "model_results['diff'] = model_results['predicted'] - model_results['close_spread']\n", "model_results" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "model[1].summary()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#On the run spread differences\n", "spreads_diff = curve_spread_diff(index, 6)\n", "spreads_diff.plot()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Table of Spread Differences, and Z-score of current spread differences\n", "spreads_diff_table(spreads_diff)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Theta per unit duration\n", "ct.theta_matrix_by_series(index)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#on the run theta\n", "ct.on_the_run_theta(index)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "rolling = 20\n", "years = 5\n", "ret = ct.curve_returns(index, rolling, years)\n", "if index == 'IG':\n", " ret1 = ct.curve_returns('HY', rolling, years)\n", " suf = ' HY'\n", "else:\n", " ret1 = ct.curve_returns('IG', rolling, years)\n", " suf = ' IG'\n", "ret = ret.join(ret1['5yr long'], rsuffix=suf)\n", "col_name = '5yr long' + suf" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Strategy Cumulative Return\n", "#Margin Requirement: 3% for IG Long only (33.3x), 25bps for curve (400x)\n", "#Assume Margin Requirement of 10% for IG Long only (10x) and size the curve trade margin to\n", "lev = 10\n", "#1) have the same return volatility or \n", "#curve_lev = ret['5yr long'].std()/ret['3-5-10'].std()\n", "#2) have the same cumulative return\n", "ret['5yr long lev'] = lev * ret['5yr long']\n", "def aux(x, ret, col_a, col_b):\n", " ret[col_b + ' lev'] = x * ret[col_b]\n", " cum_ret = (ret+1).cumprod()\n", " return cum_ret[col_a][-1] - cum_ret[col_b + ' lev'][-1]\n", "\n", "curve_lev = brentq(aux, 0.01, 3 * lev, args=(ret, '5yr long lev', '5-10'))\n", "other_lev = brentq(aux, 0.01, 3 * lev, args=(ret, '5yr long lev', col_name))\n", "\n", "ret['5-10 lev'] = curve_lev * ret['5-10']\n", "ret[col_name + ' lev'] = other_lev * ret[col_name]\n", "cum_ret = (ret+1).cumprod()\n", "cum_ret_ax = cum_ret[['5yr long lev', '5-10 lev', col_name + ' lev']].plot()\n", "cum_ret_ax.figure.savefig(\"/home/serenitas/edwin/PythonGraphs/curve_trades_cum_return.png\", bbox_inches='tight')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "curve_lev, other_lev" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Curve Trade returns\n", "ct.curve_returns_stats(ret)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#2016 scenario: max drawdown from the 2015 peak to 2016 trough\n", "peak = cum_ret['2015'].max()\n", "trough = cum_ret['2016'].min()\n", "scenario_2016 = pd.DataFrame({'peak': peak,\n", " 'trough': trough,\n", " 'max_drawdown': (peak - trough)/peak,\n", " 'peak_dates': cum_ret['2015'].idxmax(),\n", " 'trough_dates': cum_ret['2016'].idxmin()})\n", "scenario_2016" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ct.cross_series_curve(index)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Theta with 3-5-10 Strategy\n", "df = ct.ratio_within_series(param='duration')\n", "s = - df.theta['3yr'] / df.duration_ratio_to_5yr['3yr'] \\\n", " + 2 * df.theta['5yr'] \\\n", " - df.theta['10yr'] / df.duration_ratio_to_5yr['10yr']\n", "s.dropna().unstack(-1).plot()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Theta with 5-10 Strategy: buy sell 5y, buy 10y\n", "s = df.theta['5yr'] - df.theta['10yr'] / df.duration_ratio_to_5yr['10yr']\n", "s.dropna().unstack(-1).plot()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Relative Spread Difference\n", "spread_ratio = ct.ratio_within_series(param = 'close_spread')\n", "spread_ratio.groupby(level = ['date']).last()['close_spread_ratio_to_5yr'].plot()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "df = ct.spot_forward(index)\n", "df = df.rename(columns={'1yr': 'Spot Spread - 1 Year Forward', 'current': 'Spot Spread - Today'})\n", "ax = df.plot(title = 'Credit Curve Roll Down')\n", "plt.ylabel('spread (bps)')\n", "ax.figure.savefig(\"/home/serenitas/edwin/PythonGraphs/curve_trades_roll_down.png\", bbox_inches='tight')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "portf = ct.curve_pos(report_date, index)\n", "shock_min = -.5\n", "shock_max = .8\n", "spread_shock = np.arange(shock_min, shock_max, 0.05)\n", "sql_string = \"SELECT closespread FROM index_quotes where index = %s and series = %s and tenor = %s and date = %s\"\n", "spread_df = pd.read_sql_query(sql_string, dbengine('serenitasdb'),\n", " params=[index, ct.on_the_run(index), '5yr', report_date])\n", "spread_range = np.round((1+ spread_shock) * spread_df.iloc[0][0], 2)\n", "closest_mat = min([t.end_date for t in portf.trades])\n", "date_range = pd.bdate_range(report_date, min(closest_mat, (report_date + 180* pd.offsets.DateOffset()).date()), freq='5B')\n", "curve_per = np.arange(.01, .99, .1)\n", "\n", "df = run_curve_scenarios(portf, spread_range, date_range, curve_per)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Plot the shape of the scenario that was run above\n", "ct.plot_curve_shape(report_date)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Scenario Anslysis on current position\n", "#curve_positions = ct.curve_pos(report_date, index)\n", "#origpv = curve_positions.pv\n", "#flat_curve = ct.curve_shape(report_date, index, percentile = .05)\n", "#for ind in curve_positions.indices:\n", "# ind.spread = flat_curve((pd.to_datetime(ind.end_date) - report_date).days/365)\n", "#PNL in flattening to a 5% case\n", "#curve_positions.pv - origpv" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "curve_positions = ct.curve_pos(report_date, index)\n", "df = ct.pos_pnl_abs(curve_positions, report_date)\n", "navs = go.get_net_navs()\n", "df_plot = df.pnl/navs.iloc[-1].endbooknav" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "fig, ax = plt.subplots()\n", "ax.plot(df_plot.index, df_plot.values)\n", "ax.set(xlabel='date', ylabel='% of NAV',\n", " title='PNL impact from spread curve scenario')\n", "plt.xticks(rotation=90)\n", "y_ticks = ax.get_yticks()\n", "ax.set_yticklabels(['{:.2f}%'.format(y*100) for y in y_ticks])\n", "plt.tight_layout()\n", "#ax.figure.savefig(\"/home/serenitas/edwin/PythonGraphs/curve_trades.png\", bbox_inches='tight')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Historical PNL in a 5% case\n", "df.pnl.quantile(.05)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "scen_table = ct.curve_scen_table(curve_positions)\n", "scen_table.pnl = scen_table.pnl/navs.iloc[-1].endbooknav *100\n", "scen_table.pivot(index='tighter', columns='wider')" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3.9.1 64-bit", "language": "python", "name": "python39164bit6ddd573894c04d6a858a9a58880cc9d4" }, "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.9.1-final" } }, "nbformat": 4, "nbformat_minor": 4 }