Skip to content

Commit

Permalink
correct begBalance for asset cashflow statuts
Browse files Browse the repository at this point in the history
  • Loading branch information
yellowbean committed Oct 15, 2024
1 parent a195faa commit 2675f95
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 34 deletions.
4 changes: 3 additions & 1 deletion src/AssetClass/FixedAsset.hs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ instance Ast.Asset FixedAsset where
cumuDepreciation = tail $ scanl (+) cumuDep amortizedBals

txns = zipWith6 CF.FixedFlow pdates scheduleBals amortizedBals cumuDepreciation units cash
futureTxns = cutBy Inc Future asOfDay txns
begBal = CF.buildBegBal futureTxns
in
(CF.CashFlowFrame (head scheduleBals,asOfDay,Nothing) $ cutBy Inc Future asOfDay txns, Map.empty)
(CF.CashFlowFrame (begBal,asOfDay,Nothing) $ futureTxns, Map.empty)

10 changes: 7 additions & 3 deletions src/AssetClass/Installment.hs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ projectInstallmentFlow (startBal, lastPaidDate, (originRepay,originInt), startRa

instance Asset Installment where
calcCashflow inst@(Installment (LoanOriginalInfo ob or ot p sd ptype _) cb rt st) asOfDay _
= CF.CashFlowFrame (cb,asOfDay,Nothing) flows
= CF.CashFlowFrame (begBal,asOfDay,Nothing) flows
where
lastPayDate:cf_dates = lastN (rt+1) $ sd:getPaymentDates inst 0
opmt = divideBI ob ot
Expand All @@ -99,6 +99,7 @@ instance Asset Installment where
(replicate _rt orate) (replicate _rt Nothing)

flows = cutBy Inc Future asOfDay _flows
begBal = CF.buildBegBal flows


getCurrentBal (Installment _ b _ _ ) = b
Expand Down Expand Up @@ -130,7 +131,7 @@ instance Asset Installment where
asOfDay
pAssump@(A.InstallmentAssump defaultAssump prepayAssump recoveryAssump ams,_,_)
mRates
= (applyHaircut ams (CF.CashFlowFrame (cb,asOfDay,Nothing) futureTxns), historyM)
= (applyHaircut ams (CF.CashFlowFrame (begBal,asOfDay,Nothing) futureTxns), historyM)
where
recoveryLag = maybe 0 getRecoveryLag recoveryAssump
lastPayDate:cfDates = lastN (rt + recoveryLag +1) $ sd:getPaymentDates inst recoveryLag
Expand All @@ -149,6 +150,7 @@ instance Asset Installment where
defRates = Ast.buildDefaultRates (lastPayDate:cfDates) defaultAssump
(txns,_) = projectInstallmentFlow (cb,lastPayDate,(opmt,ofee),orate,currentFactor,pt,ot) (cfDates,defRates,ppyRates,remainTerms)
(futureTxns,historyM) = CF.cutoffTrs asOfDay (patchLossRecovery txns recoveryAssump)
begBal = CF.buildBegBal futureTxns


-- ^ project with defaulted at a date
Expand All @@ -162,8 +164,10 @@ instance Asset Installment where
recoveries = calcRecoveriesFromDefault cb rr timing
bals = scanl (-) cb recoveries
_txns = [ CF.LoanFlow d b 0 0 0 0 r 0 cr Nothing | (b,d,r) <- zip3 bals cf_dates2 recoveries ]
futureTxns = cutBy Inc Future asOfDay $ beforeRecoveryTxn++_txns
begBal = CF.buildBegBal futureTxns
in
(CF.CashFlowFrame (cb,asOfDay,Nothing)$ cutBy Inc Future asOfDay (beforeRecoveryTxn++_txns),Map.empty)
(CF.CashFlowFrame (begBal,asOfDay,Nothing) futureTxns ,Map.empty)
where
cr = getOriginRate inst

Expand Down
4 changes: 3 additions & 1 deletion src/AssetClass/Lease.hs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ instance Asset Lease where
= fst . patchBalance $ RegularLease (LeaseInfo sd ot dp dr ob) bal ot st

projCashflow l asOfDay ((AP.LeaseAssump gapAssump rentAssump ed exStress),_,_) mRates
= (CF.CashFlowFrame (0,asOfDay,Nothing) allTxns, Map.empty)
= (CF.CashFlowFrame (begBal,asOfDay,Nothing) allTxns, Map.empty)
where
currentCf = calcCashflow l asOfDay mRates
-- (rc,rcCurve,mgTbl,gapDays,ed) = extractAssump (A.LeaseAssump gapAssump rentAssump) -- (0.0,mkTs [],([(0.0,0)],0),0,epocDate)-- `debug` ("7")
Expand All @@ -232,6 +232,8 @@ instance Asset Lease where
[]
newCfs = [ calcCashflow l asOfDay mRates | l <- newLeases ] -- `debug` ("new leases"++ show newLeases )
allTxns = view CF.cashflowTxn currentCf ++ (concat $ (view CF.cashflowTxn) <$> newCfs)
begBal = CF.buildBegBal allTxns


getCurrentBal l = case l of
StepUpLease _ _ bal _ _ -> bal
Expand Down
6 changes: 4 additions & 2 deletions src/AssetClass/Loan.hs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ instance Asset Loan where
asOfDay
(A.LoanAssump defaultAssump prepayAssump recoveryAssump ams,_,_)
mRate
= (applyHaircut ams (CF.CashFlowFrame (cb,asOfDay,Nothing) futureTxns), historyM)
= (applyHaircut ams (CF.CashFlowFrame (begBal,asOfDay,Nothing) futureTxns), historyM)
where
recoveryLag = maybe 0 getRecoveryLag recoveryAssump
lastPayDate:cfDates = lastN (rt + recoveryLag + 1) $ sd:getPaymentDates pl recoveryLag
Expand All @@ -145,6 +145,7 @@ instance Asset Loan where
_ -> 1.0
(txns,_) = projectLoanFlow ((ob,ot,getOriginRate pl), cb,lastPayDate,prinPayType,dc,cr,initFactor) (cfDates,defRates,ppyRates,rateVector,remainTerms) -- `debug` (" rateVector"++show rateVector)
(futureTxns,historyM) = CF.cutoffTrs asOfDay (patchLossRecovery txns recoveryAssump)
begBal = CF.buildBegBal futureTxns

-- ^ Project cashflow for defautled loans
projCashflow m@(PersonalLoan (LoanOriginalInfo ob or ot p sd prinPayType _) cb cr rt (Defaulted (Just defaultedDate)))
Expand All @@ -158,8 +159,9 @@ instance Asset Loan where
_txns = [ CF.LoanFlow d 0 0 0 0 0 r 0 cr Nothing | (d,r) <- zip cf_dates2 recoveries ]
(_, txns) = splitByDate (beforeRecoveryTxn++_txns) asOfDay EqToRight -- `debug` ("AS OF Date"++show asOfDay)
(futureTxns,historyM) = CF.cutoffTrs asOfDay txns
begBal = CF.buildBegBal futureTxns
in
(CF.CashFlowFrame (cb,asOfDay,Nothing) futureTxns, historyM)
(CF.CashFlowFrame (begBal,asOfDay,Nothing) futureTxns, historyM)

projCashflow m@(PersonalLoan (LoanOriginalInfo ob or ot p sd prinPayType _) cb cr rt (Defaulted Nothing)) asOfDay assumps _
= (CF.CashFlowFrame (cb,asOfDay,Nothing) [CF.LoanFlow asOfDay 0 0 0 0 0 0 0 cr Nothing],Map.empty)
Expand Down
32 changes: 21 additions & 11 deletions src/AssetClass/Mortgage.hs
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,7 @@ instance Ast.Asset Mortgage where
asOfDay
mars@(A.MortgageAssump (Just (A.DefaultByAmt (dBal,vs))) amp amr ams ,_ ,_)
mRates =
(applyHaircut ams $ patchPrepayPenaltyFlow (ot,mpn) (CF.CashFlowFrame (cb,asOfDay,Nothing) futureTxns) ,historyM)
(applyHaircut ams $ patchPrepayPenaltyFlow (ot,mpn) (CF.CashFlowFrame (begBal,asOfDay,Nothing) futureTxns) ,historyM)
where
recoveryLag = maybe 0 getRecoveryLag amr
lastPayDate:cfDates = lastN (succ (recoveryLag + rt)) $ sd:getPaymentDates m recoveryLag
Expand All @@ -423,13 +423,14 @@ instance Ast.Asset Mortgage where
txns = projCashflowByDefaultAmt (cb,lastPayDate,prinPayType,p,cr,mbn)
(cfDates,(expectedDefaultBals,unAppliedDefaultBals),ppyRates,rateVector,remainTerms)
(futureTxns,historyM)= CF.cutoffTrs asOfDay (patchLossRecovery txns amr)
begBal = CF.buildBegBal futureTxns

-- project current adjMortgage with total default amt
projCashflow m@(AdjustRateMortgage (MortgageOriginalInfo ob or ot p sd prinPayType mpn _) arm cb cr rt mbn Current)
asOfDay
mars@(A.MortgageAssump (Just (A.DefaultByAmt (dBal,vs))) amp amr ams,_,_)
mRates =
(applyHaircut ams $ patchPrepayPenaltyFlow (ot,mpn) (CF.CashFlowFrame (cb,asOfDay,Nothing) futureTxns) ,historyM)
(applyHaircut ams $ patchPrepayPenaltyFlow (ot,mpn) (CF.CashFlowFrame (begBal,asOfDay,Nothing) futureTxns) ,historyM)
where
ARM initPeriod initCap periodicCap lifeCap lifeFloor = arm
passInitPeriod = (ot - rt) >= initPeriod
Expand All @@ -445,11 +446,12 @@ instance Ast.Asset Mortgage where
remainTerms = paddingDefault 0 (reverse [0..(length cfDates - recoveryLag)]) (length cfDates)
txns = projCashflowByDefaultAmt (cb,lastPayDate,prinPayType,p,cr,mbn) (cfDates,(expectedDefaultBals,unAppliedDefaultBals),ppyRates,rateVector,remainTerms)
(futureTxns,historyM)= CF.cutoffTrs asOfDay (patchLossRecovery txns amr)
begBal = CF.buildBegBal futureTxns

-- project schedule cashflow with total default amount
projCashflow (ScheduleMortgageFlow begDate flows dp) asOfDay
assumps@(pAssump@(A.MortgageAssump (Just (A.DefaultByAmt (dBal,vs))) amp amr ams ),dAssump,fAssump) _
= (applyHaircut ams (CF.CashFlowFrame (begBal,asOfDay,Nothing) futureTxns) ,historyM) -- `debug` ("Future txn"++ show futureTxns)
= (applyHaircut ams (CF.CashFlowFrame (begBalAfterCut,asOfDay,Nothing) futureTxns) ,historyM) -- `debug` ("Future txn"++ show futureTxns)
where
begBal = CF.mflowBegBalance $ head flows
begDate = getDate $ head flows
Expand All @@ -469,14 +471,15 @@ instance Ast.Asset Mortgage where
(begBal,begDate,begRate,begMbn)
(flowsWithEx,(expectedDefaultBals,unAppliedDefaultBals),ppyRates) -- `debug` ("exted flows"++ show flowsWithEx)
(futureTxns,historyM) = CF.cutoffTrs asOfDay (patchLossRecovery txns amr) -- `debug` ("txn"++show txns)
begBalAfterCut = CF.buildBegBal futureTxns


-- project current mortgage(without delinq)
projCashflow m@(Mortgage (MortgageOriginalInfo ob or ot p sd prinPayType mpn _) cb cr rt mbn Current)
asOfDay
mars@(A.MortgageAssump amd amp amr ams ,_ ,_)
mRates =
(applyHaircut ams $ patchPrepayPenaltyFlow (ot,mpn) (CF.CashFlowFrame (cb,asOfDay,Nothing) futureTxns) ,historyM)
(applyHaircut ams $ patchPrepayPenaltyFlow (ot,mpn) (CF.CashFlowFrame (begBal,asOfDay,Nothing) futureTxns) ,historyM)
where
recoveryLag = maybe 0 getRecoveryLag amr
lastPayDate:cfDates = lastN (rt + 1) $ sd:getPaymentDates m 0
Expand All @@ -500,6 +503,7 @@ instance Ast.Asset Mortgage where
extraTxns = [ CF.emptyTsRow d lastProjTxn | d <- recoveryDates ]

(futureTxns,historyM)= CF.cutoffTrs asOfDay (patchLossRecovery (txns++extraTxns) amr)
begBal = CF.buildBegBal futureTxns

-- project current mortgage(with delinq)
projCashflow m@(Mortgage (MortgageOriginalInfo ob or ot p sd prinPayType mpn _) cb cr rt mbn Current)
Expand All @@ -508,7 +512,7 @@ instance Ast.Asset Mortgage where
,_
,_)
mRates =
(applyHaircut ams $ patchPrepayPenaltyFlow (ot,mpn) (CF.CashFlowFrame (cb,asOfDay, Nothing) futureTxns) ,historyM)
(applyHaircut ams $ patchPrepayPenaltyFlow (ot,mpn) (CF.CashFlowFrame (begBal,asOfDay, Nothing) futureTxns) ,historyM)
where
lastPayDate:cfDates = lastN (recoveryLag + defaultLag + rt + 1) $ sd:getPaymentDates m (recoveryLag+defaultLag)
cfDatesLength = length cfDates + recoveryLag + defaultLag
Expand All @@ -521,6 +525,7 @@ instance Ast.Asset Mortgage where
(defaultPct,defaultLag,recoveryRate,recoveryLag,p,prinPayType,ot)
(replicate cfDatesLength 0.0,replicate cfDatesLength 0.0,replicate cfDatesLength 0.0)
(futureTxns,historyM)= CF.cutoffTrs asOfDay txns
begBal = CF.buildBegBal futureTxns

-- project defaulted Mortgage
projCashflow m@(Mortgage (MortgageOriginalInfo ob or ot p sd prinPayType mpn _) cb cr rt mbn (Defaulted (Just defaultedDate)) )
Expand All @@ -531,8 +536,10 @@ instance Ast.Asset Mortgage where
beforeRecoveryTxn = [ CF.MortgageFlow d 0 0 0 0 0 0 0 cr mbn Nothing Nothing | d <- emptyDates ]
recoveries = calcRecoveriesFromDefault cb rr timing
txns = [ CF.MortgageFlow d 0 0 0 0 0 r 0 cr mbn Nothing Nothing | (d,r) <- zip recoveryDates recoveries ]
futureTxns = cutBy Inc Future asOfDay $ beforeRecoveryTxn ++ txns
begBal = CF.buildBegBal futureTxns
in
(CF.CashFlowFrame (cb,asOfDay,Nothing) $ cutBy Inc Future asOfDay (beforeRecoveryTxn ++ txns) ,Map.empty)
(CF.CashFlowFrame (begBal,asOfDay,Nothing) futureTxns ,Map.empty)

-- project defaulted adjMortgage with a defaulted Date
projCashflow m@(AdjustRateMortgage mo arm cb cr rt mbn (Defaulted (Just defaultedDate)) ) asOfDay assumps mRates
Expand All @@ -549,7 +556,7 @@ instance Ast.Asset Mortgage where
asOfDay
mars@(A.MortgageAssump amd amp amr ams,_,_)
mRates =
(applyHaircut ams $ patchPrepayPenaltyFlow (ot,mpn) (CF.CashFlowFrame (cb,asOfDay,Nothing) futureTxns) ,historyM)
(applyHaircut ams $ patchPrepayPenaltyFlow (ot,mpn) (CF.CashFlowFrame (begBal,asOfDay,Nothing) futureTxns) ,historyM)
where
ARM initPeriod initCap periodicCap lifeCap lifeFloor = arm
passInitPeriod = (ot - rt) >= initPeriod
Expand All @@ -567,13 +574,14 @@ instance Ast.Asset Mortgage where
scheduleBalToday = calcScheduleBalaceToday m mRates asOfDay
(txns,_) = projectMortgageFlow (scheduleBalToday, cb,lastPayDate,mbn,prinPayType,dc,cr,p,ot) (cfDates, defRates, ppyRates,rateVector,remainTerms)
(futureTxns,historyM)= CF.cutoffTrs asOfDay (patchLossRecovery txns amr)
begBal = CF.buildBegBal futureTxns

-- project current AdjMortgage with delinq
projCashflow m@(AdjustRateMortgage (MortgageOriginalInfo ob or ot p sd prinPayType mpn _) arm cb cr rt mbn Current)
asOfDay
mars@(A.MortgageAssump amd amp amr ams,_,_)
mRates =
(applyHaircut ams $ patchPrepayPenaltyFlow (ot,mpn) (CF.CashFlowFrame (cb,asOfDay,Nothing) futureTxns) ,historyM)
(applyHaircut ams $ patchPrepayPenaltyFlow (ot,mpn) (CF.CashFlowFrame (begBal,asOfDay,Nothing) futureTxns) ,historyM)
where
ARM initPeriod initCap periodicCap lifeCap lifeFloor = arm
passInitPeriod = (ot - rt) >= initPeriod
Expand All @@ -589,11 +597,12 @@ instance Ast.Asset Mortgage where
(defaultPct,defaultLag,recoveryRate,recoveryLag,p,prinPayType,ot)
(replicate cfDatesLength 0.0,replicate cfDatesLength 0.0,replicate cfDatesLength 0.0)
(futureTxns,historyM)= CF.cutoffTrs asOfDay txns
begBal = CF.buildBegBal futureTxns

-- schedule mortgage flow without delinq
projCashflow (ScheduleMortgageFlow begDate flows dp) asOfDay
assumps@(pAssump@(A.MortgageAssump _ _ _ ams ),dAssump,fAssump) _
= (applyHaircut ams (CF.CashFlowFrame (begBal,asOfDay,Nothing) futureTxns) ,historyM)
= (applyHaircut ams (CF.CashFlowFrame (begBalAfterCutoff,asOfDay,Nothing) futureTxns) ,historyM)
where
begBal = CF.mflowBegBalance $ head flows
(ppyRates,defRates,recoveryRate,recoveryLag) = buildAssumptionPpyDefRecRate (begDate:cfDates) pAssump
Expand All @@ -607,13 +616,13 @@ instance Ast.Asset Mortgage where
(replicate curveDatesLength 0.0)
(recoveryLag,recoveryRate)
(futureTxns,historyM) = CF.cutoffTrs asOfDay txns
cb = (CF.mflowBegBalance . head) futureTxns
begBalAfterCutoff = CF.buildBegBal futureTxns


