{ "cells": [ { "cell_type": "markdown", "id": "b6a6179c", "metadata": {}, "source": [ "### CLO IC Test (WIP)" ] }, { "cell_type": "code", "execution_count": null, "id": "b8d9117c", "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", "pd.set_option('display.max_rows', None)" ] }, { "cell_type": "code", "execution_count": null, "id": "39cc2d83", "metadata": {}, "outputs": [], "source": [ "from absbox import Generic\n", "\n", "bonds = (\n", " (\"A1\",{\"balance\":1000\n", " ,\"rate\":0.07\n", " ,\"originBalance\":1000\n", " ,\"originRate\":0.07\n", " ,\"startDate\":\"2020-01-03\"\n", " ,\"rateType\":{\"Fixed\":0.08}\n", " ,\"bondType\":{\"Sequential\":None}})\n", " ,(\"B\",{\"balance\":1000\n", " ,\"rate\":0.0\n", " ,\"originBalance\":1000\n", " ,\"originRate\":0.07\n", " ,\"startDate\":\"2020-01-03\"\n", " ,\"rateType\":{\"Fixed\":0.00}\n", " ,\"bondType\":{\"Sequential\":None}\n", " })\n", " ,(\"E\",{\"balance\":500\n", " ,\"rate\":0.0\n", " ,\"originBalance\":500\n", " ,\"originRate\":0.07\n", " ,\"startDate\":\"2020-01-03\"\n", " ,\"rateType\":{\"Fixed\":0.00}\n", " ,\"bondType\":{\"Equity\":None}\n", " }) \n", ")\n", "\n", "bond_OCs = [(\"A1\",(\"A1\",),1.1),(\"B\",(\"A1\",\"B\"),1.05)]\n", "\n", "OC_triggers = {f\"OC_{tName}\":\n", " {\"condition\":((\"/\",(\"poolBalance\",)\n", " ,(\"bondBalance\",*b))\n", " ,\"<\"\n", " ,threshold)\n", " ,\"effects\":None\n", " ,\"status\":False\n", " ,\"curable\":True}\n", " for (tName,b,threshold) in bond_OCs}\n", "\n", "bond_ICs = [(\"A\",(\"A1\",),1.05),(\"B\",(\"A1\",\"B\"),1.03)]\n", "\n", "IC_triggers = {f\"IC_{tName}\":\n", " {\"condition\":[\"all\"\n", " ,[(\"bondDueInt\",*b),\">\",0]\n", " ,[(\"/\", (\"accountBalance\",\"intAcc\"),(\"bondDueInt\",*b))\n", " ,\"<\"\n", " ,threshold]\n", " ]\n", " ,\"effects\":None\n", " ,\"status\":False\n", " ,\"curable\":True}\n", " for (tName,b,threshold) in bond_OCs}\n", "\n", "IC_triggerNames = list(IC_triggers.keys())\n", "OC_triggerNames = list(OC_triggers.keys())\n", "\n", "\n", "CLO_sample = Generic(\n", " \"CLO_sample\"\n", " ,{\"cutoff\":\"2021-03-01\",\"closing\":\"2021-06-15\",\"firstPay\":\"2021-07-26\"\n", " ,\"payFreq\":[\"DayOfMonth\",20],\"poolFreq\":\"MonthEnd\",\"stated\":\"2030-01-01\"}\n", " ,{'assets':[[\"Mortgage\"\n", " ,{\"originBalance\":2200,\"originRate\":[\"fix\",0.045],\"originTerm\":30\n", " ,\"freq\":\"Monthly\",\"type\":\"Level\",\"originDate\":\"2021-02-01\"}\n", " ,{\"currentBalance\":2200\n", " ,\"currentRate\":0.02\n", " ,\"remainTerm\":30\n", " ,\"status\":\"current\"}]]}\n", " ,((\"intAcc\",{\"balance\":0}),(\"prinAcc\",{\"balance\":0}))\n", " ,bonds\n", " ,((\"seniorFee\",{\"type\":{\"annualPctFee\":[(\"poolBalance\",),0.003]},\"feeStart\":\"2021-06-15\"})\n", " ,(\"subFee\",{\"type\":{\"annualPctFee\":[(\"poolBalance\",),0.002]},\"feeStart\":\"2021-06-15\"})\n", " ,)\n", " ,{\"amortizing\":[\n", " # intereset waterfall\n", " # accrue and pay senior fee \n", " [\"calcAndPayFee\",\"intAcc\",['seniorFee']]\n", " # accrue interest for both bonds (NO payment) \n", " ,[\"calcInt\",\"A1\",\"B\"]\n", " # calculate OC and IC test\n", " ,['runTriggers',*(IC_triggerNames)]\n", " # payout interest of A1 \n", " ,[\"payInt\",\"intAcc\",[\"A1\"]]\n", " # if all IC test is passing \n", " ,[\"IfElse\",[(\"trigger\",\"InDistribution\", \"IC_A1\"),False],\n", " # if passing\n", " [[\"payInt\",\"intAcc\",[\"B\"]]\n", " ,[\"calcAndPayFee\",\"intAcc\",['subFee']]\n", " ,[\"payIntResidual\",\"intAcc\",\"E\"]]\n", " # if failing, redemption senior to satisfy IC\n", " ,[[\"payPrin\",\"intAcc\",[\"A1\"]\n", " ,{\"limit\":{\"formula\":(\"bondBalance\",\"A1\")}}\n", " ]\n", " # update IC test again\n", " #,['runTriggers',*IC_triggerNames]\n", " # if IC test is passing\n", " ,[\"If\",[(\"trigger\",\"InDistribution\", \"IC_A1\"), False],\n", " # pay interest of B and residual to E\n", " [\"payInt\",\"intAcc\",[\"B\"]],\n", " [\"calcAndPayFee\",\"intAcc\",['subFee']],\n", " [\"payIntResidual\",\"intAcc\",\"E\"]]\n", " ]]\n", " # principal waterfall\n", " ,[\"payPrinBySeq\",\"prinAcc\",[\"A1\",\"B\"]]\n", " ,[\"payPrinResidual\",\"prinAcc\",[\"E\"]]\n", " ]}\n", " ,[[\"CollectedInterest\",\"intAcc\"]\n", " ,[\"CollectedPrincipal\",\"prinAcc\"]\n", " ,[\"CollectedPrepayment\",\"prinAcc\"]\n", " ,[\"CollectedRecoveries\",\"prinAcc\"]]\n", " ,None\n", " ,None\n", " ,None\n", " ,{\"InDistribution\":OC_triggers | IC_triggers}\n", " ,(\"PreClosing\",\"Amortizing\")\n", " )" ] }, { "cell_type": "code", "execution_count": null, "id": "79adf3c9", "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.28.7, server:0.28.11\n",
       "
\n" ], "text/plain": [ "✅\u001b[1;32mConnected, local li\u001b[0m\u001b[1;32mb:0\u001b[0m\u001b[1;32m.\u001b[0m\u001b[1;32m28.7\u001b[0m\u001b[1;32m, server:\u001b[0m\u001b[1;32m0.28\u001b[0m\u001b[1;32m.\u001b[0m\u001b[1;32m11\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
Warning Message from server:\n",
       "Bond E is not paid off\n",
       "
\n" ], "text/plain": [ "Warning Message from server:\n", "\u001b[1;33mBond E is not paid off\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from absbox import API,mkDeal,EnginePath\n", "localAPI = API(EnginePath.DEV,check=False)\n", "\n", "r = localAPI.run(CLO_sample\n", " ,poolAssump = None\n", " ,runAssump = None\n", " ,read=True)" ] }, { "cell_type": "code", "execution_count": null, "id": "f748d10e", "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", "
statusmemo
date
2021-07-26False<Tag:1.74 L 1.10>
2021-08-20True<Tag:0.91 L 1.10>
2021-08-20True<Tag:0.00 L 1.10>
2021-09-20True<Tag:0.70 L 1.10>
2021-09-20True<Tag:0.00 L 1.10>
2021-10-20True<Tag:0.62 L 1.10>
2021-10-20True<Tag:0.00 L 1.10>
2021-11-20True<Tag:0.57 L 1.10>
2021-11-20True<Tag:0.00 L 1.10>
2021-12-20True<Tag:0.58 L 1.10>
2021-12-20True<Tag:0.00 L 1.10>
2022-01-20True<Tag:0.62 L 1.10>
2022-01-20True<Tag:0.00 L 1.10>
2022-02-20True<Tag:0.74 L 1.10>
2022-02-20True<Tag:0.00 L 1.10>
2022-03-20False<Tag:1.19 L 1.10>
2022-04-20False<Tag:2.65 L 1.10>
2022-05-20False<Tag:5.85 L 1.10>
2022-06-20False<Tag:inf L 1.10>
2022-07-20False<Tag:inf L 1.10>
2022-08-20False<Tag:inf L 1.10>
2022-09-20False<Tag:inf L 1.10>
2022-10-20False<Tag:inf L 1.10>
2022-11-20False<Tag:inf L 1.10>
2022-12-20False<Tag:inf L 1.10>
2023-01-20False<Tag:inf L 1.10>
2023-02-20False<Tag:inf L 1.10>
2023-03-20False<Tag:inf L 1.10>
2023-04-20False<Tag:inf L 1.10>
2023-05-20False<Tag:inf L 1.10>
2023-06-20False<Tag:inf L 1.10>
2023-07-20False<Tag:inf L 1.10>
2023-08-20False<Tag:inf L 1.10>
2023-09-20False<Tag:inf L 1.10>
\n", "
" ], "text/plain": [ " status memo\n", "date \n", "2021-07-26 False \n", "2021-08-20 True \n", "2021-08-20 True \n", "2021-09-20 True \n", "2021-09-20 True \n", "2021-10-20 True \n", "2021-10-20 True \n", "2021-11-20 True \n", "2021-11-20 True \n", "2021-12-20 True \n", "2021-12-20 True \n", "2022-01-20 True \n", "2022-01-20 True \n", "2022-02-20 True \n", "2022-02-20 True \n", "2022-03-20 False \n", "2022-04-20 False \n", "2022-05-20 False \n", "2022-06-20 False \n", "2022-07-20 False \n", "2022-08-20 False \n", "2022-09-20 False \n", "2022-10-20 False \n", "2022-11-20 False \n", "2022-12-20 False \n", "2023-01-20 False \n", "2023-02-20 False \n", "2023-03-20 False \n", "2023-04-20 False \n", "2023-05-20 False \n", "2023-06-20 False \n", "2023-07-20 False \n", "2023-08-20 False \n", "2023-09-20 False " ] }, "execution_count": 65, "metadata": {}, "output_type": "execute_result" } ], "source": [ "r['triggers']['InWF']['IC_A1'].head(20)" ] }, { "cell_type": "code", "execution_count": null, "id": "ede47df5", "metadata": {}, "outputs": [], "source": [ "r['triggers']['InWF']['IC_A1'].head(20).loc['2021-07-26'].memo" ] }, { "cell_type": "code", "execution_count": 66, "id": "1e8ee62d", "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-07-2613.69-0.23<SeqPayFee:seniorFee>
2021-07-265.83-7.86<PayInt:A1>
2021-07-265.830.00<PayInt:B>
2021-07-265.68-0.15<SeqPayFee:subFee>
2021-07-260.00-5.68<PayYield:E>
\n", "
" ], "text/plain": [ " balance change memo\n", "date \n", "2021-07-26 13.69 -0.23 \n", "2021-07-26 5.83 -7.86 \n", "2021-07-26 5.83 0.00 \n", "2021-07-26 5.68 -0.15 \n", "2021-07-26 0.00 -5.68 " ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "r['accounts']['intAcc'].loc[\"2021-07-26\"]" ] }, { "cell_type": "code", "execution_count": 67, "id": "08fd886d", "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", "
balancechangememo
date
2021-08-203.11-0.07<SeqPayFee:seniorFee>
2021-08-200.00-3.11<PayInt:A1>
2021-08-200.000.00[<PayPrin:A1>, <DS:CurrentBondBalanceOf [\"A1\"]>]
\n", "
" ], "text/plain": [ " balance change memo\n", "date \n", "2021-08-20 3.11 -0.07 \n", "2021-08-20 0.00 -3.11 \n", "2021-08-20 0.00 0.00 [, ]" ] }, "execution_count": 67, "metadata": {}, "output_type": "execute_result" } ], "source": [ "r['accounts']['intAcc'].loc[\"2021-08-20\"]" ] }, { "cell_type": "code", "execution_count": 68, "id": "b1d1f1ec", "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", "
balanceinterestprincipalratecashintDueintOverIntfactormemo
date
2021-07-26712.967.86287.040.07294.900.0000.71296[<PayInt:A1>, <PayPrin:A1>]
2021-08-20640.903.1172.060.0775.170.3000.64090[[<PayInt:A1>, <PayPrin:A1>], <PayPrin:A1>]
2021-09-20568.722.9072.180.0775.081.2100.56872[[<PayInt:A1>, <PayPrin:A1>], <PayPrin:A1>]
2021-10-20496.422.8072.300.0775.101.6800.49642[[<PayInt:A1>, <PayPrin:A1>], <PayPrin:A1>]
2021-11-20424.002.6772.420.0775.091.9600.42400[[<PayInt:A1>, <PayPrin:A1>], <PayPrin:A1>]
2021-12-20351.462.5772.540.0775.111.8200.35146[[<PayInt:A1>, <PayPrin:A1>], <PayPrin:A1>]
2022-01-20278.802.4472.660.0775.101.4600.27880[[<PayInt:A1>, <PayPrin:A1>], <PayPrin:A1>]
2022-02-20206.022.3372.780.0775.110.7800.20602[[<PayInt:A1>, <PayPrin:A1>], <PayPrin:A1>]
2022-03-20133.121.8872.900.0774.780.0000.13312[<PayInt:A1>, <PayPrin:A1>]
2022-04-2060.110.7973.010.0773.800.0000.06011[<PayInt:A1>, <PayPrin:A1>]
2022-05-200.000.3460.110.0760.450.0000.00000[<PayInt:A1>, <PayPrin:A1>]
\n", "
" ], "text/plain": [ " balance interest principal rate cash intDue intOverInt \\\n", "date \n", "2021-07-26 712.96 7.86 287.04 0.07 294.90 0.00 0 \n", "2021-08-20 640.90 3.11 72.06 0.07 75.17 0.30 0 \n", "2021-09-20 568.72 2.90 72.18 0.07 75.08 1.21 0 \n", "2021-10-20 496.42 2.80 72.30 0.07 75.10 1.68 0 \n", "2021-11-20 424.00 2.67 72.42 0.07 75.09 1.96 0 \n", "2021-12-20 351.46 2.57 72.54 0.07 75.11 1.82 0 \n", "2022-01-20 278.80 2.44 72.66 0.07 75.10 1.46 0 \n", "2022-02-20 206.02 2.33 72.78 0.07 75.11 0.78 0 \n", "2022-03-20 133.12 1.88 72.90 0.07 74.78 0.00 0 \n", "2022-04-20 60.11 0.79 73.01 0.07 73.80 0.00 0 \n", "2022-05-20 0.00 0.34 60.11 0.07 60.45 0.00 0 \n", "\n", " factor memo \n", "date \n", "2021-07-26 0.71296 [, ] \n", "2021-08-20 0.64090 [[, ], ] \n", "2021-09-20 0.56872 [[, ], ] \n", "2021-10-20 0.49642 [[, ], ] \n", "2021-11-20 0.42400 [[, ], ] \n", "2021-12-20 0.35146 [[, ], ] \n", "2022-01-20 0.27880 [[, ], ] \n", "2022-02-20 0.20602 [[, ], ] \n", "2022-03-20 0.13312 [, ] \n", "2022-04-20 0.06011 [, ] \n", "2022-05-20 0.00000 [, ] " ] }, "execution_count": 68, "metadata": {}, "output_type": "execute_result" } ], "source": [ "r['bonds']['A1']" ] }, { "cell_type": "code", "execution_count": null, "id": "5a02fb0d", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "AbsBox (3.13.3)", "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.13.3" } }, "nbformat": 4, "nbformat_minor": 5 }