aboutsummaryrefslogtreecommitdiffstats
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/pnl_explain.py107
1 files changed, 69 insertions, 38 deletions
diff --git a/python/pnl_explain.py b/python/pnl_explain.py
index 73c76fe6..360dc45f 100644
--- a/python/pnl_explain.py
+++ b/python/pnl_explain.py
@@ -1,13 +1,12 @@
import pandas as pd
from functools import reduce
from position import get_list
-from sqlalchemy import create_engine
+from db import dbengine
from dates import bus_day, imm_dates
def pnl_explain(identifier, start_date = None, end_date = None,
- uri = 'postgresql://dawn_user@debian/dawndb'):
+ engine = dbengine("dawndb")):
""" if start_date is None, pnl since inception"""
- engine = create_engine(uri)
trades = pd.read_sql_query("SELECT * FROM bonds where identifier=%s", engine,
params=(identifier,), parse_dates=['trade_date', 'settle_date'],
index_col=['settle_date'])
@@ -44,42 +43,61 @@ def pnl_explain(identifier, start_date = None, end_date = None,
daily['clean_nav'] = daily.price/100 * daily.factor * daily.faceamount
daily['realized_accrued'] = daily.interest/100 * daily.faceamount
days_accrued = daily.index - daily.prev_cpn_date
- daily['unrealized_accrued'] = days_accrued.dt.days/360*daily.coupon/100*daily.factor*daily.faceamount
+ daily['accrued'] = days_accrued.dt.days/360*daily.coupon/100*daily.factor*daily.faceamount
extra_pnl = daily.clean_nav.diff() - daily.principal_payment
daily.loc[daily.principal_payment>0 , 'unrealized_pnl'] += extra_pnl[daily.principal_payment>0]
daily.loc[daily.principal_payment<0, 'realized_pnl'] += extra_pnl[daily.principal_payment<0]
daily['realized_accrued'] -= daily.accrued_payment
- daily['accrued'] = daily.unrealized_accrued.diff() + daily.realized_accrued
- return daily[['unrealized_pnl', 'realized_pnl', 'unrealized_accrued', 'realized_accrued', 'accrued']].iloc[1:,]
+ daily['unrealized_accrued'] = daily.accrued.diff() + daily.realized_accrued
+ return daily[['clean_nav', 'accrued', 'unrealized_pnl', 'realized_pnl', 'unrealized_accrued',
+ 'realized_accrued']].iloc[1:,]
-def pnl_explain_list(engine, id_list, start_date = None, end_date = None):
- return reduce(lambda x,y: x.add(y, fill_value=0),
- (pnl_explain(engine, identifier, start_date, end_date) for identifier in id_list))
+def pnl_explain_list(id_list, start_date = None, end_date = None, engine = dbengine("dawndb")):
+ return {identifier: pnl_explain(identifier, start_date, end_date, engine)
+ for identifier in id_list}
-def cds_explain(engine, index, series, tenor, attach = None, detach = None,
- start_date = None, end_date = None):
- factors = pd.read_sql_query("SELECT * FROM index_desc WHERE index=%s AND series=%s AND tenor=%s "\
- "ORDER BY lastdate",
- engine, parse_dates=['lastdate'],
- index_col='lastdate', params = (index, series, tenor))
+def cds_explain(index, series, tenor, attach = None, detach = None,
+ start_date = None, end_date = None, engine = dbengine('serenitasdb')):
if attach is None:
- quotes = pd.read_sql_query("SELECT * from index_quotes WHERE index=%s AND series=%s AND tenor=%s " \
- "ORDER BY date",
+ quotes = pd.read_sql_query("SELECT date, (100-closeprice) AS upfront FROM index_quotes " \
+ "WHERE index=%s AND series=%s AND tenor=%s ORDER BY date",
engine, parse_dates=['date'],
index_col='date', params = (index, series, tenor))
+ factors = pd.read_sql_query("""
+SELECT indexfactor/100 AS indexfactor, cumulativeloss/100 AS cumulativeloss
+lastdate FROM index_desc WHERE index=%s AND series=%s AND tenor=%s ORDER BY lastdate
+""",
+ engine, parse_dates=['lastdate'], index_col='lastdate',
+ params = (attach, detach, index, series, tenor))
else:
- quotes = pd.read_sql_query("SELECT quotedate, upfront_mid AS closeprice, tranche_spread " \
- "FROM markit_tranche_quotes JOIN index_version " \
- "USING (basketid) WHERE index=%s AND series=%s " \
+ #we take the latest version available
+ quotes = pd.read_sql_query("SELECT DISTINCT ON (quotedate) quotedate, upfront_mid AS upfront, "\
+ "tranche_spread FROM markit_tranche_quotes " \
+ "JOIN index_version USING (basketid) " \
+ "WHERE index=%s AND series=%s " \
"AND tenor=%s AND attach=%s AND detach=%s " \
- "ORDER by quotedate",
+ "ORDER by quotedate, version desc",
engine, parse_dates=['quotedate'], index_col='quotedate',
params = (index, series, tenor, attach, detach))
+ factors = pd.read_sql_query("""
+SELECT tranche_factor(%s::smallint, %s::smallint, indexfactor, cumulativeloss/100),
+indexfactor/100 AS indexfactor, cumulativeloss/100 AS cumulativeloss, lastdate
+FROM index_desc WHERE index=%s AND series=%s AND tenor=%s ORDER BY lastdate
+""",
+ "postgresql://serenitas_user@debian/serenitasdb",
+ parse_dates=['lastdate'], index_col='lastdate',
+ params = (attach, detach, index, series, tenor))
if start_date is None:
start_date = quotes.index.min()
if end_date is None:
end_date = pd.datetime.today()
- coupon = 0.01
+
+ #we use tranche_factor
+ if attach:
+ factors['factor'] = factors.tranche_factor
+ else:
+ factors['factor'] = factors.indexfactor
+
dates = pd.date_range(start_date, end_date, freq = bus_day)
yearfrac = imm_dates(start_date, end_date)
yearfrac = yearfrac.to_series().reindex(dates, method='ffill')
@@ -89,25 +107,38 @@ def cds_explain(engine, index, series, tenor, attach = None, detach = None,
quotes = quotes.reindex(dates, method='ffill')
recovery = -factors.indexfactor.diff()-factors.cumulativeloss.diff()
recovery.name = 'recovery'
- recovery = recovery.shift(-1)/100
+ recovery = recovery.shift(-1)
recovery = recovery.reindex(dates, fill_value=0).shift()
df = (quotes.
- join(factors[['indexfactor']], how='left').
+ join(factors[['factor']], how='left').
join(recovery).join(yearfrac))
- df.indexfactor = df.indexfactor.bfill()/100
- df.loc[df.indexfactor.isnull(), 'indexfactor'] = factors.indexfactor.iat[-1]/100
- df['unrealized_accrued'] = df.yearfrac*coupon*df.indexfactor
- df['accrued'] = df.unrealized_accrued.diff()
- df['realized_accrued'] = -df.accrued.where(df.accrued<0, 0)
- df.accrued = df.accrued.where(df.accrued>0, df.unrealized_accrued)
- df.loc[df.realized_accrued>0, 'realized_accrued'] += df.loc[df.realized_accrued>0, 'accrued']
- df['unrealized_pnl'] = df.closeprice.diff() * df.indexfactor.shift()/100
- df['realized_pnl'] = df.closeprice/100*df.indexfactor.diff()+df.recovery
+ if attach:
+ coupon = df.tranche_spread.iat[0]/10000
+ else:
+ coupon = factors.coupon.iat[0]/10000
+ df.indexfactor = df.indexfactor.bfill()
+ df.loc[df.indexfactor.isnull(), 'indexfactor'] = factors.factor.iat[-1]
+ df['clean_nav'] = df.upfront*df.factor
+ df['accrued'] = df.yearfrac*coupon*df.factor
+ df['unrealized_accrued'] = df.accrued.diff()
+ df['realized_accrued'] = -df.unrealized_accrued.where(df.unrealized_accrued.isnull() |
+ (df.unrealized_accrued<0), 0)
+ df['unrealized_accrued'] = df.unrealized_accrued.where(df.unrealized_accrued.isnull()|
+ (df.unrealized_accrued>0), df.accrued)
+ df.loc[df.realized_accrued>0, 'realized_accrued'] += df.loc[df.realized_accrued>0, 'unrealized_accrued']
+ df['unrealized_pnl'] = df.upfront.diff() * df.factor.shift()/100
+ df['realized_pnl'] = df.upfront/100*df.indexfactor.diff()+df.recovery
return df
+
+def cds_explain2(dealid):
+ pass
+
if __name__=="__main__":
- # workdate = pd.datetime.today()
- # clo_list = get_list(workdate, 'Subprime')
- # df = pnl_explain_list(engine, clo_list.identifier.tolist(), '2015-10-30', '2015-11-30')
- engine = create_engine("postgresql://serenitas_user@debian/serenitasdb")
- df = cds_explain(engine, 'IG', 9, '10yr')
+ workdate = pd.datetime.today()
+ engine = dbengine("dawndb")
+ clo_list = get_list(engine, workdate, 'CLO')
+ df = pnl_explain_list(clo_list.identifier.tolist(), '2015-10-30', '2015-11-30', engine)
+ df = pd.concat(df)
+ df_agg = df.groupby(level=1).sum()
+ cds_df = cds_explain('HY', 21, '5yr', 25, 35, '2014-07-18')