Master Trust Example

Deal need to have a BondGroup to be qualifed as Master Trust deal.

In the run assumption, the new issue bond will be inserted into that BondGroup by BondGroup Name

In this example, the bond group name is A, which has a syntax as:

(<Bond Group Name>, <Map: bondName, bond dict> )
from absbox import Generic,API,EnginePath,readBondsCf

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":20
          ,"status":"current"}]]}
    ,(("acc01",{"balance":0}),)
    ,(("A",{"A-1":
        {"balance":400
         ,"rate":0.09
         ,"originBalance":400
         ,"originRate":0.07
         ,"startDate":"2021-06-15"
         ,"rateType":{"Fixed":0.08}
         ,"bondType":{"Sequential":None}
         ,"maturityDate":"2025-01-01"}
        ,"A-2":
        {"balance":600
         ,"rate":0.08
         ,"originBalance":600
         ,"originRate":0.07
         ,"startDate":"2021-06-15"
         ,"rateType":{"Fixed":0.08}
         ,"bondType":{"Sequential":None}
        ,"maturityDate":"2026-01-01"}
       })
      ,("B",{"balance":1000
             ,"rate":0.0
             ,"originBalance":1000
             ,"originRate":0.07
             ,"startDate":"2020-01-03"
             ,"rateType":{"Fixed":0.00}
             ,"bondType":{"Equity":None}
             }))
    ,(("trusteeFee",{"type":{"fixFee":30},"feeStart":"2021-06-15"}),)
    ,{"amortizing":[
         ["payFee","acc01",['trusteeFee']]
         ,["accrueAndPayIntByGroup","acc01","A","byStartDate"]
         ,["payPrinByGroup","acc01","A","byStartDate"]
         ,["payPrin","acc01",["B"]]
         ,["payIntResidual","acc01","B"]
     ]}
    ,[["CollectedInterest","acc01"]
      ,["CollectedPrincipal","acc01"]
      ,["CollectedPrepayment","acc01"]
      ,["CollectedRecoveries","acc01"]]
    ,None
    ,None
    ,None
    ,None
    ,("PreClosing","Amortizing")
    )
    
localAPI = API(EnginePath.LOCAL,check=False)
Connecting engine server -> http://localhost:8081
Connected, local lib:0.28.7, server:0.28.21

Issuance by ganrantee

User can specify a series of bond issuance events. All these events are going to be executed.

("issueBond", ("date1","bondGroupName", "accountName", <bondObject1>)
            , ("date2","bondGroupName", "accountName", <bondObject2>)
            , ...
)
fundingPlan = [("2022-04-02","A","acc01"
                      ,{"balance":600
                         ,"rate":0.08
                         ,"name":"A-3"
                         ,"originBalance":600
                         ,"originRate":0.07
                         ,"startDate":"2022-04-02"
                         ,"rateType":{"Fixed":0.08}
                         ,"bondType":{"Sequential":None}
                        ,"maturityDate":"2026-01-01"}
                      )]

r = localAPI.run(test01
                 ,runAssump = [
                     ("issueBond",*fundingPlan)
                 ]
                 ,read=True)
Warning Message from server:

readBondsCf(r['bonds']).loc["2022-02-20":"2022-06-20"]
BondGroup A B
Bond A-1 A-2 A-3 -
Field balance interest principal rate cash balance interest principal rate cash balance interest principal rate cash balance interest principal rate cash
date
2022-02-20 369.57 24.60 30.43 0.09 55.03 600.00 32.83 0.00 0.08 32.83 NaN NaN NaN NaN NaN 1000.0 0.0 0.0 0 0.0
2022-03-20 257.94 2.55 111.63 0.09 114.18 600.00 3.68 0.00 0.08 3.68 NaN NaN NaN NaN NaN 1000.0 0.0 0.0 0 0.0
2022-04-20 0.00 1.97 257.94 0.09 259.91 148.19 4.07 451.81 0.08 455.88 600.00 2.07 0.00 0.07 2.07 1000.0 0.0 0.0 0 0.0
2022-05-20 NaN NaN NaN NaN NaN 34.75 0.97 113.44 0.08 114.41 600.00 3.45 0.00 0.07 3.45 1000.0 0.0 0.0 0 0.0
2022-06-20 NaN NaN NaN NaN NaN 0.00 0.23 34.75 0.08 34.98 520.69 3.56 79.31 0.07 82.87 1000.0 0.0 0.0 0 0.0
r['accounts']['acc01'].loc["2022-04-01":"2022-04-28"]
balance change memo
date
2022-04-02 717.86 600.00 <IssuanceProceeds:A-3>
2022-04-20 717.86 0.00 <SeqPayFee:trusteeFee>
2022-04-20 709.75 -8.11 <PayInt:A>
2022-04-20 0.00 -709.75 <PayPrin:A>
2022-04-20 0.00 0.00 <PayPrin:B>
2022-04-20 0.00 0.00 <PayYield:B>
r['bonds']['A']['A-3']
balance interest principal rate cash intDue intOverInt factor memo
date
2022-04-20 600.00 2.07 0.00 0.07 2.07 0 0 1.000000 [<PayInt:A-3>, <PayPrin:A-3>]
2022-05-20 600.00 3.45 0.00 0.07 3.45 0 0 1.000000 [<PayInt:A-3>, <PayPrin:A-3>]
2022-06-20 520.69 3.56 79.31 0.07 82.87 0 0 0.867817 [<PayInt:A-3>, <PayPrin:A-3>]
2022-07-20 405.82 2.99 114.87 0.07 117.86 0 0 0.676367 [<PayInt:A-3>, <PayPrin:A-3>]
2022-08-20 290.38 2.41 115.44 0.07 117.85 0 0 0.483967 [<PayInt:A-3>, <PayPrin:A-3>]
2022-09-20 174.25 1.72 116.13 0.07 117.85 0 0 0.290417 [<PayInt:A-3>, <PayPrin:A-3>]
2022-10-20 57.39 1.00 116.86 0.07 117.86 0 0 0.095650 [<PayInt:A-3>, <PayPrin:A-3>]
2022-11-20 0.00 0.34 57.39 0.07 57.73 0 0 0.000000 [<PayInt:A-3>, <PayPrin:A-3>]

