{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE DeriveGeneric #-}

module AssetClass.Loan 
  (projectLoanFlow,updateOriginDate)
  where

import qualified Data.Time as T
import qualified Cashflow as CF -- (Cashflow,Amount,Interests,Principals)
import qualified Assumptions as A
import InterestRate
import Asset
import Lib
import Util
import DateUtil
import Types
import qualified Data.Map as Map
import Data.List
import Data.Maybe
import Data.Aeson hiding (json)
import Language.Haskell.TH
import Data.Aeson.TH
import Data.Aeson.Types
import GHC.Generics

import AssetClass.AssetBase
import AssetClass.AssetCashflow

import Debug.Trace
import Assumptions (AssetDefaultAssumption(DefaultCDR))
import qualified Asset as A
import Control.Lens hiding (element)
import Control.Lens.TH
debug :: c -> String -> c
debug = (String -> c -> c) -> c -> String -> c
forall a b c. (a -> b -> c) -> b -> a -> c
flip String -> c -> c
forall a. String -> a -> a
trace


-- instance Asset Loan where
projectLoanFlow :: ((Balance,Int,IRate), Balance, Date, AmortPlan, DayCount, IRate, Rational) -> (Dates, [DefaultRate],[PrepaymentRate],[IRate],[Int]) -> ([CF.TsRow],Rational)
projectLoanFlow :: ((Recovery, Int, IRate), Recovery, Date, AmortPlan, DayCount,
 IRate, Rational)
-> (Dates, [Rational], [Rational], [IRate], [Int])
-> ([TsRow], Rational)
projectLoanFlow ((Recovery
originBal,Int
ot,IRate
or), Recovery
startBal, Date
lastPayDate, AmortPlan
pt, DayCount
dc,IRate
startRate, Rational
begFactor) (Dates
cfDates,[Rational]
defRates,[Rational]
ppyRates,[IRate]
rateVector,[Int]
remainTerms) = 
  let 
    initRow :: TsRow
initRow = Date
-> Recovery
-> Recovery
-> Recovery
-> Recovery
-> Recovery
-> Recovery
-> Recovery
-> IRate
-> Maybe CumulativeStat
-> TsRow
CF.LoanFlow Date
lastPayDate Recovery
startBal Recovery
0.0 Recovery
0.0 Recovery
0.0 Recovery
0.0 Recovery
0.0 Recovery
0.0 IRate
startRate Maybe CumulativeStat
forall a. Maybe a
Nothing
  in 
    (([TsRow], Rational)
 -> (Date, Rational, Rational, IRate, Int) -> ([TsRow], Rational))
-> ([TsRow], Rational)
-> [(Date, Rational, Rational, IRate, Int)]
-> ([TsRow], Rational)
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl
      (\([TsRow]
acc,Rational
factor) (Date
pDate, Rational
ppyRate, Rational
defRate, IRate
intRate, Int
rt)
        -> let 
             begBal :: Recovery
begBal = Getting Recovery TsRow Recovery -> TsRow -> Recovery
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Recovery TsRow Recovery
Lens' TsRow Recovery
CF.tsRowBalance ([TsRow] -> TsRow
forall a. HasCallStack => [a] -> a
last [TsRow]
acc)
             lastPaidDate :: Date
lastPaidDate = TsRow -> Date
forall ts. TimeSeries ts => ts -> Date
getDate ([TsRow] -> TsRow
forall a. HasCallStack => [a] -> a
last [TsRow]
acc)
             newDefault :: Recovery
newDefault = Recovery -> Rational -> Recovery
mulBR Recovery
begBal Rational
defRate
             newPrepay :: Recovery
newPrepay = Recovery -> Rational -> Recovery
mulBR (Recovery
begBal Recovery -> Recovery -> Recovery
forall a. Num a => a -> a -> a
- Recovery
newDefault) Rational
ppyRate
             intBal :: Recovery
intBal = Recovery
begBal Recovery -> Recovery -> Recovery
forall a. Num a => a -> a -> a
- Recovery
newDefault Recovery -> Recovery -> Recovery
forall a. Num a => a -> a -> a
- Recovery
newPrepay
             newFactor :: Rational
newFactor = Rational
factor Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
* (Rational
1Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
-Rational
defRate) Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
* (Rational
1Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
- Rational
ppyRate )
             newInt :: Recovery
newInt = case (Int
rt,AmortPlan
pt) of
                        (Int
0,AmortPlan
F_P) -> Recovery
0
                        (Int
_,AmortPlan
F_P) -> Recovery -> Rational -> Recovery
mulBR (Recovery -> IRate -> Recovery
mulBIR Recovery
originBal IRate
or) Rational
newFactor
                        (Int, AmortPlan)
_ -> Recovery -> Date -> Date -> IRate -> DayCount -> Recovery
calcInt Recovery
intBal Date
lastPaidDate Date
pDate IRate
intRate DayCount
dc 
             newPrin :: Recovery
newPrin = case (Int
rt,AmortPlan
pt) of
                         (Int
1,AmortPlan
I_P) -> Recovery
intBal
                         (Int
1,AmortPlan
F_P) -> Recovery
intBal
                         (Int
0,AmortPlan
F_P) -> Recovery
0
                         (Int
_,AmortPlan
F_P) -> Recovery -> Rational -> Recovery
mulBR (Recovery -> Int -> Recovery
divideBI Recovery
intBal Int
rt)  Rational
newFactor
                         (Int
_,AmortPlan
I_P) -> Recovery
0
                         (Int
0,ScheduleRepayment Ts
cf Maybe DatePattern
_) -> Recovery
intBal
                         (Int
_,ScheduleRepayment Ts
cf Maybe DatePattern
_) -> 
                          let 
                            projAmt :: Recovery
projAmt = Rational -> Recovery
forall a. Fractional a => Rational -> a
fromRational (Rational -> Recovery) -> Rational -> Recovery
forall a b. (a -> b) -> a -> b
$ Ts -> CutoffType -> Date -> Rational
getValByDate Ts
cf CutoffType
Inc Date
pDate 
                          in 
                            if Int
rt Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1 then
                              Recovery
intBal
                            else
                              Recovery -> Rational -> Recovery
mulBR Recovery
projAmt Rational
newFactor
                         (Int, AmortPlan)
_ -> String -> Recovery
forall a. HasCallStack => String -> a
error (String -> Recovery) -> String -> Recovery
forall a b. (a -> b) -> a -> b
$ String
"failed to match Loan Project newPrin"String -> String -> String
forall a. [a] -> [a] -> [a]
++ (Int, AmortPlan) -> String
forall a. Show a => a -> String
show (Int
rt,AmortPlan
pt)
             endBal :: Recovery
endBal = Recovery
intBal Recovery -> Recovery -> Recovery
forall a. Num a => a -> a -> a
- Recovery
newPrin
           in
             ([TsRow]
acc [TsRow] -> [TsRow] -> [TsRow]
forall a. [a] -> [a] -> [a]
++ [Date
-> Recovery
-> Recovery
-> Recovery
-> Recovery
-> Recovery
-> Recovery
-> Recovery
-> IRate
-> Maybe CumulativeStat
-> TsRow
CF.LoanFlow Date
pDate Recovery
endBal Recovery
newPrin Recovery
newInt Recovery
newPrepay Recovery
newDefault Recovery
0.0 Recovery
0.0 IRate
intRate Maybe CumulativeStat
forall a. Maybe a
Nothing]
             ,Rational
newFactor))
      ([TsRow
initRow],Rational
begFactor)
      (Dates
-> [Rational]
-> [Rational]
-> [IRate]
-> [Int]
-> [(Date, Rational, Rational, IRate, Int)]
forall a b c d e.
[a] -> [b] -> [c] -> [d] -> [e] -> [(a, b, c, d, e)]
zip5 Dates
cfDates [Rational]
ppyRates [Rational]
defRates [IRate]
rateVector [Int]
remainTerms)  

instance Asset Loan where
  calcCashflow :: Loan
-> Date -> Maybe [RateAssumption] -> Either String CashFlowFrame
calcCashflow pl :: Loan
pl@(PersonalLoan (LoanOriginalInfo Recovery
ob RateType
or Int
ot Period
p Date
sd AmortPlan
ptype Maybe Obligor
_) Recovery
bal IRate
rate Int
term Status
_ ) Date
asOfDay Maybe [RateAssumption]
mRates 
    = (CashFlowFrame, Map CutoffFields Recovery) -> CashFlowFrame
forall a b. (a, b) -> a
fst ((CashFlowFrame, Map CutoffFields Recovery) -> CashFlowFrame)
-> Either String (CashFlowFrame, Map CutoffFields Recovery)
-> Either String CashFlowFrame
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
      Loan
-> Date
-> AssetPerf
-> Maybe [RateAssumption]
-> Either String (CashFlowFrame, Map CutoffFields Recovery)
forall a.
Asset a =>
a
-> Date
-> AssetPerf
-> Maybe [RateAssumption]
-> Either String (CashFlowFrame, Map CutoffFields Recovery)
projCashflow Loan
pl
                   Date
asOfDay
                   (Maybe AssetDefaultAssumption
-> Maybe AssetPrepayAssumption
-> Maybe RecoveryAssumption
-> Maybe ExtraStress
-> AssetPerfAssumption
A.LoanAssump Maybe AssetDefaultAssumption
forall a. Maybe a
Nothing Maybe AssetPrepayAssumption
forall a. Maybe a
Nothing Maybe RecoveryAssumption
forall a. Maybe a
Nothing Maybe ExtraStress
forall a. Maybe a
Nothing
                    ,AssetDelinqPerfAssumption
A.DummyDelinqAssump
                    ,AssetDefaultedPerfAssumption
A.DummyDefaultAssump)
                   Maybe [RateAssumption]
mRates

  getCurrentBal :: Loan -> Recovery
getCurrentBal pl :: Loan
pl@(PersonalLoan (LoanOriginalInfo Recovery
ob RateType
or Int
ot Period
p Date
sd AmortPlan
ptype Maybe Obligor
_) Recovery
_bal IRate
_rate Int
_term Status
_ )
    = Recovery
_bal

  getOriginRate :: Loan -> IRate
getOriginRate pl :: Loan
pl@(PersonalLoan (LoanOriginalInfo Recovery
ob RateType
or Int
ot Period
p Date
sd AmortPlan
ptype Maybe Obligor
_) Recovery
_bal IRate
_rate Int
_term Status
_ )
    = case RateType
or of
        Fix DayCount
_ IRate
_r -> IRate
_r
        Floater DayCount
_ Index
_ IRate
_ IRate
_r DatePattern
_ RateFloor
_ RateFloor
_ Maybe (RoundingBy IRate)
_ -> IRate
_r 

  getCurrentRate :: Loan -> IRate
getCurrentRate pl :: Loan
pl@(PersonalLoan (LoanOriginalInfo Recovery
ob RateType
or Int
ot Period
p Date
sd AmortPlan
ptype Maybe Obligor
_) Recovery
_bal IRate
_rate Int
_term Status
_ )
    = IRate
_rate

  getOriginBal :: Loan -> Recovery
getOriginBal pl :: Loan
pl@(PersonalLoan (LoanOriginalInfo Recovery
ob RateType
_ Int
_ Period
_ Date
_ AmortPlan
_ Maybe Obligor
_) Recovery
_ IRate
_ Int
_ Status
_ ) = Recovery
ob

  isDefaulted :: Loan -> Bool
isDefaulted pl :: Loan
pl@(PersonalLoan OriginalInfo
_ Recovery
_ IRate
_ Int
_ (Defaulted Maybe Date
_)) = Bool
True
  isDefaulted PersonalLoan {} = Bool
False
 
  getOriginInfo :: Loan -> OriginalInfo
getOriginInfo (PersonalLoan OriginalInfo
oi Recovery
cb IRate
cr Int
rt Status
st) = OriginalInfo
oi
  getOriginDate :: Loan -> Date
getOriginDate (PersonalLoan (LoanOriginalInfo Recovery
ob RateType
or Int
ot Period
p Date
sd AmortPlan
I_P Maybe Obligor
_) Recovery
cb IRate
cr Int
rt Status
st ) = Date
sd
  
  resetToOrig :: Loan -> Loan
resetToOrig m :: Loan
m@(PersonalLoan (LoanOriginalInfo Recovery
ob RateType
or Int
ot Period
p Date
sd AmortPlan
I_P Maybe Obligor
obr) Recovery
cb IRate
cr Int
rt Status
st ) 
    = OriginalInfo -> Recovery -> IRate -> Int -> Status -> Loan
PersonalLoan (Recovery
-> RateType
-> Int
-> Period
-> Date
-> AmortPlan
-> Maybe Obligor
-> OriginalInfo
LoanOriginalInfo Recovery
ob RateType
or Int
ot Period
p Date
sd AmortPlan
I_P Maybe Obligor
obr) Recovery
ob (Loan -> IRate
forall a. Asset a => a -> IRate
getOriginRate Loan
m) Int
ot Status
st
  
  getRemainTerms :: Loan -> Int
getRemainTerms (PersonalLoan (LoanOriginalInfo Recovery
ob RateType
or Int
ot Period
p Date
sd AmortPlan
I_P Maybe Obligor
_) Recovery
cb IRate
cr Int
rt Status
st ) = Int
rt

  updateOriginDate :: Loan -> Date -> Loan
updateOriginDate (PersonalLoan (LoanOriginalInfo Recovery
ob RateType
or Int
ot Period
p Date
sd AmortPlan
I_P Maybe Obligor
obr) Recovery
cb IRate
cr Int
rt Status
st ) Date
nd
    = OriginalInfo -> Recovery -> IRate -> Int -> Status -> Loan
PersonalLoan (Recovery
-> RateType
-> Int
-> Period
-> Date
-> AmortPlan
-> Maybe Obligor
-> OriginalInfo
LoanOriginalInfo Recovery
ob RateType
or Int
ot Period
p Date
nd AmortPlan
I_P Maybe Obligor
obr) Recovery
cb IRate
cr Int
rt Status
st 

  getPaymentDates :: Loan -> Int -> Dates
getPaymentDates pl :: Loan
pl@(PersonalLoan (LoanOriginalInfo Recovery
ob RateType
_ Int
ot Period
p Date
sd (ScheduleRepayment Ts
ts Maybe DatePattern
mDp) Maybe Obligor
_) Recovery
_bal IRate
_rate Int
_term Status
_ ) Int
extra
    = let 
        pdays :: Dates
pdays = Ts -> Dates
getTsDates Ts
ts 
        extraDates :: Dates
extraDates = DatePattern -> CutoffType -> Date -> Int -> Dates
genSerialDates (DatePattern -> Maybe DatePattern -> DatePattern
forall a. a -> Maybe a -> a
fromMaybe DatePattern
MonthEnd Maybe DatePattern
mDp) CutoffType
Inc (Dates -> Date
forall a. HasCallStack => [a] -> a
last Dates
pdays) Int
extra
      in 
        Dates
pdays Dates -> Dates -> Dates
forall a. [a] -> [a] -> [a]
++ Dates
extraDates
  
  getPaymentDates pl :: Loan
pl@(PersonalLoan (LoanOriginalInfo Recovery
ob RateType
_ Int
ot Period
p Date
sd AmortPlan
_ Maybe Obligor
_) Recovery
_bal IRate
_rate Int
_term Status
_ )  Int
extra
    = Date -> Period -> Int -> Dates
genDates Date
sd Period
p (Int
otInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
extra)
  
  -- ^ Project cashflow for loans with prepayment/default/loss and interest rate assumptions
  projCashflow :: Loan
-> Date
-> AssetPerf
-> Maybe [RateAssumption]
-> Either String (CashFlowFrame, Map CutoffFields Recovery)
projCashflow pl :: Loan
pl@(PersonalLoan (LoanOriginalInfo Recovery
ob RateType
or Int
ot Period
p Date
sd AmortPlan
prinPayType Maybe Obligor
_) Recovery
cb IRate
cr Int
rt Status
Current) 
               Date
asOfDay 
               (A.LoanAssump Maybe AssetDefaultAssumption
defaultAssump Maybe AssetPrepayAssumption
prepayAssump Maybe RecoveryAssumption
recoveryAssump Maybe ExtraStress
ams,AssetDelinqPerfAssumption
_,AssetDefaultedPerfAssumption
_)
               Maybe [RateAssumption]
mRate 
    = let
        recoveryLag :: Int
recoveryLag = Int
-> (RecoveryAssumption -> Int) -> Maybe RecoveryAssumption -> Int
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Int
0 RecoveryAssumption -> Int
getRecoveryLag Maybe RecoveryAssumption
recoveryAssump
        Date
lastPayDate:Dates
cfDates = Int -> Dates -> Dates
forall a. Int -> [a] -> [a]
lastN (Int
rt Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
recoveryLag Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) (Dates -> Dates) -> Dates -> Dates
forall a b. (a -> b) -> a -> b
$ Date
sdDate -> Dates -> Dates
forall a. a -> [a] -> [a]
:Loan -> Int -> Dates
forall a. Asset a => a -> Int -> Dates
getPaymentDates Loan
pl Int
recoveryLag
      in
        do
          [IRate]
rateVector <- IRate
-> RateType
-> Maybe [RateAssumption]
-> Dates
-> Either String [IRate]
A.projRates IRate
cr RateType
or Maybe [RateAssumption]
mRate Dates
cfDates
          [Rational]
ppyRates <- Loan
-> Dates -> Maybe AssetPrepayAssumption -> Either String [Rational]
forall b.
Asset b =>
b
-> Dates -> Maybe AssetPrepayAssumption -> Either String [Rational]
A.buildPrepayRates Loan
pl (Date
lastPayDateDate -> Dates -> Dates
forall a. a -> [a] -> [a]
:Dates
cfDates) Maybe AssetPrepayAssumption
prepayAssump 
          [Rational]
defRates <- Loan
-> Dates
-> Maybe AssetDefaultAssumption
-> Either String [Rational]
forall b.
Asset b =>
b
-> Dates
-> Maybe AssetDefaultAssumption
-> Either String [Rational]
A.buildDefaultRates Loan
pl (Date
lastPayDateDate -> Dates -> Dates
forall a. a -> [a] -> [a]
:Dates
cfDates) Maybe AssetDefaultAssumption
defaultAssump
          let dc :: DayCount
dc = RateType -> DayCount
getDayCount RateType
or          
          let remainTerms :: [Int]
remainTerms = [Int] -> [Int]
forall a. [a] -> [a]
reverse ([Int] -> [Int]) -> [Int] -> [Int]
forall a b. (a -> b) -> a -> b
$ Int -> Int -> [Int]
forall a. Int -> a -> [a]
replicate Int
recoveryLag Int
0 [Int] -> [Int] -> [Int]
forall a. [a] -> [a] -> [a]
++ [Int
0..Int
rt] -- `debug` ("rateVector"++show rateVector)
          let initFactor :: Rational
initFactor = case AmortPlan
prinPayType of 
                         ScheduleRepayment Ts
ts Maybe DatePattern
_ -> 
                          let 
                            scheduleBals :: [Recovery]
scheduleBals = (Recovery -> Recovery -> Recovery)
-> Recovery -> [Recovery] -> [Recovery]
forall b a. (b -> a -> b) -> b -> [a] -> [b]
scanl (-) Recovery
ob ([Recovery] -> [Recovery]) -> [Recovery] -> [Recovery]
forall a b. (a -> b) -> a -> b
$ Rational -> Recovery
forall a. Fractional a => Rational -> a
fromRational (Rational -> Recovery) -> [Rational] -> [Recovery]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Ts -> [Rational]
getTsVals Ts
ts
                          in 
                            Recovery -> Recovery -> Rational
divideBB Recovery
cb ([Recovery]
scheduleBals[Recovery] -> Int -> Recovery
forall a. HasCallStack => [a] -> Int -> a
!!(Int
ot Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
rt))
                         AmortPlan
_ -> Rational
1.0  
          let ([TsRow]
txns,Rational
_) = ((Recovery, Int, IRate), Recovery, Date, AmortPlan, DayCount,
 IRate, Rational)
-> (Dates, [Rational], [Rational], [IRate], [Int])
-> ([TsRow], Rational)
projectLoanFlow ((Recovery
ob,Int
ot,Loan -> IRate
forall a. Asset a => a -> IRate
getOriginRate Loan
pl), Recovery
cb,Date
lastPayDate,AmortPlan
prinPayType,DayCount
dc,IRate
cr,Rational
initFactor) (Dates
cfDates,[Rational]
defRates,[Rational]
ppyRates,[IRate]
rateVector,[Int]
remainTerms)  -- `debug` (" rateVector"++show rateVector)
          let ([TsRow]
futureTxns,Map CutoffFields Recovery
historyM) = Date -> [TsRow] -> ([TsRow], Map CutoffFields Recovery)
CF.cutoffTrs Date
asOfDay ([TsRow] -> Maybe RecoveryAssumption -> [TsRow]
patchLossRecovery [TsRow]
txns Maybe RecoveryAssumption
recoveryAssump)
          let begBal :: Recovery
begBal = [TsRow] -> Recovery
CF.buildBegBal [TsRow]
futureTxns
          (CashFlowFrame, Map CutoffFields Recovery)
-> Either String (CashFlowFrame, Map CutoffFields Recovery)
forall a. a -> Either String a
forall (m :: * -> *) a. Monad m => a -> m a
return ((CashFlowFrame, Map CutoffFields Recovery)
 -> Either String (CashFlowFrame, Map CutoffFields Recovery))
-> (CashFlowFrame, Map CutoffFields Recovery)
-> Either String (CashFlowFrame, Map CutoffFields Recovery)
forall a b. (a -> b) -> a -> b
$ (Maybe ExtraStress -> CashFlowFrame -> CashFlowFrame
applyHaircut Maybe ExtraStress
ams (BeginStatus -> [TsRow] -> CashFlowFrame
CF.CashFlowFrame (Recovery
begBal,Date
asOfDay,Maybe Recovery
forall a. Maybe a
Nothing) [TsRow]
futureTxns), Map CutoffFields Recovery
historyM)
  -- ^ Project cashflow for defautled loans 
  projCashflow m :: Loan
m@(PersonalLoan (LoanOriginalInfo Recovery
ob RateType
or Int
ot Period
p Date
sd AmortPlan
prinPayType Maybe Obligor
_) Recovery
cb IRate
cr Int
rt (Defaulted (Just Date
defaultedDate))) 
               Date
asOfDay 
               (AssetPerfAssumption
_,AssetDelinqPerfAssumption
_,A.DefaultedRecovery Rational
rr Int
lag [Rational]
timing)
               Maybe [RateAssumption]
_
    = let 
        (Dates
cf_dates1,Dates
cf_dates2) = Int -> Dates -> (Dates, Dates)
forall a. Int -> [a] -> ([a], [a])
splitAt (Int -> Int
forall a. Enum a => a -> a
pred Int
lag) (Dates -> (Dates, Dates)) -> Dates -> (Dates, Dates)
forall a b. (a -> b) -> a -> b
$ Date -> Period -> Int -> Dates
genDates Date
defaultedDate Period
p (Int
lagInt -> Int -> Int
forall a. Num a => a -> a -> a
+ [Rational] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Rational]
timing)
        beforeRecoveryTxn :: [TsRow]