-- schedule mortgage flow WITH delinq
projCashflow (ScheduleMortgageFlow begDate flows dp) asOfDay assumps@(pAssump@(A.MortgageDeqAssump _ _ _ ams),dAssump,fAssump) mRates
=
(applyHaircut ams (CF.CashFlowFrame (begBal, asOfDay,Nothing) futureTxns) ,historyM)
(applyHaircut ams (CF.CashFlowFrame (begBalAfterCutoff, asOfDay,Nothing) futureTxns) ,historyM)
where
begBal = CF.mflowBegBalance $ head flows -- `debug` ("beg date"++show beg_date)
(ppyRates, delinqRates,(defaultPct,defaultLag),recoveryRate,recoveryLag) = Ast.buildAssumptionPpyDelinqDefRecRate (begDate:getDates flows) pAssump
Expand All @@ -628,6 +637,7 @@ instance Ast.Asset Mortgage where
(replicate curveDatesLength 0.0) (replicate curveDatesLength 0.0)
(replicate curveDatesLength 0.0) (defaultPct,defaultLag,recoveryRate,recoveryLag) -- `debug` ("Delinq rates"++ show delinqRates++">>ppy rates"++ show ppyRates)
(futureTxns,historyM) = CF.cutoffTrs asOfDay txns
begBalAfterCutoff = CF.buildBegBal futureTxns

