SRT Example

import pandas as pd
pd.set_option('display.max_rows', None)

Deal Structure

  • waterfall

    • Distribution Day :

      • Principal : Pro Rata to senior (A) and protected tranche (B)

      • Interest : “issuer” will pay interest to tranches

    • End of Colleciton : allocate pool loss by move fund from collateral cash account to “Issuer”

    • Closing Day: fund collateral cash account with SRT tranche balance

    • Clean up: when deal was called, pay all cash from collateral cash account to protected tranche (B)

from absbox import Generic

seniorBalance = 1000
srtTrancheBal = 200
srtRate = 0.08
closingDate = "2021-06-15"
periodPrincipal = ("curPoolCollection", None, "Principal","Prepayment","Recovery")
reinvestRate = 0.00


srt01 = Generic(
    "SRT Example"
    ,{"cutoff":"2021-06-01","closing":closingDate,"firstPay":"2021-07-20"
     ,"payFreq":["DayOfMonth",20],"poolFreq":"MonthEnd","stated":"2030-01-01"}
    ,{'assets':[["Mortgage"
        ,{"originBalance":2200,"originRate":["fix",0.045],"originTerm":24
          ,"freq":"Monthly","type":"Level","originDate":"2021-06-01"}
          ,{"currentBalance":2200
          ,"currentRate":0.08
          ,"remainTerm":24
          ,"status":"current"}]],
     }
    ,(("acc01",{"balance":0})
      ,("srtAcc",{"balance":0.0
                  ,"interest":{"period":"QuarterEnd"
                               ,"rate":reinvestRate
                               ,"lastSettleDate":closingDate}})
      ,("dummy",{"balance":0.0})
      ,)
    ,(("A1",{"balance":seniorBalance
             ,"rate":0.00
             ,"originBalance":seniorBalance
             ,"originRate":0.00
             ,"startDate":closingDate
             ,"rateType":{"Fixed":0.00}
             ,"bondType":{"Sequential":None}})
      ,("B",{"balance":0.0
             ,"rate":srtRate
             ,"originBalance":0
             ,"originRate":srtRate
             ,"startDate":closingDate
             ,"rateType":{"Fixed":srtRate}
             ,"bondType":{"Sequential":None}
             }))
    ,tuple()
    ,{"amortizing":[
          # pay prorata to senior and SRT tranch
         ['accrueAndPayInt',"dummy",["A1"],{"support":["facility","originator"]}]
         ,["calcInt","B"]
         ,["payInt","dummy",["B"],{"support":["facility","originator"]}]

         ,["calcBondPrin",["A1","B"],{"formula":periodPrincipal}] 

         ,["payPrinWithDue","acc01",["A1"]]         
         ,["payPrinWithDue","srtAcc",["B"]]

     ],
      "closingDay":[
                    ["fundWith","srtAcc","B",{"formula":("const",srtTrancheBal)}]
                   ],
      "endOfCollection":[
          # draw loss amount and pay to originator
          ["liqRepayResidual","srtAcc", "originator", {"formula":("curPoolCollection",None,"Losses")}]
      ],
      "cleanUp":[
          ["payIntResidual","srtAcc","B"]
      ]
     }
    ,[["CollectedInterest","acc01"]
      ,["CollectedPrincipal","acc01"]
      ,["CollectedPrepayment","acc01"]
      ,["CollectedRecoveries","acc01"]]
    ,{"originator":{"type" : "Unlimit", "start": closingDate}}
    ,None
    ,None
    ,None
    ,("PreClosing","Amortizing")
    )
from absbox import API,EnginePath

localAPI = API(EnginePath.DEV, lang='english', check=False)