beforeRecoveryTxn = [  Date
-> Recovery
-> Recovery
-> Recovery
-> Recovery
-> Recovery
-> Recovery
-> Recovery
-> IRate
-> Maybe CumulativeStat
-> TsRow
CF.LoanFlow Date
d Recovery
cb Recovery
0 Recovery
0 Recovery
0 Recovery
0 Recovery
0 Recovery
0 IRate
cr Maybe CumulativeStat
forall a. Maybe a
Nothing| Date
d <- Dates
cf_dates1 ]
        recoveries :: [Recovery]
recoveries = Recovery -> Rational -> [Rational] -> [Recovery]
calcRecoveriesFromDefault Recovery
cb Rational
rr [Rational]
timing
        _txns :: [TsRow]
_txns = [  Date
-> Recovery
-> Recovery
-> Recovery
-> Recovery
-> Recovery
-> Recovery
-> Recovery
-> IRate
-> Maybe CumulativeStat
-> TsRow
CF.LoanFlow Date
d Recovery
0 Recovery
0 Recovery
0 Recovery
0 Recovery
0 Recovery
r Recovery
0 IRate
cr Maybe CumulativeStat
forall a. Maybe a
Nothing | (Date
d,Recovery
r) <- Dates -> [Recovery] -> [(Date, Recovery)]
forall a b. [a] -> [b] -> [(a, b)]
zip Dates
cf_dates2 [Recovery]
recoveries ]
        ([TsRow]
_, [TsRow]
txns) = [TsRow] -> Date -> SplitType -> ([TsRow], [TsRow])
forall a. TimeSeries a => [a] -> Date -> SplitType -> ([a], [a])
splitByDate ([TsRow]
beforeRecoveryTxn[TsRow] -> [TsRow] -> [TsRow]
forall a. [a] -> [a] -> [a]
++[TsRow]
_txns) Date
asOfDay SplitType
EqToRight -- `debug` ("AS OF Date"++show asOfDay)
        ([TsRow]
futureTxns,Map CutoffFields Recovery
historyM) = Date -> [TsRow] -> ([TsRow], Map CutoffFields Recovery)
CF.cutoffTrs Date
asOfDay [TsRow]
txns 
        begBal :: Recovery
