@@ -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
8185class 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
0 commit comments