Issue new bonds by predicate

| new after Hastructure: 0.29.x

User can supply a series of bond issuance event which has a prefix of Condition . Then engine will execute the issuance of bonds if the Condition evaluates to True

syntax

("date1", <Pre> ,"bondGroupName", "accountName", <bondObject1>, None, None)
bondToBeIssue = {"balance":600
                 ,"rate":0.08
                 ,"name":"A-3"
                 ,"originBalance":600
                 ,"originRate":0.07
                 ,"startDate":"2022-04-02"
                 ,"rateType":{"Fixed":0.08}
                 ,"bondType":{"Sequential":None}
                ,"maturityDate":"2026-01-01"}

bondToBeIssue2 = bondToBeIssue | {"name":"A-4"}
bondToNotIssue = bondToBeIssue | {"name":"A-0"}

fundingPlan = [("2022-04-02","A","acc01",bondToBeIssue)
              ,("2022-07-19",[("bondBalance","A"),"<",600],"A","acc01",bondToBeIssue2,None,None)
              ,("2022-07-19",[("bondBalance","A"),"<",600],"A","acc01",bondToNotIssue,None,None)
              ]

r = localAPI.run(test01
                 ,runAssump = [
                     ("issueBond",*fundingPlan)
                 ]
                 ,read=True)
Warning Message from server:
Failed to issue to bond groupA:If L (CurrentBondBalanceOf ["A"]) 600.00

In this example, the first bond bondToBeIssue2 will be issued, becasue the condition (bondBalance, "A") < 600 evaluates to True. But the bond bondNotIssue won’t be issued as the condition (bondBalance, "A") < 600 won’t be True as, the bond group balance just get increased by 600 by issuing the bond A-4

readBondsCf(r['bonds'])['A'].head()
Bond A-1 A-2 A-3 A-4
Field balance interest principal rate cash balance interest principal rate cash balance interest principal rate cash balance interest principal rate cash
date
2021-07-26 400.0 0.0 0.0 0.09 0.0 600.0 0.0 0.0 0.08 0.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2021-08-20 400.0 0.0 0.0 0.09 0.0 600.0 0.0 0.0 0.08 0.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2021-09-20 400.0 0.0 0.0 0.09 0.0 600.0 0.0 0.0 0.08 0.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2021-10-20 400.0 0.0 0.0 0.09 0.0 600.0 0.0 0.0 0.08 0.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2021-11-20 400.0 0.0 0.0 0.09 0.0 600.0 0.0 0.0 0.08 0.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN

Issue new bonds by overriding Balance

What if the size of issuance depends on a Formula instead of a hard code amount ?

User can override the bond balance by supplying a Formula in the tuple

syntax

("date1", <Pre> ,"bondGroupName", "accountName", <bondObject1>, <Formula for bond balance>, None)
bondToBeIssue = {"balance":600
                 ,"rate":0.08
                 ,"name":"A-3"
                 ,"originBalance":600
                 ,"originRate":0.07
                 ,"startDate":"2022-04-02"
                 ,"rateType":{"Fixed":0.08}
                 ,"bondType":{"Sequential":None}
                ,"maturityDate":"2026-01-01"}

sizeOfBondBalance = ("excess", ("poolBalance",), ("bondBalance","A"))


fundingPlan = [
               ("2022-07-18",[("bondBalance","A"),"<",600],"A","acc01"
                              , bondToBeIssue
                              , sizeOfBondBalance,None)
              ]

r = localAPI.run(test01
                 ,runAssump = [
                     ("issueBond",*fundingPlan)
                     ,("inspect"#,[["CustomDate","2022-07-18"],sizeOfBondBalance]
                                ,[["CustomDate","2022-07-18"],("poolBalance",)]
                                ,[["CustomDate","2022-07-18"],("bondBalance","A")]
                      )
                 ]
                 ,read=True)
