{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", "import numpy as np\n", "import datetime\n", "import exploration.dispersion as disp\n", "import matplotlib.pyplot as plt\n", "import statsmodels.formula.api as smf\n", "\n", "from serenitas.analytics.basket_index import MarkitBasketIndex\n", "from serenitas.analytics.base import Trade\n", "from statsmodels.graphics.regressionplots import plot_fit\n", "from pygam import LinearGAM, s, f, GAM\n", "from serenitas.utils.db import dbengine\n", "\n", "serenitas_engine = dbengine('serenitasdb')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%matplotlib inline" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "value_date = (datetime.date.today() - pd.offsets.BDay(1)).date()\n", "index_type = 'IG'\n", "series = 37" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "series_back = 2\n", "sql_string = \"select * from index_members(%s, %s)\"\n", "\n", "df = pd.read_sql_query(sql_string, serenitas_engine, params=(index_type + str(series), value_date), index_col=['markit_ticker'])\n", "df1 = pd.read_sql_query(sql_string, serenitas_engine, params=(index_type + str(series-series_back), value_date), index_col=['markit_ticker'])\n", "\n", "default_prob = {}\n", "for s in [series, series-series_back]:\n", " index = MarkitBasketIndex(index_type, s, ['5yr'])\n", " surv_prob, tickers = index.survival_matrix()\n", " default_prob[s] = pd.Series(1 - np.ravel(surv_prob), index=tickers)\n", "default_prob = pd.concat(default_prob, names=['series', 'markit_ticker'])\n", "default_prob.name = 'default_prob'\n", "\n", "df = df.merge(default_prob.loc[series], left_index=True, right_index = True)\n", "df1 = df1.merge(default_prob.loc[series-series_back], left_index=True, right_index = True)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Removals\n", "df1.loc[df1.index.difference(df.index)]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Additions\n", "df.loc[df.index.difference(df1.index)]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "index_type, series, df.nlargest(10, columns='default_prob')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "index_type, series-series_back, df1.nlargest(10, columns='default_prob')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "date_range = pd.bdate_range(end=value_date, freq='1BM',periods=12)\n", "index = MarkitBasketIndex(index_type, series, ['5yr'])\n", "default_prob = {}\n", "for d in date_range:\n", " index.value_date = d\n", " surv_prob, tickers = index.survival_matrix()\n", " default_prob[d] = pd.Series(1 - np.ravel(surv_prob), index=tickers)\n", "default_prob = pd.concat(default_prob)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Top 20 highest cumulative\n", "top20 = default_prob.unstack(-1)\n", "top20 = top20[top20.iloc[-1].nlargest(25).index]\n", "top20.index.name='date'\n", "top20.columns.name='tickers'\n", "ax = top20.plot(title=f'market implied default probabilities to {index.maturities[0]}', figsize=(10,6))\n", "ax.legend(loc='upper center', bbox_to_anchor=(1.3, 1), ncol=1)\n", "ax.set(xlabel='date', ylabel='probability')\n", "plt.tight_layout()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "tenors = ['3yr', '5yr', '7yr', '10yr']\n", "#index_type = 'IG'\n", "#series = 26\n", "indices = MarkitBasketIndex(index_type, series, tenors)\n", "indices.value_date = datetime.date.today()\n", "today_surv_prob, tickers = indices.survival_matrix()\n", "today_default_prob = pd.DataFrame(1 - today_surv_prob, index=tickers, columns=tenors)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "####################### NAV Basis\n", "\n", "# HY | IG\n", "#+ve index trades risk rich | index trades risk cheap\n", "#-ve single trades risk rich | single trades risk cheap\n", "\n", "sql_string = \"select * from index_quotes where index = %s and tenor = '5yr'\"\n", "df = pd.read_sql_query(sql_string, serenitas_engine, params=(index_type,), index_col=['date'])\n", "df[\"dist_on_the_run\"] = df.groupby(\"date\")[\"series\"].transform(\n", " lambda x: x.max() - x\n", ")\n", "df = df.groupby(['date', 'series']).nth(-1) #take the last version\n", "df['basis'] = df.closespread - df.modelspread if index_type == 'IG' else df.closeprice - df.modelprice\n", "df.set_index('dist_on_the_run', append=True, inplace=True)\n", "df.reset_index('series', inplace=True)\n", "basis = df['basis'].unstack()\n", "stats = pd.DataFrame([basis.min(), basis.mean(), basis.max(), \n", " basis.quantile(.01), basis.quantile(.05), basis.quantile(.95), basis.quantile(.99)],\n", " index=['min', 'mean', 'max', \n", " '1%tile', '5%tile', '95%tile', '99%tile'])\n", "stats" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#######################OLS regression of NAV basis to spread/duration\n", "#basis_gini_model = smf.ols(\"basis ~ np.log(duration) + np.log(closespread) + np.log(gini_spread)\", data=df_gini_calc).fit()\n", "#basis_gini_model.summary()\n", "\n", "#Let's use a GAM model instead?\n", "df_gini_calc = df.dropna().loc[datetime.date(2019,1,1):, :].reset_index('dist_on_the_run')[\n", " ['index','series', 'tenor', 'duration', 'basis', 'closespread', 'gini']]\n", "\n", "X = np.array(df_gini_calc[['duration', 'closespread', 'gini']])\n", "y = np.array(df_gini_calc[['basis']])\n", "\n", "basis_model = GAM(s(0, constraints='concave') +\n", " s(1, constraints='concave') +\n", " s(2, constraints='concave'))\n", "\n", "lam = np.logspace(-3, 5, 5, base=10)\n", "lams = [lam] * 3\n", "\n", "basis_model.gridsearch(X, y, lam=lams)\n", "basis_model.summary()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "## plotting\n", "fig, axs = plt.subplots(1,3);\n", "\n", "titles = ['duration', 'closespread', 'gini_spread']\n", "for i, ax in enumerate(axs):\n", " XX = basis_model.generate_X_grid(term=i)\n", " ax.plot(XX[:, i], basis_model.partial_dependence(term=i, X=XX))\n", " ax.plot(XX[:, i], basis_model.partial_dependence(term=i, X=XX, width=.95)[1], c='r', ls='--')\n", " if i == 0:\n", " ax.set_ylim(-30,30)\n", " ax.set_title(titles[i]);" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "############## predict\n", "predict = basis_model.predict(X)\n", "plt.scatter(y, predict)\n", "plt.xlabel('actual basis')\n", "plt.ylabel('predicted basis')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "############## today's basis\n", "y[-1], predict[-1]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.10.4" } }, "nbformat": 4, "nbformat_minor": 4 }