from pyisda.curve import YieldCurve, BadDay, SpreadCurve, BasketIndex from pyisda.legs import FeeLeg, ContingentLeg from pyisda.logging import enable_logging import datetime import math import pandas as pd from yieldcurve import YC, ql_to_jp from quantlib.settings import Settings from quantlib.time.api import Date import numpy as np from db import dbconn from concurrent.futures import ProcessPoolExecutor, as_completed from itertools import zip_longest, chain def get_singlenames_quotes(indexname, date): conn = dbconn('serenitasdb') with conn.cursor() as c: c.execute("SELECT * FROM curve_quotes(%s, %s)", vars=(indexname, date)) return [r for r in c] def build_curve(r, today_date, yc, start_date, step_in_date, value_date, end_dates): spread_curve = 1e-4 * np.array(r['spread_curve'][1:]) upfront_curve = 1e-2 * np.array(r['upfront_curve'][1:]) recovery_curve = np.array(r['recovery_curve'][1:]) sc = SpreadCurve(today_date, yc, start_date, step_in_date, value_date, end_dates, spread_curve, upfront_curve, recovery_curve, True) return (r['cds_ticker'], sc) def grouper(iterable, n, fillvalue=None): "Collect data into fixed-length chunks or blocks" # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx args = [iter(iterable)] * n return zip_longest(fillvalue=fillvalue, *args) def build_curves_dist(quotes, args, workers=4): ## about twice as fast as the non distributed version ## non thread safe for some reason so need ProcessPool with ProcessPoolExecutor(workers) as e: fs = [e.submit(build_curves, *(q, args)) for q in grouper(quotes, 30)] return list(chain.from_iterable([f.result() for f in as_completed(fs)])) def build_curves(quotes, args): return [build_curve(q, *args) for q in quotes if q is not None] Settings().evaluation_date = Date(6, 2, 2017) yc = YC() jp_yc = ql_to_jp(yc) today_date = datetime.date(2017, 2, 6) step_in_date = datetime.date(2017, 2, 7) value_date = datetime.date(2017, 2, 9) start_date = datetime.date(2016, 12, 20) end_dates = [datetime.date(2017, 12, 20), datetime.date(2018, 12, 20), datetime.date(2019, 12, 20), datetime.date(2020, 12, 20), datetime.date(2021, 12, 20), datetime.date(2023, 12, 20), datetime.date(2026, 12, 20)] quotes = get_singlenames_quotes("ig27", today_date) args = (today_date, jp_yc, start_date, step_in_date, value_date, end_dates) curves = build_curves_dist(quotes, args) def all_curves_pv(curves, today_date, jp_yc, start_date, step_in_date, value_date, end_dates): r = {} for d in end_dates: tenor = {} coupon_leg = FeeLeg(start_date, d, True, 1., 1.) default_leg = ContingentLeg(start_date, d, True) accrued = coupon_leg.accrued(step_in_date) tickers = [] data = [] for ticker, sc in curves: coupon_leg_pv = coupon_leg.pv(today_date, step_in_date, value_date, jp_yc, sc, False) default_leg_pv = default_leg.pv(today_date, step_in_date, value_date, jp_yc, sc, 0.4) tickers.append(ticker) data.append((coupon_leg_pv-accrued, default_leg_pv)) r[pd.Timestamp(d)] = pd.DataFrame.from_records(data, index=tickers, columns=['duration', 'protection_pv']) indexpv = r.mean().unstack() return indexpv.protection_pv-indexpv.duration*0.01 def stack_curves(curves): dates = [d for d, _ in curves[0].inspect()['data']] hazard_rates = np.empty((len(curves), len(dates))) for i, sc in enumerate(curves): hazard_rates[i] = np.array([h for _, h in sc.inspect()['data']]) return hazard_rates, dates def all_curves_pv2(curves, today_date, jp_yc, start_date, step_in_date, value_date, end_dates): tickers = [t for t, _ in curves] hazard_rates, end_dates = stack_curves([c for _, c in curves]) r = {} for maturity in end_dates: data = [] ig27 = BasketIndex(today_date, start_date, maturity, end_dates, hazard_rates) data.append(ig27.pv(step_in_date, value_date, jp_yc, 0.4)) r[pd.Timestamp(d)] = pd.DataFrame.from_records(data, index=tickers, columns=['duration', 'protection_pv']) return r def forward_hazard_rates(sc): r = [] t = [] t1 = 0 h1 = 0 base_date = sc.base_date for d, h in sc.inspect()['data']: h2 = math.log1p(h) t2 = (d - base_date).days / 365 r.append( (h2 * t2 - h1 * t1) / (t2 - t1) ) t.append(t2) h1, t1 = h2, t2 return t, r ticker, sc = curves[0] sc2 = sc.tweak_curve(0.01, inplace=False) # class CreditIndex: # def __init__(name, trade_date): # @property # def quotes(): # pass # forward_hazard_rates() # for d, q in # @quotes.setter # def quotes(val): # self._quotes = val # for d, q in self._quotes: