Waterfall Example
A simple waterfall with actions in different places
sampleWaterfall = {
"amortizing":[
["calcAndPayFee","acc01",['trusteeFee']]
,["accrueAndPayInt","acc01",["A1"]]
,["payPrin","acc01",["A1"]]
,["payPrin","acc01",["B"]]
,["payIntResidual","acc01","B"]
],
"endOfCollection":[["calcAndPayFee","acc01",['serviceFee']],
],
"cleanUp":[["sellAsset", ["Current|Defaulted", 1.0, 0.2],"acc01"]
,["payIntResidual","acc01","B"]
],
"closingDay":[["calcAndPayFee","acc01",['issuanceFee']],
]
}
Plug in the waterfall into the deal object
from absbox import Generic
test01 = Generic(
"TEST01"
,{"cutoff":"2021-03-01","closing":"2021-06-15","firstPay":"2021-07-26"
,"payFreq":["DayOfMonth",20],"poolFreq":"MonthEnd","stated":"2030-01-01"}
,{'assets':[["Mortgage"
,{"originBalance":2200,"originRate":["fix",0.045],"originTerm":30
,"freq":"Monthly","type":"Level","originDate":"2021-02-01"}
,{"currentBalance":2200
,"currentRate":0.08
,"remainTerm":30
,"status":"current"}]]}
,(("acc01",{"balance":0}),)
,(("A1",{"balance":1000
,"rate":0.07
,"originBalance":1000
,"originRate":0.07
,"startDate":"2020-01-03"
,"rateType":{"Fixed":0.08}
,"bondType":{"Sequential":None}})
,("B",{"balance":1000
,"rate":0.0
,"originBalance":1000
,"originRate":0.07
,"startDate":"2020-01-03"
,"rateType":{"Fixed":0.00}
,"bondType":{"Equity":None}
}))
,(("issuanceFee",{"type":{"fixFee":30},"feeStart":"2021-06-15"})
,("serviceFee",{"type":{"annualPctFee":[("poolBalance",),0.02]},"feeStart":"2021-06-15"})
,("trusteeFee",{"type":{"annualPctFee":[("poolBalance",),0.01]},"feeStart":"2021-06-15"})
)
,sampleWaterfall
,[["CollectedInterest","acc01"]
,["CollectedPrincipal","acc01"]
,["CollectedPrepayment","acc01"]
,["CollectedRecoveries","acc01"]]
,None
,None
,None
,None
,("PreClosing","Amortizing")
)
Adding a call assumption to trigger the clean up action in the waterfall
from absbox import API,EnginePath
localAPI = API(EnginePath.DEV,check=False)
r = localAPI.run(test01
,poolAssump = None
,runAssump = [("call",("poolBalance",300))]
,read=True)
Connecting engine server -> https://absbox.org/api/dev
/home/docs/checkouts/readthedocs.org/user_builds/absbox-doc/envs/stable/lib/python3.11/site-packages/urllib3/connectionpool.py:1097: InsecureRequestWarning: Unverified HTTPS request is being made to host 'absbox.org'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#tls-warnings
warnings.warn(
✅Connected, local lib:0.52.3, server:0.52.3
/home/docs/checkouts/readthedocs.org/user_builds/absbox-doc/envs/stable/lib/python3.11/site-packages/urllib3/connectionpool.py:1097: InsecureRequestWarning: Unverified HTTPS request is being made to host 'absbox.org'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#tls-warnings
warnings.warn(
Warning Message from server:Bond B is not paid off
On Closing Day
The action only performs on Closing Day for deal with PreClosing status
test01.dates
{'cutoff': '2021-03-01',
'closing': '2021-06-15',
'firstPay': '2021-07-26',
'payFreq': ['DayOfMonth', 20],
'poolFreq': 'MonthEnd',
'stated': '2030-01-01'}
Action to be performed on Closing Day
sampleWaterfall['closingDay']
[['calcAndPayFee', 'acc01', ['issuanceFee']]]
Transaction log from the account
r['accounts']['acc01'].loc['2021-06-15']
| balance | change | memo | |
|---|---|---|---|
| date | |||
| 2021-06-15 | 55.97 | 55.97 | <Pool:CollectedInterest> |
| 2021-06-15 | 324.60 | 268.63 | <Pool:CollectedPrincipal> |
| 2021-06-15 | 324.60 | 0.00 | <Pool:CollectedPrepayment> |
| 2021-06-15 | 324.60 | 0.00 | <Pool:CollectedRecoveries> |
| 2021-06-15 | 294.60 | -30.00 | <SeqPayFee:issuanceFee> |
Pool Collect Days
test01.dates
{'cutoff': '2021-03-01',
'closing': '2021-06-15',
'firstPay': '2021-07-26',
'payFreq': ['DayOfMonth', 20],
'poolFreq': 'MonthEnd',
'stated': '2030-01-01'}
The action in the endOfCollection will be performed each time when collecting proceeds from the pool
The dates were described by poolFreq
sampleWaterfall['endOfCollection']
[['calcAndPayFee', 'acc01', ['serviceFee']]]
r['accounts']['acc01'].loc['2021-07-31']
| balance | change | memo | |
|---|---|---|---|
| date | |||
| 2021-07-31 | 12.87 | 12.87 | <Pool:CollectedInterest> |
| 2021-07-31 | 81.15 | 68.28 | <Pool:CollectedPrincipal> |
| 2021-07-31 | 81.15 | 0.00 | <Pool:CollectedPrepayment> |
| 2021-07-31 | 81.15 | 0.00 | <Pool:CollectedRecoveries> |
| 2021-07-31 | 77.87 | -3.28 | <SeqPayFee:serviceFee> |
Distribution Day
test01.dates
{'cutoff': '2021-03-01',
'closing': '2021-06-15',
'firstPay': '2021-07-26',
'payFreq': ['DayOfMonth', 20],
'poolFreq': 'MonthEnd',
'stated': '2030-01-01'}
The action in the amortizing will be performed each time on the dates were described by payFreq
sampleWaterfall['amortizing']
[['calcAndPayFee', 'acc01', ['trusteeFee']],
['accrueAndPayInt', 'acc01', ['A1']],
['payPrin', 'acc01', ['A1']],
['payPrin', 'acc01', ['B']],
['payIntResidual', 'acc01', 'B']]
r['accounts']['acc01'].loc['2021-08-20']
| balance | change | memo | |
|---|---|---|---|
| date | |||
| 2021-08-20 | 77.61 | -0.26 | <SeqPayFee:trusteeFee> |
| 2021-08-20 | 74.18 | -3.43 | <PayInt:A1> |
| 2021-08-20 | 0.00 | -74.18 | <PayPrin:A1> |
Clean Up
The clean up waterfall only perform when the deal met the conditin from runAssump assumption
In this case, the clean up happens at date 2023-06-20,we can inspect that via result``status
r['result']['status']
| Date | From | To | Comment | |
|---|---|---|---|---|
| 0 | 2021-06-15 | PreClosing | Amortizing | By Deal Close |
| 1 | 2023-06-20 | Amortizing | Called | Call by triggers before waterfall distribution |
| 2 | 2023-06-20 | DealEnd | Clean Up |
We are able to identify the actions via account transaction
r['accounts']['acc01'].loc['2023-06-20']
| balance | change | memo | |
|---|---|---|---|
| date | |||
| 2023-06-20 | 320.85 | 240.24 | <Liquidation:> |
| 2023-06-20 | 0.00 | -320.85 | <PayYield:B> |
Summary Via [result][waterfall]
There is a function that would summaries which waterfall actions are being executed by dates
r['result']['waterfall'].head()
| Date | Waterfall Location | |
|---|---|---|
| 0 | 2021-06-15 | <EndOfPoolCollection> |
| 1 | 2021-06-15 | <OnClosingDay> |
| 2 | 2021-06-30 | <EndOfPoolCollection> |
| 3 | 2021-07-26 | <DistributionDay:<Amortizing>> |
| 4 | 2021-07-31 | <EndOfPoolCollection> |