projCashflow a b c d = error $ "Failed to match when proj mortgage>>" ++ show a ++ show b ++ show c ++ show d

Expand Down
7 changes: 6 additions & 1 deletion src/Cashflow.hs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ module Cashflow (CashFlowFrame(..),Principals,Interests,Amount
,cashflowTxn,clawbackInt,scaleTsRow,mflowFeePaid, currentCumulativeStat, patchCumulativeAtInit
,mergeCf,buildStartTsRow
,txnCumulativeStats,consolidateCashFlow, cfBeginStatus, getBegBalCashFlowFrame
,splitCashFlowFrameByDate, mergePoolCf2) where
,splitCashFlowFrameByDate, mergePoolCf2, buildBegBal) where

import Data.Time (Day)
import Data.Fixed
Expand Down Expand Up @@ -393,6 +393,11 @@ addTsCF (ReceivableFlow d1 b1 af1 p1 fp1 def1 rec1 los1 st1) (ReceivableFlow d2
= ReceivableFlow d1 (min b1 b2) (af1 + af2) (p1 + p2) (fp1 + fp2) (def1 + def2) (rec1 + rec2) (los1 + los2) (maxStats st1 st2)


buildBegBal :: [TsRow] -> Balance
buildBegBal [] = 0
buildBegBal (x:_) = mflowBegBalance x


sumTs :: [TsRow] -> Date -> TsRow
sumTs trs = tsSetDate (foldr1 addTs trs)

Expand Down
19 changes: 4 additions & 15 deletions src/Deal/DealAction.hs
Original file line number Diff line number Diff line change
Expand Up @@ -89,19 +89,6 @@ pricingAssets pm assetsAndAssump ras d
pricingResults



liquidatePool :: Ast.Asset a => PricingMethod -> Date -> String -> TestDeal a -> TestDeal a
liquidatePool lm d accName t@TestDeal { accounts = accs , pool = pool} =
t {accounts = Map.adjust updateFn accName accs} -- `debug` ("Accs->"++show(accs))
where
proceedsByPool = case pool of
MultiPool pm -> Map.map (\p -> P.calcLiquidationAmount lm p d) pm
SoloPool p -> Map.fromList [(PoolConsol,P.calcLiquidationAmount lm p d)]
ResecDeal uDeals -> error "Not implement on liquidate resec deal"

proceeds = sum $ Map.elems proceedsByPool
updateFn = A.deposit proceeds d LiquidationProceeds

-- actual payout amount to bond with due mounts
allocAmtToBonds :: W.PayOrderBy -> Amount -> [(L.Bond,Amount)] -> [(L.Bond,Amount)]
allocAmtToBonds theOrder amt bndsWithDue =
Expand Down Expand Up @@ -1149,9 +1136,11 @@ performAction d t@TestDeal{bonds=bndMap } (W.WriteOffBySeq mlimit bnds)
(bndWrited, _) = paySequentially d writeAmtCapped L.bndBalance (L.writeOff d) [] bondsToWriteOff
bndMapUpdated = lstToMapByFn L.bndName bndWrited


-- TODO need to sell assets/ in the future , in run time
-- TODO need to remove assets/cashflow frame
-- TODO need to set a limit
performAction d t@TestDeal{accounts=accMap, pool = pool} (W.LiquidatePool lm an mPid) =
t {accounts = accMapAfterLiq } -- TODO need to remove assets/cashflow frame
t {accounts = accMapAfterLiq }
where
liqAmtByPool = case (pool,mPid) of
(MultiPool pm,Nothing) -> Map.map (\p -> P.calcLiquidationAmount lm p d) pm
Expand Down

0 comments on commit 2675f95

Please sign in to comment.