From 0d56a013c4a385711d40e69624af70d4c42d6f55 Mon Sep 17 00:00:00 2001 From: Xiaoyu Date: Sat, 22 Jun 2024 21:41:00 +0800 Subject: [PATCH] expose bond issuance assumption --- app/Main.hs | 7 +- src/Asset.hs | 2 +- src/AssetClass/AssetBase.hs | 5 + src/AssetClass/ProjectedCashFlow.hs | 240 +++++++++++ src/Assumptions.hs | 28 +- src/Cashflow.hs | 6 +- src/Deal.hs | 41 +- src/Deal/DealBase.hs | 93 +++- src/Deal/DealDate.hs | 1 + src/InterestRate.hs | 3 +- src/Liability.hs | 52 +-- src/Lib.hs | 5 +- src/Stmt.hs | 9 +- src/Triggers.hs | 2 +- src/Types.hs | 636 +++++++++++++--------------- src/Waterfall.hs | 4 +- swagger.json | 286 ++++++++++++- test/DealTest/DealTest.hs | 2 +- test/DealTest/MultiPoolDealTest.hs | 2 +- 19 files changed, 1014 insertions(+), 410 deletions(-) create mode 100644 src/AssetClass/ProjectedCashFlow.hs diff --git a/app/Main.hs b/app/Main.hs index 2ac2d799..181f77e5 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -134,8 +134,8 @@ instance ToSchema AB.AssetUnion instance ToSchema PoolId instance ToSchema DealStatus instance ToSchema DateType -instance ToSchema DateDesp -instance ToSchema ActionOnDate +instance ToSchema DB.DateDesp +instance ToSchema DB.ActionOnDate instance ToSchema DealStats instance ToSchema Cmp instance ToSchema PricingMethod @@ -181,7 +181,7 @@ instance ToSchema CE.LiqDrawType instance ToSchema CustomDataType instance ToSchema TRG.Trigger instance ToSchema TRG.TriggerEffect -instance ToSchema OverrideType +instance ToSchema DB.OverrideType instance ToSchema Types.BalanceSheetReport instance ToSchema Types.CashflowReport instance ToSchema Types.BookItem @@ -191,6 +191,7 @@ instance ToSchema AB.AssociateExp instance ToSchema AB.AssociateIncome instance ToSchema RV.RevolvingPool instance ToSchema (TsPoint [AB.AssetUnion]) +instance ToSchema (TsPoint AP.IssueBondEvent) instance ToSchema AP.NonPerfAssumption instance ToSchema AP.BondPricingInput instance ToSchema AP.RevolvingAssumption diff --git a/src/Asset.hs b/src/Asset.hs index e33b8688..3493f02a 100644 --- a/src/Asset.hs +++ b/src/Asset.hs @@ -77,7 +77,7 @@ class (Show a,IR.UseRate a) => Asset a where splitWith :: a -> [Rate] -> [a] -- | ! Change the origination date of an asset updateOriginDate :: a -> Date -> a - -- | get Last Interest Payment date + -- | Get Last Interest Payment date getLastInterestPaymentDate :: a -> Maybe Date -- | Calculate Accrued Interest calcAccruedInterest :: a -> Date -> Balance diff --git a/src/AssetClass/AssetBase.hs b/src/AssetClass/AssetBase.hs index e8b93289..4397663a 100644 --- a/src/AssetClass/AssetBase.hs +++ b/src/AssetClass/AssetBase.hs @@ -9,6 +9,7 @@ module AssetClass.AssetBase ,LeaseStepUp(..),AccrualPeriod(..),PrepayPenaltyType(..) ,AmortPlan(..),Loan(..),Mortgage(..),AssetUnion(..),MixedAsset(..),FixedAsset(..) ,AmortRule(..),Capacity(..),AssociateExp(..),AssociateIncome(..),ReceivableFeeType(..),Receivable(..) + ,ProjectedCashflow(..) ,calcAssetPrinInt, calcPmt ) where @@ -171,6 +172,10 @@ data Mortgage = Mortgage OriginalInfo Balance IRate RemainTerms (Maybe BorrowerN | ScheduleMortgageFlow Date [CF.TsRow] DatePattern deriving (Show,Generic,Eq,Ord) +data ProjectedCashflow = ProjectedFlowFixed Date [CF.TsRow] DatePattern + | ProjectedFlowMixFloater Date [CF.TsRow] DatePattern (Rate, IRate) [(Rate, Spread, Index)] + deriving (Show,Generic,Eq,Ord) + data Receivable = Invoice OriginalInfo Status | DUMMY4 deriving (Show,Generic,Eq,Ord) diff --git a/src/AssetClass/ProjectedCashFlow.hs b/src/AssetClass/ProjectedCashFlow.hs new file mode 100644 index 00000000..8954672a --- /dev/null +++ b/src/AssetClass/ProjectedCashFlow.hs @@ -0,0 +1,240 @@ +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE DeriveGeneric #-} + +module AssetClass.ProjectedCashFlow + () + where + +import qualified Data.Time as T +import qualified Cashflow as CF +import qualified Assumptions as A +import Asset as Ast +import Types +import Lib +import Util +import DateUtil +import InterestRate as IR + +import qualified Data.Map as Map +import Data.List +import Data.Ratio +import Data.Maybe +import GHC.Generics +import Data.Aeson hiding (json) +import Language.Haskell.TH +import Data.Aeson.TH +import Data.Aeson.Types + +import qualified Cashflow as CF + +import AssetClass.AssetBase +import AssetClass.AssetCashflow + +import qualified Assumptions as A + +import Cashflow (extendTxns,TsRow(..),mflowBalance) + +import Debug.Trace + +projectScheduleFlow :: [CF.TsRow] -> Rate -> Balance -> [CF.TsRow] -> [DefaultRate] -> [PrepaymentRate] -> [Amount] -> [Amount] -> (Int, Rate) -> [CF.TsRow] +projectScheduleFlow trs _ last_bal [] _ _ [] [] (_,_) = trs +projectScheduleFlow trs bal_factor last_bal (flow:flows) (defRate:defRates) (ppyRate:ppyRates) recV lossV (recoveryLag,recoveryRate) + = projectScheduleFlow (trs++[tr]) surviveRate endBal flows defRates ppyRates (tail recVector) (tail lossVector) (recoveryLag,recoveryRate) -- `debug` ("===>C") + where + startBal = last_bal + defAmt = mulBR startBal defRate + ppyAmt = mulBR (startBal - defAmt) ppyRate + afterBal = startBal - defAmt - ppyAmt + + surviveRate = (1 - defRate) * (1 - ppyRate) * bal_factor + schedulePrin = mulBR (CF.mflowPrincipal flow) surviveRate --TODO round trip -- `debug` ("Schedule Principal"++(printf "%.2f" (CF.mflowPrincipal flow))++" Rate"++show(_schedule_rate)) + scheduleInt = mulBR (CF.mflowInterest flow) surviveRate + + newRec = mulBR defAmt recoveryRate + newLoss = mulBR defAmt (1 - recoveryRate) + + recVector = replace recV recoveryLag newRec + lossVector = replace lossV recoveryLag newLoss + + endBal = max 0 $ afterBal - schedulePrin + + tr = CF.MortgageFlow (CF.getDate flow) endBal schedulePrin scheduleInt ppyAmt defAmt (head recVector) (head lossVector) 0.0 Nothing Nothing Nothing--TODO missing ppy-penalty here + +projectScheduleFlow trs b_factor lastBal [] _ _ (r:rs) (l:ls) (recovery_lag,recovery_rate) + = projectScheduleFlow (trs++[tr]) b_factor lastBal [] [] [] rs ls (recovery_lag - 1,recovery_rate) + where + remain_length = length rs + lastDate = CF.getDate (last trs) + flowDate = nextDate lastDate Lib.Monthly + tr = CF.MortgageFlow flowDate lastBal 0 0 0 0 r l 0.0 Nothing Nothing Nothing + + + +projCfwithAssumption :: (CF.CashFlowFrame, DatePattern) -> A.AssetPerfAssumption -> Date -> Maybe [RateAssumption] -> CF.CashFlowFrame +projCfwithAssumption (cf@(CF.CashFlowFrame (begBal, begDate, accInt) flows), dp) + pAssump@(A.MortgageAssump mDefault mPrepay mRecovery mEs) + asOfDay + mRates + = CF.CashFlowFrame (cb,asOfDay,Nothing) futureTxns + where + curveDatesLength = recoveryLag + length flows + endDate = CF.getDate (last flows) + (ppyRates,defRates,recoveryRate,recoveryLag) = buildAssumptionPpyDefRecRate (begDate:cfDates) pAssump + extraDates = genSerialDates dp Exc endDate recoveryLag + cfDates = (CF.getDate <$> flows) ++ extraDates + + txns = projectScheduleFlow [] 1.0 begBal flows defRates ppyRates + (replicate curveDatesLength 0.0) + (replicate curveDatesLength 0.0) + (recoveryLag,recoveryRate) + + (futureTxns,historyM) = CF.cutoffTrs asOfDay txns + + cb = (CF.mflowBegBalance . head) futureTxns + +projIndexCashflows :: ([Date],[Balance],[Principal],Index,Spread) -> Maybe [RateAssumption] -> CF.CashFlowFrame +projIndexCashflows (ds,bals,principals,index,spd) (Just ras) = + let + mIndexToApply = A.getRateAssumption ras index + indexRates = A.lookupRate0 ras index <$> ds + + rates = (spd +) <$> indexRates + interestFlow = zipWith (flip mulBIR) rates bals + flowSize = length bals + in + CF.CashFlowFrame (head bals, head ds, Nothing) $ + zipWith12 MortgageFlow + ds + bals + principals + interestFlow + (replicate flowSize 0 ) + (replicate flowSize 0 ) + (replicate flowSize 0 ) + (replicate flowSize 0 ) + rates + (replicate flowSize Nothing) + (replicate flowSize Nothing) + (replicate flowSize Nothing) + + + + +-- projMortgageFlow :: (Date,[Balance]) -> A.AssetPerfAssumption -> Maybe [RateAssumption] -> ([Balance],[Balance],[Balance]) +-- projMortgageFlow (begDate,bals) pAssump mRates = +-- let +-- curveDatesLength = recoveryLag + length bals +-- extraPeriods = recoveryLag +-- endDate = last ds +-- extraDates = genSerialDates dp Exc endDate recoveryLag +-- cfDates = ds ++ extraDates +-- begBal = head bals +-- (ppyRates,defRates,recoveryRate,recoveryLag) = buildAssumptionPpyDefRecRate (begDate:cfDates) pAssump +-- +-- txns = projectScheduleFlow [] 1.0 begBal flows defRates ppyRates +-- (replicate curveDatesLength 0.0) +-- (replicate curveDatesLength 0.0) +-- (recoveryLag,recoveryRate) +-- +-- (futureTxns,historyM) = CF.cutoffTrs asOfDay txns +-- +-- cb = (CF.mflowBegBalance . head) futureTxns +-- in +-- (cb, futureTxns, historyM) + + +seperateCashflows :: ProjectedCashflow -> Maybe A.AssetPerfAssumption -> Maybe [RateAssumption] -> (CF.CashFlowFrame, [CF.CashFlowFrame]) +seperateCashflows (ProjectedFlowMixFloater begDate flows _ (fixPct,fixRate) floaterList) + (Just pAssump) + mRates + = let + begBal = CF.mflowBegBalance $ head flows + totalBals = begBal: (CF.mflowBalance <$> flows) + ds = CF.mflowDate <$> flows + + (ppyRates,defRates,recoveryRate,recoveryLag) = buildAssumptionPpyDefRecRate (begDate:ds) pAssump + + + flowSize = length ds + fixedBals = (flip mulBR) fixPct <$> totalBals + fixedPrincipalFlow = replicate flowSize 0 -- flip mulBR fixPct <$> CF.mflowPrincipal <$> flows + fixedInterestFlow = replicate flowSize 0 -- flip mulBIR fixRate <$> fixedBals + fixedCashFlow = CF.CashFlowFrame (head fixedBals, begDate, Nothing) [] + -- zipWith12 CF.MortgageFlow $ + -- ds $ + -- init fixedBals $ + -- fixedPrincipalFlow $ + -- fixedInterestFlow $ + -- replicate flowSize 0 $ + -- replicate flowSize 0 $ + -- replicate flowSize 0 $ + -- replicate flowSize 0 $ + -- replicate flowSize fixRate $ + -- replicate flowSize Nothing $ + -- replicate flowSize Nothing $ + -- replicate flowSize Nothing + + floatBals = zipWith (-) totalBals fixedBals + floatPrincipalFlow = zipWith (-) (CF.mflowPrincipal <$> flows) fixedPrincipalFlow + + -- rs = (head <$> floaterList) + -- floaterSize = length rs + -- indexes = last <$> floaterList + -- spds = (\(a,b,c) -> b) <$> floaterList + -- floatBalsBreakDown = zipWith mulBR floatBals rs + -- floatPrincipalFlowBreakDown = zipWith mulBR floatPrincipalFlow rs + -- floatedCashFlow = \x -> projIndexCashflows x mRates <$> zip5 + -- (repeat ds) + -- floatBalsBreakDown + -- floatPrincipalFlowBreakDown + -- indexes + -- spds + in + -- (fixedCashFlow, floatedCashFlow) + (fixedCashFlow, [CF.CashFlowFrame (0, begDate, Nothing) []]) + + + +instance Ast.Asset ProjectedCashflow where + + getCurrentBal (ProjectedFlowFixed _ cf _ ) = CF.mflowBalance (head cf) + getCurrentBal (ProjectedFlowMixFloater _ cf _ _ _ ) = CF.mflowBegBalance (head cf) + + getOriginBal (ProjectedFlowFixed _ cf _ ) = CF.mflowBegBalance (head cf) + getOriginBal (ProjectedFlowMixFloater _ cf _ _ _ ) = CF.mflowBegBalance (head cf) + + isDefaulted f = error "" + getOriginDate f = error "" + getOriginInfo f = error "" + + calcCashflow f@(ProjectedFlowFixed begDate flows _) d _ + = CF.CashFlowFrame ( (CF.mflowBalance . head) flows, begDate, Nothing ) flows + + calcCashflow f@(ProjectedFlowMixFloater {}) d mRate + = let + (fixedCashFlow, floatedCashFlow) = seperateCashflows f Nothing mRate + in + -- Map.foldl CF.mergePoolCf fixedCashFlow floatedCashFlow + fixedCashFlow + + projCashflow f asOfDay _ mRates = (calcCashflow f asOfDay mRates, Map.empty) + + + projCashflow f asOfDay (_, _, _) mRates + = let + (fixedCashFlow, floatedCashFlow) = seperateCashflows f Nothing mRates + in + -- Map.foldl CF.mergePoolCf fixedCashFlow floatedCashFlow + (fixedCashFlow, Map.empty) + + getBorrowerNum f = 0 + + splitWith f rs = [f] + +instance IR.UseRate ProjectedCashflow where + isAdjustbleRate _ = False + + getIndex _ = Nothing + getIndexes _ = Nothing + getResetDates _ = [] diff --git a/src/Assumptions.hs b/src/Assumptions.hs index ebc809f6..6bc680c6 100644 --- a/src/Assumptions.hs +++ b/src/Assumptions.hs @@ -14,11 +14,12 @@ module Assumptions (BondPricingInput(..) ,NonPerfAssumption(..),AssetPerf ,AssetDelinquencyAssumption(..) ,AssetDelinqPerfAssumption(..),AssetDefaultedPerfAssumption(..) - ,getCDR,calcResetDates,AssumpReceipes) + ,getCDR,calcResetDates,AssumpReceipes,IssueBondEvent) where import Call as C import Lib (Ts(..),TsPoint(..),toDate,mkRateTs) +import Liability (Bond) import Util import DateUtil import qualified Data.Map as Map @@ -64,18 +65,21 @@ data ApplyAssumptionType = PoolLevel AssetPerf -- ^ assumption for a named deal deriving (Show, Generic) +type IssueBondEvent = (String,AccName,Bond) -- bond group name, account name, bond + data NonPerfAssumption = NonPerfAssumption { - stopRunBy :: Maybe Date -- ^ optional stop day,which will stop cashflow projection - ,projectedExpense :: Maybe [(FeeName,Ts)] -- ^ optional expense projection - ,callWhen :: Maybe [C.CallOption] -- ^ optional call options set, once any of these were satisfied, then clean up waterfall is triggered - ,revolving :: Maybe RevolvingAssumption -- ^ optional revolving assumption with revoving assets - ,interest :: Maybe [RateAssumption] -- ^ optional interest rates assumptions - ,inspectOn :: Maybe [(DatePattern,DealStats)] -- ^ optional tuple list to inspect variables during waterfall run - ,buildFinancialReport :: Maybe DatePattern -- ^ optional dates to build financial reports - ,pricing :: Maybe BondPricingInput -- ^ optional bond pricing input( discount curve etc) - ,fireTrigger :: Maybe [(Date,DealCycle,String)] -- ^ optional fire a trigger + stopRunBy :: Maybe Date -- ^ optional stop day,which will stop cashflow projection + ,projectedExpense :: Maybe [(FeeName,Ts)] -- ^ optional expense projection + ,callWhen :: Maybe [C.CallOption] -- ^ optional call options set, once any of these were satisfied, then clean up waterfall is triggered + ,revolving :: Maybe RevolvingAssumption -- ^ optional revolving assumption with revoving assets + ,interest :: Maybe [RateAssumption] -- ^ optional interest rates assumptions + ,inspectOn :: Maybe [(DatePattern,DealStats)] -- ^ optional tuple list to inspect variables during waterfall run + ,buildFinancialReport :: Maybe DatePattern -- ^ optional dates to build financial reports + ,pricing :: Maybe BondPricingInput -- ^ optional bond pricing input( discount curve etc) + ,fireTrigger :: Maybe [(Date,DealCycle,String)] -- ^ optional fire a trigger ,makeWholeWhen :: Maybe (Date,Spread,Table Float Spread) -} deriving (Show,Generic) + ,issueBondSchedule :: Maybe [TsPoint IssueBondEvent] +} deriving (Show, Generic) data AssumptionInput = Single ApplyAssumptionType NonPerfAssumption -- ^ one assumption request | Multiple (Map.Map String ApplyAssumptionType) NonPerfAssumption -- ^ multiple assumption request in a single request @@ -225,6 +229,8 @@ calcResetDates (r:rs) bs $(deriveJSON defaultOptions ''BondPricingInput) +-- $(deriveJSON defaultOptions ''IssueBondEvent) + $(concat <$> traverse (deriveJSON defaultOptions) [''ApplyAssumptionType, ''AssetPerfAssumption , ''AssetDefaultedPerfAssumption, ''AssetDelinqPerfAssumption, ''NonPerfAssumption, ''AssetDefaultAssumption , ''AssetPrepayAssumption, ''RecoveryAssumption, ''ExtraStress diff --git a/src/Cashflow.hs b/src/Cashflow.hs index 75e0fb61..edc35167 100644 --- a/src/Cashflow.hs +++ b/src/Cashflow.hs @@ -28,6 +28,7 @@ import Lib (weightedBy,toDate,getIntervalFactors,daysBetween,paySeqLiabilitiesAm import Util (mulBR,mulBInt,mulIR,lastOf) import DateUtil ( splitByDate ) import Types +--import Deal.DealType import qualified Data.Map as Map import qualified Data.Time as T import qualified Data.List as L @@ -146,7 +147,7 @@ scaleTsRow r (MortgageDelinqFlow d b p i prep delinq def rec los rat mbn pp st) rat mbn pp - ((splitStats r) <$> st) + (splitStats r <$> st) scaleTsRow r (LoanFlow d b p i prep def rec los rat st) = LoanFlow d (fromRational r * b) (fromRational r * p) (fromRational r * i) (fromRational r * prep) (fromRational r * def) (fromRational r * rec) (fromRational r * los) rat ((splitStats r) <$> st) scaleTsRow r (LeaseFlow d b rental) = LeaseFlow d (fromRational r * b) (fromRational r * rental) @@ -161,6 +162,7 @@ type BeginStatus = (BeginBalance, BeginDate, AccuredInterest) data CashFlowFrame = CashFlowFrame BeginStatus [TsRow] | MultiCashFlowFrame (Map.Map String [CashFlowFrame]) +-- | CashFlowFrameIndex BeginStatus [TsRow] IR.Index deriving (Eq,Generic,Ord) instance Show CashFlowFrame where @@ -844,6 +846,8 @@ setPrepaymentPenalty _ _ = error "prepay pental only applies to MortgageFlow" setPrepaymentPenaltyFlow :: [Balance] -> [TsRow] -> [TsRow] setPrepaymentPenaltyFlow bals trs = [ setPrepaymentPenalty bal tr | (bal,tr) <- zip bals trs] + +-- ^ split single cashflow record by a rate splitTs :: Rate -> TsRow -> TsRow splitTs r (MortgageDelinqFlow d bal p i ppy delinq def recovery loss rate mB mPPN mStat) = MortgageDelinqFlow d (mulBR bal r) (mulBR p r) (mulBR i r) (mulBR ppy r) diff --git a/src/Deal.hs b/src/Deal.hs index 03a3648e..36429ce6 100644 --- a/src/Deal.hs +++ b/src/Deal.hs @@ -11,6 +11,7 @@ module Deal (run,runPool,getInits,runDeal,ExpectReturn(..) ,calcTargetAmount,updateLiqProvider ,projAssetUnion,priceAssetUnion ,removePoolCf,setFutureCF,runPoolType,PoolType + ,ActionOnDate(..),DateDesp(..),OverrideType(..) ) where import qualified Accounts as A @@ -78,6 +79,8 @@ import qualified Hedge as HE debug = flip trace + + setBondNewRate :: Ast.Asset a => TestDeal a -> Date -> [RateAssumption] -> L.Bond -> L.Bond setBondNewRate t d ras b@(L.Bond _ _ _ ii (Just (L.PassDateSpread _ spd)) bal currentRate _ dueInt _ (Just dueIntDate) _ _ _) = b { L.bndRate = currentRate + spd, L.bndDueInt = dueInt + accrueInt, L.bndDueIntDate = Just d} @@ -526,7 +529,30 @@ run t@TestDeal{accounts=accMap,fees=feeMap,triggers=mTrgMap,bonds=bndMap,status= bondPricingResult in run t {bonds = depositBondFlow, status = Ended } poolFlowMap (Just []) rates calls rAssump $ log++[EndRun (Just d) "MakeWhole call"] - + IssueBond d bGroupName accName bnd -> + let + newBndName = L.bndName bnd + + newBonds = case Map.lookup bGroupName bndMap of + Nothing -> bndMap + Just (L.Bond {}) -> bndMap + Just (L.BondGroup bndGrpMap) -> let + bndOInfo = (L.bndOriginInfo bnd) {L.originDate = d} + bndToInsert = bnd {L.bndOriginInfo = bndOInfo, + L.bndDueIntDate = Just d, + L.bndLastIntPay = Just d, + L.bndLastPrinPay = Just d} + in + Map.insert bGroupName + (L.BondGroup (Map.insert newBndName bndToInsert bndGrpMap)) + bndMap + + issuanceProceeds = L.bndBalance bnd + newAcc = Map.adjust (A.deposit issuanceProceeds d (Tag ("Issuance Proceeds:"++newBndName))) + accName + accMap + in + run t{bonds = newBonds, accounts = newAcc} poolFlowMap (Just ads) rates calls rAssump log _ -> error $ "Failed to match action on Date"++ show ad where cleanUpActions = Map.findWithDefault [] W.CleanUp (waterfall t) -- `debug` ("Running AD"++show(ad)) @@ -784,7 +810,7 @@ runPoolType (ResecDeal dm) mAssumps mNonPerfAssump Map.mapWithKey (\(DealBondFlow dn bn sd pct) (uDeal, mAssump) -> let (poolAssump,dealAssump) = case mAssump of - Nothing -> (Nothing, AP.NonPerfAssumption Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing) + Nothing -> (Nothing, AP.NonPerfAssumption Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing) Just (_poolAssump, _dealAssump) -> (Just _poolAssump, _dealAssump) (dealRunned, _, _, _) = runDeal uDeal DealPoolFlowPricing poolAssump dealAssump bondFlow = cutBy Inc Future sd $ concat $ Map.elems $ Map.map Stmt.getTxns $ getBondStmtByName dealRunned (Just [bn]) -- `debug` ("Bondflow from underlying runned"++ show (getBondStmtByName dealRunned (Just [bn]))) @@ -877,11 +903,18 @@ getInits t@TestDeal{fees=feeMap,pool=thePool,status=status,bonds=bndMap} mAssump Just AP.NonPerfAssumption{AP.makeWholeWhen = Just (_d,_s,_t)} -> [MakeWhole _d _s _t] _ -> [] + -- issue bonds in the future + bondIssuePlan = case mNonPerfAssump of + Just AP.NonPerfAssumption{AP.issueBondSchedule = Just bndPlan} + -> [ IssueBond _d bGroupName accName b | TsPoint _d (bGroupName,accName,b) <- bndPlan] + _ -> [] + allActionDates = let __actionDates = let a = concat [bActionDates,pActionDates,iAccIntDates,makeWholeDate ,feeAccrueDates,liqResetDates,mannualTrigger,concat rateCapSettleDates - ,concat irSwapRateDates,inspectDates, bndRateResets,financialRptDates] + ,concat irSwapRateDates,inspectDates, bndRateResets,financialRptDates + ,bondIssuePlan] in case dates t of PreClosingDates {} -> sortBy sortActionOnDate $ DealClosed closingDate:a -- `debug` ("add a closing date"++show closingDate) @@ -1003,4 +1036,4 @@ depositPoolFlow rules d pFlowMap amap -- = foldr (\pflowM acc -> depositPoolInflow rules d pflowM acc) amap $ pFlowMap `debug` ("Deposit p fd"++ show (Map.elems pFlowMap)) = foldr (\rule acc -> depositInflow d rule pFlowMap acc) amap rules -$(deriveJSON defaultOptions ''ExpectReturn) +$(deriveJSON defaultOptions ''ExpectReturn) \ No newline at end of file diff --git a/src/Deal/DealBase.hs b/src/Deal/DealBase.hs index eb4d8511..82160129 100644 --- a/src/Deal/DealBase.hs +++ b/src/Deal/DealBase.hs @@ -9,7 +9,9 @@ module Deal.DealBase (TestDeal(..),SPV(..),dealBonds,dealFees,dealAccounts,dealPool,PoolType(..),getIssuanceStats ,getAllAsset,getAllAssetList,getAllCollectedFrame,getLatestCollectFrame,getAllCollectedTxns ,getIssuanceStatsConsol,getAllCollectedTxnsList,dealScheduledCashflow - ,getPoolIds,getBondByName, UnderlyingDeal(..),dealCashflow, uDealFutureTxn,viewDealAllBonds) + ,getPoolIds,getBondByName, UnderlyingDeal(..),dealCashflow, uDealFutureTxn,viewDealAllBonds,DateDesp(..),ActionOnDate(..),OverrideType(..) + ,sortActionOnDate + ) where import qualified Accounts as A import qualified Ledger as LD @@ -60,6 +62,93 @@ debug = flip trace -- import Data.Text (unpack) -- import Control.Monad.IO.Class (liftIO) + + + +data ActionOnDate = EarnAccInt Date AccName -- ^ sweep bank account interest + | ChangeDealStatusTo Date DealStatus -- ^ change deal status + | AccrueFee Date FeeName -- ^ accure fee + | ResetLiqProvider Date String -- ^ reset credit for liquidity provider + | ResetLiqProviderRate Date String -- ^ accure interest/premium amount for liquidity provider + | PoolCollection Date String -- ^ collect pool cashflow and deposit to accounts + | RunWaterfall Date String -- ^ execute waterfall + | DealClosed Date -- ^ actions to perform at the deal closing day, and enter a new deal status + | FireTrigger Date DealCycle String -- ^ fire a trigger + | InspectDS Date DealStats -- ^ inspect formula + | ResetIRSwapRate Date String -- ^ reset interest rate swap dates + | AccrueCapRate Date String -- ^ reset interest rate cap dates + | ResetBondRate Date String -- ^ reset bond interest rate per bond's interest rate info + | ResetSrtRate Date String + | AccrueSrt Date String + | MakeWhole Date Spread (Table Float Spread) + | IssueBond Date String AccName L.Bond + | BuildReport StartDate EndDate -- ^ build cashflow report between dates and balance report at end date + | StopRunFlag Date -- ^ stop the run with a message + | HitStatedMaturity Date -- ^ hit the stated maturity date + deriving (Show,Generic,Read) + +instance Ord ActionOnDate where + compare a1 a2 = compare (getDate a1) (getDate a2) + +instance Eq ActionOnDate where + a1 == a2 = getDate a1 == getDate a2 + + +instance TimeSeries ActionOnDate where + getDate (RunWaterfall d _) = d + getDate (ResetLiqProvider d _) = d + getDate (PoolCollection d _) = d + getDate (EarnAccInt d _) = d + getDate (AccrueFee d _) = d + getDate (DealClosed d) = d + getDate (FireTrigger d _ _) = d + getDate (ChangeDealStatusTo d _ ) = d + getDate (InspectDS d _ ) = d + getDate (ResetIRSwapRate d _ ) = d + getDate (AccrueCapRate d _ ) = d + getDate (ResetBondRate d _ ) = d + getDate (MakeWhole d _ _) = d + getDate (BuildReport sd ed) = ed + getDate (IssueBond d _ _ _) = d + + +sortActionOnDate :: ActionOnDate -> ActionOnDate -> Ordering +sortActionOnDate a1 a2 + | d1 == d2 = case (a1,a2) of + (BuildReport sd1 ed1 ,_) -> GT -- build report should be executed last + (_ , BuildReport sd1 ed1) -> LT -- build report should be executed last + (ResetIRSwapRate _ _ ,_) -> LT -- reset interest swap should be first + (_ , ResetIRSwapRate _ _) -> GT -- reset interest swap should be first + (ResetBondRate {} ,_) -> LT -- reset bond rate should be first + (_ , ResetBondRate {}) -> GT -- reset bond rate should be first + (EarnAccInt {} ,_) -> LT -- earn should be first + (_ , EarnAccInt {}) -> GT -- earn should be first + (ResetLiqProvider {} ,_) -> LT -- reset liq be first + (_ , ResetLiqProvider {}) -> GT -- reset liq be first + (PoolCollection {}, RunWaterfall {}) -> LT -- pool collection should be executed before waterfall + (RunWaterfall {}, PoolCollection {}) -> GT -- pool collection should be executed before waterfall + (_,_) -> EQ + | otherwise = compare d1 d2 + where + d1 = getDate a1 + d2 = getDate a2 + + +data OverrideType = CustomActionOnDates [ActionOnDate] + deriving (Show,Generic,Ord,Eq) + + +data DateDesp = FixInterval (Map.Map DateType Date) Period Period + -- cutoff pool closing bond payment dates + | CustomDates Date [ActionOnDate] Date [ActionOnDate] + | PatternInterval (Map.Map DateType (Date, DatePattern, Date)) + -- cutoff closing mRevolving end-date dp1-pc dp2-bond-pay + | PreClosingDates Date Date (Maybe Date) Date DateVector DateVector + -- (last collect,last pay), mRevolving end-date dp1-pool-pay dp2-bond-pay + | CurrentDates (Date,Date) (Maybe Date) Date DateVector DateVector + deriving (Show,Eq, Generic,Ord) + + class SPV a where getBondsByName :: a -> Maybe [String] -> Map.Map String L.Bond getBondBegBal :: a -> String -> Balance @@ -385,7 +474,7 @@ getAllCollectedTxnsList t mPns data UnderBond b = UnderBond BondName Rate (TestDeal b) -$(concat <$> traverse (deriveJSON defaultOptions) [''TestDeal, ''UnderlyingDeal, ''PoolType]) +$(concat <$> traverse (deriveJSON defaultOptions) [''TestDeal, ''UnderlyingDeal, ''PoolType, ''DateDesp, ''ActionOnDate, ''OverrideType]) -- $(deriveJSON defaultOptions ''UnderlyingDeal) -- $(deriveJSON defaultOptions ''PoolType) -- $(deriveJSON defaultOptions ''TestDeal) diff --git a/src/Deal/DealDate.hs b/src/Deal/DealDate.hs index 20608c16..f8fa70d2 100644 --- a/src/Deal/DealDate.hs +++ b/src/Deal/DealDate.hs @@ -7,6 +7,7 @@ module Deal.DealDate (DealDates,getClosingDate,getFirstPayDate) where import qualified Data.Map as Map +import Deal.DealBase import Types import Lib diff --git a/src/InterestRate.hs b/src/InterestRate.hs index 8d14dc98..a67dec79 100644 --- a/src/InterestRate.hs +++ b/src/InterestRate.hs @@ -31,7 +31,8 @@ import Types IRate, Dates, Date, - Balance, DealStats ) + Balance ) +-- import Deal.DealType import Util import Lib diff --git a/src/Liability.hs b/src/Liability.hs index 86f73f78..f4335add 100644 --- a/src/Liability.hs +++ b/src/Liability.hs @@ -27,6 +27,7 @@ import Util import DateUtil import Types hiding (BondGroup) import Analytics + import Data.Ratio import Data.Maybe @@ -49,27 +50,6 @@ import Stmt (getTxnAmt) debug = flip trace -type RateReset = DatePattern - -data InterestOverInterestType = OverCurrRateBy Rational -- ^ inflat ioi rate by pct over current rate - | OverFixSpread Spread -- ^ inflat ioi rate by fix spread - deriving (Show, Eq, Generic, Ord) - - ---------------------------- start Rate, index, spread, reset dates, daycount, floor, cap -data InterestInfo = Floater IRate Index Spread RateReset DayCount (Maybe Floor) (Maybe Cap) - | Fix IRate DayCount -- ^ fixed rate - | InterestByYield IRate - | RefRate IRate DealStats Float RateReset -- ^ interest rate depends to a formula - | CapRate InterestInfo IRate -- ^ cap rate - | FloorRate InterestInfo IRate -- ^ floor rate - | WithIoI InterestInfo InterestOverInterestType -- ^ Interest Over Interest(normal on left,IoI on right) - deriving (Show, Eq, Generic, Ord) - -data StepUp = PassDateSpread Date Spread -- ^ add a spread on a date and effective afterwards - | PassDateLadderSpread Date Spread RateReset -- ^ add a spread on the date pattern - deriving (Show, Eq, Generic, Ord) - -- | test if a bond may changes its interest rate isAdjustble :: InterestInfo -> Bool isAdjustble Floater {} = True @@ -104,14 +84,34 @@ getDayCountFromInfo (FloorRate info _) = getDayCountFromInfo info getDayCountFromInfo (WithIoI info _) = getDayCountFromInfo info getDayCountFromInfo _ = Nothing +type RateReset = DatePattern +type PlannedAmorSchedule = Ts + +data InterestOverInterestType = OverCurrRateBy Rational -- ^ inflat ioi rate by pct over current rate + | OverFixSpread Spread -- ^ inflat ioi rate by fix spread + deriving (Show, Eq, Generic, Ord, Read) + + +--------------------------- start Rate, index, spread, reset dates, daycount, floor, cap +data InterestInfo = Floater IRate Index Spread RateReset DayCount (Maybe Floor) (Maybe Cap) + | Fix IRate DayCount -- ^ fixed rate + | InterestByYield IRate + | RefRate IRate DealStats Float RateReset -- ^ interest rate depends to a formula + | CapRate InterestInfo IRate -- ^ cap rate + | FloorRate InterestInfo IRate -- ^ floor rate + | WithIoI InterestInfo InterestOverInterestType -- ^ Interest Over Interest(normal on left,IoI on right) + deriving (Show, Eq, Generic, Ord, Read) + +data StepUp = PassDateSpread Date Spread -- ^ add a spread on a date and effective afterwards + | PassDateLadderSpread Date Spread RateReset -- ^ add a spread on the date pattern + deriving (Show, Eq, Generic, Ord, Read) + data OriginalInfo = OriginalInfo { originBalance::Balance -- ^ issuance balance ,originDate::Date -- ^ issuance date ,originRate::Rate -- ^ issuance rate of the bond ,maturityDate :: Maybe Date -- ^ optional maturity date -} deriving (Show, Eq, Generic, Ord) - -type PlannedAmorSchedule = Ts +} deriving (Show, Eq, Generic, Ord, Read) data BondType = Sequential -- ^ Pass through type tranche | PAC PlannedAmorSchedule -- ^ bond with schedule amortization @@ -119,7 +119,7 @@ data BondType = Sequential -- ^ Pass through typ | Lockout Date -- ^ No principal due till date | Z -- ^ Z tranche | Equity -- ^ Equity type tranche - deriving (Show, Eq, Generic, Ord) + deriving (Show, Eq, Generic, Ord, Read) data Bond = Bond { bndName :: String @@ -139,7 +139,7 @@ data Bond = Bond { ,bndStmt :: Maybe S.Statement -- ^ transaction history } | BondGroup (Map.Map String Bond) -- ^ bond group - deriving (Show, Eq, Generic, Ord) + deriving (Show, Eq, Generic, Ord, Read) consolStmt :: Bond -> Bond consolStmt (BondGroup bMap) = BondGroup $ Map.map consolStmt bMap diff --git a/src/Lib.hs b/src/Lib.hs index aa05ec7f..46618849 100644 --- a/src/Lib.hs +++ b/src/Lib.hs @@ -14,8 +14,8 @@ module Lib ,getValOnByDate,sumValTs,subTsBetweenDates,splitTsByDate ,paySeqLiabilitiesAmt,getIntervalDays,getIntervalFactors ,zipWith8,zipWith9,zipWith10,zipWith11,zipWith12 - ,weightedBy, mkTs, DealStatus(..) - ,mkRateTs,Pre(..) + ,weightedBy, mkTs + ,mkRateTs ) where import qualified Data.Time as T @@ -33,6 +33,7 @@ import Types import Control.Lens import Data.List.Lens import Control.Lens.TH +-- import Deal.DealType import Debug.Trace debug = flip trace diff --git a/src/Stmt.hs b/src/Stmt.hs index c041a219..b71cac18 100644 --- a/src/Stmt.hs +++ b/src/Stmt.hs @@ -42,6 +42,13 @@ import Debug.Trace debug = flip trace + + + + + + + aggByTxnComment :: [Txn] -> M.Map TxnComment [Txn] -> M.Map TxnComment Balance aggByTxnComment [] m = M.map sumTxn m aggByTxnComment (txn:txns) m @@ -142,7 +149,7 @@ weightAvgBalance sd ed txns data Statement = Statement [Txn] - deriving (Show, Generic, Eq, Ord) + deriving (Show, Generic, Eq, Ord, Read) appendStmt :: Maybe Statement -> Txn -> Maybe Statement appendStmt (Just stmt@(Statement txns)) txn = Just $ Statement (txns++[txn]) diff --git a/src/Triggers.hs b/src/Triggers.hs index 1634b4e4..ce8e37c9 100644 --- a/src/Triggers.hs +++ b/src/Triggers.hs @@ -10,7 +10,7 @@ module Triggers( import qualified Data.Text as T import qualified Stmt as S import Text.Read (readMaybe) -import Lib ( Pre, DealStatus ) +import Lib import Types import Accounts (ReserveAmount) import Waterfall (Action) diff --git a/src/Types.hs b/src/Types.hs index 1217802e..d2b7924a 100644 --- a/src/Types.hs +++ b/src/Types.hs @@ -6,25 +6,28 @@ module Types - (DayCount(..),DateType(..),OverrideType(..),CutoffFields(..) - ,ActionOnDate(..),DealStatus(..),DatePattern(..) + (DayCount(..),DateType(..) + ,DatePattern(..) ,BondName,BondNames,FeeName,FeeNames,AccName,AccNames,AccountName - ,Pre(..),Ts(..),TsPoint(..),PoolSource(..) - ,DateDesp(..),Period(..), Threshold(..) - ,RangeType(..),CutoffType(..),CustomDataType(..) - ,Balance,DealStats(..),Index(..) - ,DealCycle(..),Cmp(..),TimeHorizion(..) + ,Ts(..),TsPoint(..),PoolSource(..) + ,Period(..), Threshold(..) + ,RangeType(..),CutoffType(..),DealStatus(..) + ,Balance,Index(..) + ,Cmp(..),TimeHorizion(..) ,Date,Dates,TimeSeries(..),IRate,Amount,Rate,StartDate,EndDate,Lag ,Spread,Floor,Cap,Interest,Principal,Cash,Default,Loss,Rental,PrepaymentPenalty - ,ResultComponent(..),SplitType(..),BookItem(..),BookItems,BalanceSheetReport(..),CashflowReport(..) + ,SplitType(..),BookItem(..),BookItems,BalanceSheetReport(..),CashflowReport(..) ,Floater,CeName,RateAssumption(..) ,PrepaymentRate,DefaultRate,RecoveryRate,RemainTerms,Recovery,Prepayment ,Table(..),lookupTable,Direction(..),epocDate,BorrowerNum - ,PricingMethod(..),sortActionOnDate,PriceResult(..),IRR,Limit(..) + ,Txn(..),TxnComment(..) ,RoundingBy(..),DateDirection(..) - ,TxnComment(..),BookDirection(..),DealStatType(..),getDealStatType + ,BookDirection(..),IRR(..),DealCycle(..),Limit(..),Pre(..) ,Liable(..),CumPrepay,CumDefault,CumDelinq,CumPrincipal,CumLoss,CumRecovery,PoolId(..) - ,DealName,lookupIntervalTable,getPriceValue,Txn(..) + ,DealName,lookupIntervalTable,CutoffFields(..),PriceResult(..) + ,DueInt,DuePremium, DueIoI,DateVector,DealStats(..) + ,PricingMethod(..),CustomDataType(..),ResultComponent(..),DealStatType(..) + ,getDealStatType,getPriceValue ) where @@ -43,12 +46,14 @@ import Language.Haskell.TH import Text.Read (readMaybe) + import Data.Aeson hiding (json) import Data.Aeson.TH import Data.Aeson.Types import Data.Fixed import Data.Ix + import Data.List (intercalate, findIndex) -- import Cashflow (CashFlowFrame) @@ -104,6 +109,17 @@ type RemainTerms = Int type BorrowerNum = Int type Lag = Int + +type Valuation = Centi +type PerFace = Micro +type WAL = Centi +type Duration = Balance +type Convexity = Micro +type Yield = Micro +type AccruedInterest = Centi +type IRR = Rational +data YieldResult = Yiel + data Index = LPR5Y | LPR1Y | LIBOR1M @@ -132,7 +148,7 @@ data Index = LPR5Y | BBSW | IRPH -- The IRPH (Índice de Referencia de Préstamos Hipotecarios) is a reference index used in Spain to fix the interest rate of mortgage loans | SONIA - deriving (Show,Eq,Generic,Ord) + deriving (Show,Eq,Generic,Ord,Read) type Floater = (Index,Spread) @@ -150,7 +166,7 @@ data DayCount = DC_30E_360 -- ^ ISMA European 30S/360 Special German Eurob | DC_30_360_ISDA -- ^ IDSA | DC_30_360_German -- ^ Gernman | DC_30_360_US -- ^ 30/360 US Municipal , Bond basis - deriving (Show,Eq,Generic,Ord) + deriving (Show,Eq,Generic,Ord,Read) data DateType = ClosingDate -- ^ deal closing day @@ -179,7 +195,7 @@ data DatePattern = MonthEnd | Exclude DatePattern [DatePattern] | OffsetBy DatePattern Int -- | DayOfWeek Int -- T.DayOfWeek - deriving (Show, Eq, Generic, Ord) + deriving (Show, Eq, Generic, Ord, Read) data Period = Daily @@ -193,23 +209,6 @@ data Period = Daily type DateVector = (Date, DatePattern) -data DealCycle = EndCollection -- ^ | collection period collection action , waterfall action - | EndCollectionWF -- ^ | collection period collection action , waterfall action - | BeginDistributionWF -- ^ | collection period collection action , waterfall action - | EndDistributionWF -- ^ | collection period collection action , waterfall action - | InWF -- ^ | collection period collection action , waterfall action - deriving (Show, Ord, Eq, Read, Generic) - - -data DealStatus = DealAccelerated (Maybe Date) -- ^ Deal is accelerated status with optinal accerlerated date - | DealDefaulted (Maybe Date) -- ^ Deal is defaulted status with optinal default date - | Amortizing -- ^ Deal is amortizing - | Revolving -- ^ Deal is revolving - | RampUp -- ^ Deal is being ramping up - | Ended -- ^ Deal is marked as closed - | PreClosing DealStatus -- ^ Deal is not closed - | Called -- ^ Deal is called - deriving (Show,Ord,Eq,Read, Generic) data RoundingBy a = RoundCeil a @@ -335,18 +334,6 @@ data BookDirection = Credit | Debit deriving (Show,Ord, Eq,Read, Generic) -data Limit = DuePct Rate -- ^ up to % of total amount due - | DueCapAmt Balance -- ^ up to $ amount - | KeepBalAmt DealStats -- ^ pay till a certain amount remains in an account - | DS DealStats -- ^ transfer with limit described by a `DealStats` - | ClearLedger String -- ^ when transfer, clear the ledger by transfer amount - | BookLedger String -- ^ when transfer, book the ledger by the transfer amount - | RemainBalPct Rate -- ^ pay till remain balance equals to a percentage of `stats` - | TillTarget -- ^ transfer amount which make target account up reach reserve balanace - | TillSource -- ^ transfer amount out till source account down back to reserve balance - | Multiple Limit Float -- ^ factor of a limit - deriving (Show,Ord,Eq,Read,Generic) - type DueInt = Balance type DuePremium = Balance @@ -354,15 +341,66 @@ type DueIoI = Balance -data Txn = BondTxn Date Balance Interest Principal IRate Cash DueInt DueIoI (Maybe Float) TxnComment -- ^ bond transaction record for interest and principal - | AccTxn Date Balance Amount TxnComment -- ^ account transaction record - | ExpTxn Date Balance Amount Balance TxnComment -- ^ expense transaction record - | SupportTxn Date (Maybe Balance) Amount Balance DueInt DuePremium TxnComment -- ^ liquidity provider transaction record - | IrsTxn Date Balance Amount IRate IRate Balance TxnComment -- ^ interest swap transaction record - | EntryTxn Date Balance Amount TxnComment -- ^ ledger book entry - | TrgTxn Date Bool TxnComment - deriving (Show, Generic, Eq) +data DealCycle = EndCollection -- ^ | collection period collection action , waterfall action + | EndCollectionWF -- ^ | collection period collection action , waterfall action + | BeginDistributionWF -- ^ | collection period collection action , waterfall action + | EndDistributionWF -- ^ | collection period collection action , waterfall action + | InWF -- ^ | collection period collection action , waterfall action + deriving (Show, Ord, Eq, Read, Generic) + + +data DealStatus = DealAccelerated (Maybe Date) -- ^ Deal is accelerated status with optinal accerlerated date + | DealDefaulted (Maybe Date) -- ^ Deal is defaulted status with optinal default date + | Amortizing -- ^ Deal is amortizing + | Revolving -- ^ Deal is revolving + | RampUp -- ^ Deal is being ramping up + | Ended -- ^ Deal is marked as closed + | PreClosing DealStatus -- ^ Deal is not closed + | Called -- ^ Deal is called + deriving (Show,Ord,Eq,Read, Generic) + + +data PricingMethod = BalanceFactor Rate Rate -- ^ [balance] to be multiply with rate1 and rate2 if status of asset is "performing" or "defaulted" + | BalanceFactor2 Rate Rate Rate -- ^ [balance] by performing/delinq/default factor + | DefaultedBalance Rate -- ^ [balance] only liquidate defaulted balance + | PV IRate IRate -- ^ discount factor, recovery pct on default + | PVCurve Ts -- ^ [CF] Pricing cashflow with a Curve + | PvRate Rate -- ^ [CF] Pricing cashflow with a constant rate + | PvByRef DealStats -- ^ [CF] Pricing cashflow with a ref rate + | Custom Rate -- ^ custom amount + deriving (Show, Eq ,Generic, Read,Ord) + + +data Pre = IfZero DealStats + | If Cmp DealStats Balance + | IfRate Cmp DealStats Micro + | IfInt Cmp DealStats Int + | IfCurve Cmp DealStats Ts + | IfRateCurve Cmp DealStats Ts + | IfIntCurve Cmp DealStats Ts + | IfDate Cmp Date + | IfBool DealStats Bool + -- compare deal + | If2 Cmp DealStats DealStats + | IfRate2 Cmp DealStats DealStats + | IfInt2 Cmp DealStats DealStats + -- | IfRateCurve DealStats Cmp Ts + | IfDealStatus DealStatus + | Always Bool + | IfNot Pre + | Any [Pre] + | All [Pre] -- ^ + deriving (Show,Generic,Eq,Ord) + + +data Table a b = ThresholdTable [(a,b)] + deriving (Show,Eq,Ord,Read,Generic) + + +data ActionType = ActionResetRate -- ^ reset interest rate from curve + | ActionAccrue -- ^ accrue liablity + deriving (Show,Eq,Ord,Read,Generic) data TxnComment = PayInt [BondName] | PayYield BondName @@ -394,23 +432,14 @@ data TxnComment = PayInt [BondName] | TxnComments [TxnComment] deriving (Eq, Show, Ord ,Read, Generic) - - -type Valuation = Centi -type PerFace = Micro -type WAL = Centi -type Duration = Balance -type Convexity = Micro -type Yield = Micro -type AccruedInterest = Centi -type IRR = Rational -data YieldResult = Yield - -data PriceResult = PriceResult Valuation PerFace WAL Duration Convexity AccruedInterest [Txn] - | AssetPrice Valuation WAL Duration Convexity AccruedInterest - | OASResult PriceResult [Valuation] Spread - | ZSpread Spread - deriving (Show, Eq, Generic) +data Txn = BondTxn Date Balance Interest Principal IRate Cash DueInt DueIoI (Maybe Float) TxnComment -- ^ bond transaction record for interest and principal + | AccTxn Date Balance Amount TxnComment -- ^ account transaction record + | ExpTxn Date Balance Amount Balance TxnComment -- ^ expense transaction record + | SupportTxn Date (Maybe Balance) Amount Balance DueInt DuePremium TxnComment -- ^ liquidity provider transaction record + | IrsTxn Date Balance Amount IRate IRate Balance TxnComment -- ^ interest swap transaction record + | EntryTxn Date Balance Amount TxnComment -- ^ ledger book entry + | TrgTxn Date Bool TxnComment + deriving (Show, Generic, Eq, Read) data DealStats = CurrentBondBalance @@ -520,165 +549,18 @@ data DealStats = CurrentBondBalance deriving (Show,Eq,Ord,Read,Generic) -data PricingMethod = BalanceFactor Rate Rate -- ^ [balance] to be multiply with rate1 and rate2 if status of asset is "performing" or "defaulted" - | BalanceFactor2 Rate Rate Rate -- ^ [balance] by performing/delinq/default factor - | DefaultedBalance Rate -- ^ [balance] only liquidate defaulted balance - | PV IRate IRate -- ^ discount factor, recovery pct on default - | PVCurve Ts -- ^ [CF] Pricing cashflow with a Curve - | PvRate Rate -- ^ [CF] Pricing cashflow with a constant rate - | PvByRef DealStats -- ^ [CF] Pricing cashflow with a ref rate - | Custom Rate -- ^ custom amount - deriving (Show, Eq ,Generic, Read,Ord) - - -data Table a b = ThresholdTable [(a,b)] - deriving (Show,Eq,Ord,Read,Generic) - - -data ActionType = ActionResetRate -- ^ reset interest rate from curve - | ActionAccrue -- ^ accrue liablity - deriving (Show,Eq,Ord,Read,Generic) - -data ActionOnDate = EarnAccInt Date AccName -- ^ sweep bank account interest - | ChangeDealStatusTo Date DealStatus -- ^ change deal status - | AccrueFee Date FeeName -- ^ accure fee - | ResetLiqProvider Date String -- ^ reset credit for liquidity provider - | ResetLiqProviderRate Date String -- ^ accure interest/premium amount for liquidity provider - | PoolCollection Date String -- ^ collect pool cashflow and deposit to accounts - | RunWaterfall Date String -- ^ execute waterfall - | DealClosed Date -- ^ actions to perform at the deal closing day, and enter a new deal status - | FireTrigger Date DealCycle String -- ^ fire a trigger - | InspectDS Date DealStats -- ^ inspect formula - | ResetIRSwapRate Date String -- ^ reset interest rate swap dates - | AccrueCapRate Date String -- ^ reset interest rate cap dates - | ResetBondRate Date String -- ^ reset bond interest rate per bond's interest rate info - | ResetSrtRate Date String - | AccrueSrt Date String - | MakeWhole Date Spread (Table Float Spread) - | BuildReport StartDate EndDate -- ^ build cashflow report between dates and balance report at end date - | StopRunFlag Date -- ^ stop the run with a message - | HitStatedMaturity Date -- ^ hit the stated maturity date - deriving (Show,Generic,Read) - - -data DateDesp = FixInterval (Map.Map DateType Date) Period Period - -- cutoff pool closing bond payment dates - | CustomDates Date [ActionOnDate] Date [ActionOnDate] - | PatternInterval (Map.Map DateType (Date, DatePattern, Date)) - -- cutoff closing mRevolving end-date dp1-pc dp2-bond-pay - | PreClosingDates Date Date (Maybe Date) Date DateVector DateVector - -- (last collect,last pay), mRevolving end-date dp1-pool-pay dp2-bond-pay - | CurrentDates (Date,Date) (Maybe Date) Date DateVector DateVector - deriving (Show,Eq, Generic,Ord) - - -sortActionOnDate :: ActionOnDate -> ActionOnDate -> Ordering -sortActionOnDate a1 a2 - | d1 == d2 = case (a1,a2) of - (BuildReport sd1 ed1 ,_) -> GT -- build report should be executed last - (_ , BuildReport sd1 ed1) -> LT -- build report should be executed last - (ResetIRSwapRate _ _ ,_) -> LT -- reset interest swap should be first - (_ , ResetIRSwapRate _ _) -> GT -- reset interest swap should be first - (ResetBondRate {} ,_) -> LT -- reset bond rate should be first - (_ , ResetBondRate {}) -> GT -- reset bond rate should be first - (EarnAccInt {} ,_) -> LT -- earn should be first - (_ , EarnAccInt {}) -> GT -- earn should be first - (ResetLiqProvider {} ,_) -> LT -- reset liq be first - (_ , ResetLiqProvider {}) -> GT -- reset liq be first - (PoolCollection {}, RunWaterfall {}) -> LT -- pool collection should be executed before waterfall - (RunWaterfall {}, PoolCollection {}) -> GT -- pool collection should be executed before waterfall - (_,_) -> EQ - | otherwise = compare d1 d2 - where - d1 = getDate a1 - d2 = getDate a2 - -opts :: JSONKeyOptions -opts = defaultJSONKeyOptions -- { keyModifier = toLower } - -data OverrideType = CustomActionOnDates [ActionOnDate] - deriving (Show,Generic,Ord,Eq) - -data CustomDataType = CustomConstant Rational - | CustomCurve Ts - | CustomDS DealStats - deriving (Show,Ord,Eq,Read,Generic) - -data CutoffFields = IssuanceBalance -- ^ pool issuance balance - | HistoryRecoveries -- ^ cumulative recoveries - | HistoryInterest -- ^ cumulative interest collected - | HistoryPrepayment -- ^ cumulative prepayment collected - | HistoryPrincipal -- ^ cumulative principal collected - | HistoryRental -- ^ cumulative rental collected - | HistoryDefaults -- ^ cumulative default balance - | HistoryDelinquency -- ^ cumulative delinquency balance - | HistoryLoss -- ^ cumulative loss/write-off balance - | HistoryCash -- ^ cumulative cash - | AccruedInterest -- ^ accrued interest at closing - deriving (Show,Ord,Eq,Read,Generic) - - -data DealStatType = RtnBalance - | RtnRate - | RtnBool - | RtnInt - deriving (Show,Eq,Ord,Read,Generic) - -getDealStatType :: DealStats -> DealStatType -getDealStatType (CumulativePoolDefaultedRateTill _ _) = RtnRate -getDealStatType (CumulativePoolDefaultedRate _) = RtnRate -getDealStatType (CumulativeNetLossRatio _) = RtnRate -getDealStatType BondFactor = RtnRate -getDealStatType (PoolFactor _) = RtnRate -getDealStatType (FutureCurrentBondFactor _) = RtnRate -getDealStatType (FutureCurrentPoolFactor _ _) = RtnRate -getDealStatType (BondWaRate _) = RtnRate -getDealStatType (PoolWaRate _) = RtnRate -getDealStatType (BondRate _) = RtnRate - -getDealStatType (CurrentPoolBorrowerNum _) = RtnInt -getDealStatType (MonthsTillMaturity _) = RtnInt -getDealStatType ProjCollectPeriodNum = RtnInt - -getDealStatType (IsMostSenior _ _) = RtnBool -getDealStatType (TriggersStatus _ _)= RtnBool -getDealStatType (IsDealStatus _)= RtnBool -getDealStatType TestRate {} = RtnBool -getDealStatType (TestAny _ _) = RtnBool -getDealStatType (TestAll _ _) = RtnBool - -getDealStatType (Avg dss) = getDealStatType (head dss) -getDealStatType (Max dss) = getDealStatType (head dss) -getDealStatType (Min dss) = getDealStatType (head dss) -getDealStatType (Divide ds1 ds2) = getDealStatType ds1 -getDealStatType _ = RtnBalance - -dealStatType _ = RtnBalance - - - -data Pre = IfZero DealStats - | If Cmp DealStats Balance - | IfRate Cmp DealStats Micro - | IfInt Cmp DealStats Int - | IfCurve Cmp DealStats Ts - | IfRateCurve Cmp DealStats Ts - | IfIntCurve Cmp DealStats Ts - | IfDate Cmp Date - | IfBool DealStats Bool - -- compare deal - | If2 Cmp DealStats DealStats - | IfRate2 Cmp DealStats DealStats - | IfInt2 Cmp DealStats DealStats - -- | IfRateCurve DealStats Cmp Ts - | IfDealStatus DealStatus - | Always Bool - | IfNot Pre - | Any [Pre] - | All [Pre] -- ^ - deriving (Show,Generic,Eq,Ord) - +data Limit = DuePct Rate -- ^ up to % of total amount due + | DueCapAmt Balance -- ^ up to $ amount + | KeepBalAmt DealStats -- ^ pay till a certain amount remains in an account + | DS DealStats -- ^ transfer with limit described by a `DealStats` + | ClearLedger String -- ^ when transfer, clear the ledger by transfer amount + | BookLedger String -- ^ when transfer, book the ledger by the transfer amount + | RemainBalPct Rate -- ^ pay till remain balance equals to a percentage of `stats` + | TillTarget -- ^ transfer amount which make target account up reach reserve balanace + | TillSource -- ^ transfer amount out till source account down back to reserve balance + | Multiple Limit Float -- ^ factor of a limit + deriving (Show,Ord,Eq,Read, Generic) type BookItems = [BookItem] @@ -702,21 +584,6 @@ data CashflowReport = CashflowReport { ,endDate :: Date } deriving (Show,Read,Generic) -data ResultComponent = CallAt Date -- ^ the date when deal called - | DealStatusChangeTo Date DealStatus DealStatus -- ^ record when status changed - | BondOutstanding String Balance Balance -- ^ when deal ends,calculate oustanding principal balance - | BondOutstandingInt String Balance Balance -- ^ when deal ends,calculate oustanding interest due - | InspectBal Date DealStats Balance -- ^ A bal value from inspection - | InspectInt Date DealStats Int -- ^ A int value from inspection - | InspectRate Date DealStats Micro -- ^ A rate value from inspection - | InspectBool Date DealStats Bool -- ^ A bool value from inspection - | FinancialReport StartDate EndDate BalanceSheetReport CashflowReport - | InspectWaterfall Date (Maybe String) [DealStats] [String] - | ErrorMsg String - | WarningMsg String - | EndRun (Maybe Date) String -- ^ end of run with a message - -- | SnapshotCashflow Date String CashFlowFrame - deriving (Show, Generic) data Threshold = Below | EqBelow @@ -731,6 +598,40 @@ data SplitType = EqToLeft -- if equal, the element belongs to left | EqToLeftKeepOnes deriving (Show, Eq, Generic) + +data CutoffFields = IssuanceBalance -- ^ pool issuance balance + | HistoryRecoveries -- ^ cumulative recoveries + | HistoryInterest -- ^ cumulative interest collected + | HistoryPrepayment -- ^ cumulative prepayment collected + | HistoryPrincipal -- ^ cumulative principal collected + | HistoryRental -- ^ cumulative rental collected + | HistoryDefaults -- ^ cumulative default balance + | HistoryDelinquency -- ^ cumulative delinquency balance + | HistoryLoss -- ^ cumulative loss/write-off balance + | HistoryCash -- ^ cumulative cash + | AccruedInterest -- ^ accrued interest at closing + deriving (Show,Ord,Eq,Read,Generic) + +data PriceResult = PriceResult Valuation PerFace WAL Duration Convexity AccruedInterest [Txn] + | AssetPrice Valuation WAL Duration Convexity AccruedInterest + | OASResult PriceResult [Valuation] Spread + | ZSpread Spread + deriving (Show, Eq, Generic) + + + +getPriceValue :: PriceResult -> Balance +getPriceValue (AssetPrice v _ _ _ _ ) = v +getPriceValue (PriceResult v _ _ _ _ _ _) = v +getPriceValue x = error $ "failed to match with type when geting price value" ++ show x + + +getValuation :: PriceResult -> PerFace +getValuation (PriceResult _ val _ _ _ _ _) = val +getValuation (OASResult pr _ _) = getValuation pr +getValuation pr = error $ "not support for pricing result"++ show pr + + class Liable lb where -- must implement @@ -759,7 +660,7 @@ lookupIntervalTable :: Ord a => Table a b -> Direction -> (a -> Bool) -> Maybe ( lookupIntervalTable (ThresholdTable rows) direction lkUpFunc = case findIndex lkUpFunc rs of Nothing -> Nothing - Just i -> if (succ i) == length rows then + Just i -> if succ i == length rows then Nothing else Just $ (rows!!i, rows!!(i+1)) -- `debug` ("Find index"++ show i) @@ -779,48 +680,88 @@ lookupIntervalTable (ThresholdTable rows) direction lkUpFunc -data RateAssumption = RateCurve Index Ts --om a:message^ a rate curve ,which value of rates depends on time +data RateAssumption = RateCurve Index Ts -- ^ a rate curve ,which value of rates depends on time | RateFlat Index IRate -- ^ a rate constant deriving (Show, Generic) -getPriceValue :: PriceResult -> Balance -getPriceValue (AssetPrice v _ _ _ _ ) = v -getPriceValue (PriceResult v _ _ _ _ _ _) = v -getPriceValue x = error $ "failed to match with type when geting price value" ++ show x - - -getValuation :: PriceResult -> PerFace -getValuation (PriceResult _ val _ _ _ _ _) = val -getValuation (OASResult pr _ _) = getValuation pr -getValuation pr = error $ "not support for pricing result"++ show pr - data TimeHorizion = ByMonth | ByYear | ByQuarter +instance TimeSeries (TsPoint a) where + getDate (TsPoint d a) = d + +instance Ord a => Ord (TsPoint a) where + compare (TsPoint d1 tv1) (TsPoint d2 tv2) = compare d1 d2 + + + +instance Show PoolId where + show (PoolName n) = n + show PoolConsol = "PoolConsol" + show (DealBondFlow dn bn sd r) = "BondFlow:"++dn++":"++bn++":"++show sd++":"++show r + +instance (Read PoolId) where + readsPrec d "PoolConsol" = [(PoolConsol,"")] + readsPrec d rStr = + let + pn = Data.List.Split.splitOn ":" rStr + in + case pn of + [dn,bn,sd,r] -> + let + sd' = TF.parseTimeOrError True TF.defaultTimeLocale "%Y-%m-%d" sd + r' = read r::Rate + in + [(DealBondFlow dn bn sd' r',"")] + ["PoolName",pn] -> [(PoolName pn,"")] + _ -> error $ "Invalid PoolId: "++ show pn + + +-- instance ToJSON PoolId +-- instance FromJSON PoolId + + + + +$(deriveJSON defaultOptions ''TsPoint) +$(deriveJSON defaultOptions ''Ts) +$(deriveJSON defaultOptions ''Cmp) +$(deriveJSON defaultOptions ''PoolSource) +$(deriveJSON defaultOptions ''RoundingBy) +$(deriveJSON defaultOptions ''PoolId) + +instance ToJSONKey PoolId where + toJSONKey :: ToJSONKeyFunction PoolId + toJSONKey = toJSONKeyText (T.pack . show) + +instance FromJSONKey PoolId where + fromJSONKey = FromJSONKeyTextParser $ \t -> case readMaybe (T.unpack t) of + Just k -> pure k + Nothing -> fail ("Invalid key: " ++ show t++">>"++ show (T.unpack t)) + -instance Ord ActionOnDate where - compare a1 a2 = compare (getDate a1) (getDate a2) -instance Eq ActionOnDate where - a1 == a2 = getDate a1 == getDate a2 -instance TimeSeries ActionOnDate where - getDate (RunWaterfall d _) = d - getDate (ResetLiqProvider d _) = d - getDate (PoolCollection d _) = d - getDate (EarnAccInt d _) = d - getDate (AccrueFee d _) = d - getDate (DealClosed d) = d - getDate (FireTrigger d _ _) = d - getDate (ChangeDealStatusTo d _ ) = d - getDate (InspectDS d _ ) = d - getDate (ResetIRSwapRate d _ ) = d - getDate (AccrueCapRate d _ ) = d - getDate (ResetBondRate d _ ) = d - getDate (MakeWhole d _ _) = d - getDate (BuildReport sd ed) = ed + + + +data ResultComponent = CallAt Date -- ^ the date when deal called + | DealStatusChangeTo Date DealStatus DealStatus -- ^ record when status changed + | BondOutstanding String Balance Balance -- ^ when deal ends,calculate oustanding principal balance + | BondOutstandingInt String Balance Balance -- ^ when deal ends,calculate oustanding interest due + | InspectBal Date DealStats Balance -- ^ A bal value from inspection + | InspectInt Date DealStats Int -- ^ A int value from inspection + | InspectRate Date DealStats Micro -- ^ A rate value from inspection + | InspectBool Date DealStats Bool -- ^ A bool value from inspection + | FinancialReport StartDate EndDate BalanceSheetReport CashflowReport + | InspectWaterfall Date (Maybe String) [DealStats] [String] + | ErrorMsg String + | WarningMsg String + | EndRun (Maybe Date) String -- ^ end of run with a message + -- | SnapshotCashflow Date String CashFlowFrame + deriving (Show, Generic) @@ -916,104 +857,128 @@ parseTxn t = case tagName of contents = head sr!!2::String +data DealStatType = RtnBalance + | RtnRate + | RtnBool + | RtnInt + deriving (Show,Eq,Ord,Read,Generic) -instance TimeSeries (TsPoint a) where - getDate (TsPoint d a) = d +getDealStatType :: DealStats -> DealStatType +getDealStatType (CumulativePoolDefaultedRateTill _ _) = RtnRate +getDealStatType (CumulativePoolDefaultedRate _) = RtnRate +getDealStatType (CumulativeNetLossRatio _) = RtnRate +getDealStatType BondFactor = RtnRate +getDealStatType (PoolFactor _) = RtnRate +getDealStatType (FutureCurrentBondFactor _) = RtnRate +getDealStatType (FutureCurrentPoolFactor _ _) = RtnRate +getDealStatType (BondWaRate _) = RtnRate +getDealStatType (PoolWaRate _) = RtnRate +getDealStatType (BondRate _) = RtnRate -instance Ord a => Ord (TsPoint a) where - compare (TsPoint d1 tv1) (TsPoint d2 tv2) = compare d1 d2 +getDealStatType (CurrentPoolBorrowerNum _) = RtnInt +getDealStatType (MonthsTillMaturity _) = RtnInt +getDealStatType ProjCollectPeriodNum = RtnInt +getDealStatType (IsMostSenior _ _) = RtnBool +getDealStatType (TriggersStatus _ _)= RtnBool +getDealStatType (IsDealStatus _)= RtnBool +getDealStatType TestRate {} = RtnBool +getDealStatType (TestAny _ _) = RtnBool +getDealStatType (TestAll _ _) = RtnBool +getDealStatType (Avg dss) = getDealStatType (head dss) +getDealStatType (Max dss) = getDealStatType (head dss) +getDealStatType (Min dss) = getDealStatType (head dss) +getDealStatType (Divide ds1 ds2) = getDealStatType ds1 +getDealStatType _ = RtnBalance -instance Show PoolId where - show (PoolName n) = n - show PoolConsol = "PoolConsol" - show (DealBondFlow dn bn sd r) = "BondFlow:"++dn++":"++bn++":"++show sd++":"++show r +dealStatType _ = RtnBalance -instance (Read PoolId) where - readsPrec d "PoolConsol" = [(PoolConsol,"")] - readsPrec d rStr = - let - pn = Data.List.Split.splitOn ":" rStr - in - case pn of - [dn,bn,sd,r] -> - let - sd' = TF.parseTimeOrError True TF.defaultTimeLocale "%Y-%m-%d" sd - r' = read r::Rate - in - [(DealBondFlow dn bn sd' r',"")] - ["PoolName",pn] -> [(PoolName pn,"")] - _ -> error $ "Invalid PoolId: "++ show pn +data CustomDataType = CustomConstant Rational + | CustomCurve Ts + | CustomDS DealStats + deriving (Show,Ord,Eq,Read,Generic) --- instance ToJSON PoolId --- instance FromJSON PoolId +$(deriveJSON defaultOptions ''DealStatus) +$(concat <$> traverse (deriveJSON defaultOptions) [''DealStats, ''PricingMethod, ''DealCycle, ''DateType, ''Period, + ''DatePattern, ''Table, ''BalanceSheetReport, ''BookItem, ''CashflowReport, ''Txn] ) -$(deriveJSON defaultOptions ''TsPoint) -$(deriveJSON defaultOptions ''Ts) -$(deriveJSON defaultOptions ''Cmp) -$(deriveJSON defaultOptions ''PoolSource) -$(deriveJSON defaultOptions ''RoundingBy) -$(deriveJSON defaultOptions ''PoolId) -instance ToJSONKey PoolId where - toJSONKey :: ToJSONKeyFunction PoolId +instance ToJSONKey DateType where + toJSONKey = genericToJSONKey defaultJSONKeyOptions + +instance FromJSONKey DateType where + fromJSONKey = genericFromJSONKey defaultJSONKeyOptions + +$(deriveJSON defaultOptions ''Pre) + + +$(deriveJSON defaultOptions ''CustomDataType) +$(deriveJSON defaultOptions ''ResultComponent) + +$(deriveJSON defaultOptions ''PriceResult) +$(deriveJSON defaultOptions ''CutoffFields) + + + + +instance ToJSONKey DealCycle where toJSONKey = toJSONKeyText (T.pack . show) -instance FromJSONKey PoolId where +instance FromJSONKey DealCycle where fromJSONKey = FromJSONKeyTextParser $ \t -> case readMaybe (T.unpack t) of Just k -> pure k - Nothing -> fail ("Invalid key: " ++ show t++">>"++ show (T.unpack t)) - + Nothing -> fail ("Invalid key: " ++ show t) -$(deriveJSON defaultOptions ''DealStatus) +instance ToJSONKey CutoffFields where + toJSONKey = toJSONKeyText (Text.pack . show) +instance FromJSONKey CutoffFields where + fromJSONKey = FromJSONKeyTextParser $ \t -> case readMaybe (Text.unpack t) of + Just k -> pure k + Nothing -> fail ("Invalid key: " ++ show t) -$(concat <$> traverse (deriveJSON defaultOptions) [''DealStats, ''PricingMethod, ''DealCycle, ''DateDesp, ''DateType, ''Period, ''ActionOnDate - ,''DatePattern, ''Table, ''BalanceSheetReport, ''BookItem, ''CashflowReport] ) -instance ToJSONKey DateType where - toJSONKey = genericToJSONKey defaultJSONKeyOptions +opts :: JSONKeyOptions +opts = defaultJSONKeyOptions -- { keyModifier = toLower } -instance FromJSONKey DateType where - fromJSONKey = genericFromJSONKey defaultJSONKeyOptions $(deriveJSON defaultOptions ''Index) -$(deriveJSON defaultOptions ''Pre) $(deriveJSON defaultOptions ''DayCount) -- $(deriveJSON defaultOptions ''Table) -- $(deriveJSON defaultOptions ''ActionOnDate) -$(deriveJSON defaultOptions ''OverrideType) -- $(deriveJSON defaultOptions ''DatePattern) -- $(deriveJSON defaultOptions ''DateType) $(deriveJSON defaultOptions ''Threshold) +instance ToJSONKey Threshold where + toJSONKey = genericToJSONKey opts +instance FromJSONKey Threshold where + fromJSONKey = genericFromJSONKey opts -- $(deriveJSON defaultOptions ''DateDesp) -- $(deriveJSON defaultOptions ''Period) -$(deriveJSON defaultOptions ''CustomDataType) -$(deriveJSON defaultOptions ''ResultComponent) -- $(deriveJSON defaultOptions ''CashflowReport) -- $(deriveJSON defaultOptions ''BookItem) -- $(deriveJSON defaultOptions ''BalanceSheetReport) -- $(deriveJSON defaultOptions ''DealCycle) -$(deriveJSON defaultOptions ''Txn) -$(deriveJSON defaultOptions ''PriceResult) -$(deriveJSON defaultOptions ''Limit) -$(deriveJSON defaultOptions ''CutoffFields) + $(deriveJSON defaultOptions ''RateAssumption) $(deriveJSON defaultOptions ''BookDirection) $(deriveJSON defaultOptions ''Direction) +-- $(deriveJSON defaultOptions ''DealStats) +-- $(deriveJSON defaultOptions ''Limit) +-- $(deriveJSON defaultOptions ''TxnComment) +-- $(deriveJSON defaultOptions ''Txn) + +$(concat <$> traverse (deriveJSON defaultOptions) [''Limit] ) -- $(deriveJSON defaultOptions ''DateType) -- $(deriveJSON defaultOptions ''Threshold) -instance ToJSONKey Threshold where - toJSONKey = genericToJSONKey opts -instance FromJSONKey Threshold where - fromJSONKey = genericFromJSONKey opts + --instance FromJSON Threshold --instance ToJSON Threshold @@ -1022,26 +987,11 @@ instance FromJSONKey Threshold where -- instance ToJSON CutoffFields -- instance FromJSON CutoffFields -instance ToJSONKey CutoffFields where - toJSONKey = toJSONKeyText (Text.pack . show) - -instance FromJSONKey CutoffFields where - fromJSONKey = FromJSONKeyTextParser $ \t -> case readMaybe (Text.unpack t) of - Just k -> pure k - Nothing -> fail ("Invalid key: " ++ show t) - -- instance ToJSON DealCycle -- instance FromJSON DealCycle -instance ToJSONKey DealCycle where - toJSONKey = toJSONKeyText (T.pack . show) - -instance FromJSONKey DealCycle where - fromJSONKey = FromJSONKeyTextParser $ \t -> case readMaybe (T.unpack t) of - Just k -> pure k - Nothing -> fail ("Invalid key: " ++ show t) -- instance FromJSON DateType diff --git a/src/Waterfall.hs b/src/Waterfall.hs index c1e69c7c..57dbfee7 100644 --- a/src/Waterfall.hs +++ b/src/Waterfall.hs @@ -118,8 +118,8 @@ data Action = Transfer (Maybe Limit) AccountName AccountName (Maybe TxnComment) -- Record booking | BookBy BookType -- ^ book an ledger with book types -- Pre - | ActionWithPre L.Pre [Action] -- ^ execute actions if
 is true 
-            | ActionWithPre2 L.Pre [Action] [Action]  -- ^ execute action1 if 
 is true ,else execute action2 
+            | ActionWithPre Pre [Action]            -- ^ execute actions if 
 is true 
+            | ActionWithPre2 Pre [Action] [Action]  -- ^ execute action1 if 
 is true ,else execute action2 
             -- Trigger
             | RunTrigger DealCycle String        -- ^ update the trigger status during the waterfall execution
             -- Debug
diff --git a/swagger.json b/swagger.json
index 58783b9a..ad8d947d 100644
--- a/swagger.json
+++ b/swagger.json
@@ -2048,6 +2048,41 @@
                         "title": "MakeWhole",
                         "type": "object"
                     },