begBal = [TsRow] -> Recovery
CF.buildBegBal [TsRow]
futureTxns
      in 
        (CashFlowFrame, Map CutoffFields Recovery)
-> Either String (CashFlowFrame, Map CutoffFields Recovery)
forall a b. b -> Either a b
Right ((CashFlowFrame, Map CutoffFields Recovery)
 -> Either String (CashFlowFrame, Map CutoffFields Recovery))
-> (CashFlowFrame, Map CutoffFields Recovery)
-> Either String (CashFlowFrame, Map CutoffFields Recovery)
forall a b. (a -> b) -> a -> b
$ (BeginStatus -> [TsRow] -> CashFlowFrame
CF.CashFlowFrame (Recovery
begBal,Date
asOfDay,Maybe Recovery
forall a. Maybe a
Nothing) [TsRow]
futureTxns, Map CutoffFields Recovery
historyM)

  projCashflow m :: Loan
m@(PersonalLoan (LoanOriginalInfo Recovery
ob RateType
or Int
ot Period
p Date
sd AmortPlan
prinPayType Maybe Obligor
_) Recovery
cb IRate
cr Int
rt (Defaulted Maybe Date
Nothing)) Date
asOfDay AssetPerf
assumps Maybe [RateAssumption]
_
    = (CashFlowFrame, Map CutoffFields Recovery)
