{ "cells": [ { "cell_type": "markdown", "id": "76e3281d", "metadata": {}, "source": [ "### SRT Example" ] }, { "cell_type": "code", "execution_count": 1, "id": "0ed52953", "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", "pd.set_option('display.max_rows', None)" ] }, { "cell_type": "markdown", "id": "7db52899", "metadata": {}, "source": [ "#### Deal Structure\n", "\n", "* waterfall\n", " * Distribution Day : \n", " * Principal : `Pro Rata` to senior (A) and protected tranche (B)\n", " * Interest : \"issuer\" will pay interest to tranches\n", " * End of Colleciton : allocate pool loss by move fund from collateral cash account to \"Issuer\"\n", " * Closing Day: fund collateral cash account with SRT tranche balance\n", " * Clean up: when deal was called, pay all cash from collateral cash account to protected tranche (B)\n", " " ] }, { "cell_type": "code", "execution_count": 2, "id": "3696a851", "metadata": {}, "outputs": [], "source": [ "from absbox import Generic\n", "\n", "seniorBalance = 1000\n", "srtTrancheBal = 200\n", "srtRate = 0.08\n", "closingDate = \"2021-06-15\"\n", "periodPrincipal = (\"curPoolCollection\", None, \"Principal\",\"Prepayment\",\"Recovery\")\n", "reinvestRate = 0.00\n", "\n", "\n", "srt01 = Generic(\n", " \"SRT Example\"\n", " ,{\"cutoff\":\"2021-06-01\",\"closing\":closingDate,\"firstPay\":\"2021-07-20\"\n", " ,\"payFreq\":[\"DayOfMonth\",20],\"poolFreq\":\"MonthEnd\",\"stated\":\"2030-01-01\"}\n", " ,{'assets':[[\"Mortgage\"\n", " ,{\"originBalance\":2200,\"originRate\":[\"fix\",0.045],\"originTerm\":24\n", " ,\"freq\":\"Monthly\",\"type\":\"Level\",\"originDate\":\"2021-06-01\"}\n", " ,{\"currentBalance\":2200\n", " ,\"currentRate\":0.08\n", " ,\"remainTerm\":24\n", " ,\"status\":\"current\"}]],\n", " }\n", " ,((\"acc01\",{\"balance\":0})\n", " ,(\"srtAcc\",{\"balance\":0.0\n", " ,\"interest\":{\"period\":\"QuarterEnd\"\n", " ,\"rate\":reinvestRate\n", " ,\"lastSettleDate\":closingDate}})\n", " ,(\"dummy\",{\"balance\":0.0})\n", " ,)\n", " ,((\"A1\",{\"balance\":seniorBalance\n", " ,\"rate\":0.00\n", " ,\"originBalance\":seniorBalance\n", " ,\"originRate\":0.00\n", " ,\"startDate\":closingDate\n", " ,\"rateType\":{\"Fixed\":0.00}\n", " ,\"bondType\":{\"Sequential\":None}})\n", " ,(\"B\",{\"balance\":0.0\n", " ,\"rate\":srtRate\n", " ,\"originBalance\":0\n", " ,\"originRate\":srtRate\n", " ,\"startDate\":closingDate\n", " ,\"rateType\":{\"Fixed\":srtRate}\n", " ,\"bondType\":{\"Sequential\":None}\n", " }))\n", " ,tuple()\n", " ,{\"amortizing\":[\n", " # pay prorata to senior and SRT tranch\n", " ['accrueAndPayInt',\"dummy\",[\"A1\"],{\"support\":[\"facility\",\"originator\"]}]\n", " ,[\"calcInt\",\"B\"]\n", " ,[\"payInt\",\"dummy\",[\"B\"],{\"support\":[\"facility\",\"originator\"]}]\n", "\n", " ,[\"calcBondPrin\",[\"A1\",\"B\"],{\"formula\":periodPrincipal}] \n", "\n", " ,[\"payPrinWithDue\",\"acc01\",[\"A1\"]] \n", " ,[\"payPrinWithDue\",\"srtAcc\",[\"B\"]]\n", "\n", " ],\n", " \"closingDay\":[\n", " [\"fundWith\",\"srtAcc\",\"B\",{\"formula\":(\"const\",srtTrancheBal)}]\n", " ],\n", " \"endOfCollection\":[\n", " # draw loss amount and pay to originator\n", " [\"liqRepayResidual\",\"srtAcc\", \"originator\", {\"formula\":(\"curPoolCollection\",None,\"Losses\")}]\n", " ],\n", " \"cleanUp\":[\n", " [\"payIntResidual\",\"srtAcc\",\"B\"]\n", " ]\n", " }\n", " ,[[\"CollectedInterest\",\"acc01\"]\n", " ,[\"CollectedPrincipal\",\"acc01\"]\n", " ,[\"CollectedPrepayment\",\"acc01\"]\n", " ,[\"CollectedRecoveries\",\"acc01\"]]\n", " ,{\"originator\":{\"type\" : \"Unlimit\", \"start\": closingDate}}\n", " ,None\n", " ,None\n", " ,None\n", " ,(\"PreClosing\",\"Amortizing\")\n", " )" ] }, { "cell_type": "code", "execution_count": 3, "id": "e4aabb0c", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
Connecting engine server -> https://absbox.org/api/dev\n",
       "
\n" ], "text/plain": [ "\u001b[1;35mConnecting engine server -> \u001b[0m\u001b[1;4;35mhttps://absbox.org/api/dev\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
Connected, local lib:0.26.4, server:0.27.17\n",
       "
\n" ], "text/plain": [ "✅\u001b[1;32mConnected, local li\u001b[0m\u001b[1;32mb:0\u001b[0m\u001b[1;32m.\u001b[0m\u001b[1;32m26.4\u001b[0m\u001b[1;32m, server:\u001b[0m\u001b[1;32m0.27\u001b[0m\u001b[1;32m.\u001b[0m\u001b[1;32m17\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
Warning Message from server:\n",
       "Bond B is not paid off\n",
       "Account acc01 has cash to be distributed\n",
       "LiquidityProvider originator is not paid off\n",
       "
\n" ], "text/plain": [ "Warning Message from server:\n", "\u001b[1;33mBond B is not paid off\u001b[0m\n", "\u001b[1;33mAccount acc01 has cash to be distributed\u001b[0m\n", "\u001b[1;33mLiquidityProvider originator is not paid off\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from absbox import API,EnginePath\n", "\n", "localAPI = API(EnginePath.DEV, lang='english', check=False)\n", "\n", "r = localAPI.run(srt01\n", " ,poolAssump=(\"Pool\",(\"Mortgage\", {\"CDR\":0.01}, None, None, None)\n", " ,None\n", " ,None)\n", " ,runAssump=[(\"call\",(\"poolFactor\",0.10))]\n", " ,read=True)" ] }, { "cell_type": "markdown", "id": "4fea9e73", "metadata": {}, "source": [ "#### View Bond Cashflow" ] }, { "cell_type": "code", "execution_count": 4, "id": "7594eedd", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
BondA1B
Fieldbalanceinterestprincipalratecashbalanceinterestprincipalratecash
date
2021-06-15NaNNaNNaNNaNNaN200.000.00-200.000.000.00
2021-07-201000.000.00.000.00.00200.001.530.000.081.53
2021-08-20929.370.070.630.070.63185.881.3514.120.0815.47
2021-09-20858.330.071.040.071.04171.671.2614.210.0815.47
2021-10-20786.880.071.450.071.45157.381.1214.290.0815.41
\n", "
" ], "text/plain": [ "Bond A1 B \\\n", "Field balance interest principal rate cash balance interest principal \n", "date \n", "2021-06-15 NaN NaN NaN NaN NaN 200.00 0.00 -200.00 \n", "2021-07-20 1000.00 0.0 0.00 0.0 0.00 200.00 1.53 0.00 \n", "2021-08-20 929.37 0.0 70.63 0.0 70.63 185.88 1.35 14.12 \n", "2021-09-20 858.33 0.0 71.04 0.0 71.04 171.67 1.26 14.21 \n", "2021-10-20 786.88 0.0 71.45 0.0 71.45 157.38 1.12 14.29 \n", "\n", "Bond \n", "Field rate cash \n", "date \n", "2021-06-15 0.00 0.00 \n", "2021-07-20 0.08 1.53 \n", "2021-08-20 0.08 15.47 \n", "2021-09-20 0.08 15.47 \n", "2021-10-20 0.08 15.41 " ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from absbox import readBondsCf\n", "\n", "readBondsCf(r['bonds']).head()" ] }, { "cell_type": "markdown", "id": "24c86e6b", "metadata": {}, "source": [ "#### Pool Loss metrics" ] }, { "cell_type": "markdown", "id": "fdc15e80", "metadata": {}, "source": [ "Here, we can identify total pool loss is `23.11`" ] }, { "cell_type": "code", "execution_count": 5, "id": "46e3a376", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "23.11" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "r['pool']['flow'].Loss.sum()" ] }, { "cell_type": "markdown", "id": "21519905", "metadata": {}, "source": [ "How much pool loss was cured via SRT traction ? we can filter out transaction in the `srtAcc` ,the collateral cash account draw out " ] }, { "cell_type": "code", "execution_count": 6, "id": "d6cbc863", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
balancechangememo
date
2021-06-15200.000.00<Support:originator>
2021-06-30200.000.00<Support:originator>
2021-07-31198.19-1.81<Support:originator>
2021-08-31182.27-1.80<Support:originator>
2021-09-30166.34-1.72<Support:originator>
\n", "
" ], "text/plain": [ " balance change memo\n", "date \n", "2021-06-15 200.00 0.00 \n", "2021-06-30 200.00 0.00 \n", "2021-07-31 198.19 -1.81 \n", "2021-08-31 182.27 -1.80 \n", "2021-09-30 166.34 -1.72 " ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "r['accounts']['srtAcc'].loc[lambda df: df.memo == \"\"].head()" ] }, { "cell_type": "markdown", "id": "6a15057c", "metadata": {}, "source": [ "Summing up all loss cured by SRT account, that's total cured `18.11`" ] }, { "cell_type": "code", "execution_count": 7, "id": "6107b7b4", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "-18.11" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "r['accounts']['srtAcc'].loc[lambda df: df.memo == \"\"].change.sum()" ] }, { "cell_type": "markdown", "id": "455ec929", "metadata": {}, "source": [ "We can tie out `18.11` loss in the SRT tranche (B). There 18.11 oustanding balance at end of projection." ] }, { "cell_type": "code", "execution_count": 8, "id": "72b5f6f4", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
balanceinterestprincipalratecashfactormemo
date
2023-01-2018.110.120.00.080.12None[<PayInt:B>, <PayPrin:B>]
2023-02-2018.110.120.00.080.12None[<PayInt:B>, <PayPrin:B>]
2023-03-2018.110.110.00.080.11None[<PayInt:B>, <PayPrin:B>]
2023-04-2018.110.120.00.080.12None[<PayInt:B>, <PayPrin:B>]
2023-05-2018.110.110.00.080.11None[[<PayInt:B>, <PayPrin:B>], <PayYield:B>]
\n", "
" ], "text/plain": [ " balance interest principal rate cash factor \\\n", "date \n", "2023-01-20 18.11 0.12 0.0 0.08 0.12 None \n", "2023-02-20 18.11 0.12 0.0 0.08 0.12 None \n", "2023-03-20 18.11 0.11 0.0 0.08 0.11 None \n", "2023-04-20 18.11 0.12 0.0 0.08 0.12 None \n", "2023-05-20 18.11 0.11 0.0 0.08 0.11 None \n", "\n", " memo \n", "date \n", "2023-01-20 [, ] \n", "2023-02-20 [, ] \n", "2023-03-20 [, ] \n", "2023-04-20 [, ] \n", "2023-05-20 [[, ], ] " ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "r['bonds']['B'].tail()" ] }, { "cell_type": "markdown", "id": "0308ce41", "metadata": {}, "source": [ "#### Return of SRT transaction\n", "\n", "Let's calculate the IRR of protect tranche" ] }, { "cell_type": "code", "execution_count": 9, "id": "b5cbb05d", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
balanceinterestprincipalratecashfactormemo
date
2021-06-15200.000.00-200.000.000.00None<FundWith:B,200.00>
2021-07-20200.001.530.000.081.53None[<PayInt:B>, <PayPrin:B>]
2021-08-20185.881.3514.120.0815.47None[<PayInt:B>, <PayPrin:B>]
2021-09-20171.671.2614.210.0815.47None[<PayInt:B>, <PayPrin:B>]
2021-10-20157.381.1214.290.0815.41None[<PayInt:B>, <PayPrin:B>]
\n", "
" ], "text/plain": [ " balance interest principal rate cash factor \\\n", "date \n", "2021-06-15 200.00 0.00 -200.00 0.00 0.00 None \n", "2021-07-20 200.00 1.53 0.00 0.08 1.53 None \n", "2021-08-20 185.88 1.35 14.12 0.08 15.47 None \n", "2021-09-20 171.67 1.26 14.21 0.08 15.47 None \n", "2021-10-20 157.38 1.12 14.29 0.08 15.41 None \n", "\n", " memo \n", "date \n", "2021-06-15 \n", "2021-07-20 [, ] \n", "2021-08-20 [, ] \n", "2021-09-20 [, ] \n", "2021-10-20 [, ] " ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "r['bonds']['B'].head()" ] }, { "cell_type": "markdown", "id": "96c1d3e0", "metadata": {}, "source": [ "Let's build a simple irr function" ] }, { "cell_type": "code", "execution_count": 10, "id": "ac4e0851", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "-0.04323574436198406" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from pyxirr import xirr\n", "\n", "def calcIRR(df, init):\n", " investDate,investAmount = init\n", " ds = [investDate] + df.index.to_list()\n", " vs = [investAmount] + df.cash.to_list()\n", " return xirr(ds, vs)\n", "\n", "calcIRR(r['bonds']['B'], (\"2021-06-15\",-200))" ] }, { "cell_type": "markdown", "id": "9c21274d", "metadata": {}, "source": [ "##### Sensitiviy Analysis : Pool Perf vs. IRR\n", "\n", "let's assump how different prepayment behavior would impact on the IRR\n", "\n", "1. build an assumption Map\n", "2. run with ..runByScenarios()\n" ] }, { "cell_type": "code", "execution_count": 11, "id": "fc360467", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
Warning Message from server:\n",
       "Account acc01 has cash to be distributed\n",
       "LiquidityProvider originator is not paid off\n",
       "Account acc01 has cash to be distributed\n",
       "LiquidityProvider originator is not paid off\n",
       "Account acc01 has cash to be distributed\n",
       "LiquidityProvider originator is not paid off\n",
       "
\n" ], "text/plain": [ "Warning Message from server:\n", "\u001b[1;33mAccount acc01 has cash to be distributed\u001b[0m\n", "\u001b[1;33mLiquidityProvider originator is not paid off\u001b[0m\n", "\u001b[1;33mAccount acc01 has cash to be distributed\u001b[0m\n", "\u001b[1;33mLiquidityProvider originator is not paid off\u001b[0m\n", "\u001b[1;33mAccount acc01 has cash to be distributed\u001b[0m\n", "\u001b[1;33mLiquidityProvider originator is not paid off\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from lenses import lens\n", "\n", "myAssumption = (\"Pool\",(\"Mortgage\",None,None,None,None)\n", " ,None\n", " ,None)\n", "myAssumption2 = myAssumption & lens[1][2].set({\"CPR\":0.01})\n", "myAssumption3 = myAssumption & lens[1][2].set({\"CPR\":0.02})\n", "\n", "\n", "rs = localAPI.runByScenarios(srt01\n", " ,poolAssump={\"CPR-0\":myAssumption\n", " ,\"CPR-1\":myAssumption2\n", " ,\"CPR-2\":myAssumption3\n", " }\n", " ,read=True)" ] }, { "cell_type": "markdown", "id": "d6a832fe", "metadata": {}, "source": [ "View pool cashflow from multiple scenarios" ] }, { "cell_type": "code", "execution_count": 12, "id": "d7f1c1b9", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
ScenarioCPR-0CPR-1CPR-2
FieldBalancePrepaymentBalancePrepaymentBalancePrepayment
Date
2021-06-152200.0002200.000.002200.000.00
2021-06-302200.0002200.000.002200.000.00
2021-07-312115.1702113.431.812111.663.65
2021-08-312029.7702026.371.802022.933.62
2021-09-301943.8101938.901.721933.943.46
\n", "
" ], "text/plain": [ "Scenario CPR-0 CPR-1 CPR-2 \n", "Field Balance Prepayment Balance Prepayment Balance Prepayment\n", "Date \n", "2021-06-15 2200.00 0 2200.00 0.00 2200.00 0.00\n", "2021-06-30 2200.00 0 2200.00 0.00 2200.00 0.00\n", "2021-07-31 2115.17 0 2113.43 1.81 2111.66 3.65\n", "2021-08-31 2029.77 0 2026.37 1.80 2022.93 3.62\n", "2021-09-30 1943.81 0 1938.90 1.72 1933.94 3.46" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from absbox import readMultiFlowsByScenarios\n", "readMultiFlowsByScenarios(rs, (lens['pool']['flow'],[\"Balance\",'Prepayment'])).head()" ] }, { "cell_type": "code", "execution_count": 13, "id": "f9fb1138", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'CPR-0': 0.0822966584499679,\n", " 'CPR-1': 0.08250918429431883,\n", " 'CPR-2': 0.08235205608296689}" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import toolz as tz\n", "\n", "tz.valmap(lambda x: calcIRR(x['bonds']['B'], (\"2021-06-15\",-200)), rs)" ] }, { "cell_type": "markdown", "id": "d7d45394", "metadata": {}, "source": [ "Whoa, interesting ! CPR=1% will yield most IRR" ] }, { "cell_type": "markdown", "id": "9d73930f", "metadata": {}, "source": [ "#### What's the protection exposure ? \n", "\n", "To what extend the current capital structure will hedge the default risk ? \n", "\n", "\n", "let's assump how different default stress would impact on the IRR\n", "\n", "1. build an assumption Map\n", "2. run with ..runByScenarios()" ] }, { "cell_type": "markdown", "id": "0fed485d", "metadata": {}, "source": [ "##### Sensitiviy Analysis : Pool Perf vs. Exposed Loss\n", "\n", "Exposed Loss : the loss not being hedged by SRT tranche" ] }, { "cell_type": "code", "execution_count": 14, "id": "82b9633b", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
Warning Message from server:\n",
       "Account acc01 has cash to be distributed\n",
       "LiquidityProvider originator is not paid off\n",
       "Bond B is not paid off\n",
       "Account acc01 has cash to be distributed\n",
       "LiquidityProvider originator is not paid off\n",
       "Bond B is not paid off\n",
       "Account acc01 has cash to be distributed\n",
       "LiquidityProvider originator is not paid off\n",
       "
\n" ], "text/plain": [ "Warning Message from server:\n", "\u001b[1;33mAccount acc01 has cash to be distributed\u001b[0m\n", "\u001b[1;33mLiquidityProvider originator is not paid off\u001b[0m\n", "\u001b[1;33mBond B is not paid off\u001b[0m\n", "\u001b[1;33mAccount acc01 has cash to be distributed\u001b[0m\n", "\u001b[1;33mLiquidityProvider originator is not paid off\u001b[0m\n", "\u001b[1;33mBond B is not paid off\u001b[0m\n", "\u001b[1;33mAccount acc01 has cash to be distributed\u001b[0m\n", "\u001b[1;33mLiquidityProvider originator is not paid off\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "myAssumption = (\"Pool\",(\"Mortgage\",None,None,None,None)\n", " ,None\n", " ,None)\n", "myAssumption2 = myAssumption & lens[1][1].set({\"CDR\":0.01})\n", "myAssumption3 = myAssumption & lens[1][1].set({\"CDR\":0.02})\n", "\n", "\n", "rs = localAPI.runByScenarios(srt01\n", " ,poolAssump={\"CDR-0\":myAssumption\n", " ,\"CDR-1\":myAssumption2\n", " ,\"CDR-2\":myAssumption3\n", " }\n", " ,read=True)" ] }, { "cell_type": "markdown", "id": "260a7cd5", "metadata": {}, "source": [ "View pool cashflows" ] }, { "cell_type": "code", "execution_count": 15, "id": "817dbb7b", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
ScenarioCDR-0CDR-1CDR-2
FieldBalanceDefaultBalanceDefaultBalanceDefault
Date
2021-06-152200.0002200.000.002200.000.00
2021-06-302200.0002200.000.002200.000.00
2021-07-312115.1702113.431.812111.663.65
2021-08-312029.7702026.371.802022.933.62
2021-09-301943.8101938.901.721933.943.46
\n", "
" ], "text/plain": [ "Scenario CDR-0 CDR-1 CDR-2 \n", "Field Balance Default Balance Default Balance Default\n", "Date \n", "2021-06-15 2200.00 0 2200.00 0.00 2200.00 0.00\n", "2021-06-30 2200.00 0 2200.00 0.00 2200.00 0.00\n", "2021-07-31 2115.17 0 2113.43 1.81 2111.66 3.65\n", "2021-08-31 2029.77 0 2026.37 1.80 2022.93 3.62\n", "2021-09-30 1943.81 0 1938.90 1.72 1933.94 3.46" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from absbox import readMultiFlowsByScenarios\n", "readMultiFlowsByScenarios(rs, (lens['pool']['flow'],[\"Balance\",'Default'])).head()" ] }, { "cell_type": "markdown", "id": "320a9a7c", "metadata": {}, "source": [ "By writing a small function to calculate unhendge amount,we are able to tell in all the scenarios, the unhedge amount" ] }, { "cell_type": "code", "execution_count": 16, "id": "77c1499e", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'CDR-0': 0.0, 'CDR-1': 41.449999999999996, 'CDR-2': 81.19999999999999}" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def unHedgeAmount(x:dict):\n", " \"x is the single run result\"\n", " \n", " poolLoss = x['pool']['flow'].Loss.sum()\n", " hedgedAmount = x['accounts']['srtAcc'].loc[lambda df: df.memo == \"\"].change.sum()\n", " \n", " return max(poolLoss - hedgedAmount,0)\n", "\n", "tz.valmap(unHedgeAmount, rs)" ] }, { "cell_type": "markdown", "id": "1263c1a8", "metadata": {}, "source": [ "#### Others ?\n", "\n", "Actuall `absbox` is flexible enough to perform sensitivity analysis on any two variables :\n", "\n", "* It could be reinvestment rate v.s IRR on SRT tranche..\n", "* It could be capital structure v.s IRR on SRT tranche.." ] }, { "cell_type": "markdown", "id": "e36c4c50", "metadata": {}, "source": [ "#### SRT with 3 tranches" ] }, { "cell_type": "markdown", "id": "e82ad65e", "metadata": {}, "source": [ "The key for 3 tranches is , the `srtAcc` only move funds to the loss which is the excess amount over the first loss tranche" ] }, { "cell_type": "code", "execution_count": 17, "id": "e3b9c7fa", "metadata": {}, "outputs": [], "source": [ "firstLossTranche = 5\n", "\n", "formulaToCurLoss = (\"excess\", (\"cumPoolNetLoss\",)\n", " , (\"abs\",(\"accountTxnAmount\",\"\",\"srtAcc\"))\n", " , (\"originalBondBalance\",\"C\"))" ] }, { "cell_type": "code", "execution_count": 18, "id": "522418dc", "metadata": {}, "outputs": [], "source": [ "seniorBalance = 1000\n", "srtTrancheBal = 200\n", "\n", "srtRate = 0.08\n", "closingDate = \"2021-06-15\"\n", "periodPrincipal = (\"curPoolCollection\", None, \"Principal\",\"Prepayment\",\"Recovery\")\n", "reinvestRate = 0.00\n", "\n", "\n", "\n", "srt02 = Generic(\n", " \"SRT Example\"\n", " ,{\"cutoff\":\"2021-06-01\",\"closing\":closingDate,\"firstPay\":\"2021-07-20\"\n", " ,\"payFreq\":[\"DayOfMonth\",20],\"poolFreq\":\"MonthEnd\",\"stated\":\"2030-01-01\"}\n", " ,{'assets':[[\"Mortgage\"\n", " ,{\"originBalance\":2200,\"originRate\":[\"fix\",0.045],\"originTerm\":24\n", " ,\"freq\":\"Monthly\",\"type\":\"Level\",\"originDate\":\"2021-06-01\"}\n", " ,{\"currentBalance\":2200\n", " ,\"currentRate\":0.08\n", " ,\"remainTerm\":24\n", " ,\"status\":\"current\"}]],\n", " }\n", " ,((\"acc01\",{\"balance\":0})\n", " ,(\"srtAcc\",{\"balance\":0.0\n", " ,\"interest\":{\"period\":\"QuarterEnd\"\n", " ,\"rate\":reinvestRate\n", " ,\"lastSettleDate\":closingDate}})\n", " ,(\"dummy\",{\"balance\":0.0})\n", " ,)\n", " ,((\"A1\",{\"balance\":seniorBalance\n", " ,\"rate\":0.00\n", " ,\"originBalance\":seniorBalance\n", " ,\"originRate\":0.00\n", " ,\"startDate\":closingDate\n", " ,\"rateType\":{\"Fixed\":0.00}\n", " ,\"bondType\":{\"Sequential\":None}})\n", " ,(\"B\",{\"balance\":0.0\n", " ,\"rate\":srtRate\n", " ,\"originBalance\":0\n", " ,\"originRate\":srtRate\n", " ,\"startDate\":closingDate\n", " ,\"rateType\":{\"Fixed\":srtRate}\n", " ,\"bondType\":{\"Sequential\":None}\n", " })\n", " ,(\"C\",{\"balance\":firstLossTranche\n", " ,\"rate\":0.0\n", " ,\"originBalance\":firstLossTranche\n", " ,\"originRate\":0.0\n", " ,\"startDate\":closingDate\n", " ,\"rateType\":{\"Fixed\":0.0}\n", " ,\"bondType\":{\"Sequential\":None}\n", " }) \n", " )\n", " ,tuple()\n", " ,{\"amortizing\":[\n", " # pay prorata to senior and SRT tranch\n", " [\"calcInt\",\"B\"]\n", " ,[\"payInt\",\"dummy\",[\"B\"],{\"support\":[\"facility\",\"originator\"]}]\n", " ,[\"calcBondPrin\",[\"A1\",\"B\"],{\"formula\":periodPrincipal}] \n", " ,[\"payPrinWithDue\",\"acc01\",[\"A1\"]] \n", " ,[\"payPrinWithDue\",\"srtAcc\",[\"B\"]]\n", " ,[\"liqRepayResidual\",\"acc01\", \"originator\"]\n", " ,[\"If\", [('isPaidOff',\"A1\",\"B\"),True]\n", " ,[\"payPrin\",\"acc01\",[\"C\"]]]\n", " ],\n", " \"closingDay\":[[\"fundWith\",\"srtAcc\",\"B\",{\"formula\":(\"const\",srtTrancheBal)}]],\n", " \"endOfCollection\":[\n", " # draw loss amount and pay to originator\n", " [\"liqRepayResidual\",\"srtAcc\", \"originator\", {\"formula\":formulaToCurLoss}]\n", " ],\n", " \"cleanUp\":[\n", " [\"payIntResidual\",\"srtAcc\",\"B\"]\n", " ]\n", " }\n", " ,[#[\"CollectedInterest\",\"acc01\"]\n", " [\"CollectedPrincipal\",\"acc01\"]\n", " ,[\"CollectedPrepayment\",\"acc01\"]\n", " ,[\"CollectedRecoveries\",\"acc01\"]]\n", " ,{\"originator\":{\"type\" : \"Unlimited\", \"start\": closingDate}}\n", " ,None\n", " ,None\n", " ,None\n", " ,(\"PreClosing\",\"Amortizing\")\n", " )" ] }, { "cell_type": "code", "execution_count": 19, "id": "684ea2ca", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
Warning Message from server:\n",
       "Bond B is not paid off\n",
       "Bond C is not paid off\n",
       "LiquidityProvider originator is not paid off\n",
       "
\n" ], "text/plain": [ "Warning Message from server:\n", "\u001b[1;33mBond B is not paid off\u001b[0m\n", "\u001b[1;33mBond C is not paid off\u001b[0m\n", "\u001b[1;33mLiquidityProvider originator is not paid off\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from absbox import API,EnginePath\n", "\n", "r02 = localAPI.run(srt02\n", " ,poolAssump=(\"Pool\",(\"Mortgage\", {\"CDR\":0.01}, None, None, None)\n", " ,None\n", " ,None)\n", " ,runAssump=[(\"call\",(\"poolFactor\",0.10))\n", " ,(\"inspect\"\n", " ,(\"MonthEnd\",(\"excess\", (\"cumPoolNetLoss\",)\n", " , (\"abs\",(\"accountTxnAmount\",\"\",\"srtAcc\"))\n", " , (\"constant\",firstLossTranche))\n", " ))\n", " ]\n", " ,read=True)" ] }, { "cell_type": "code", "execution_count": 30, "id": "44907e00", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
BondA1B
Fieldbalanceinterestprincipalratecashbalanceinterestprincipalratecash
date
2021-06-15NaNNaNNaNNaNNaN200.000.00-200.000.000.00
2021-07-201000.000.00.000.00.00200.001.530.000.081.53
2021-08-20929.370.070.630.070.63185.881.3514.120.0815.47
2021-09-20858.330.071.040.071.04171.671.2614.210.0815.47
2021-10-20786.880.071.450.071.45157.381.1214.290.0815.41
\n", "
" ], "text/plain": [ "Bond A1 B \\\n", "Field balance interest principal rate cash balance interest principal \n", "date \n", "2021-06-15 NaN NaN NaN NaN NaN 200.00 0.00 -200.00 \n", "2021-07-20 1000.00 0.0 0.00 0.0 0.00 200.00 1.53 0.00 \n", "2021-08-20 929.37 0.0 70.63 0.0 70.63 185.88 1.35 14.12 \n", "2021-09-20 858.33 0.0 71.04 0.0 71.04 171.67 1.26 14.21 \n", "2021-10-20 786.88 0.0 71.45 0.0 71.45 157.38 1.12 14.29 \n", "\n", "Bond \n", "Field rate cash \n", "date \n", "2021-06-15 0.00 0.00 \n", "2021-07-20 0.08 1.53 \n", "2021-08-20 0.08 15.47 \n", "2021-09-20 0.08 15.47 \n", "2021-10-20 0.08 15.41 " ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "readBondsCf(r02['bonds']).head()" ] }, { "cell_type": "markdown", "id": "aeb05d89", "metadata": {}, "source": [ "Now , the loss from the pool only will be cured from `srtAcc` account if cumulative loss is greater than `5`\n", "\n", "Here, at `2021-09-30`, the cumulative loss is 5.33 from the pool, the engine will only allocate `0.33` " ] }, { "cell_type": "code", "execution_count": 21, "id": "470b159f", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
balancechangememoCumLoss
2021-09-30171.670.00<BankInterest:>NaN
2021-09-30171.34-0.33<Support:originator>NaN
2021-09-30NaNNaNNaN5.33
\n", "
" ], "text/plain": [ " balance change memo CumLoss\n", "2021-09-30 171.67 0.00 NaN\n", "2021-09-30 171.34 -0.33 NaN\n", "2021-09-30 NaN NaN NaN 5.33" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pd.concat([r02['accounts']['srtAcc'],r02['pool']['flow'].CumLoss.to_frame()]).sort_index().loc[\"2021-09-30\"]" ] }, { "cell_type": "markdown", "id": "ebd90c2c", "metadata": {}, "source": [ "#### How thickness of FirstLossTranche would affect the IRR ?" ] }, { "cell_type": "code", "execution_count": 22, "id": "0fcda130", "metadata": {}, "outputs": [], "source": [ "firstLossTrancheDraft = {\"FirstLoss-1\": 5,\"FirstLoss-2\":10,\"FirstLoss-3\":20}" ] }, { "cell_type": "markdown", "id": "b4e99f43", "metadata": {}, "source": [ "build deal structures with a map( and lenses !)" ] }, { "cell_type": "code", "execution_count": 23, "id": "17bfb804", "metadata": {}, "outputs": [], "source": [ "dealDrafts = tz.valmap(lambda x: srt02 & lens.bonds[2][1].Fork(lens['balance'],lens['originBalance']).set(x) \n", " ,firstLossTrancheDraft)" ] }, { "cell_type": "markdown", "id": "0846733d", "metadata": {}, "source": [ "run differnt deal structures with funciton `runStructs()`" ] }, { "cell_type": "code", "execution_count": 24, "id": "f97d5999", "metadata": {}, "outputs": [], "source": [ "rm02 = localAPI.runStructs(dealDrafts\n", " ,poolAssump=(\"Pool\",(\"Mortgage\", {\"CDR\":0.01}, None, None, None)\n", " ,None\n", " ,None)\n", " ,nonPoolAssump=[(\"call\",(\"poolFactor\",0.10))\n", " ,(\"inspect\"\n", " ,(\"MonthEnd\",(\"excess\", (\"cumPoolNetLoss\",)\n", " , (\"abs\",(\"accountTxnAmount\",\"\",\"srtAcc\"))\n", " , (\"constant\",firstLossTranche))\n", " ))\n", " ]\n", " ,read=True)" ] }, { "cell_type": "code", "execution_count": 25, "id": "4f546cf6", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'FirstLoss-1': -0.008036217135081734,\n", " 'FirstLoss-2': 0.020824974743072763,\n", " 'FirstLoss-3': 0.08232329854365725}" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tz.valmap(lambda x: calcIRR(x['bonds']['B'], (\"2021-06-15\",-200)), rm02)" ] }, { "cell_type": "markdown", "id": "ea4e3df4", "metadata": {}, "source": [ "#### SRT with trigger on Prorata to Sequential\n", "\n", "user won't have to create a seperate new deal object but only need to `create a new one` from the old one: `srt02`\n", "\n", "* add a trigger which will be fired if pool performance hit\n", "* add extra branch of waterfall which will be execute after the trigger has been fired." ] }, { "cell_type": "code", "execution_count": 26, "id": "159637b9", "metadata": {}, "outputs": [], "source": [ "srt03 = srt02 & lens.trigger.set(\n", " {\"BeforeCollect\": \n", " {\"defaultTrigger\":\n", " {\"condition\":[(\"cumPoolDefaultedRate\",),\">\",0.01]\n", " ,\"effects\":(\"newStatus\",\"Accelerated\")\n", " ,\"status\":False\n", " ,\"curable\":False}\n", " }\n", " }\n", " )\n", "\n", "acceleratedWaterfall = [\n", " ['calcInt', 'B'],\n", " ['payInt', 'dummy', ['B'], {'support': ['facility', 'originator']}],\n", " ['payPrin','acc01',[\"A1\"]],\n", " ['liqRepayResidual', 'acc01', 'originator'],\n", " [\"If\", [('isPaidOff', 'A1'), True], \n", " ['payPrin',\"srtAcc\", [\"B\"],\n", " {\"limit\":\n", " {\"formula\": periodPrincipal}}]],\n", " ['If', [('isPaidOff', 'A1', 'B'), True], ['payPrin', 'acc01', ['C']]] \n", "]\n", "\n", "\n", "srt03 &= lens.waterfall.modify(lambda x: tz.assoc(x,(\"amortizing\", \"accelerated\"),acceleratedWaterfall ))" ] }, { "cell_type": "code", "execution_count": 27, "id": "a6ca45b9", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
Warning Message from server:\n",
       "Bond B is not paid off\n",
       "Bond C is not paid off\n",
       "LiquidityProvider originator is not paid off\n",
       "
\n" ], "text/plain": [ "Warning Message from server:\n", "\u001b[1;33mBond B is not paid off\u001b[0m\n", "\u001b[1;33mBond C is not paid off\u001b[0m\n", "\u001b[1;33mLiquidityProvider originator is not paid off\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "r03 = localAPI.run(srt03\n", " ,poolAssump=(\"Pool\",(\"Mortgage\", {\"CDR\":0.02}, None, None, None)\n", " ,None\n", " ,None)\n", " ,runAssump=[(\"call\",(\"poolFactor\",0.05))\n", " ,(\"inspect\"\n", " ,(\"MonthEnd\",(\"excess\", (\"cumPoolNetLoss\",)\n", " , (\"abs\",(\"accountTxnAmount\",\"\",\"srtAcc\"))\n", " , (\"constant\",firstLossTranche))\n", " ))\n", " ]\n", " ,read=True)" ] }, { "cell_type": "code", "execution_count": 28, "id": "aeba36b5", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
BondA1B
Fieldbalanceinterestprincipalratecashbalanceinterestprincipalratecash
date
2021-08-20929.430.070.570.070.57185.891.3514.110.0815.46
2021-09-20858.510.070.920.070.92171.711.2614.180.0815.44
2021-10-20787.240.071.270.071.27157.461.1214.250.0815.37
2021-11-20715.610.071.630.071.63143.141.0614.320.0815.38
2021-12-20643.620.071.990.071.99128.750.9414.390.0815.33
2022-01-20571.290.072.330.072.33114.280.8714.470.0815.34
2022-02-20484.050.087.240.087.24114.280.770.000.080.77
2022-03-20396.370.087.680.087.68114.280.700.000.080.70
2022-04-20308.250.088.120.088.12114.280.770.000.080.77
2022-05-20219.690.088.560.088.56114.280.750.000.080.75
2022-06-20130.680.089.010.089.01114.280.770.000.080.77
2022-07-2041.230.089.450.089.45114.280.750.000.080.75
2022-08-200.000.041.230.041.2331.310.7782.970.0883.74
2022-09-20NaNNaNNaNNaNNaN31.310.210.000.080.21
\n", "
" ], "text/plain": [ "Bond A1 B \\\n", "Field balance interest principal rate cash balance interest principal \n", "date \n", "2021-08-20 929.43 0.0 70.57 0.0 70.57 185.89 1.35 14.11 \n", "2021-09-20 858.51 0.0 70.92 0.0 70.92 171.71 1.26 14.18 \n", "2021-10-20 787.24 0.0 71.27 0.0 71.27 157.46 1.12 14.25 \n", "2021-11-20 715.61 0.0 71.63 0.0 71.63 143.14 1.06 14.32 \n", "2021-12-20 643.62 0.0 71.99 0.0 71.99 128.75 0.94 14.39 \n", "2022-01-20 571.29 0.0 72.33 0.0 72.33 114.28 0.87 14.47 \n", "2022-02-20 484.05 0.0 87.24 0.0 87.24 114.28 0.77 0.00 \n", "2022-03-20 396.37 0.0 87.68 0.0 87.68 114.28 0.70 0.00 \n", "2022-04-20 308.25 0.0 88.12 0.0 88.12 114.28 0.77 0.00 \n", "2022-05-20 219.69 0.0 88.56 0.0 88.56 114.28 0.75 0.00 \n", "2022-06-20 130.68 0.0 89.01 0.0 89.01 114.28 0.77 0.00 \n", "2022-07-20 41.23 0.0 89.45 0.0 89.45 114.28 0.75 0.00 \n", "2022-08-20 0.00 0.0 41.23 0.0 41.23 31.31 0.77 82.97 \n", "2022-09-20 NaN NaN NaN NaN NaN 31.31 0.21 0.00 \n", "\n", "Bond \n", "Field rate cash \n", "date \n", "2021-08-20 0.08 15.46 \n", "2021-09-20 0.08 15.44 \n", "2021-10-20 0.08 15.37 \n", "2021-11-20 0.08 15.38 \n", "2021-12-20 0.08 15.33 \n", "2022-01-20 0.08 15.34 \n", "2022-02-20 0.08 0.77 \n", "2022-03-20 0.08 0.70 \n", "2022-04-20 0.08 0.77 \n", "2022-05-20 0.08 0.75 \n", "2022-06-20 0.08 0.77 \n", "2022-07-20 0.08 0.75 \n", "2022-08-20 0.08 83.74 \n", "2022-09-20 0.08 0.21 " ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "readBondsCf(r03['bonds']).loc[\"2021-08-20\":\"2022-09-20\",]" ] }, { "cell_type": "markdown", "id": "1bb8697f", "metadata": {}, "source": [ "#### SRT with Sequential\n", "\n", "Sequential waterfall" ] }, { "cell_type": "code", "execution_count": 29, "id": "5be8ab97", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
Warning Message from server:\n",
       "Bond B is not paid off\n",
       "Bond C is not paid off\n",
       "LiquidityProvider originator is not paid off\n",
       "
\n" ], "text/plain": [ "Warning Message from server:\n", "\u001b[1;33mBond B is not paid off\u001b[0m\n", "\u001b[1;33mBond C is not paid off\u001b[0m\n", "\u001b[1;33mLiquidityProvider originator is not paid off\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
BondA1B
Fieldbalanceinterestprincipalratecashbalanceinterestprincipalratecash
date
2021-08-20915.310.084.690.084.69200.001.350.000.081.35
2021-09-20830.200.085.110.085.11200.001.350.000.081.35
2021-10-20744.670.085.530.085.53200.001.310.000.081.31
2021-11-20658.710.085.960.085.96200.001.350.000.081.35
2021-12-20572.320.086.390.086.39200.001.310.000.081.31
2022-01-20485.510.086.810.086.81200.001.350.000.081.35
2022-02-20398.270.087.240.087.24200.001.350.000.081.35
2022-03-20310.590.087.680.087.68200.001.220.000.081.22
2022-04-20222.470.088.120.088.12200.001.350.000.081.35
2022-05-20133.910.088.560.088.56200.001.310.000.081.31
2022-06-2044.900.089.010.089.01200.001.350.000.081.35
2022-07-200.000.044.900.044.90110.551.3189.450.0890.76
2022-08-20NaNNaNNaNNaNNaN31.310.7579.240.0879.99
2022-09-20NaNNaNNaNNaNNaN31.310.210.000.080.21
\n", "
" ], "text/plain": [ "Bond A1 B \\\n", "Field balance interest principal rate cash balance interest principal \n", "date \n", "2021-08-20 915.31 0.0 84.69 0.0 84.69 200.00 1.35 0.00 \n", "2021-09-20 830.20 0.0 85.11 0.0 85.11 200.00 1.35 0.00 \n", "2021-10-20 744.67 0.0 85.53 0.0 85.53 200.00 1.31 0.00 \n", "2021-11-20 658.71 0.0 85.96 0.0 85.96 200.00 1.35 0.00 \n", "2021-12-20 572.32 0.0 86.39 0.0 86.39 200.00 1.31 0.00 \n", "2022-01-20 485.51 0.0 86.81 0.0 86.81 200.00 1.35 0.00 \n", "2022-02-20 398.27 0.0 87.24 0.0 87.24 200.00 1.35 0.00 \n", "2022-03-20 310.59 0.0 87.68 0.0 87.68 200.00 1.22 0.00 \n", "2022-04-20 222.47 0.0 88.12 0.0 88.12 200.00 1.35 0.00 \n", "2022-05-20 133.91 0.0 88.56 0.0 88.56 200.00 1.31 0.00 \n", "2022-06-20 44.90 0.0 89.01 0.0 89.01 200.00 1.35 0.00 \n", "2022-07-20 0.00 0.0 44.90 0.0 44.90 110.55 1.31 89.45 \n", "2022-08-20 NaN NaN NaN NaN NaN 31.31 0.75 79.24 \n", "2022-09-20 NaN NaN NaN NaN NaN 31.31 0.21 0.00 \n", "\n", "Bond \n", "Field rate cash \n", "date \n", "2021-08-20 0.08 1.35 \n", "2021-09-20 0.08 1.35 \n", "2021-10-20 0.08 1.31 \n", "2021-11-20 0.08 1.35 \n", "2021-12-20 0.08 1.31 \n", "2022-01-20 0.08 1.35 \n", "2022-02-20 0.08 1.35 \n", "2022-03-20 0.08 1.22 \n", "2022-04-20 0.08 1.35 \n", "2022-05-20 0.08 1.31 \n", "2022-06-20 0.08 1.35 \n", "2022-07-20 0.08 90.76 \n", "2022-08-20 0.08 79.99 \n", "2022-09-20 0.08 0.21 " ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sequentialWaterfall = [\n", " ['calcInt', 'B'],\n", " ['payInt', 'dummy', ['B'], {'support': ['facility', 'originator']}],\n", " ['payPrin','acc01',[\"A1\"]],\n", " ['liqRepayResidual', 'acc01', 'originator'],\n", " [\"If\", [('isPaidOff', 'A1'), True], \n", " ['payPrin',\"srtAcc\", [\"B\"],\n", " {\"limit\":\n", " {\"formula\": periodPrincipal}}]],\n", " ['If', [('isPaidOff', 'A1', 'B'), True], ['payPrin', 'acc01', ['C']]] \n", "]\n", "\n", "srt04 = lens.waterfall.modify(lambda x: tz.assoc(x,\"amortizing\", sequentialWaterfall))(srt03)\n", "\n", "\n", "r04 = localAPI.run(srt04\n", " ,poolAssump=(\"Pool\",(\"Mortgage\", {\"CDR\":0.02}, None, None, None)\n", " ,None\n", " ,None)\n", " ,runAssump=[(\"call\",(\"poolFactor\",0.05))]\n", " ,read=True)\n", "\n", "readBondsCf(r04['bonds']).loc[\"2021-08-20\":\"2022-09-20\",]" ] }, { "cell_type": "code", "execution_count": null, "id": "4000a24d", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.9" } }, "nbformat": 4, "nbformat_minor": 5 }