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>