+                    {
+                        "properties": {
+                            "contents": {
+                                "items": [
+                                    {
+                                        "$ref": "#/components/schemas/Day"
+                                    },
+                                    {
+                                        "type": "string"
+                                    },
+                                    {
+                                        "type": "string"
+                                    },
+                                    {
+                                        "$ref": "#/components/schemas/Bond"
+                                    }
+                                ],
+                                "maxItems": 4,
+                                "minItems": 4,
+                                "type": "array"
+                            },
+                            "tag": {
+                                "enum": [
+                                    "IssueBond"
+                                ],
+                                "type": "string"
+                            }
+                        },
+                        "required": [
+                            "tag",
+                            "contents"
+                        ],
+                        "title": "IssueBond",
+                        "type": "object"
+                    },
                     {
                         "properties": {
                             "contents": {
@@ -8487,19 +8522,34 @@
                                         "type": "number"
                                     },
                                     {
-                                        "$ref": "#/components/schemas/Day"
+                                        "$ref": "#/components/schemas/Index"
+                                    },
+                                    {
+                                        "multipleOf": 1.0e-6,
+                                        "type": "number"
                                     },
                                     {
                                         "$ref": "#/components/schemas/DatePattern"
+                                    },
+                                    {
+                                        "$ref": "#/components/schemas/DayCount"
+                                    },
+                                    {
+                                        "multipleOf": 1.0e-6,
+                                        "type": "number"
+                                    },
+                                    {
+                                        "multipleOf": 1.0e-6,
+                                        "type": "number"
                                     }
                                 ],
-                                "maxItems": 3,
-                                "minItems": 3,
+                                "maxItems": 7,
+                                "minItems": 7,
                                 "type": "array"
                             },
                             "tag": {
                                 "enum": [
-                                    "BankAccount"
+                                    "Floater"
                                 ],
                                 "type": "string"
                             }