r = localAPI.run(srt01
                ,poolAssump=("Pool",("Mortgage", {"CDR":0.01}, None, None, None)
                                   ,None
                                   ,None)
                ,runAssump=[("call",("poolFactor",0.10))]
                ,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(
---------------------------------------------------------------------------
EngineError                               Traceback (most recent call last)
Cell In[3], line 5
      1 from absbox import API,EnginePath
      3 localAPI = API(EnginePath.DEV, lang='english', check=False)
----> 5 r = localAPI.run(srt01
      6                 ,poolAssump=("Pool",("Mortgage", {"CDR":0.01}, None, None, None)
      7                                    ,None
      8                                    ,None)
      9                 ,runAssump=[("call",("poolFactor",0.10))]
     10                 ,read=True)

File ~/checkouts/readthedocs.org/user_builds/absbox-doc/envs/stable/lib/python3.11/site-packages/absbox/client.py:358, in API.run(self, deal, poolAssump, runAssump, read, showWarning, rtn, debug)
    355 if debug:
    356     return req
--> 358 result = self._send_req(req, url)
    360 if result is None or 'error' in result or 'Left' in result:
    361     leftVal = result.get("Left","")

File ~/checkouts/readthedocs.org/user_builds/absbox-doc/envs/stable/lib/python3.11/site-packages/absbox/client.py:828, in API._send_req(self, _req, _url, timeout, headers)
    826     raise AbsboxError("❌ Failed to get response from server")
    827 if r.status_code != 200:
--> 828     raise EngineError(r)
    829 try:
    830     return json.loads(r.text)

EngineError: Error in $.liqProvider.originator.liqCredit: When parsing Types.SupportAvailType expected Object but got String.

View Bond Cashflow

from absbox import readBondsCf

readBondsCf(r['bonds']).head()
Bond A1 B
Field balance interest principal rate cash balance interest principal rate cash
date
2021-06-15 NaN NaN NaN NaN NaN 200.00 0.00 -200.00 0.00 0.00
2021-07-20 1000.00 0.0 0.00 0.0 0.00 200.00 1.53 0.00 0.08 1.53
2021-08-20 929.37 0.0 70.63 0.0 70.63 185.88 1.35 14.12 0.08 15.47
2021-09-20 858.33 0.0 71.04 0.0 71.04 171.67 1.26 14.21 0.08 15.47
2021-10-20 786.88 0.0 71.45 0.0 71.45 157.38 1.12 14.29 0.08 15.41

Pool Loss metrics

Here, we can identify total pool loss is 23.11

r['pool']['flow'].Loss.sum()
23.11

How much pool loss was cured via SRT traction ? we can filter out transaction in the srtAcc ,the collateral cash account draw out

r['accounts']['srtAcc'].loc[lambda df: df.memo == "<Support:originator>"].head()
balance change memo
date
2021-06-15 200.00 0.00 <Support:originator>
2021-06-30 200.00 0.00 <Support:originator>
2021-07-31 198.19 -1.81 <Support:originator>
2021-08-31 182.27 -1.80 <Support:originator>
2021-09-30 166.34 -1.72 <Support:originator>

Summing up all loss cured by SRT account, that’s total cured 18.11

r['accounts']['srtAcc'].loc[lambda df: df.memo == "<Support:originator>"].change.sum()
-18.11

We can tie out 18.11 loss in the SRT tranche (B). There 18.11 oustanding balance at end of projection.

r['bonds']['B'].tail()
balance interest principal rate cash factor memo
date
2023-01-20 18.11 0.12 0.0 0.08 0.12 None [<PayInt:B>, <PayPrin:B>]
2023-02-20 18.11 0.12 0.0 0.08 0.12 None [<PayInt:B>, <PayPrin:B>]
2023-03-20 18.11 0.11 0.0 0.08 0.11 None [<PayInt:B>, <PayPrin:B>]
2023-04-20 18.11 0.12 0.0 0.08 0.12 None [<PayInt:B>, <PayPrin:B>]
2023-05-20 18.11 0.11 0.0 0.08 0.11 None [[<PayInt:B>, <PayPrin:B>], <PayYield:B>]

Return of SRT transaction

Let’s calculate the IRR of protect tranche

r['bonds']['B'].head()
balance interest principal rate cash factor memo
date
2021-06-15 200.00 0.00 -200.00 0.00 0.00 None <FundWith:B,200.00>
2021-07-20 200.00 1.53 0.00 0.08 1.53 None [<PayInt:B>, <PayPrin:B>]
2021-08-20 185.88 1.35 14.12 0.08 15.47 None [<PayInt:B>, <PayPrin:B>]
2021-09-20 171.67 1.26 14.21 0.08 15.47 None [<PayInt:B>, <PayPrin:B>]
2021-10-20 157.38 1.12 14.29 0.08 15.41 None [<PayInt:B>, <PayPrin:B>]

Let’s build a simple irr function

from pyxirr import xirr

def calcIRR(df, init):
    investDate,investAmount = init
    ds = [investDate] + df.index.to_list()
    vs = [investAmount] + df.cash.to_list()
    return xirr(ds, vs)

calcIRR(r['bonds']['B'], ("2021-06-15",-200))
-0.04323574436198406

Sensitiviy Analysis : Pool Perf vs. IRR

let’s assump how different prepayment behavior would impact on the IRR

  1. build an assumption Map

  2. run with ..runByScenarios()

from lenses import lens

myAssumption = ("Pool",("Mortgage",None,None,None,None)
                                ,None
                                ,None)
myAssumption2 = myAssumption & lens[1][2].set({"CPR":0.01})
myAssumption3 = myAssumption & lens[1][2].set({"CPR":0.02})


rs = localAPI.runByScenarios(srt01
                            ,poolAssump={"CPR-0":myAssumption
                                        ,"CPR-1":myAssumption2
                                        ,"CPR-2":myAssumption3
                                       }
                            ,read=True)
Warning Message from server:
Account acc01 has cash to be distributed
LiquidityProvider originator is not paid off
Account acc01 has cash to be distributed
LiquidityProvider originator is not paid off
Account acc01 has cash to be distributed
LiquidityProvider originator is not paid off

View pool cashflow from multiple scenarios

from absbox import readMultiFlowsByScenarios
readMultiFlowsByScenarios(rs, (lens['pool']['flow'],["Balance",'Prepayment'])).head()
Scenario CPR-0 CPR-1 CPR-2
Field Balance Prepayment Balance Prepayment Balance Prepayment
Date
2021-06-15 2200.00 0 2200.00 0.00 2200.00 0.00
2021-06-30 2200.00 0 2200.00 0.00 2200.00 0.00
2021-07-31 2115.17 0 2113.43 1.81 2111.66 3.65
2021-08-31 2029.77 0 2026.37 1.80 2022.93 3.62
2021-09-30 1943.81 0 1938.90 1.72 1933.94 3.46
import toolz as tz

tz.valmap(lambda x: calcIRR(x['bonds']['B'], ("2021-06-15",-200)), rs)
{'CPR-0': 0.0822966584499679,
 'CPR-1': 0.08250918429431883,
 'CPR-2': 0.08235205608296689}

Whoa, interesting ! CPR=1% will yield most IRR

What’s the protection exposure ?

To what extend the current capital structure will hedge the default risk ?

let’s assump how different default stress would impact on the IRR

  1. build an assumption Map

  2. run with ..runByScenarios()

Sensitiviy Analysis : Pool Perf vs. Exposed Loss

Exposed Loss : the loss not being hedged by SRT tranche

myAssumption = ("Pool",("Mortgage",None,None,None,None)
                                ,None
                                ,None)
myAssumption2 = myAssumption & lens[1][1].set({"CDR":0.01})
myAssumption3 = myAssumption & lens[1][1].set({"CDR":0.02})


rs = localAPI.runByScenarios(srt01
                            ,poolAssump={"CDR-0":myAssumption
                                        ,"CDR-1":myAssumption2
                                        ,"CDR-2":myAssumption3
                                       }
                            ,read=True)
Warning Message from server:
Account acc01 has cash to be distributed
LiquidityProvider originator is not paid off
Bond B is not paid off
Account acc01 has cash to be distributed
LiquidityProvider originator is not paid off
Bond B is not paid off
Account acc01 has cash to be distributed
LiquidityProvider originator is not paid off

View pool cashflows

from absbox import readMultiFlowsByScenarios
readMultiFlowsByScenarios(rs, (lens['pool']['flow'],["Balance",'Default'])).head()
Scenario CDR-0 CDR-1 CDR-2
Field Balance Default Balance Default Balance Default
Date
2021-06-15 2200.00 0 2200.00 0.00 2200.00 0.00
2021-06-30 2200.00 0 2200.00 0.00 2200.00 0.00
2021-07-31 2115.17 0 2113.43 1.81 2111.66 3.65
2021-08-31 2029.77 0 2026.37 1.80 2022.93 3.62
2021-09-30 1943.81 0 1938.90 1.72 1933.94 3.46

By writing a small function to calculate unhendge amount,we are able to tell in all the scenarios, the unhedge amount

def unHedgeAmount(x:dict):
    "x is the single run result"
    
    poolLoss = x['pool']['flow'].Loss.sum()
    hedgedAmount = x['accounts']['srtAcc'].loc[lambda df: df.memo == "<Support:originator>"].change.sum()
    
    return max(poolLoss - hedgedAmount,0)

tz.valmap(unHedgeAmount, rs)
{'CDR-0': 0.0, 'CDR-1': 41.449999999999996, 'CDR-2': 81.19999999999999}

Others ?

Actuall absbox is flexible enough to perform sensitivity analysis on any two variables :

  • It could be reinvestment rate v.s IRR on SRT tranche..

  • It could be capital structure v.s IRR on SRT tranche..

SRT with 3 tranches

The key for 3 tranches is , the srtAcc only move funds to the loss which is the excess amount over the first loss tranche

firstLossTranche = 5

formulaToCurLoss = ("excess", ("cumPoolNetLoss",)
                            , ("abs",("accountTxnAmount","<Support:originator>","srtAcc"))
                            , ("originalBondBalance","C"))
seniorBalance = 1000
srtTrancheBal = 200

srtRate = 0.08
closingDate = "2021-06-15"
periodPrincipal = ("curPoolCollection", None, "Principal","Prepayment","Recovery")
reinvestRate = 0.00



srt02 = Generic(
    "SRT Example"
    ,{"cutoff":"2021-06-01","closing":closingDate,"firstPay":"2021-07-20"
     ,"payFreq":["DayOfMonth",20],"poolFreq":"MonthEnd","stated":"2030-01-01"}
    ,{'assets':[["Mortgage"
        ,{"originBalance":2200,"originRate":["fix",0.045],"originTerm":24
          ,"freq":"Monthly","type":"Level","originDate":"2021-06-01"}
          ,{"currentBalance":2200
          ,"currentRate":0.08
          ,"remainTerm":24
          ,"status":"current"}]],
     }
    ,(("acc01",{"balance":0})
      ,("srtAcc",{"balance":0.0
                  ,"interest":{"period":"QuarterEnd"
                               ,"rate":reinvestRate
                               ,"lastSettleDate":closingDate}})
      ,("dummy",{"balance":0.0})
      ,)
    ,(("A1",{"balance":seniorBalance
             ,"rate":0.00
             ,"originBalance":seniorBalance
             ,"originRate":0.00
             ,"startDate":closingDate
             ,"rateType":{"Fixed":0.00}
             ,"bondType":{"Sequential":None}})
      ,("B",{"balance":0.0
             ,"rate":srtRate
             ,"originBalance":0
             ,"originRate":srtRate
             ,"startDate":closingDate
             ,"rateType":{"Fixed":srtRate}
             ,"bondType":{"Sequential":None}
             })
      ,("C",{"balance":firstLossTranche
             ,"rate":0.0
             ,"originBalance":firstLossTranche
             ,"originRate":0.0
             ,"startDate":closingDate
             ,"rateType":{"Fixed":0.0}
             ,"bondType":{"Sequential":None}
             })     
     )
    ,tuple()
    ,{"amortizing":[
          # pay prorata to senior and SRT tranch
         ["calcInt","B"]
         ,["payInt","dummy",["B"],{"support":["facility","originator"]}]
         ,["calcBondPrin",["A1","B"],{"formula":periodPrincipal}] 
         ,["payPrinWithDue","acc01",["A1"]]         
         ,["payPrinWithDue","srtAcc",["B"]]
         ,["liqRepayResidual","acc01", "originator"]
         ,["If", [('isPaidOff',"A1","B"),True]
           ,["payPrin","acc01",["C"]]]
     ],
      "closingDay":[["fundWith","srtAcc","B",{"formula":("const",srtTrancheBal)}]],
      "endOfCollection":[
          # draw loss amount and pay to originator
          ["liqRepayResidual","srtAcc", "originator", {"formula":formulaToCurLoss}]
      ],
      "cleanUp":[
          ["payIntResidual","srtAcc","B"]
      ]
     }
    ,[#["CollectedInterest","acc01"]
      ["CollectedPrincipal","acc01"]
      ,["CollectedPrepayment","acc01"]
      ,["CollectedRecoveries","acc01"]]
    ,{"originator":{"type" : "Unlimited", "start": closingDate}}
    ,None
    ,None
    ,None
    ,("PreClosing","Amortizing")
    )
from absbox import API,EnginePath

r02 = localAPI.run(srt02
                ,poolAssump=("Pool",("Mortgage", {"CDR":0.01}, None, None, None)
                                   ,None
                                   ,None)
                ,runAssump=[("call",("poolFactor",0.10))
                           ,("inspect"
                             ,("MonthEnd",("excess", ("cumPoolNetLoss",)
                                                 , ("abs",("accountTxnAmount","<Support:originator>","srtAcc"))
                                                 , ("constant",firstLossTranche))
                                          ))
                            ]
                ,read=True)
Warning Message from server:
Bond B is not paid off
Bond C is not paid off
LiquidityProvider originator is not paid off
readBondsCf(r02['bonds']).head()
Bond A1 B
Field balance interest principal rate cash balance interest principal rate cash
date
2021-06-15 NaN NaN NaN NaN NaN 200.00 0.00 -200.00 0.00 0.00
2021-07-20 1000.00 0.0 0.00 0.0 0.00 200.00 1.53 0.00 0.08 1.53
2021-08-20 929.37 0.0 70.63 0.0 70.63 185.88 1.35 14.12 0.08 15.47
2021-09-20 858.33 0.0 71.04 0.0 71.04 171.67 1.26 14.21 0.08 15.47
2021-10-20 786.88 0.0 71.45 0.0 71.45 157.38 1.12 14.29 0.08 15.41

Now , the loss from the pool only will be cured from srtAcc account if cumulative loss is greater than 5

Here, at 2021-09-30, the cumulative loss is 5.33 from the pool, the engine will only allocate 0.33

pd.concat([r02['accounts']['srtAcc'],r02['pool']['flow'].CumLoss.to_frame()]).sort_index().loc["2021-09-30"]
balance change memo CumLoss
2021-09-30 171.67 0.00 <BankInterest:> NaN
2021-09-30 171.34 -0.33 <Support:originator> NaN
2021-09-30 NaN NaN NaN 5.33

How thickness of FirstLossTranche would affect the IRR ?

firstLossTrancheDraft = {"FirstLoss-1": 5,"FirstLoss-2":10,"FirstLoss-3":20}

build deal structures with a map( and lenses !)

dealDrafts = tz.valmap(lambda x: srt02 & lens.bonds[2][1].Fork(lens['balance'],lens['originBalance']).set(x) 
                     ,firstLossTrancheDraft)

run differnt deal structures with funciton runStructs()

rm02 = localAPI.runStructs(dealDrafts
                        ,poolAssump=("Pool",("Mortgage", {"CDR":0.01}, None, None, None)
                                           ,None
                                           ,None)
                        ,nonPoolAssump=[("call",("poolFactor",0.10))
                                   ,("inspect"
                                     ,("MonthEnd",("excess", ("cumPoolNetLoss",)
                                                         , ("abs",("accountTxnAmount","<Support:originator>","srtAcc"))
                                                         , ("constant",firstLossTranche))
                                                  ))
                                    ]
                        ,read=True)
tz.valmap(lambda x: calcIRR(x['bonds']['B'], ("2021-06-15",-200)), rm02)
{'FirstLoss-1': -0.008036217135081734,
 'FirstLoss-2': 0.020824974743072763,
 'FirstLoss-3': 0.08232329854365725}

SRT with trigger on Prorata to Sequential

user won’t have to create a seperate new deal object but only need to create a new one from the old one: srt02

  • add a trigger which will be fired if pool performance hit

  • add extra branch of waterfall which will be execute after the trigger has been fired.

srt03 = srt02 & lens.trigger.set(
            {"BeforeCollect": 
              {"defaultTrigger":
                {"condition":[("cumPoolDefaultedRate",),">",0.01]
                ,"effects":("newStatus","Accelerated")
                ,"status":False
                ,"curable":False}
              }
            }
        )

acceleratedWaterfall = [
    ['calcInt', 'B'],
      ['payInt', 'dummy', ['B'], {'support': ['facility', 'originator']}],
      ['payPrin','acc01',["A1"]],
      ['liqRepayResidual', 'acc01', 'originator'],
      ["If", [('isPaidOff', 'A1'), True], 
             ['payPrin',"srtAcc", ["B"],
               {"limit":
                {"formula": periodPrincipal}}]],
      ['If', [('isPaidOff', 'A1', 'B'), True], ['payPrin', 'acc01', ['C']]]    
]


srt03 &= lens.waterfall.modify(lambda x: tz.assoc(x,("amortizing", "accelerated"),acceleratedWaterfall ))
r03 = localAPI.run(srt03
                ,poolAssump=("Pool",("Mortgage", {"CDR":0.02}, None, None, None)
                                   ,None
                                   ,None)
                ,runAssump=[("call",("poolFactor",0.05))
                           ,("inspect"
                             ,("MonthEnd",("excess", ("cumPoolNetLoss",)
                                                 , ("abs",("accountTxnAmount","<Support:originator>","srtAcc"))
                                                 , ("constant",firstLossTranche))
                                          ))
                            ]
                ,read=True)
Warning Message from server:
Bond B is not paid off
Bond C is not paid off
LiquidityProvider originator is not paid off
readBondsCf(r03['bonds']).loc["2021-08-20":"2022-09-20",]
Bond A1 B
Field balance interest principal rate cash balance interest principal rate cash
date
2021-08-20 929.43 0.0 70.57 0.0 70.57 185.89 1.35 14.11 0.08 15.46
2021-09-20 858.51 0.0 70.92 0.0 70.92 171.71 1.26 14.18 0.08 15.44
2021-10-20 787.24 0.0 71.27 0.0 71.27 157.46 1.12 14.25 0.08 15.37
2021-11-20 715.61 0.0 71.63 0.0 71.63 143.14 1.06 14.32 0.08 15.38
2021-12-20 643.62 0.0 71.99 0.0 71.99 128.75 0.94 14.39 0.08 15.33
2022-01-20 571.29 0.0 72.33 0.0 72.33 114.28 0.87 14.47 0.08 15.34
2022-02-20 484.05 0.0 87.24 0.0 87.24 114.28 0.77 0.00 0.08 0.77
2022-03-20 396.37 0.0 87.68 0.0 87.68 114.28 0.70 0.00 0.08 0.70
2022-04-20 308.25 0.0 88.12 0.0 88.12 114.28 0.77 0.00 0.08 0.77
2022-05-20 219.69 0.0 88.56 0.0 88.56 114.28 0.75 0.00 0.08 0.75
2022-06-20 130.68 0.0 89.01 0.0 89.01 114.28 0.77 0.00 0.08 0.77
2022-07-20 41.23 0.0 89.45 0.0 89.45 114.28 0.75 0.00 0.08 0.75
2022-08-20 0.00 0.0 41.23 0.0 41.23 31.31 0.77 82.97 0.08 83.74
2022-09-20 NaN NaN NaN NaN NaN 31.31 0.21 0.00 0.08 0.21

SRT with Sequential

Sequential waterfall

sequentialWaterfall = [
  ['calcInt', 'B'],
  ['payInt', 'dummy', ['B'], {'support': ['facility', 'originator']}],
  ['payPrin','acc01',["A1"]],
  ['liqRepayResidual', 'acc01', 'originator'],
  ["If", [('isPaidOff', 'A1'), True], 
         ['payPrin',"srtAcc", ["B"],
           {"limit":
            {"formula": periodPrincipal}}]],
  ['If', [('isPaidOff', 'A1', 'B'), True], ['payPrin', 'acc01', ['C']]]    
]

srt04 = lens.waterfall.modify(lambda x: tz.assoc(x,"amortizing", sequentialWaterfall))(srt03)


r04 = localAPI.run(srt04
                ,poolAssump=("Pool",("Mortgage", {"CDR":0.02}, None, None, None)
                                   ,None
                                   ,None)
                ,runAssump=[("call",("poolFactor",0.05))]
                ,read=True)

readBondsCf(r04['bonds']).loc["2021-08-20":"2022-09-20",]
Warning Message from server:
Bond B is not paid off
Bond C is not paid off
LiquidityProvider originator is not paid off
Bond A1 B
Field balance interest principal rate cash balance interest principal rate cash
date
2021-08-20 915.31 0.0 84.69 0.0 84.69 200.00 1.35 0.00 0.08 1.35
2021-09-20 830.20 0.0 85.11 0.0 85.11 200.00 1.35 0.00 0.08 1.35
2021-10-20 744.67 0.0 85.53 0.0 85.53 200.00 1.31 0.00 0.08 1.31
2021-11-20 658.71 0.0 85.96 0.0 85.96 200.00 1.35 0.00 0.08 1.35
2021-12-20 572.32 0.0 86.39 0.0 86.39 200.00 1.31 0.00 0.08 1.31
2022-01-20 485.51 0.0 86.81 0.0 86.81 200.00 1.35 0.00 0.08 1.35
2022-02-20 398.27 0.0 87.24 0.0 87.24 200.00 1.35 0.00 0.08 1.35
2022-03-20 310.59 0.0 87.68 0.0 87.68 200.00 1.22 0.00 0.08 1.22
2022-04-20 222.47 0.0 88.12 0.0 88.12 200.00 1.35 0.00 0.08 1.35
2022-05-20 133.91 0.0 88.56 0.0 88.56 200.00 1.31 0.00 0.08 1.31
2022-06-20 44.90 0.0 89.01 0.0 89.01 200.00 1.35 0.00 0.08 1.35
2022-07-20 0.00 0.0 44.90 0.0 44.90 110.55 1.31 89.45 0.08 90.76
2022-08-20 NaN NaN NaN NaN NaN 31.31 0.75 79.24 0.08 79.99
2022-09-20 NaN NaN NaN NaN NaN 31.31 0.21 0.00 0.08 0.21