11from absbox .local .util import mkTag , mkTs , readTagStr , subMap , subMap2 , renameKs , ensure100
22from absbox .local .util import mapListValBy , uplift_m_list , mapValsBy , allList , getValWithKs , applyFnToKey ,flat
33from absbox .local .util import earlyReturnNone , mkFloatTs , mkRateTs , mkRatioTs , mkTbl , mapNone , guess_pool_flow_header
4- from absbox .local .util import filter_by_tags , enumVals , lmap , readTagMap , patchDicts
4+ from absbox .local .util import filter_by_tags , enumVals , lmap , readTagMap , patchDicts , updateKs
55from absbox .local .base import *
66
77import sys
@@ -1193,6 +1193,7 @@ def mkWaterfall(r, x):
11931193 r [_w_tag ] = lmap (mkAction , _v )
11941194 return mkWaterfall (r , x )
11951195
1196+
11961197def mkRoundingType (x ):
11971198 match x :
11981199 case ["floor" , r ]:
@@ -1202,6 +1203,7 @@ def mkRoundingType(x):
12021203 case _:
12031204 raise RuntimeError (f"Failed to match { x } :mkRoundingType" )
12041205
1206+
12051207def mkAssetRate (x ):
12061208 match x :
12071209 case ["固定" , r ] | ["fix" , r ]:
@@ -1297,6 +1299,7 @@ def mkAccRule(x):
12971299 case _ :
12981300 raise RuntimeError (f"Failed to match { x } :mkAccRule" )
12991301
1302+
13001303def mkInvoiceFeeType (x ):
13011304 match x :
13021305 case ("Fixed" , amt ) | ("固定" , amt ):
@@ -1312,6 +1315,7 @@ def mkInvoiceFeeType(x):
13121315 case _:
13131316 raise RuntimeError (f"Failed to match { x } :mkInvoiceFeeType" )
13141317
1318+
13151319def mkCapacity (x ):
13161320 match x :
13171321 case ("固定" , c ) | ("Fixed" , c ):
@@ -1321,6 +1325,7 @@ def mkCapacity(x):
13211325 case _ :
13221326 raise RuntimeError (f"Failed to match { x } :mkCapacity" )
13231327
1328+
13241329def mkObligor (x :dict ) -> dict :
13251330 def mkObligorFields (y :dict ) -> dict :
13261331 if not y :
@@ -1462,7 +1467,7 @@ def id_by_pool_assets(z):
14621467 return "MDeal"
14631468 case {"assets" : [], "futureCf" : cfs } if cfs ['contents' ][1 ][0 ]['tag' ] == 'MortgageFlow' :
14641469 return "MDeal"
1465- case {"assets" : [{'tag' : 'Installment' }, * rest ]}:
1470+ case {"assets" : [{'tag' : 'Installment' }, * rest ]} :
14661471 return "IDeal"
14671472 case {"assets" : [{'tag' : 'Lease' }, * rest ]} | {"assets" : [{'tag' : 'RegularLease' }, * rest ]}:
14681473 return "RDeal"
@@ -1474,28 +1479,34 @@ def id_by_pool_assets(z):
14741479 return "VDeal"
14751480 case {"assets" : [{'tag' : 'ProjectedFlowMix' }, * rest ]} | {"assets" : [{'tag' : 'ProjectedFlowMixFloater' }, * rest ]}:
14761481 return "PDeal"
1482+ case {"assets" : [{'tag' : 'IL' }, * rest ]} | {"assets" : [{'tag' : 'MO' }, * rest ]} | \
1483+ {"assets" : [{'tag' : 'LO' }, * rest ]} | {"assets" : [{'tag' : 'LS' }, * rest ]} | \
1484+ {"assets" : [{'tag' : 'FA' }, * rest ]} | {"assets" : [{'tag' : 'RE' }, * rest ]} | \
1485+ {"assets" : [{'tag' : 'PF' }, * rest ]} :
1486+ return "UDeal"
14771487 case _:
1478- raise RuntimeError (f"Failed to identify deal type { z } " )
1488+ raise RuntimeError (f"Failed to identify pool type { z } " )
14791489 y = None
14801490 match x :
1491+ # single pool
14811492 case {"pool" :{"tag" :"MultiPool" ,"contents" :{"PoolConsol" :{"assets" :[]}}}} if len (x ['pool' ]['contents' ]['PoolConsol' ]['futureCf' ])> 0 :
14821493 return id_by_pool_assets (x ['pool' ]['contents' ]['PoolConsol' ])
14831494 case {"pool" :{"tag" :"MultiPool" ,"contents" :{"PoolConsol" :{"assets" :assetList }}}} if len (assetList ) > 1 :
14841495 return id_by_pool_assets (x ['pool' ]['contents' ]['PoolConsol' ])
1496+ # multiple pools
14851497 case {"pool" :{"tag" :"MultiPool" ,"contents" :poolMap }}:
14861498 pools = list (map (id_by_pool_assets , poolMap & lens .Values ().collect ()))
1487-
14881499 if len (set (pools ))> 1 :
14891500 return "UDeal"
14901501 else :
14911502 return pools [0 ]
1503+ # resec deals
14921504 case {"pool" :{"tag" :"ResecDeal" }}:
14931505 vs = [ v ['deal' ] for k ,v in x ["pool" ]['contents' ].items () ]
14941506 assetTypes = set (map (identify_deal_type , vs ))
14951507 if len (assetTypes )> 1 :
14961508 return "UDeal"
14971509 else :
1498- print (assetTypes , "<<<" )
14991510 return list (assetTypes )[0 ]
15001511 case _:
15011512 raise RuntimeError (f"Failed to match pool type { x } " )
@@ -1789,25 +1800,30 @@ def mkPoolType(assetDate, x, mixedFlag) -> dict:
17891800 {"deal" :dealObj .json ['contents' ],"future" :None ,"futureScheduleCf" :None ,"issuanceStat" :None }\
17901801 for ((bn ,pct ,sd ),dealObj ) in x ['deals' ].items ()} ))
17911802 case x if all ([ isinstance (_ ,dict ) for _ in x .values () ]):
1792- return mkTag (("MultiPool" ,{f"PoolName:{ k } " :mkPoolComp (vDate (assetDate ),v ,mixedFlag ) for (k ,v ) in x .items ()}))
1803+ return mkTag (("MultiPool"
1804+ ,{f"PoolName:{ k } " :mkPoolComp (vDate (assetDate ),v ,mixedFlag )
1805+ for (k ,v ) in x .items ()})
1806+ )
17931807 case _ :
17941808 raise RuntimeError ("Failed to match pool type " ,x )
17951809
17961810
17971811def mkPoolComp (asOfDate , x , mixFlag ) -> dict :
1798- assetFactory = mkAsset if ( not mixFlag ) else mkAssetUnion
1799- r = {"assets" : [assetFactory (y ) for y in getValWithKs (x , ['assets' , "清单" ],defaultReturn = [])]
1812+ assetFactory = mkAssetUnion if mixFlag else mkAsset
1813+ r = {"assets" : [assetFactory (y ) for y in getValWithKs (x , ['assets' , "清单" ], defaultReturn = [])]
18001814 , "asOfDate" : asOfDate
1801- , "issuanceStat" : getValWithKs (x ,["issuanceStat" , "统计" , "发行" ,"Issuance" ])
1802- , "futureCf" :mkCf (getValWithKs (x ,['cashflow' , '现金流归集表' , '归集表' ],[]))
1803- , "extendPeriods" :mkDatePattern (getValWithKs (x ,['extendBy' ], "MonthEnd" ))}
1815+ , "issuanceStat" : tz .pipe (getValWithKs (x , ["issuanceStat" , "统计" , "发行" , "Issuance" ],defaultReturn = {})
1816+ , lambda y : updateKs (y , validCutoffFields )
1817+ )
1818+ , "futureCf" :mkCf (getValWithKs (x , ['cashflow' , '现金流归集表' , '归集表' ], []))
1819+ , "extendPeriods" :mkDatePattern (getValWithKs (x , ['extendBy' ], "MonthEnd" ))}
18041820 return r
18051821
18061822
18071823def mkPool (x : dict ):
18081824 mapping = {"LDeal" : "LPool" , "MDeal" : "MPool" ,
18091825 "IDeal" : "IPool" , "RDeal" : "RPool" , "FDeal" :"FPool" ,
1810- "VDeal" : "VPool" , "UDeal" :"UPool" }
1826+ "VDeal" : "VPool" , "UDeal" : "UPool" }
18111827 match x :
18121828 case {"清单" : assets , "封包日" : d } | {"assets" : assets , "cutoffDate" : d }:
18131829 _pool = {"assets" : [mkAsset (a ) for a in assets ] , "asOfDate" : d }
@@ -1898,7 +1914,8 @@ def mkCf(x:list):
18981914 else :
18991915 cfs = [mkTag (("MortgageFlow" , _x + [0.0 ]* 5 + [None ,None ,None ])) for _x in x ]
19001916 return mkTag (("CashFlowFrame" , [[0 ,"1900-01-01" ,None ],cfs ]))
1901-
1917+
1918+
19021919def mkCashFlowFrame (x ):
19031920 """ Make cashflow frame """
19041921 flows = x .get ("flows" ,[])
@@ -2208,6 +2225,7 @@ def mkRateAssumption(x):
22082225 case _ :
22092226 raise RuntimeError (f"Failed to match RateAssumption:{ x } " )
22102227
2228+
22112229def mkFundingPlan (x :tuple ):
22122230 # IssueBondEvent mPre bondName accountName Bond mFormula mFormula
22132231 match x :
@@ -2229,6 +2247,7 @@ def mkRefiPlan(x:tuple):
22292247 case _:
22302248 raise RuntimeError (f"Failed to match mkRefinancePlan:{ x } " )
22312249
2250+
22322251def mkInspect (x ):
22332252 match x :
22342253 case (dp ,ds ) if isinstance (ds , tuple ):
0 commit comments