1010from rich .console import Console
1111
1212
13- from .interface import mkTag ,readAeson
13+ from .interface import mkTag ,readAeson , mkCurve
1414from .util import mkTs , readTagStr , subMap , subMap2 , renameKs , ensure100
1515from .util import mapListValBy , uplift_m_list , mapValsBy , allList , getValWithKs , applyFnToKey ,flat
1616from .util import earlyReturnNone , mkFloatTs , mkRateTs , mkRatioTs , mkTbl , mapNone , guess_pool_flow_header
1717from .util import filter_by_tags , enumVals , lmap , readTagMap , patchDicts ,updateKs , ensureKeysInMap
1818from .base import *
1919
20- from ..validation import vDict , vList , vStr , vNum , vInt , vDate , vFloat , vBool , vTuple , vListOfList
21-
20+ from ..validation import vDict , vList , vStr , vNum , vInt , vDate , vFloat , vBool , vTuple , vListOfList , vListOfDict , vMap , vEnum , vOr , vOpt , vAny
21+ from .. validation import isListOfDict
2222
2323numVal = Or (float ,int )
2424console = Console ()
@@ -180,27 +180,45 @@ def mkDsRate(x):
180180
181181def mkFeeType (x ):
182182 match x :
183- case {"年化费率" : [base , rate ]} | {"annualPctFee" : [base , rate ]} | ("annualPctFee" , base , rate ):
183+ case {"年化费率" : [base , rate ]} | {"annualPctFee" : [base , rate ]} | ("annualPctFee" , base , rate ) | { "base" : base , "annualisedRate" : rate } :
184184 return mkTag (("AnnualRateFee" , [mkDs (base ), mkDsRate (rate )]))
185- case {"百分比费率" : [base , _rate ]} | {"pctFee" : [base , _rate ]} | ("pctFee" , base , _rate ):
185+ case {"百分比费率" : [base , _rate ]} | {"pctFee" : [base , _rate ]} | ("pctFee" , base , _rate ) | { "base" : base , "pctFeeRate" : _rate } :
186186 rate = mkDsRate (_rate )
187187 return mkTag (("PctFee" , [mkDs (base ), rate ]))
188188 case {"固定费用" : amt } | {"fixFee" : amt } | ("fixFee" , amt ):
189189 return mkTag (("FixFee" , vNum (amt )))
190- case {"周期费用" : [p , amt ]} | {"recurFee" : [p , amt ]} | ("recurFee" , p , amt ):
190+ case {"周期费用" : [p , amt ]} | {"recurFee" : [p , amt ]} | ("recurFee" , p , amt ) | { "recurFeeAmt" : amt , "recurDates" : p } :
191191 return mkTag (("RecurFee" , [mkDatePattern (p ), vNum (amt )]))
192+ case {"customFee" : fflow } if isListOfDict (fflow ):
193+ vs = [ [m ['date' ],m ['amount' ]] for m in fflow ]
194+ return mkTag (("FeeFlow" , mkTs ("BalanceCurve" , vs )))
192195 case {"自定义" : fflow } | {"customFee" : fflow } | ("customFee" , fflow ):
193196 return mkTag (("FeeFlow" , mkTs ("BalanceCurve" , fflow )))
194- case {"计数费用" : [p , s , amt ]} | {"numFee" : [p , s , amt ]} | ("numFee" , p , s , amt ):
197+ case {"计数费用" : [p , s , amt ]} | {"numFee" : [p , s , amt ]} | ("numFee" , p , s , amt ) | { "numFeeDates" : p , "base" : s , "numFeeAmount" : amt } :
195198 return mkTag (("NumFee" , [mkDatePattern (p ), mkDs (s ), amt ]))
199+
200+ case {"targetBalDue" : ds1 , "targetBalOffset" : ds2 }:
201+ return mkTag (("TargetBalanceFee" , [mkDs (ds1 ), mkDs (ds2 )]))
196202 case {"差额费用" : [ds1 , ds2 ]} | {"targetBalanceFee" : [ds1 , ds2 ]} | ("targetBalanceFee" , ds1 , ds2 ):
197203 return mkTag (("TargetBalanceFee" , [mkDs (ds1 ), mkDs (ds2 )]))
204+
198205 case {"回款期间费用" : amt } | {"byPeriod" : amt } | ("byPeriod" , amt ):
199206 return mkTag (("ByCollectPeriod" , amt ))
207+
208+ case {"tableDates" :dp ,"tableRef" :ds ,"table" :tbl } :
209+ return mkTag (("AmtByTbl" , [mkDatePattern (dp ), mkDs (ds ), tbl ]))
210+
200211 case {"分段费用" : [dp , ds , tbl ]} | {"byTable" : [dp , ds , tbl ]} | ("byTable" , dp , ds , tbl ):
201212 return mkTag (("AmtByTbl" , [mkDatePattern (dp ), mkDs (ds ), tbl ]))
213+
214+ case {"flowByBondPeriod" : fflow } if isListOfDict (fflow ):
215+ vs = [ [m ['index' ],m ['amount' ]] for m in fflow ]
216+ return mkTag (("FeeFlowByBondPeriod" , mkTs ("CurrentVal" , vs )))
202217 case {"flowByBondPeriod" : curve } | ("flowByBondPeriod" , curve ):
203218 return mkTag (("FeeFlowByBondPeriod" , mkTag (("CurrentVal" , curve ))))
219+ case {"flowByPoolPeriod" : fflow } if isListOfDict (fflow ):
220+ vs = [ [m ['index' ],m ['amount' ]] for m in fflow ]
221+ return mkTag (("FeeFlowByPoolPeriod" , mkTs ("CurrentVal" , vs )))
204222 case {"flowByPoolPeriod" : curve } | ("flowByPoolPeriod" , curve ):
205223 return mkTag (("FeeFlowByPoolPeriod" , mkTag (("CurrentVal" , curve ))))
206224 case _:
@@ -494,8 +512,6 @@ def mkDs(x):
494512 except TypeError as e :
495513 raise RuntimeError (f"Failed to match DS/Formula: { x } " , e )
496514
497- def mkCurve (tag , xs ):
498- return mkTag ((tag , xs ))
499515
500516
501517def mkPre (p ):
@@ -667,9 +683,9 @@ def mkBondType(x):
667683
668684def mkBondIoItype (x ):
669685 match x :
670- case ("上浮" , f ) | ("inflate" , f ):
686+ case ("上浮" , f ) | ("inflate" , f ) | { "inflate" : f } :
671687 return mkTag (("OverCurrRateBy" , vNum (f )))
672- case ("利差" , spd ) | ("spread" , spd ):
688+ case ("利差" , spd ) | ("spread" , spd ) | { "spread" : spd } :
673689 return mkTag (("OverFixSpread" , vNum (spd )))
674690 case _:
675691 raise RuntimeError (f"Failed to match bond IoI type:{ x } " )
@@ -684,9 +700,10 @@ def mkBondRate(x:dict)->dict:
684700 return mkTag (("Floater" , [r , _index , Spread , mkDatePattern (resetInterval ), dc , None , None ]))
685701 # floater rate with default daycount
686702 case {"浮动" : [r , _index , Spread , resetInterval ]} | \
687- {"floater" : [r , _index , Spread , resetInterval ]} | \
688- ("floater" , (r , _index , Spread , resetInterval )) :
703+ {"floater" : [r , _index , Spread , resetInterval ]} | \
704+ ("floater" , (r , _index , Spread , resetInterval )) :
689705 return mkTag (("Floater" , [r , _index , Spread , mkDatePattern (resetInterval ), DC .DC_ACT_365F .value , None , None ]))
706+
690707 # fix rate with day count
691708 case {"固定" : _rate , "日历" : dc } | {"fix" : _rate , "dayCount" : dc }:
692709 return mkTag (("Fix" , [vNum (_rate ), dc ]))
@@ -696,31 +713,50 @@ def mkBondRate(x:dict)->dict:
696713 # fix rate with default day count
697714 case {"固定" : _rate } | {"Fixed" : _rate } | {"fix" : _rate } | ("fix" , _rate ) | ["fix" , _rate ]:
698715 return mkTag (("Fix" , [vNum (_rate ), DC .DC_ACT_365F .value ]))
699- case {"期间收益" : _yield } | {"interimYield" : _yield }:
700- return mkTag (("InterestByYield" , vNum (_yield )))
701- case ("refBalance" , ds , ii ):
716+
717+ case ("refBalance" , ds , ii ) | {"refBalance" : ds , "rateType" : ii }:
702718 return mkTag (("RefBal" , [mkDs (ds ), mkBondRate (ii )]))
719+ case ("ref" , _rate , ds , factor , reset ) | {"rate" :_rate , "refRate" : ds , "factor" : factor , "reset" : reset }: # | RefRate IRate DealStats Float RateReset
720+ return mkTag (("RefRate" , [vNum (_rate ), mkDs (ds ), vNum (factor ), mkDatePattern (reset )]))
721+
703722 # rate with cap
704723 case ("上限" , cap , br ) | ("cap" , cap , br ):
705724 return mkTag (("CapRate" , [mkBondRate (br ), vNum (cap )]))
706725 # rate with floor
707726 case ("下限" , floor , br ) | ("floor" , floor , br ):
708727 return mkTag (("FloorRate" , [mkBondRate (br ), vNum (floor )]))
709- case ("罚息" , pRateInfo ,bRateInfo ) | ("withIntOverInt" , pRateInfo , bRateInfo ):
728+
729+ case ("罚息" , pRateInfo ,bRateInfo ) | ("withIntOverInt" , pRateInfo , bRateInfo )\
730+ | {"intOverInt" : pRateInfo , "rateType" : bRateInfo } :
710731 return mkTag (("WithIoI" , [mkBondRate (bRateInfo ), mkBondIoItype (pRateInfo )]))
711- case ("ref" , _rate , ds , factor , reset ): # | RefRate IRate DealStats Float RateReset
712- return mkTag (("RefRate" , [vNum (_rate ), mkDs (ds ), vNum (factor ), mkDatePattern (reset )]))
732+
713733 case None :
714- return mkTag (("Fix" ,[0 , DC .DC_ACT_365F ]))
734+ return mkTag (("Fix" ,[0 , DC .DC_ACT_365F ]))
735+
736+ case {"rate" : rate ,"index" : idx , "spread" : spd , "reset" : resetInterval , ** p } :
737+ dc = p .get ("dayCount" , DC .DC_ACT_365F .value )
738+ cap = p .get ("cap" , None )
739+ floor = p .get ("floor" , None )
740+ match (cap ,floor ):
741+ case (None , None ):
742+ return mkTag (("Floater" , [vNum (rate ), idx , vNum (spd ), mkDatePattern (resetInterval ), dc , None , None ]))
743+ case (None , floor ):
744+ return mkBondRate (("floor" , floor , tz .dissoc (x ,'floor' )))
745+ case (cap , None ):
746+ return mkBondRate (("cap" , cap , tz .dissoc (x ,'cap' )))
747+ case _ :
748+ raise RuntimeError (f"Failed to match bond rate with both cap and floor: { x } " )
749+
750+
715751 case _:
716752 raise RuntimeError (f"Failed to match bond rate type:{ x } " )
717753
718754
719755def mkStepUp (x ):
720756 match x :
721- case ("ladder" , d , spd , dp ):
757+ case ("ladder" , d , spd , dp ) | { "date" : d , "spread" : spd , "changeDates" : dp } :
722758 return mkTag (("PassDateLadderSpread" , [vDate (d ), vNum (spd ), mkDatePattern (dp )]))
723- case ("once" , d , spd ):
759+ case ("once" , d , spd ) | { "date" : d , "spread" : spd } :
724760 return mkTag (("PassDateSpread" , [vDate (d ), vNum (spd )]))
725761 case _:
726762 raise RuntimeError (f"Failed to match bond step up type:{ x } " )
@@ -783,13 +819,13 @@ def mkBnd(bn, x:dict):
783819 mStmt = mkTxn ("bond" , mTxns ) if mTxns else None
784820 match x :
785821 case {"balance" : bndBalance
786- , "rates" : bndRates
787- , "rateTypes" : bndInterestInfos
788- , "bondType" : bndType
789- , "originBalance" : originBalance
790- , "originRate" : originRate
791- , "startDate" : originDate
792- }:
822+ , "rates" : bndRates
823+ , "rateTypes" : bndInterestInfos
824+ , "bondType" : bndType
825+ , "originBalance" : originBalance
826+ , "originRate" : originRate
827+ , "startDate" : originDate
828+ }:
793829 l = len (bndInterestInfos )
794830 dueInts = getValWithKs (x , ["应付利息" , "dueInt" ], defaultReturn = [0 ]* l )
795831 dueIntOverInts = getValWithKs (x , ["拖欠利息" , "dueIntOverInt" ], defaultReturn = [0 ]* l )
@@ -830,15 +866,15 @@ def mkBnd(bn, x:dict):
830866
831867def mkLiqMethod (x ):
832868 match x :
833- case ["正常|违约" , a , b ] | ["Current|Defaulted" , a , b ]:
869+ case ["正常|违约" , a , b ] | ["Current|Defaulted" , a , b ] | { "currentFactor" : a , "defaultFactor" : b } :
834870 return mkTag (("BalanceFactor" , [vNum (a ), vNum (b )]))
835871 case ["正常|拖欠|违约" , a , b , c ] | ["Current|Delinquent|Defaulted" , a , b , c ]:
836872 return mkTag (("BalanceFactor2" , [vNum (a ), vNum (b ), vNum (c )]))
837873 case ["贴现|违约" , a , b ] | ["PV|Defaulted" , a , b ]:
838874 return mkTag (("PV" , [a , b ]))
839875 case ["贴现曲线" , ts ] | ["PVCurve" , ts ]:
840876 return mkTag (("PVCurve" , mkTs ("PricingCurve" , ts )))
841- case ["贴现率" , r ] | ["PvRate" , r ] | ("PvRate" , r ) if isinstance (r , float ):
877+ case ["贴现率" , r ] | ["PvRate" , r ] | ("PvRate" , r ) | { "PvRate" : r } if isinstance (r , float ):
842878 return mkTag (("PvRate" , r ))
843879 case ["贴现率" , r ] | ["PvRate" , r ] | ("PvRate" , r ):
844880 return mkTag (("PvByRef" , mkDs (r )))
@@ -988,25 +1024,34 @@ def mkRateCap(x):
9881024def mkRateType (x ):
9891025 match x :
9901026 case {"fix" :r , "dayCount" :dc } | {"固定" :r , "日历" :dc } | \
991- ["fix" , r , dc ] | ["固定" , r , dc ] | ("fix" , r , dc ) | ("固定" , r , dc ):
1027+ ["fix" , r , dc ] | ["固定" , r , dc ] | ("fix" , r , dc ) | ("固定" , r , dc ):
9921028 return mkTag (("Fix" , [dc , vNum (r )]))
9931029 case {"fix" :r } | {"固定" :r } | ["fix" , r ] | ["固定" , r ] | ("fix" , r ) | ("固定" , r ):
9941030 return mkTag (("Fix" , [DC .DC_ACT_365F .value , vNum (r )]))
1031+
9951032 case {"floater" :(idx , spd ), "rate" :r , "reset" :dp , ** p } | \
9961033 {"浮动" :(idx , spd ), "利率" :r , "重置" :dp , ** p }:
9971034 mf , mc , mrnd = tz .get (["floor" , "cap" , "rounding" ], p , None )
9981035 dc = p .get ("dayCount" , DC .DC_ACT_365F .value )
9991036 return mkTag (("Floater" ,[dc , vStr (idx ), vNum (spd ), vNum (r ), mkDatePattern (dp ), mf , mc , mrnd ]))
1037+
1038+ case {"index" :idx ,"spread" :spd ,"reset" :dp , "rate" :r , ** p } :
1039+ mf , mc , mrnd = tz .get (["floor" , "cap" , "rounding" ], p , None )
1040+ dc = p .get ("dayCount" , DC .DC_ACT_365F .value )
1041+ return mkTag (("Floater" ,[dc , vStr (idx ), vNum (spd ), vNum (r ), mkDatePattern (dp ), mf , mc , mrnd ]))
1042+
10001043 case ["浮动" , r , {"基准" :idx , "利差" :spd , "重置频率" :dp , ** p }] | \
10011044 ["floater" , r , {"index" :idx , "spread" :spd , "reset" :dp , ** p }] :
10021045 mf , mc , mrnd = tz .get (["floor" , "cap" , "rounding" ], p , None )
10031046 dc = p .get ("dayCount" , DC .DC_ACT_365F .value )
10041047 return mkTag (("Floater" , [dc , vStr (idx ), vNum (spd ), vNum (r ), mkDatePattern (dp ), mf , mc , mrnd ]))
1048+
10051049 case ("浮动" , r , {"基准" :idx , "利差" :spd , "重置频率" :dp , ** p }) | \
10061050 ("floater" , r , {"index" :idx , "spread" :spd , "reset" :dp , ** p }) :
10071051 mf , mc , mrnd = tz .get (["floor" , "cap" , "rounding" ], p , None )
10081052 dc = p .get ("dayCount" , DC .DC_ACT_365F .value )
10091053 return mkTag (("Floater" , [dc , vStr (idx ), vNum (spd ), vNum (r ), mkDatePattern (dp ), mf , mc , mrnd ]))
1054+
10101055 case None :
10111056 return None
10121057 case _ :
@@ -1303,6 +1348,8 @@ def mkStatus(x: tuple|str):
13031348 return mkTag (("DealDefaulted" , None ))
13041349 case "结束" | "Ended" :
13051350 return mkTag (("Ended" , None ))
1351+ case {"current" : "PreClosing" , "next" :st }:
1352+ return mkTag (("PreClosing" , mkStatus (st )))
13061353 case ("设计" , st ) | ("PreClosing" , st ) | ("preclosing" , st ):
13071354 return mkTag (("PreClosing" , mkStatus (st )))
13081355 case _:
@@ -2220,14 +2267,32 @@ def mkCollection(x):
22202267 return mkTag (("Collect" ,[None , mkPoolSource (s ), acc ]))
22212268 case [s , * pcts ] if isinstance (pcts , list ) and isinstance (s , str ):
22222269 return mkTag (("CollectByPct" ,[None , mkPoolSource (s ), pcts ]))
2270+
22232271 case [None , s , acc ] if isinstance (acc , str ):
22242272 return mkTag (("Collect" ,[None , mkPoolSource (s ), acc ]))
22252273 case [None , s , * pcts ] if isinstance (pcts , list ):
22262274 return mkTag (("CollectByPct" ,[None , mkPoolSource (s ), pcts ]))
2275+
22272276 case [mPids , s , acc ] if isinstance (acc , str ):
22282277 return mkTag (("Collect" ,[lmap (mkPid ,mPids ), mkPoolSource (s ), acc ]))
22292278 case [mPids , s , * pcts ] if isinstance (pcts , list ):
22302279 return mkTag (("CollectByPct" ,[lmap (mkPid ,mPids ), mkPoolSource (s ), pcts ]))
2280+
2281+ case {"source" :s , "account" :acc }:
2282+ if (_pids := x .get ("poolId" , False )):
2283+ pids = lmap (mkPid , _pids )
2284+ else :
2285+ pids = None
2286+ return mkTag (("Collect" ,[pids , mkPoolSource (s ), acc ]))
2287+
2288+ case {"source" :s , "accountByPct" :accs }:
2289+ if (_pids := x .get ("poolId" , False )):
2290+ pids = lmap (mkPid , _pids )
2291+ else :
2292+ pids = None
2293+ accsWithPct = [ [vNum (accPct ),vStr (accName )] for accName ,accPct in accs .items () ]
2294+ return mkTag (("CollectByPct" ,[pids , mkPoolSource (s ), accsWithPct ]))
2295+
22312296 case _:
22322297 raise RuntimeError (f"Failed to match collection rule { x } " )
22332298
0 commit comments