aboutsummaryrefslogtreecommitdiffstats
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/analytics/curve_trades.py29
-rw-r--r--python/notebooks/Curve Trades.ipynb79
2 files changed, 98 insertions, 10 deletions
diff --git a/python/analytics/curve_trades.py b/python/analytics/curve_trades.py
index 455d1422..f76f6b88 100644
--- a/python/analytics/curve_trades.py
+++ b/python/analytics/curve_trades.py
@@ -82,12 +82,11 @@ def on_the_run_theta(index='IG', rolling=6):
theta_matrix = df.groupby(level=['date', 'tenor']).nth(-1)['theta_per_dur']
theta_matrix.unstack(-1).plot()
-
-def curve_returns(index='IG', rolling=6):
+def curve_returns(index='IG', rolling=6, years=3):
# look at returns
otr = on_the_run(index)
df = index_returns(index=index, series=list(range(otr - rolling, otr + 1)),
- tenor=['3yr', '5yr', '7yr', '10yr'])
+ tenor=['3yr', '5yr', '7yr', '10yr'], years=years)
# on-the-run returns
df = df.reset_index('index', drop=True)
returns = df.price_return.dropna().unstack('tenor').groupby(level='date').nth(-1)
@@ -97,7 +96,17 @@ def curve_returns(index='IG', rolling=6):
'7-10': 1.33 * returns['7yr'] - returns['10yr'],
'3-5-10': -2 * returns['3yr'] + 3 * returns['5yr'] - returns['10yr'],
'3-5': returns['5yr'] - 1.56 * returns['3yr'],
- '3-7': returns['7yr'] - 2.07 * returns['3yr']})
+ '3-7': returns['7yr'] - 2.07 * returns['3yr'],
+ '5yr long': returns['5yr']})
+
+ return strategies_return
+
+
+def curve_returns_stats(strategies_return):
+
+ '''
+ Takes a curve_return df'''
+
strategies_return_monthly = (strategies_return.
groupby(pd.Grouper(freq='M')).
agg(lambda df: (1 + df).prod() - 1))
@@ -108,10 +117,10 @@ def curve_returns(index='IG', rolling=6):
else:
return df.mean() / df.std() * math.sqrt(12)
- results = strategies_return.agg([sharpe, lambda df: df.nsmallest(10).mean()])
+ results = strategies_return.agg([sharpe, lambda df: df.nsmallest(10).mean(), lambda df: df.std()])
sharpe_monthly = strategies_return_monthly.agg(sharpe, period="monthly")
sharpe_monthly.name = 'Monthly Sharpe'
- results.index = ['Sharpe', 'Mean Worst 10 Days DrawDown']
+ results.index = ['Sharpe', 'Mean Worst 10 Days DrawDown', 'Standard Deviation']
return results.append(sharpe_monthly)
@@ -169,7 +178,11 @@ def curve_model(tenor_1='5yr', tenor_2='10yr'):
def curve_model_results(df, model):
df = df.dropna()
- prstd_ols, df['down_2_stdev'], df['up_2_stdev'] = wls_prediction_std(model)
+ a, b, c = wls_prediction_std(model)
+ b.name = 'down_2_stdev'
+ c.name = 'up_2_stdev'
+ df = df.join(b)
+ df = df.join(c)
#dr/dspread = exp(k) + spread_coeff * duration ^ dur_coeff * spread ^ (spread_coeff-1)
cols = ['ratio', 'closespread', 'down_2_stdev', 'up_2_stdev']
df[cols] = np.exp(df[cols])
@@ -324,7 +337,7 @@ def pos_pnl_abs(portf, value_date, index='IG', rolling=6, years=3):
for date, row in df.iterrows():
f = interp1d(np.hstack([0, lookup_table['year_frac']]), np.hstack([row[0]/2, row]))
for ind in portf_copy.indices:
- ind.spread = f((pd.to_datetime(ind.end_date) - value_date).days/365)
+ ind.spread = f((ind.end_date - value_date).days/365)
r.append([[date, f(5)] + [portf_copy.pnl]])
df = pd.DataFrame.from_records(chain(*r), columns=['date', 'five_yr_spread', 'pnl'])
return df.set_index('date')
diff --git a/python/notebooks/Curve Trades.ipynb b/python/notebooks/Curve Trades.ipynb
index a6ae0b7e..b2cde72e 100644
--- a/python/notebooks/Curve Trades.ipynb
+++ b/python/notebooks/Curve Trades.ipynb
@@ -16,6 +16,7 @@
"\n",
"from ipywidgets import widgets\n",
"from analytics.scenarios import run_curve_scenarios\n",
+ "from scipy.optimize import brentq\n",
"from db import dbengine"
]
},
@@ -41,7 +42,7 @@
"outputs": [],
"source": [
"index = w.value\n",
- "report_date = (pd.datetime.today() - pd.offsets.BDay(2)).normalize()"
+ "report_date = (pd.datetime.today() - pd.offsets.BDay(2)).date()"
]
},
{
@@ -91,8 +92,82 @@
"metadata": {},
"outputs": [],
"source": [
+ "rolling = 10\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', '3-5-10'))\n",
+ "other_lev = brentq(aux, 0.01, 3 * lev, args=(ret, '5yr long lev', col_name))\n",
+ "\n",
+ "ret['3-5-10 lev'] = curve_lev * ret['3-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', '3-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()"
+ "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"
]
},
{