Warning Message from server:

readBondsCf(r['bonds'])['A'].head()
Bond A-1 A-2 A-3
Field balance interest principal rate cash balance interest principal rate cash balance interest principal rate cash
date
2021-07-26 400.0 0.0 0.0 0.09 0.0 600.0 0.0 0.0 0.08 0.0 NaN NaN NaN NaN NaN
2021-08-20 400.0 0.0 0.0 0.09 0.0 600.0 0.0 0.0 0.08 0.0 NaN NaN NaN NaN NaN
2021-09-20 400.0 0.0 0.0 0.09 0.0 600.0 0.0 0.0 0.08 0.0 NaN NaN NaN NaN NaN
2021-10-20 400.0 0.0 0.0 0.09 0.0 600.0 0.0 0.0 0.08 0.0 NaN NaN NaN NaN NaN
2021-11-20 400.0 0.0 0.0 0.09 0.0 600.0 0.0 0.0 0.08 0.0 NaN NaN NaN NaN NaN
from absbox import unifyTs

unifyTs(r['result']['inspect'].values())
<CurrentBondBalanceOf:A> <CurrentPoolBalance>
Date
2021-03-01 1000.00 0.00
2022-07-18 519.75 1570.39

Now , it should issue with balance of 1050.64

1570.39 - 519.75
1050.64

We can inspect on that day, we had the bond proceed with value of 1050.64

r['accounts']['acc01'].loc["2022-07-18"]
balance                    1168.5
change                    1050.64
memo       <IssuanceProceeds:A-3>
Name: 2022-07-18, dtype: object
r['bonds']['A']["A-3"].loc["2022-07-20"]
balance                               405.7
interest                                0.4
principal                            644.94
rate                                   0.07
cash                                 645.34
intDue                                    0
intOverInt                                0
factor                             0.386146
memo          [<PayInt:A-3>, <PayPrin:A-3>]
Name: 2022-07-20, dtype: object
644.94 + 405.70
1050.64

Issue new bonds by overriding Rate

Other than overriding the balance, we can override the rate as well

Here, we have using a formula to describle the bond issuance rate.

bondToBeIssue = {"balance":600
                 ,"rate":0.08
                 ,"name":"A-3"
                 ,"originBalance":600
                 ,"originRate":0.07
                 ,"startDate":"2022-04-02"
                 ,"rateType":{"Fixed":0.08}
                 ,"bondType":{"Sequential":None}
                ,"maturityDate":"2026-01-01"}

newBondRate = ("*", ("poolWaRate",), ("const",1.1))


fundingPlan = [
               ("2022-07-18",[("bondBalance","A"),"<",600],"A","acc01"
                              , bondToBeIssue
                              , ("const",300) , newBondRate)
              ]

r = localAPI.run(test01
                 ,runAssump = [
                     ("issueBond",*fundingPlan)
                     ,("inspect"#,[["CustomDate","2022-07-18"],sizeOfBondBalance]
                                ,[["CustomDate","2022-07-18"],("poolBalance",)]
                                ,[["CustomDate","2022-07-18"],("bondBalance","A")]
                      )
                 ]
                 ,read=True)
Warning Message from server:

r['bonds']['A']["A-3"]
balance interest principal rate cash intDue intOverInt factor memo
date
2022-07-20 300.00 0.14 0.00 0.088 0.14 0 0 1.000000 [<PayInt:A-3>, <PayPrin:A-3>]
2022-08-20 290.54 2.24 9.46 0.088 11.70 0 0 0.968467 [<PayInt:A-3>, <PayPrin:A-3>]
2022-09-20 174.86 2.17 115.68 0.088 117.85 0 0 0.582867 [<PayInt:A-3>, <PayPrin:A-3>]
2022-10-20 58.26 1.26 116.60 0.088 117.86 0 0 0.194200 [<PayInt:A-3>, <PayPrin:A-3>]
2022-11-20 0.00 0.43 58.26 0.088 58.69 0 0 0.000000 [<PayInt:A-3>, <PayPrin:A-3>]

Here, we set the new issue bond rate as 110% of pool weighted average rate

r['pool']['flow'].head()
Balance Principal Interest Prepayment Default Recovery Loss WAC BorrowerNum PrepayPenalty CumPrincipal CumPrepay CumDelinq CumDefault CumRecovery CumLoss
Date
2021-06-15 2200.0 0.0 0.0 0 0 0 0 0.08 None None 0.0 0 0 0 0 0
2021-06-30 2200.0 0.0 0.0 0 0 0 0 0.08 None None 0.0 0 0 0 0 0
2021-07-31 2200.0 0.0 0.0 0 0 0 0 0.08 None None 0.0 0 0 0 0 0
2021-08-31 2200.0 0.0 0.0 0 0 0 0 0.08 None None 0.0 0 0 0 0 0
2021-09-30 2200.0 0.0 0.0 0 0 0 0 0.08 None None 0.0 0 0 0 0 0