-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
adding structures, interpcurve, etc.
- Loading branch information
bart mosley
committed
Jul 31, 2011
1 parent
7a5849a
commit 6e2945c
Showing
6 changed files
with
439 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
''' | ||
Structures | ||
''' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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_) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
|
Oops, something went wrong.