@@ -8508,7 +8558,7 @@
                             "tag",
                             "contents"
                         ],
-                        "title": "BankAccount",
+                        "title": "Floater",
                         "type": "object"
                     },
                     {
@@ -8516,14 +8566,65 @@
                             "contents": {
                                 "items": [
                                     {
-                                        "$ref": "#/components/schemas/Index"
+                                        "multipleOf": 1.0e-6,
+                                        "type": "number"
                                     },
+                                    {
+                                        "$ref": "#/components/schemas/DayCount"
+                                    }
+                                ],
+                                "maxItems": 2,
+                                "minItems": 2,
+                                "type": "array"
+                            },
+                            "tag": {
+                                "enum": [
+                                    "Fix"
+                                ],
+                                "type": "string"
+                            }
+                        },
+                        "required": [
+                            "tag",
+                            "contents"
+                        ],
+                        "title": "Fix",
+                        "type": "object"
+                    },
+                    {
+                        "properties": {
+                            "contents": {
+                                "multipleOf": 1.0e-6,
+                                "type": "number"
+                            },
+                            "tag": {
+                                "enum": [
+                                    "InterestByYield"
+                                ],
+                                "type": "string"
+                            }
+                        },
+                        "required": [
+                            "tag",
+                            "contents"
+                        ],
+                        "title": "InterestByYield",
+                        "type": "object"
+                    },
+                    {
+                        "properties": {
+                            "contents": {
+                                "items": [
                                     {
                                         "multipleOf": 1.0e-6,
                                         "type": "number"
                                     },
                                     {
-                                        "$ref": "#/components/schemas/Day"
+                                        "$ref": "#/components/schemas/DealStats"
+                                    },
+                                    {
+                                        "format": "float",
+                                        "type": "number"
                                     },
                                     {
                                         "$ref": "#/components/schemas/DatePattern"
@@ -8535,7 +8636,96 @@
                             },
                             "tag": {
                                 "enum": [
-                                    "InvestmentAccount"
+                                    "RefRate"
+                                ],
+                                "type": "string"
+                            }
+                        },
+                        "required": [
+                            "tag",
+                            "contents"
+                        ],
+                        "title": "RefRate",
+                        "type": "object"
+                    },
+                    {
+                        "properties": {
+                            "contents": {
+                                "items": [
+                                    {
+                                        "$ref": "#/components/schemas/InterestInfo"
+                                    },
+                                    {
+                                        "multipleOf": 1.0e-6,
+                                        "type": "number"
+                                    }
+                                ],
+                                "maxItems": 2,
+                                "minItems": 2,
+                                "type": "array"
+                            },
+                            "tag": {
+                                "enum": [
+                                    "CapRate"
+                                ],
+                                "type": "string"
+                            }
+                        },
+                        "required": [
+                            "tag",
+                            "contents"
+                        ],
+                        "title": "CapRate",
+                        "type": "object"
+                    },
+                    {
+                        "properties": {
+                            "contents": {
+                                "items": [
+                                    {
+                                        "$ref": "#/components/schemas/InterestInfo"
+                                    },
+                                    {
+                                        "multipleOf": 1.0e-6,
+                                        "type": "number"
+                                    }
+                                ],
+                                "maxItems": 2,
+                                "minItems": 2,
+                                "type": "array"
+                            },
+                            "tag": {
+                                "enum": [
+                                    "FloorRate"
+                                ],
+                                "type": "string"
+                            }
+                        },
+                        "required": [
+                            "tag",
+                            "contents"
+                        ],
+                        "title": "FloorRate",
+                        "type": "object"
+                    },
+                    {
+                        "properties": {
+                            "contents": {
+                                "items": [
+                                    {
+                                        "$ref": "#/components/schemas/InterestInfo"
+                                    },
+                                    {
+                                        "$ref": "#/components/schemas/InterestOverInterestType"
+                                    }
+                                ],
+                                "maxItems": 2,
+                                "minItems": 2,
+                                "type": "array"
+                            },
+                            "tag": {
+                                "enum": [
+                                    "WithIoI"
                                 ],
                                 "type": "string"
                             }
@@ -8544,7 +8734,51 @@
                             "tag",
                             "contents"
                         ],
-                        "title": "InvestmentAccount",
+                        "title": "WithIoI",
+                        "type": "object"
+                    }
+                ]
+            },
+            "InterestOverInterestType": {
+                "oneOf": [
+                    {
+                        "properties": {
+                            "contents": {
+                                "format": "double",
+                                "type": "number"
+                            },
+                            "tag": {
+                                "enum": [
+                                    "OverCurrRateBy"
+                                ],
+                                "type": "string"
+                            }
+                        },
+                        "required": [
+                            "tag",
+                            "contents"
+                        ],
+                        "title": "OverCurrRateBy",
+                        "type": "object"
+                    },
+                    {
+                        "properties": {
+                            "contents": {
+                                "multipleOf": 1.0e-6,
+                                "type": "number"
+                            },
+                            "tag": {
+                                "enum": [
+                                    "OverFixSpread"
+                                ],
+                                "type": "string"
+                            }
+                        },
+                        "required": [
+                            "tag",
+                            "contents"
+                        ],
+                        "title": "OverFixSpread",
                         "type": "object"
                     }
                 ]
@@ -9522,6 +9756,12 @@
                         },
                         "type": "array"
                     },
