packages feed

Hastructure-0.45.0: src/AssetClass/FixedAsset.hs

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

module AssetClass.FixedAsset
  ()
  where

import qualified Data.Time as T
import Data.Ratio

import Data.Aeson hiding (json)
import Language.Haskell.TH
import Data.Maybe
import Data.List
import Data.Aeson.TH
import qualified Data.Map as Map
import Data.Aeson.Types
import GHC.Generics

import qualified Assumptions as A
import Types hiding (startDate)
import Lib
import Util
import DateUtil
import qualified Cashflow as CF

import AssetClass.AssetBase


import Debug.Trace
import AssetClass.AssetCashflow
import qualified Asset as Ast
import Asset (Asset(projCashflow))
import Assumptions (AssetDelinqPerfAssumption(DummyDelinqAssump))
debug = flip trace


-- life time schedule amortization amount list
calcAmortAmt ::FixedAsset -> Either String [Balance]
calcAmortAmt fa@(FixedAsset fai@FixedAssetInfo{originBalance=ob, accRule=ar, originTerm=ot
                                               ,residualBalance=rb ,capacity=cap} b rt)
  = case ar of
      StraightLine -> Right $ replicate ot $ divideBI (b-rb) rt
      DecliningBalance -> 
        let 
          amortizeRate = realToFrac $ 2 % ot
          futureBals' = scaleByFstElement b $ lastN (succ rt) $ scanl (\acc r -> acc * (1 - r)) ob (replicate ot amortizeRate)
          -- straigh lines
          futureBals'' = scanl 
                          (\acc (bal',amt',rt') ->
                            (acc - (max amt' (divideBI (acc - rb) (rt - rt'))))
                           )
                          (head futureBals')
                          (zip3 futureBals' (diffNum futureBals') [0..succ rt])
        in 
          Right (diffNum futureBals'')

      _ -> Left ("Not implemented for depreciation rule"++show ar)
 
calcAmortBals ::FixedAsset -> Either String [Balance]
calcAmortBals fa@(FixedAsset fai@FixedAssetInfo{originBalance=ob, accRule=ar, originTerm=ot
                                               ,residualBalance=rb ,capacity=cap} b rt)
  = do 
      bals <- calcAmortAmt fa
      return $ scanl (-) ob bals
 

instance Ast.Asset FixedAsset where 

  calcCashflow fa@(FixedAsset {}) asOfDay _ = 
     fst <$> projCashflow fa asOfDay (A.FixedAssetAssump (mkTs []) (mkTs []) Nothing, A.DummyDelinqAssump, A.DummyDefaultAssump) Nothing

  getCurrentBal  fa@(FixedAsset fai@FixedAssetInfo{originBalance=ob, accRule=ar, originTerm=ot
                                                 ,residualBalance=rb ,capacity=cap} curBal rt) 
    = curBal

  resetToOrig fa@(FixedAsset fai@FixedAssetInfo{originBalance=ob, accRule=ar, originTerm=ot
                                                 ,residualBalance=rb ,capacity=cap} b rt) 
    = FixedAsset fai b ot
  
  getPaymentDates 
    (FixedAsset fo@FixedAssetInfo{startDate=sd ,period=p,originTerm=ot} _ rt)
    extra
    = genDates sd p (ot+extra)

  projCashflow fa@(FixedAsset fai@FixedAssetInfo{originBalance=ob, accRule=ar, originTerm=ot
                                                 ,residualBalance=rb ,capacity=cap} curBalance rt) 
               asOfDay
               (A.FixedAssetAssump uCurve pCurve mExtPeriods,_,_)
               _
    = let 
        extPeriods = fromMaybe 0 mExtPeriods
        cfLength =  rt + extPeriods
        pdates = lastN cfLength $ Ast.getPaymentDates fa extPeriods
        capacityCaps = case cap of
                        FixedCapacity b -> replicate cfLength b
                        CapacityByTerm tbl -> lastN cfLength $ concat [ replicate i b | (i,b)  <- tbl ] ++ (replicate extPeriods (snd (last tbl)))

        utilsVec = getValByDates uCurve Inc pdates
        units = [ mulBR c u | (u,c) <- zip utilsVec capacityCaps]
        prices = getValByDates pCurve Inc pdates
        cash = [ mulBR u p | (p,u) <- zip prices units]
      in 
        do 
          scheduleAmt <- calcAmortAmt fa 
          let amortizedBals = lastN cfLength $ scheduleAmt ++ replicate extPeriods 0 
          let scheduleBals = tail $ scanl (-) curBalance (amortizedBals ++ [0])
          let cumuDep = ob - curBalance
          let cumuDepreciation = tail $ scanl (+) cumuDep amortizedBals 
          let txns = zipWith6 CF.FixedFlow pdates scheduleBals amortizedBals cumuDepreciation units cash
          let futureTxns = cutBy Inc Future asOfDay txns
          let begBal = CF.buildBegBal futureTxns
          return $ (CF.CashFlowFrame (begBal,asOfDay,Nothing) $ futureTxns, Map.empty)