-> Either String (CashFlowFrame, Map CutoffFields Recovery)
forall a b. b -> Either a b
Right ((CashFlowFrame, Map CutoffFields Recovery)
 -> Either String (CashFlowFrame, Map CutoffFields Recovery))
-> (CashFlowFrame, Map CutoffFields Recovery)
-> Either String (CashFlowFrame, Map CutoffFields Recovery)
forall a b. (a -> b) -> a -> b
$ (BeginStatus -> [TsRow] -> CashFlowFrame
CF.CashFlowFrame (Recovery
cb,Date
asOfDay,Maybe Recovery
forall a. Maybe a
Nothing) [Date
-> Recovery
-> Recovery
-> Recovery
-> Recovery
-> Recovery
-> Recovery
-> Recovery
-> IRate
-> Maybe CumulativeStat
-> TsRow
CF.LoanFlow Date
asOfDay Recovery
0 Recovery
0 Recovery
0 Recovery
0 Recovery
0 Recovery
0 Recovery
0 IRate
cr Maybe CumulativeStat
forall a. Maybe a
Nothing],Map CutoffFields Recovery
forall k a. Map k a
Map.empty)
  
  projCashflow Loan
a Date
b AssetPerf
c Maybe [RateAssumption]
d = String -> Either String (CashFlowFrame, Map CutoffFields Recovery)
forall a b. a -> Either a b
Left (String
 -> Either String (CashFlowFrame, Map CutoffFields Recovery))
