{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Analytics (calcConvexity,calcDuration,pv,calcWAL,pv2,pv3
,fv2,pv21,calcRequiredAmtForIrrAtDate,calcIRR
,calcSurvivorFactors)
where
import Types
import Lib
import Util
import DateUtil
import Data.Aeson hiding (json)
import Language.Haskell.TH
import Data.Aeson.TH
import Data.Aeson.Types
import GHC.Generics
import Data.Ratio
import Numeric.RootFinding
import Debug.Trace
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
calcSurvivorFactors :: Date -> [Date] -> Double -> [Double]
calcSurvivorFactors :: Date -> [Date] -> Double -> [Double]
calcSurvivorFactors Date
sd [Date]
ds Double
0 = Int -> Double -> [Double]
forall a. Int -> a -> [a]
replicate ([Date] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Date]
ds) Double
1.0
calcSurvivorFactors Date
sd [Date]
ds Double
survivalRate =
let
[Double]
yearFractions::[Double] = [ Integer -> Double
forall a b. (Real a, Fractional b) => a -> b
realToFrac (Date -> Date -> Integer
daysBetween Date
sd Date
d) Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
365.0 | Date
d <- [Date]
ds ]
factors :: [Double]
factors = [ (Double
1 Double -> Double -> Double
forall a. Num a => a -> a -> a
- Double
survivalRate) Double -> Double -> Double
forall a. Floating a => a -> a -> a
** Double
x | Double
x <- [Double]
yearFractions ]
in
[Double]
factors
calcWAL :: TimeHorizion -> Balance -> Date -> [(Balance,Date)] -> Balance
calcWAL :: TimeHorizion -> Amount -> Date -> [(Amount, Date)] -> Amount
calcWAL TimeHorizion
th Amount
bal Date
d [(Amount, Date)]
ps =
let
interval :: Integer
interval = case TimeHorizion
th of
TimeHorizion
ByYear -> Integer
365
TimeHorizion
ByMonth -> Integer
30
weightedAmts :: [Amount]
weightedAmts = [ Amount -> Rate -> Amount
mulBR Amount
futureAmt ((Date -> Date -> Integer
daysBetween Date
d Date
futureDate) Integer -> Integer -> Rate
forall a. Integral a => a -> a -> Ratio a
% Integer
interval) | (Amount
futureAmt,Date
futureDate) <- [(Amount, Date)]
ps ]
in
[Amount] -> Amount
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [Amount]
weightedAmts Amount -> Amount -> Amount
forall a. Fractional a => a -> a -> a
/ Amount
bal
calcDuration :: DayCount -> Date -> [(Date,Balance)] -> Ts -> Rate
calcDuration :: DayCount -> Date -> [(Date, Amount)] -> Ts -> Rate
calcDuration DayCount
dc Date
d [(Date, Amount)]
ps Ts
pricingCurve
= (((Date, Amount) -> Rate -> Rate)
-> Rate -> [(Date, Amount)] -> Rate
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (\(Date
_d,Amount
_b) Rate
acc ->
Rate -> Rate -> Rate
forall a. Num a => a -> a -> a
(*)
(Amount -> Amount -> Rate
divideBB (Ts -> Date -> Date -> Amount -> Amount
pv Ts
pricingCurve Date
d Date
_d Amount
_b) Amount
presentValue)
(DayCount -> Date -> Date -> Rate
yearCountFraction DayCount
dc Date
d Date
_d)
Rate -> Rate -> Rate
forall a. Num a => a -> a -> a
+ Rate
acc)
Rate
0.0000
[(Date, Amount)]
ps)
where
presentValue :: Amount
presentValue = [Amount] -> Amount
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [ Ts -> Date -> Date -> Amount -> Amount
pv Ts
pricingCurve Date
d Date
_d Amount
_b | (Date
_d,Amount
_b) <- [(Date, Amount)]
ps ]
calcConvexity :: DayCount -> Date -> [(Date,Balance)] -> Ts -> Rate
calcConvexity :: DayCount -> Date -> [(Date, Amount)] -> Ts -> Rate
calcConvexity DayCount
dc Date
d [(Date, Amount)]
ps Ts
pricingCurve
= Double -> Rate
forall a. Real a => a -> Rate
toRational (Double -> Rate) -> Double -> Rate
forall a b. (a -> b) -> a -> b
$
Double -> Double -> Double
forall a. Num a => a -> a -> a
(*)
Double
presentValue' (Double -> Double) -> Double -> Double
forall a b. (a -> b) -> a -> b
$
(((Double, Rate, Double) -> Double -> Double)
-> Double -> [(Double, Rate, Double)] -> Double
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (\(Double
_t,Rate
_c,Double
_f) Double
acc ->
(Double
_t Double -> Double -> Double
forall a. Num a => a -> a -> a
* (Double
_t Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
1) Double -> Double -> Double
forall a. Num a => a -> a -> a
* Rate -> Double
forall a. Fractional a => Rate -> a
fromRational Rate
_c) Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ ((Double
1.000 Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
_f) Double -> Double -> Double
forall a. Floating a => a -> a -> a
** (Double
_tDouble -> Double -> Double
forall a. Num a => a -> a -> a
+Double
2))
)
Double
0.0000
([Double] -> [Rate] -> [Double] -> [(Double, Rate, Double)]
forall a b c. [a] -> [b] -> [c] -> [(a, b, c)]
zip3 [Double]
ts [Rate]
payments [Double]
pvFactors))
where
[Double]
pvFactors::[Double] = Rate -> Double
forall a. Fractional a => Rate -> a
fromRational (Rate -> Double) -> (Date -> Rate) -> Date -> Double
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Ts -> CutoffType -> Date -> Rate
getValByDate Ts
pricingCurve CutoffType
Inc (Date -> Double)
-> ((Date, Amount) -> Date) -> (Date, Amount) -> Double
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Date, Amount) -> Date
forall a b. (a, b) -> a
fst ((Date, Amount) -> Double) -> [(Date, Amount)] -> [Double]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [(Date, Amount)]
ps
Double
presentValue'::Double = Double
1 Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ (Rate -> Double
forall a. Fractional a => Rate -> a
fromRational (Rate -> Double) -> (Amount -> Rate) -> Amount -> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Amount -> Rate
forall a. Real a => a -> Rate
toRational) ([Amount] -> Amount
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [ Ts -> Date -> Date -> Amount -> Amount
pv Ts
pricingCurve Date
d Date
_d Amount
_b | (Date
_d,Amount
_b) <- [(Date, Amount)]
ps ])
payments :: [Rate]
payments = Amount -> Rate
forall a. Real a => a -> Rate
toRational (Amount -> Rate)
-> ((Date, Amount) -> Amount) -> (Date, Amount) -> Rate
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Date, Amount) -> Amount
forall a b. (a, b) -> b
snd ((Date, Amount) -> Rate) -> [(Date, Amount)] -> [Rate]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [(Date, Amount)]
ps
[Double]
ts::[Double] = Rate -> Double
forall a. Fractional a => Rate -> a
fromRational (Rate -> Double) -> (Date -> Rate) -> Date -> Double
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> DayCount -> Date -> Date -> Rate
yearCountFraction DayCount
dc Date
d (Date -> Double)
-> ((Date, Amount) -> Date) -> (Date, Amount) -> Double
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Date, Amount) -> Date
forall a b. (a, b) -> a
fst ((Date, Amount) -> Double) -> [(Date, Amount)] -> [Double]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [(Date, Amount)]
ps
pv :: Ts -> Date -> Date -> Amount -> Amount
pv :: Ts -> Date -> Date -> Amount -> Amount
pv Ts
pc Date
today Date
d Amount
amt =
Double -> Amount
forall a b. (Real a, Fractional b) => a -> b
realToFrac (Double -> Amount) -> Double -> Amount
forall a b. (a -> b) -> a -> b
$ (Amount -> Double
forall a b. (Real a, Fractional b) => a -> b
realToFrac Amount
amt) Double -> Double -> Double
forall a. Num a => a -> a -> a
* (Double
1 Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
factor)
where
Double
distance::Double = Integer -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Integer -> Double) -> Integer -> Double
forall a b. (a -> b) -> a -> b
$ Date -> Date -> Integer
daysBetween Date
today Date
d
discount_rate :: Double
discount_rate = Rate -> Double
forall a. Fractional a => Rate -> a
fromRational (Rate -> Double) -> Rate -> Double
forall a b. (a -> b) -> a -> b
$ Ts -> CutoffType -> Date -> Rate
getValByDate Ts
pc CutoffType
Exc Date
d
Double
factor::Double = (Double
1 Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double -> Double
forall a b. (Real a, Fractional b) => a -> b
realToFrac Double
discount_rate) Double -> Double -> Double
forall a. Floating a => a -> a -> a
** (Double
distance Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
365)
pv2 :: IRate -> Date -> Date -> Amount -> Amount
pv2 :: IRate -> Date -> Date -> Amount -> Amount
pv2 IRate
discount_rate Date
today Date
d Amount
amt
| Date
today Date -> Date -> Bool
forall a. Eq a => a -> a -> Bool
== Date
d = Amount
amt
| Bool
otherwise
= Double -> Amount
forall a b. (Real a, Fractional b) => a -> b
realToFrac (Double -> Amount) -> Double -> Amount
forall a b. (a -> b) -> a -> b
$ (Amount -> Double
forall a b. (Real a, Fractional b) => a -> b
realToFrac Amount
amt) Double -> Double -> Double
forall a. Num a => a -> a -> a
* (Double
1Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/Double
denominator)
where
Double
denominator::Double = (Double
1 Double -> Double -> Double
forall a. Num a => a -> a -> a
+ IRate -> Double
forall a b. (Real a, Fractional b) => a -> b
realToFrac IRate
discount_rate) Double -> Double -> Double
forall a. Floating a => a -> a -> a
** (Double
distance Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
365)
Double
distance::Double = Integer -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Integer -> Double) -> Integer -> Double
forall a b. (a -> b) -> a -> b
$ Date -> Date -> Integer
daysBetween Date
today Date
d
pv21 :: IRate -> Date -> [Date] -> [Amount] -> Balance
pv21 :: IRate -> Date -> [Date] -> [Amount] -> Amount
pv21 IRate
r Date
d [Date]
ds [Amount]
vs = [Amount] -> Amount
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [ IRate -> Date -> Date -> Amount -> Amount
pv2 IRate
r Date
d Date
_d Amount
amt | (Date
_d,Amount
amt) <- [Date] -> [Amount] -> [(Date, Amount)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Date]
ds [Amount]
vs ]
pv2' :: Double -> Date -> Date -> Double -> Double
pv2' :: Double -> Date -> Date -> Double -> Double
pv2' Double
r Date
today Date
d Double
amt
| Double
amt Double -> Double -> Bool
forall a. Eq a => a -> a -> Bool
== Double
0 = Double
0
| Date
today Date -> Date -> Bool
forall a. Eq a => a -> a -> Bool
== Date
d = Double
amt
| Bool
otherwise
= Double
amt Double -> Double -> Double
forall a. Num a => a -> a -> a
* (Double
1Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/Double
denominator)
where
Double
denominator::Double = (Double
1 Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
r) Double -> Double -> Double
forall a. Floating a => a -> a -> a
** (Double
distance Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
365)
Double
distance::Double = Integer -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Integer -> Double) -> Integer -> Double
forall a b. (a -> b) -> a -> b
$ Date -> Date -> Integer
daysBetween Date
today Date
d
pv22 :: Double -> Date -> [Date] -> [Double] -> Double
pv22 :: Double -> Date -> [Date] -> [Double] -> Double
pv22 Double
r Date
d [Date]
ds [Double]
vs = [Double] -> Double
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [ Double -> Date -> Date -> Double -> Double
pv2' Double
r Date
d Date
_d Double
amt | (Date
_d,Double
amt) <- [Date] -> [Double] -> [(Date, Double)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Date]
ds [Double]
vs ]
pv3 :: Ts -> Date -> [Date] -> [Amount] -> Balance
pv3 :: Ts -> Date -> [Date] -> [Amount] -> Amount
pv3 Ts
pvCurve Date
pricingDate [Date]
ds [Amount]
vs
= let
rs :: [IRate]
rs = Rate -> IRate
forall a. Fractional a => Rate -> a
fromRational (Rate -> IRate) -> [Rate] -> [IRate]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Ts -> CutoffType -> [Date] -> [Rate]
getValByDates Ts
pvCurve CutoffType
Inc [Date]
ds
pvs :: [Amount]
pvs = [ IRate -> Date -> Date -> Amount -> Amount
pv2 IRate
r Date
pricingDate Date
d Amount
amt | (IRate
r,Date
d,Amount
amt) <- [IRate] -> [Date] -> [Amount] -> [(IRate, Date, Amount)]
forall a b c. [a] -> [b] -> [c] -> [(a, b, c)]
zip3 [IRate]
rs [Date]
ds [Amount]
vs ]
in
[Amount] -> Amount
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [Amount]
pvs
pv3' :: Ts -> Date -> [Date] -> [Amount] -> Balance
pv3' :: Ts -> Date -> [Date] -> [Amount] -> Amount
pv3' Ts
pvCurve Date
pricingDate [Date]
ds [Amount]
vs
= let
rs :: [Double]
rs = Rate -> Double
forall a. Fractional a => Rate -> a
fromRational (Rate -> Double) -> [Rate] -> [Double]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Ts -> CutoffType -> [Date] -> [Rate]
getValByDates Ts
pvCurve CutoffType
Inc [Date]
ds
vs' :: [Double]
vs' = (Rate -> Double
forall a. Fractional a => Rate -> a
fromRational (Rate -> Double) -> (Amount -> Rate) -> Amount -> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Amount -> Rate
forall a. Real a => a -> Rate
toRational) (Amount -> Double) -> [Amount] -> [Double]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Amount]
vs
pvs :: [Double]
pvs = [ Double -> Date -> Date -> Double -> Double
pv2' Double
r Date
pricingDate Date
d Double
amt | (Double
r,Date
d,Double
amt) <- [Double] -> [Date] -> [Double] -> [(Double, Date, Double)]
forall a b c. [a] -> [b] -> [c] -> [(a, b, c)]
zip3 [Double]
rs [Date]
ds [Double]
vs' ]
in
Rate -> Amount
forall a. Fractional a => Rate -> a
fromRational (Rate -> Amount) -> (Double -> Rate) -> Double -> Amount
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Double -> Rate
forall a. Real a => a -> Rate
toRational (Double -> Amount) -> Double -> Amount
forall a b. (a -> b) -> a -> b
$ (Double -> Double -> Double) -> Double -> [Double] -> Double
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr Double -> Double -> Double
forall a. Num a => a -> a -> a
(+) Double
0 [Double]
pvs
fv2 :: IRate -> Date -> Date -> Amount -> Amount
fv2 :: IRate -> Date -> Date -> Amount -> Amount
fv2 IRate
discount_rate Date
today Date
futureDay Amount
amt
= Double -> Amount
forall a b. (Real a, Fractional b) => a -> b
realToFrac (Double -> Amount) -> Double -> Amount
forall a b. (a -> b) -> a -> b
$ Amount -> Double
forall a b. (Real a, Fractional b) => a -> b
realToFrac Amount
amt Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
factor
where
Double
factor::Double = (Double
1 Double -> Double -> Double
forall a. Num a => a -> a -> a
+ IRate -> Double
forall a b. (Real a, Fractional b) => a -> b
realToFrac IRate
discount_rate) Double -> Double -> Double
forall a. Floating a => a -> a -> a
** (Double
distance Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
365)
Double
distance::Double = Integer -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Integer -> Double) -> Integer -> Double
forall a b. (a -> b) -> a -> b
$ Date -> Date -> Integer
daysBetween Date
today Date
futureDay
calcPvFromIRR :: Double -> [Date] -> [Amount] -> Date -> Double -> Double
calcPvFromIRR :: Double -> [Date] -> [Amount] -> Date -> Double -> Double
calcPvFromIRR Double
irr [] [Amount]
_ Date
d Double
amt = Double
0
calcPvFromIRR Double
irr [Date]
ds [Amount]
vs Date
d Double
amt =
let
begDate :: Date
begDate = [Date] -> Date
forall a. HasCallStack => [a] -> a
head [Date]
ds
vs' :: [Double]
vs' = Rate -> Double
forall a. Fractional a => Rate -> a
fromRational (Rate -> Double) -> (Amount -> Rate) -> Amount -> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Amount -> Rate
forall a. Real a => a -> Rate
toRational (Amount -> Double) -> [Amount] -> [Double]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Amount]
vs
pv :: Double
pv = Double -> Date -> [Date] -> [Double] -> Double
pv22 Double
irr Date
begDate ([Date]
ds[Date] -> [Date] -> [Date]
forall a. [a] -> [a] -> [a]
++[Date
d]) ([Double]
vs'[Double] -> [Double] -> [Double]
forall a. [a] -> [a] -> [a]
++[Double
amt])
in
(Rate -> Double
forall a. Fractional a => Rate -> a
fromRational (Rate -> Double) -> (Double -> Rate) -> Double -> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Double -> Rate
forall a. Real a => a -> Rate
toRational) Double
pv
calcRequiredAmtForIrrAtDate :: Double -> [Date] -> [Amount] -> Date -> Maybe Amount
calcRequiredAmtForIrrAtDate :: Double -> [Date] -> [Amount] -> Date -> Maybe Amount
calcRequiredAmtForIrrAtDate Double
irr [] [Amount]
_ Date
d = Maybe Amount
forall a. Maybe a
Nothing
calcRequiredAmtForIrrAtDate Double
irr [Date]
ds [Amount]
vs Date
d =
let
itertimes :: Int
itertimes = Int
500
def :: RiddersParam
def = RiddersParam { riddersMaxIter :: Int
riddersMaxIter = Int
itertimes, riddersTol :: Tolerance
riddersTol = Double -> Tolerance
RelTol Double
0.00000001}
in
case RiddersParam
-> (Double, Double) -> (Double -> Double) -> Root Double
ridders RiddersParam
def (Double
0.0001,Double
100000000000000) (Double -> [Date] -> [Amount] -> Date -> Double -> Double
calcPvFromIRR Double
irr [Date]
ds [Amount]
vs Date
d) of
Root Double
finalAmt -> Amount -> Maybe Amount
forall a. a -> Maybe a
Just (Rate -> Amount
forall a. Fractional a => Rate -> a
fromRational (Double -> Rate
forall a. Real a => a -> Rate
toRational Double
finalAmt))
Root Double
_ -> Maybe Amount
forall a. Maybe a
Nothing
calcIRR :: [Date] -> [Amount] -> Either String Rate
calcIRR :: [Date] -> [Amount] -> Either String Rate
calcIRR [Date]
_ [] = String -> Either String Rate
forall a b. a -> Either a b
Left String
"No cashflow amount"
calcIRR [] [Amount]
_ = String -> Either String Rate
forall a b. a -> Either a b
Left String
"No cashflow date"
calcIRR [Date]
ds [Amount]
vs
| (Amount -> Bool) -> [Amount] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Amount -> Amount -> Bool
forall a. Ord a => a -> a -> Bool
>= Amount
0) [Amount]
vs = String -> Either String Rate
forall a b. a -> Either a b
Left (String -> Either String Rate) -> String -> Either String Rate
forall a b. (a -> b) -> a -> b
$ String
"All cashflow can't be all positive:"String -> String -> String
forall a. [a] -> [a] -> [a]
++ [Amount] -> String
forall a. Show a => a -> String
show [Amount]
vs
| (Amount -> Bool) -> [Amount] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Amount -> Amount -> Bool
forall a. Ord a => a -> a -> Bool
<= Amount
0) [Amount]
vs = String -> Either String Rate
forall a b. a -> Either a b
Left (String -> Either String Rate) -> String -> Either String Rate
forall a b. (a -> b) -> a -> b
$ String
"All cashflow can't be all negative:"String -> String -> String
forall a. [a] -> [a] -> [a]
++ [Amount] -> String
forall a. Show a => a -> String
show [Amount]
vs
| (Amount -> Bool) -> [Amount] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Amount -> Amount -> Bool
forall a. Eq a => a -> a -> Bool
== Amount
0) [Amount]
vs = String -> Either String Rate
forall a b. a -> Either a b
Left String
"All cashflow can't be all zeros"
| Bool
otherwise =
let
itertimes :: Int
itertimes = Int
1000
def :: RiddersParam
def = RiddersParam { riddersMaxIter :: Int
riddersMaxIter = Int
itertimes, riddersTol :: Tolerance
riddersTol = Double -> Tolerance
RelTol Double
0.000001}
beginDate :: Date
beginDate = [Date] -> Date
forall a. HasCallStack => [a] -> a
head [Date]
ds
vs' :: [Double]
vs' = Rate -> Double
forall a. Fractional a => Rate -> a
fromRational (Rate -> Double) -> (Amount -> Rate) -> Amount -> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Amount -> Rate
forall a. Real a => a -> Rate
toRational (Amount -> Double) -> [Amount] -> [Double]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Amount]
vs
sumOfPv :: Double -> Double
sumOfPv Double
irr = Double -> Date -> [Date] -> [Double] -> Double
pv22 Double
irr Date
beginDate [Date]
ds [Double]
vs'
in
case RiddersParam
-> (Double, Double) -> (Double -> Double) -> Root Double
ridders RiddersParam
def (-Double
1,Double
1000) Double -> Double
sumOfPv of
Root Double
irrRate -> Rate -> Either String Rate
forall a b. b -> Either a b
Right (Rate -> Either String Rate) -> Rate -> Either String Rate
forall a b. (a -> b) -> a -> b
$ Double -> Rate
forall a. Real a => a -> Rate
toRational Double
irrRate
Root Double
NotBracketed -> String -> Either String Rate
forall a b. a -> Either a b
Left (String -> Either String Rate) -> String -> Either String Rate
forall a b. (a -> b) -> a -> b
$ String
"IRR: not bracketed" String -> String -> String
forall a. [a] -> [a] -> [a]
++ [Double] -> String
forall a. Show a => a -> String
show [Double]
vs' String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" and dates"String -> String -> String
forall a. [a] -> [a] -> [a]
++ [Date] -> String
forall a. Show a => a -> String
show [Date]
ds
Root Double
SearchFailed -> String -> Either String Rate
forall a b. a -> Either a b
Left (String -> Either String Rate) -> String -> Either String Rate
forall a b. (a -> b) -> a -> b
$ String
"IRR: search failed: can't be calculated with input "String -> String -> String
forall a. [a] -> [a] -> [a]
++ [Amount] -> String
forall a. Show a => a -> String
show [Amount]
vsString -> String -> String
forall a. [a] -> [a] -> [a]
++String
" and dates"String -> String -> String
forall a. [a] -> [a] -> [a]
++ [Date] -> String
forall a. Show a => a -> String
show [Date]
ds