P1: JYS
c06 JWBK378-Fletcher May 12, 2009 18:55 Printer: Yet to come
88 Financial Modelling in Python
self. legs = legs
self.
exercise info = exercise info
def legs(self):
return self.
legs
def exercise
type(self):
if not self.
exercise info:
raise RuntimeError, "missing exercise information"
return self.
exercise info[1]
def exercise
schedule(self):
if not self.
exercise info:
raise RuntimeError, "missing exercise information"
return self.
exercise info[0]
def has
exercise schedule(self):
return self.
exercise schedule != None
The following snippet shows a simple example of how to assemble a trade:
>>> #semi-annual flows
>>> flows = generate
flows(
... start = date(2007, Jun, 29)
... , end = date(2017, Jun, 29)
... , duration = ppf.date
time.months
... , period = 6
... , shift
method = shift convention.modified following
... , basis = "ACT/360")
>>> pay
leg = leg(flows, PAY)
>>> receive
leg = leg(flows, RECEIVE)
>>> #1y nc
>>> ex
sched = generate exercise table(
... start = date(2008, Jun, 29)
... , end = date(2016, Jun, 29)
... , period = 1
... , duration = ppf.date
time.years
... , shift
method = shift convention.modified following)
>>> structure = trade([pay
leg, receive leg], [ex sched, \
exercise
type.callable])
>>> print ("callable", "cancellable")[structure.exercise
type()
== -1]
callable
6.7 TRADE UTILITIES
It is not uncommon to perform standard operations on the trade representation. For example,
the writer of a pricing model may wish to insist upon the trade being single currency, or that
the trade doesn’t contain any exercise stubs. The module ppf.core.trade
utils is the
repository for such standard operations. The final
important date function, detailed
P1: JYS
c06 JWBK378-Fletcher May 12, 2009 18:55 Printer: Yet to come
Data Model 89
below, determines the last important date of a trade. The last important date is determined by
looping through the legs of a trade and for each flow in the leg keeping count of the most
distant date in the future, be it the flow pay date or the last important date of the observables
attached to the flow. The end result is the most distant date in the future contained in the trade
representation.
def final important date(trd):
final
date = date(1900, Jan, 1)
for l in trd.legs():
for f in l.flows():
candidate
date = f.pay date()
observables = f.observables()
if not observables:
raise RuntimeError, "Missing observables"
for o in observables:
if o.last
important date() > candidate date:
candidate
date = o.last important date()
if candidate
date > final date:
final
date = candidate date
return final
date
Here is a demonstration of the final important date() function:
>>> libor observables = generate libor observables(
... start = date(2007, Jun, 29)
... , end = date(2009, Jun, 29)
... , roll
period = 6
... , roll
duration = ppf.date time.months
... , reset
period = 3
... , reset
duration = ppf.date time.months
... , reset
currency = "JPY"
... , reset
basis = basis act 360
... , reset
shift method = shift convention.modified following)
>>> coupon
observables = generate fixed coupon observables(
... start = date(2007, Jun, 29)
... , end = date(2009, Jun, 29)
... , roll
period = 6
... , reset
currency = "JPY"
... , coupon
shift method = shift convention.modified following
... , coupon
rate = 0.045)
>>> #semi-annual flows
>>> pay
flows = generate flows(
... start = date(2007, Jun, 29)
... , end = date(2009, Jun, 29)
... , duration = ppf.date
time.months
... , period = 6
... , shift
method = shift convention.modified following
... , basis = "30/360"
... , observables = coupon
observables)
>>> rcv
flows = generate flows(
... start = date(2007, Jun, 29)
P1: JYS
c06 JWBK378-Fletcher May 12, 2009 18:55 Printer: Yet to come
90 Financial Modelling in Python
... , end = date(2009, Jun, 29)
... , duration = ppf.date
time.months
... , period = 6
... , shift
method = shift convention.modified following
... , basis = "A/360"
... , observables = libor
observables)
>>> pay
leg = leg(pay flows, PAY)
>>> receive
leg = leg(rcv flows, RECEIVE)
>>> #1y nc
>>> ex
sched = generate exercise table(
... start = date(2008, Jun, 29)
... , end = date(2009, Jun, 29)
... , period = 1
... , duration = ppf.date
time.years
... , shift
method = shift convention.modified following)
>>> structure = trade((pay
leg, receive leg), (ex sched, \
exercise
type.callable))
>>> print final
important date(structure)
2009-Sep-30
The enforce single currency function harvests all the currencies contained in the
trade representation, whether they bepay currencies or observable currencies, and thenenforces
that the number of unique currencies must be 1.
def enforce single currency(trd):
ccys = []
for l in trd.legs():
for f in l.flows():
pay
ccy = f.pay currency()
observables = f.observables()
if not observables:
raise RuntimeError, "Missing observables"
for o in observables:
reset
ccy = o.reset currency()
if ccys.count(reset
ccy) == 0:
ccys.append(reset
ccy)
if ccys.count(pay
ccy) == 0:
ccys.append(pay
ccy)
if len(ccys) <>1:
raise RuntimeError, "expected one currency"
return ccys[0]
Lastly, the enforce no exercise stubs function asserts that the exercise dates, if
there are any, must fall within the union of accrual start dates.
def enforce no exercise stubs(trd):
accrual
start dates = []
for l in trd.legs():
for f in l.flows():
accrual
start dates.append(f.accrual start date())
if trd.has
exercise schedule():
P1: JYS
c06 JWBK378-Fletcher May 12, 2009 18:55 Printer: Yet to come
Data Model 91
exercises = trd.exercise schedule()
for exercise in exercises:
notification
date = exercise.notification date()
if accrual
start dates.count(notification date) == 0:
raise RuntimeError, "exercise stub encountered"
All these utility functions will be used at various stages in the forthcoming chapters.
P1: JYS
c06 JWBK378-Fletcher May 12, 2009 18:55 Printer: Yet to come
92

Get Financial Modelling in Python now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.