-> String
-> Either String (CashFlowFrame, Map CutoffFields Recovery)
forall a b. (a -> b) -> a -> b
$ String
"failed to match projCashflow for Loan "String -> String -> String
forall a. [a] -> [a] -> [a]
++Loan -> String
forall a. Show a => a -> String
show Loan
aString -> String -> String
forall a. [a] -> [a] -> [a]
++Date -> String
forall a. Show a => a -> String
show Date
bString -> String -> String
forall a. [a] -> [a] -> [a]
++AssetPerf -> String
forall a. Show a => a -> String
show AssetPerf
cString -> String -> String
forall a. [a] -> [a] -> [a]
++Maybe [RateAssumption] -> String
forall a. Show a => a -> String
show Maybe [RateAssumption]
d
  
  splitWith :: Loan -> [Rational] -> [Loan]
splitWith l :: Loan
l@(PersonalLoan (LoanOriginalInfo Recovery
ob RateType
or Int
ot Period
p Date
sd AmortPlan
prinPayType Maybe Obligor
obr) Recovery
cb IRate
cr Int
rt Status
st) [Rational]
rs
    = [ OriginalInfo -> Recovery -> IRate -> Int -> Status -> Loan
PersonalLoan (Recovery
-> RateType
-> Int
-> Period
-> Date
-> AmortPlan
-> Maybe Obligor
-> OriginalInfo
LoanOriginalInfo (Recovery -> Rational -> Recovery
mulBR Recovery
ob Rational
ratio) RateType
or Int
ot Period
p Date
sd AmortPlan
prinPayType Maybe Obligor
obr) (Recovery -> Rational -> Recovery
mulBR Recovery
cb Rational
ratio) IRate
cr Int
rt Status
st | Rational
ratio <- [Rational]
rs ]