+                    "issueBondSchedule": {
+                        "items": {
+                            "$ref": "#/components/schemas/TsPoint_([Char],[Char],Bond)"
+                        },
+                        "type": "array"
+                    },
                     "makeWholeWhen": {
                         "items": [
                             {
@@ -14728,6 +14968,32 @@
                 "minItems": 2,
                 "type": "array"
             },
+            "TsPoint_([Char],[Char],Bond)": {
+                "items": [
+                    {
+                        "$ref": "#/components/schemas/Day"
+                    },
+                    {
+                        "items": [
+                            {
+                                "type": "string"
+                            },
+                            {
+                                "type": "string"
+                            },
+                            {
+                                "$ref": "#/components/schemas/Bond"
+                            }
+                        ],
+                        "maxItems": 3,
+                        "minItems": 3,
+                        "type": "array"
+                    }
+                ],
+                "maxItems": 2,
+                "minItems": 2,
+                "type": "array"
+            },
             "TsPoint_Bool": {
                 "items": [
                     {
@@ -16361,7 +16627,7 @@
             "name": "BSD 3"
         },
         "title": "Hastructure API",
-        "version": "0.28.6"
+        "version": "0.28.8"
     },
     "openapi": "3.0.0",
     "paths": {
diff --git a/test/DealTest/DealTest.hs b/test/DealTest/DealTest.hs
index 8a5e5e93..a4de6443 100644
--- a/test/DealTest/DealTest.hs
+++ b/test/DealTest/DealTest.hs
@@ -115,7 +115,7 @@ baseCase = D.TestDeal {
 
 baseTests = 
   let 
-   (dealAfterRun,poolCf,_,_) = DR.runDeal baseCase DealPoolFlowPricing Nothing (AP.NonPerfAssumption Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing)
+   (dealAfterRun,poolCf,_,_) = DR.runDeal baseCase DealPoolFlowPricing Nothing (AP.NonPerfAssumption Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing)
   in 
    testGroup "Base Deal Test" 
    [ testCase "Dates pattern" $
diff --git a/test/DealTest/MultiPoolDealTest.hs b/test/DealTest/MultiPoolDealTest.hs
index c0d04b07..cabcf019 100644
--- a/test/DealTest/MultiPoolDealTest.hs
+++ b/test/DealTest/MultiPoolDealTest.hs
@@ -93,7 +93,7 @@ baseCase = D.TestDeal {
 
 baseTests = 
   let 
-   (dealAfterRun,poolCf,_,_) = DR.runDeal baseCase DealPoolFlowPricing Nothing (AP.NonPerfAssumption Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing)
+   (dealAfterRun,poolCf,_,_) = DR.runDeal baseCase DealPoolFlowPricing Nothing (AP.NonPerfAssumption Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing)
   in 
    testGroup "Base Deal Test" 
    [ testCase "Dates pattern" $