{ "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 analytics.curve_trades as ct\n", "import datetime\n", "\n", "from ipywidgets import widgets\n", "from pandas.tseries.offsets import BDay\n", "from analytics.scenarios import run_curve_scenarios\n", "from analytics.curve_trades import curve_spread_diff, spreads_diff_table, theta_matrix_by_series\n", "from scipy.optimize import brentq\n", "from utils.db import dbengine\n", "from 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 = w.value\n", "series = 34 if index == 'IG' else 32\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": [ "#HY curve trade re-ref calculator - sell protection index_1, buy protection index_2 \n", "date = datetime.date.today()\n", "index_type = 'HY'\n", "series_1 = '29'\n", "series_2 = '34'\n", "index_1_trade_price = 104.75\n", "index_2_trade_price = 104.8\n", "reref_2 = 104.71\n", "\n", "#-----------------------------\n", "index_1 = CreditIndex(index_type, series_1, '5yr', date)\n", "index_2 = CreditIndex(index_type, series_2, '5yr', date)\n", "index_1.price = index_1_trade_price\n", "index_2.price = index_2_trade_price\n", "index_2.notional = index_1.notional * index_1.risky_annuity/index_2.risky_annuity\n", "index_1.direction = 'Seller'\n", "index_2.direction = 'Buyer'\n", "past_pv = index_2.pv\n", "index_2.price = reref_2 \n", "index_1.pv = -index_1.pv + (index_2.pv - past_pv)\n", " \n", "pd.options.display.float_format = '{:,.4f}'.format\n", "d = {index_type + series_1: [index_1_trade_price, index_1.price , index_1.notional], index_type + series_2: [index_2_trade_price, reref_2, index_2.notional]}\n", "pd.DataFrame(d, index=['original ref', 're-ref', 'notionals'])" ] }, { "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": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Do the same regression for Itrxx\n", "model = ct.curve_model('5yr', '10yr', index='EU')\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": [ "df = ct.forward_spread(report_date, index)\n", "df.plot()\n", "plt.ylabel('spread')\n", "plt.xlabel('forward spread start date')" ] }, { "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 steepness scenario at current spread\n", "#df_plot = df.set_index(['spread', 'curve_per'], append=True)\n", "#df_plot = df_plot.xs(round(spread_df.iloc[0][0], 2), level = 'spread')\n", "#df_plot.name = 'pnl'\n", "#g.plot_color_map(df_plot, spread_range)" ] }, { "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')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from exploration.VaR import hist_var\n", "IG = ct.curve_pos(report_date, 'IG')\n", "ITRX = ct.curve_pos(report_date, 'EU')\n", "VaR = hist_var(IG, 'IG') + hist_var(ITRX, 'EU')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "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.8.1" } }, "nbformat": 4, "nbformat_minor": 4 }