Skip to content

Commit

Permalink
adding structures, interpcurve, etc.
Browse files Browse the repository at this point in the history
  • Loading branch information
bart mosley committed Jul 31, 2011
1 parent 7a5849a commit 6e2945c
Show file tree
Hide file tree
Showing 6 changed files with 439 additions and 0 deletions.
4 changes: 4 additions & 0 deletions structures/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
'''
Structures
'''
72 changes: 72 additions & 0 deletions structures/interpcurve.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
"""
Structures to facilitate interpolating financial curves.
"""

import bgpy.QL as ql

from bgpy.math import interp

def is_numeric(x):
try:
return float(x)
except:
return None

class InterpCurve(object):
'''
Used to interpolate a financial curve.
Curve is given as a dict object:
curvedata = {tenor: value}
where tenor is, for example, '10Y' for 10 years.
'''
def __init__(self, curvedata=None, datadivisor=100.0):
self.divisor = datadivisor

if curvedata:
self.update(curvedata)

def update(self, curvedata):

self.curve_ = [(ql.Tenor(tnr).term, val / self.divisor)
for tnr, val in curvedata.items()
if is_numeric(val)]
self.curve_.sort()

def __call__(self, *args):
'''
Call with tenor string, e.g. 10Y or settlement, maturity.
'''
assert len(args) <= 2, "InterpCurve().__call__ takes either one or two args"

term = None
if len(args) == 1:
term = args[0]

if type(term) == str:
term = ql.Tenor(term).term

elif hasattr(term, "__iter__"):
sd, mty = term
return self.maturity(sd, mty)

else:
sd = args[0]
mty = args[1]
return self.maturity(sd, mty)

return interp(self.curve_, term)

def maturity(self, settle, maturity, daycount=ql.ActualActualISDA):
'''
Calls interp for given dates
'''
settle = ql.toDate(settle)
maturity = ql.toDate(maturity)
years_ = daycount.yearFraction(settle, maturity)
return self(years_)

56 changes: 56 additions & 0 deletions structures/modelcurve.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@

import bgpy.QL as ql

from scales import Scale
from volatility import VolCurve

class ModelScale(Scale):
'''
Inputs:
termstructure
curvedata ~ {tenor: coupon, bondyield, spread, ratio, vol}
curvedate=None
model = ql.BlackKarasinski
'''
def __init__(self, termstructure, curvedata=None, curvedate=None,
call=("10Y", 100.0),
model=ql.BlackKarasinski):

self.scalecoupons = dict([(t, curvedata[t][0]) for t in curvedata])

Scale.__init__(self, self.scalecoupons, curvedate, call=call,
coupon="par")

self.spreaddata = [(t, curvedata[t][2:]) for t in curvedata]
self.spreaddata = dict(self.spreaddata)

self.values = self.updateBondValues(termstructure, self.spreaddata)

self.curvedata = {}
for tenor in self.bonds:
prc = self.values[tenor].oasPrice
cpn = self.bonds[tenor].coupon
mty = self.bonds[tenor].maturity

self.curvedata[mty] = (cpn, prc)

self.termstructure = ql.SimpleCurve(setIborIndex=False)
self.termstructure.update(self.curvedata, self.curvedate)

self.callfeature_ = call
self.ussv = {}

for tenor in self.bonds:
thisbond = self.bonds[tenor]
prc = thisbond.toPrice(curvedata[tenor][1])
vol = thisbond.assetSwap().solveImpliedVol(self.termstructure,
prc,
0.,
1.)

self.ussv[tenor] = vol.vol

self.volCurve = VolCurve(self.ussv, datadivisor=1.0)


59 changes: 59 additions & 0 deletions structures/refbond.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import bgpy.QL as ql


def refBond(bond, issuedate=None, call='10Y', coupon=None):
"""
return a MuniBond object of the bond, adjusted for reference structure.
coupon = None, value
None: uses same coupon as bond
value: coupon to use, e.g. 5% = .05
"""

def refCall(settledate, maturitydate, tenor='10Y'):
refDate0 = ql.Tenor(tenor).advance(settledate)

refDate1 = ql.toDate(maturitydate.dayOfMonth(),
maturitydate.month(),
refDate0.year())

if ql.Thirty360().dayCount(refDate1, maturitydate) <= 0:
return maturitydate

diff = ql.Thirty360().dayCount(refDate0, refDate1)

if abs(diff) <= 180:
return refDate1
elif diff > 0:
reverseFlag = True
else:
reverseFlag = False

return ql.Tenor('6M').advance(refDate1, reverse=reverseFlag)

cpn = bond.coupon if not coupon else coupon
mty = bond.maturity

redval = bond.redvalue
oid = bond.oid

issuedate = ql.toDate(issuedate) if issuedate else bond.settlementDate

calltenor = ql.Tenor(call)
calldt = refCall(issuedate, mty)

if ql.Thirty360().dayCount(calldt, mty) > 0:
bcall = ql.Call(calldt, 100., mty)
else:
bcall = None

stl = bond.settlementDate

return ql.MuniBond(cpn,
mty,
oid = oid,
callfeature=bcall,
redvalue=redval,
settledate=stl)

Loading

0 comments on commit 6e2945c

Please sign in to comment.