Skip to content

Commit 14ff6cd

Browse files
committed
Fix UT and expose first loss/ by term
1 parent 6aa824d commit 14ff6cd

38 files changed

+18347
-17983
lines changed

absbox/client.py

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ class Endpoints(str, enum.Enum):
5353
"""Run a single deal with multiple deal run scenarios endpoint"""
5454
RunByCombo = "runByCombo"
5555
"""Run mulitple sensitivities"""
56+
RunFirstLoss = "runByFirstLoss"
57+
"""Run first loss"""
5658
RunDate = "runDate"
5759
"""Run Dates from a datepattern """
5860
Version = "version"
@@ -76,6 +78,8 @@ class RunReqType(str, enum.Enum):
7678
""" Single Pool With Multiple Assumptions """
7779
ComboSensitivity = "MultiComboReq"
7880
""" Multiple sensitivities """
81+
FirstLoss = "FirstLossReq"
82+
""" First Loss Run """
7983

8084

8185
class RunResp(int, enum.Enum):
@@ -260,9 +264,9 @@ def build_run_deal_req(self, run_type: str, deal, perfAssump=None, nonPerfAssump
260264

261265
match Schema(str).validate(run_type):
262266
case "Single" | "S":
263-
_nonPerfAssump = mkNonPerfAssumps({}, nonPerfAssump)
264267
_deal = deal.json if hasattr(deal, "json") else deal
265268
_perfAssump = earlyReturnNone(mkAssumpType, perfAssump)
269+
_nonPerfAssump = mkNonPerfAssumps({}, nonPerfAssump)
266270
r = mkTag((RunReqType.Single.value, [_deal, _perfAssump, _nonPerfAssump]))
267271
case "MultiScenarios" | "MS":
268272
_nonPerfAssump = mkNonPerfAssumps({}, nonPerfAssump)
@@ -288,6 +292,11 @@ def build_run_deal_req(self, run_type: str, deal, perfAssump=None, nonPerfAssump
288292
if mRunAssump == {}:
289293
mRunAssump = {"Empty":{}}
290294
r = mkTag((RunReqType.ComboSensitivity.value, [mDeal, mAssump, mRunAssump]))
295+
case "FirstLoss" | "FL":
296+
_deal = deal.json if hasattr(deal, "json") else deal
297+
_perfAssump = mkAssumpType(perfAssump)
298+
_nonPerfAssump = mkNonPerfAssumps({}, nonPerfAssump)
299+
r = mkTag((RunReqType.FirstLoss.value, [_deal, _perfAssump, _nonPerfAssump]))
291300
case _:
292301
raise RuntimeError(f"Failed to match run type:{run_type}")
293302
try:
@@ -449,7 +458,6 @@ def read_single(self, pool_resp) -> tuple:
449458
result = _read_cf(pool_flow['contents'][1], self.lang)
450459
return (result, pool_bals)
451460

452-
453461
def runPoolByScenarios(self, pool, poolAssump, rateAssump=None, read=True, debug=False) -> dict :
454462
""" run a pool with multiple scenario ,return result as map , with key same to pool assumption map
455463
@@ -677,6 +685,43 @@ def runByCombo(self,
677685
else:
678686
return result
679687

688+
def runFirstLoss(self, deal, bName, poolAssump=None, runAssump=[], read=True, showWarning=True, debug=False) -> dict:
689+
"""run first loss with deal and pool assumptions
690+
691+
:param deal: a deal object
692+
:type deal: Generic | SPV
693+
:param poolAssump: pool performance assumption, a tuple for single run/ a dict for multi-scenario run, defaults to None
694+
:type poolAssump: tuple, optional
695+
:param runAssump: deal level assumption, defaults to []
696+
:type runAssump: list, optional
697+
:param read: flag to convert result to pandas dataframe, defaults to True
698+
:type read: bool, optional
699+
:param showWarning: flag to show warnings, defaults to True
700+
:type showWarning: bool, optional
701+
:param debug: return request text instead of sending out such request, defaults to False
702+
:type debug: bool, optional
703+
:return: result of run, a dict of dataframe if `read` is True.
704+
:rtype: dict
705+
"""
706+
707+
if (poolAssump is None):
708+
raise AbsboxError(f"❌{MsgColor.Error.value} poolAssump must be set for first loss run")
709+
710+
url = f"{self.url}/{Endpoints.RunFirstLoss.value}"
711+
712+
req = self.build_run_deal_req("FL", deal, poolAssump, runAssump)
713+
if debug:
714+
return req
715+
716+
result = self._send_req(req & lens.Json()['contents'].modify(lambda x:x+[bName]), url)
717+
718+
if result is None or 'error' in result or 'Left' in result:
719+
leftVal = result.get("Left","")
720+
raise AbsboxError(f"❌{MsgColor.Error.value}Failed to get response from run: {leftVal}")
721+
# rawWarnMsg = map( lambda x:f"{MsgColor.Warning.value}{x['contents']}", filter_by_tags(result[RunResp.LogResp.value], enumVals(ValidationMsg)))
722+
# if rawWarnMsg and showWarning:
723+
# console.print("Warning Message from server:\n"+"\n".join(list(rawWarnMsg)))
724+
return result['Right']
680725

681726
def runAsset(self, date, _assets, poolAssump=None, rateAssump=None
682727
, pricing=None, read=True, debug=False) -> tuple:
@@ -716,8 +761,7 @@ def readResult(x):
716761
_rate = lmap(mkRateAssumption, rateAssump) if rateAssump else None
717762
_pricing = mkLiqMethod(pricing) if pricing else None
718763
assets = lmap(mkAssetUnion, _assets)
719-
req = json.dumps([date, assets, _assumptions, _rate, _pricing]
720-
, ensure_ascii=False)
764+
req = json.dumps([date, assets, _assumptions, _rate, _pricing], ensure_ascii=False)
721765
if debug:
722766
return req
723767

absbox/local/component.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import sys
88

9-
from absbox.validation import vDict, vList, vStr, vNum, vInt, vDate, vFloat, vBool, vTuple
9+
from absbox.validation import vDict, vList, vStr, vNum, vInt, vDate, vFloat, vBool, vTuple, vListOfList
1010
from schema import Or
1111
from enum import Enum
1212
import itertools
@@ -1726,6 +1726,8 @@ def mkAssumpDefault(x):
17261726
return mkTag(("DefaultAtEndByRate", [vNum(r1), vNum(r2)]))
17271727
case {"StressByCurve": [curve, assump]}:
17281728
return mkTag(("DefaultStressByTs", [ mkRateTs(curve), mkAssumpDefault(assump)]))
1729+
case {"byTerm": rs}:
1730+
return mkTag(("DefaultByTerm", vListOfList(rs, numVal)))
17291731
case _ :
17301732
raise RuntimeError(f"failed to match {x}")
17311733

@@ -1743,6 +1745,8 @@ def mkAssumpPrepay(x):
17431745
return mkTag(("PrepayStressByTs", [ mkRateTs(curve), mkAssumpPrepay(assump)]))
17441746
case {"PSA": r}:
17451747
return mkTag(("PrepaymentPSA", vNum(r)))
1748+
case {"byTerm": rs}:
1749+
return mkTag(("PrepaymentByTerm", vListOfList(rs, numVal)))
17461750
case _ :
17471751
raise RuntimeError(f"failed to match {x}")
17481752

0 commit comments

Comments
 (0)