Skip to content

Commit

Permalink
0.29.x (#206)
Browse files Browse the repository at this point in the history
* Fix date issue
* add missing formula to queryDealRate
* enhance: no dup name in funding plan
* WIP: warehousing
* expose obligor field
* implement obligor tags/id
* obligor Int -> String
* expose obligor field map
* expose refince by rate
* expose endpoint for multi run for deal run assumption
* rebuild deal action if refinance bond is floater
* add check for bond group
* add validate rule for bond group action
* expose pool history stats
* expose ratio/avgRatio to date patch
  • Loading branch information
yellowbean authored Sep 20, 2024
1 parent 157d749 commit 3da607e
Show file tree
Hide file tree
Showing 28 changed files with 1,861 additions and 669 deletions.
3 changes: 3 additions & 0 deletions Hastructure.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ library
, base
, bytestring
, containers
, generic-lens
, hashable
, lens
, numeric-limits
Expand Down Expand Up @@ -113,6 +114,7 @@ executable Hastructure-exe
, bytestring
, containers
, exceptions
, generic-lens
, hashable
, http-types
, lens
Expand Down Expand Up @@ -175,6 +177,7 @@ test-suite Hastructure-test
, base
, bytestring
, containers
, generic-lens
, hashable
, lens
, numeric-limits
Expand Down
18 changes: 15 additions & 3 deletions app/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ $(deriveJSON defaultOptions ''Version)
instance ToSchema Version

version1 :: Version
version1 = Version "0.28.21"
version1 = Version "0.29.5"



Expand Down Expand Up @@ -197,9 +197,15 @@ instance ToSchema RV.RevolvingPool
instance ToSchema (TsPoint [AB.AssetUnion])
instance ToSchema AP.IssueBondEvent
instance ToSchema (TsPoint AP.IssueBondEvent)
instance ToSchema (TsPoint AP.RefiEvent)
instance ToSchema AP.RefiEvent
instance ToSchema AP.NonPerfAssumption
instance ToSchema AP.BondPricingInput
instance ToSchema AP.RevolvingAssumption
instance ToSchema AP.TagMatchRule
instance ToSchema RangeType
instance ToSchema AP.FieldMatchRule
instance ToSchema AP.ObligorStrategy
instance ToSchema AP.ApplyAssumptionType
instance ToSchema AP.AssetPerfAssumption
instance ToSchema AP.AssetDelinqPerfAssumption
Expand Down Expand Up @@ -339,7 +345,7 @@ type ScenarioName = String
data RunDealReq = SingleRunReq DealType (Maybe AP.ApplyAssumptionType) AP.NonPerfAssumption
| MultiScenarioRunReq DealType (Map.Map ScenarioName AP.ApplyAssumptionType) AP.NonPerfAssumption
| MultiDealRunReq (Map.Map ScenarioName DealType) (Maybe AP.ApplyAssumptionType) AP.NonPerfAssumption
| MultiScenarioAndCurveRunReq DealType (Map.Map ScenarioName AP.ApplyAssumptionType) AP.NonPerfAssumption
| MultiRunAssumpReq DealType (Maybe AP.ApplyAssumptionType) (Map.Map ScenarioName AP.NonPerfAssumption)
deriving(Show, Generic)

data RunSimDealReq = OASReq DealType (Map.Map ScenarioName AP.ApplyAssumptionType) AP.NonPerfAssumption
Expand Down Expand Up @@ -374,8 +380,8 @@ type EngineAPI = "version" :> Get '[JSON] Version
:<|> "runPoolByScenarios" :> ReqBody '[JSON] RunPoolReq :> Post '[JSON] (Map.Map ScenarioName PoolRunResp)
:<|> "runDeal" :> ReqBody '[JSON] RunDealReq :> Post '[JSON] RunResp
:<|> "runDealByScenarios" :> ReqBody '[JSON] RunDealReq :> Post '[JSON] (Map.Map ScenarioName RunResp)
-- :<|> "runDealOAS" :> ReqBody '[JSON] RunDealReq :> Post '[JSON] (Map.Map ScenarioName [PriceResult])
:<|> "runMultiDeals" :> ReqBody '[JSON] RunDealReq :> Post '[JSON] (Map.Map ScenarioName RunResp)
:<|> "runDealByRunScenarios" :> ReqBody '[JSON] RunDealReq :> Post '[JSON] (Map.Map ScenarioName RunResp)
:<|> "runDate" :> ReqBody '[JSON] RunDateReq :> Post '[JSON] [Date]

-- instance NFData [Date]
Expand Down Expand Up @@ -425,6 +431,11 @@ runDate (RunDateReq sd dp md) = return $
Nothing -> DU.genSerialDatesTill2 IE sd dp (Lib.toDate "20990101")
Just d -> DU.genSerialDatesTill2 IE sd dp d

runDealByRunScenarios :: RunDealReq -> Handler (Map.Map ScenarioName RunResp)
runDealByRunScenarios (MultiRunAssumpReq dt mAssump nonPerfAssumpMap)
= return $ Map.map (\singleAssump -> wrapRun dt mAssump singleAssump) nonPerfAssumpMap


myServer :: ServerT API Handler
myServer = return engineSwagger
:<|> showVersion
Expand All @@ -434,6 +445,7 @@ myServer = return engineSwagger
:<|> runDeal
:<|> runDealScenarios
:<|> runMultiDeals
:<|> runDealByRunScenarios
:<|> runDate
-- :<|> error "not implemented"

Expand Down
1 change: 1 addition & 0 deletions package.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ dependencies:
- hashable
- time
- lens
- generic-lens
- aeson
- aeson-pretty
- text
Expand Down
9 changes: 8 additions & 1 deletion src/Accounts.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
module Accounts (Account(..),ReserveAmount(..),draw,deposit
,transfer,depositInt,depositIntByCurve
,InterestInfo(..),buildEarnIntAction,updateReserveBalance
,accBalLens)
,accBalLens,tryDraw)
where
import qualified Data.Time as T
import Stmt (Statement(..),appendStmt,getTxnBegBalance,getDate
Expand Down Expand Up @@ -133,6 +133,13 @@ deposit amount d source acc@(Account bal _ _ _ maybeStmt) =
draw :: Amount -> Date -> TxnComment -> Account -> Account
draw amount = deposit (- amount)

-- | draw cash from account with a comment,return shortfall and acccount
tryDraw :: Amount -> Date -> TxnComment -> Account -> ((Amount,Amount),Account)
tryDraw amt d tc acc@(Account bal _ _ _ maybeStmt)
| amt > bal = ((amt - bal, bal), acc {accBalance = 0})
| otherwise = ((0, amt), draw amt d tc acc)


-- | change reserve target info of account
updateReserveBalance :: ReserveAmount -> Account -> Account
updateReserveBalance ra acc = acc {accType = Just ra}
Expand Down
49 changes: 46 additions & 3 deletions src/Asset.hs
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE FlexibleContexts #-}

module Asset ( Asset(..)
,calcPiFlow
,buildAssumptionPpyDefRecRate,buildAssumptionPpyDelinqDefRecRate
,calcRecoveriesFromDefault
,priceAsset,applyHaircut,buildPrepayRates,buildDefaultRates
,priceAsset,applyHaircut,buildPrepayRates,buildDefaultRates,getObligorFields
,getObligorTags,getObligorId
) where

import qualified Data.Time as T
Expand Down Expand Up @@ -37,15 +42,18 @@ import Types hiding (Current)
import Text.Printf
import Data.Fixed
import qualified InterestRate as IR
import qualified Data.Set as Set
import Util

import AssetClass.AssetBase ( OriginalInfo, calcPmt, AssetUnion )
import AssetClass.AssetBase ( OriginalInfo(..), calcPmt, AssetUnion, Obligor(..) )

import Debug.Trace
import Assumptions (ExtraStress(ExtraStress))

import Control.Lens hiding (element)
import Control.Lens.TH
import Data.Generics.Product.Fields
import Data.Generics.Product.Any
import DateUtil (yearCountFraction)


Expand Down Expand Up @@ -96,7 +104,42 @@ class (Show a,IR.UseRate a) => Asset a where
in
T.addDays offset $ getOriginDate ast


getObligor :: a -> Maybe Obligor
getObligor a =
case getOriginInfo a of
FixedAssetInfo {} -> Nothing
MortgageOriginalInfo{obligor = x } -> x
LoanOriginalInfo{obligor = x } -> x
LeaseInfo{obligor = x } -> x
ReceivableInfo{obligor = x } -> x

getObligorTags :: a -> Set.Set String
getObligorTags a =
case getOriginInfo a of
MortgageOriginalInfo{obligor = Just obr } -> Set.fromList (obligorTag obr)
LoanOriginalInfo{obligor = Just obr } -> Set.fromList (obligorTag obr)
LeaseInfo{obligor = Just obr } -> Set.fromList (obligorTag obr)
ReceivableInfo{obligor = Just obr } -> Set.fromList (obligorTag obr)
_ -> mempty

getObligorId :: a -> Maybe String
getObligorId a =
case getOriginInfo a of
MortgageOriginalInfo{obligor = Just obr } -> Just (obligorId obr)
LoanOriginalInfo{obligor = Just obr } -> Just (obligorId obr)
LeaseInfo{obligor = Just obr } -> Just (obligorId obr)
ReceivableInfo{obligor = Just obr } -> Just (obligorId obr)
_ -> Nothing

getObligorFields :: a -> Maybe (Map.Map String (Either String Double))
getObligorFields a =
let
obInfo = getObligor a
in
case obInfo of
Nothing -> Nothing
Just ob -> Just (obligorFields ob)

{-# MINIMAL calcCashflow,getCurrentBal,getOriginBal,getOriginRate #-}


Expand Down
30 changes: 20 additions & 10 deletions src/AssetClass/AssetBase.hs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ module AssetClass.AssetBase
,LeaseStepUp(..),AccrualPeriod(..),PrepayPenaltyType(..)
,AmortPlan(..),Loan(..),Mortgage(..),AssetUnion(..),MixedAsset(..),FixedAsset(..)
,AmortRule(..),Capacity(..),AssociateExp(..),AssociateIncome(..),ReceivableFeeType(..),Receivable(..)
,ProjectedCashflow(..)
,ProjectedCashflow(..),Obligor(..)
,calcAssetPrinInt, calcPmt
)
where
Expand All @@ -30,6 +30,8 @@ import qualified Data.Map as Map
import qualified InterestRate as IR
import qualified Cashflow as CF
-- import Assumptions (RevolvingAssumption(Dummy4))
import Control.Lens hiding (element,Index)
import Control.Lens.TH

import Debug.Trace (trace)
debug = flip Debug.Trace.trace
Expand Down Expand Up @@ -127,23 +129,31 @@ data ReceivableFeeType = FixedFee Balance -- ^ a flat fee amo
deriving (Show,Generic,Eq,Ord)


data Obligor = Obligor {obligorId :: String
, obligorTag :: [String]
, obligorFields :: Map.Map String (Either String Double)
} deriving (Show,Generic,Eq,Ord)

data OriginalInfo = MortgageOriginalInfo { originBalance :: Balance
,originRate :: IR.RateType
,originTerm :: Int
,period :: Period
,startDate :: Date
,prinType :: AmortPlan
,prepaymentPenalty :: Maybe PrepayPenaltyType }
,prepaymentPenalty :: Maybe PrepayPenaltyType
,obligor :: Maybe Obligor }
| LoanOriginalInfo { originBalance :: Balance
,originRate :: IR.RateType
,originTerm :: Int
,period :: Period
,startDate :: Date
,prinType :: AmortPlan }
,prinType :: AmortPlan
,obligor :: Maybe Obligor }
| LeaseInfo { startDate :: Date -- ^ lease start date
,originTerm :: Int -- ^ total terms
,paymentDates :: DatePattern -- ^ payment dates pattern
,originRental :: Amount} -- ^ rental by day
,originRental :: Amount -- ^ rental by day
,obligor :: Maybe Obligor }
| FixedAssetInfo { startDate :: Date
,originBalance :: Balance
,residualBalance :: Balance
Expand All @@ -155,7 +165,8 @@ data OriginalInfo = MortgageOriginalInfo { originBalance :: Balance
,originBalance :: Balance
,originAdvance :: Balance
,dueDate :: Date
,feeType :: Maybe ReceivableFeeType }
,feeType :: Maybe ReceivableFeeType
,obligor :: Maybe Obligor }
deriving (Show,Generic,Ord,Eq)


Expand Down Expand Up @@ -210,8 +221,6 @@ data Revolver = Heloc OriginalInfo LineOfCredit Balance IRate RemainTerms (Maybe
| DUMMY5
deriving (Show,Generic,Eq,Ord)



-- FixedAsset
data Capacity = FixedCapacity Balance
| CapacityByTerm [(Int,Balance)]
Expand Down Expand Up @@ -283,10 +292,12 @@ instance IR.UseRate ProjectedCashflow where
= Just $ (\(a,b,c) -> c) <$> fs


$(concat <$> traverse (deriveJSON defaultOptions) [''OriginalInfo, ''FixedAsset, ''AmortPlan, ''PrepayPenaltyType
$(concat <$> traverse (deriveJSON defaultOptions) [''Obligor, ''OriginalInfo, ''FixedAsset, ''AmortPlan, ''PrepayPenaltyType
, ''Capacity, ''AmortRule, ''ReceivableFeeType])


makePrisms ''OriginalInfo

$(deriveJSON defaultOptions ''AssociateExp)
$(deriveJSON defaultOptions ''AssociateIncome)
$(deriveJSON defaultOptions ''Status)
Expand All @@ -303,15 +314,14 @@ instance ToSchema AmortRule
instance ToSchema (Ratio Integer) where
declareNamedSchema _ = NamedSchema Nothing <$> declareSchema (Proxy :: Proxy Double)


instance ToSchema PrepayPenaltyType
instance ToSchema Ts
instance ToSchema (TsPoint Balance)
instance ToSchema (TsPoint IRate)
instance ToSchema (TsPoint Rational)
instance ToSchema (TsPoint Bool)
instance ToSchema (RoundingBy IRate)

instance ToSchema Obligor
instance ToSchema Index
instance ToSchema DayCount
instance ToSchema Direction
Expand Down
28 changes: 14 additions & 14 deletions src/AssetClass/Installment.hs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,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 _
calcCashflow inst@(Installment (LoanOriginalInfo ob or ot p sd ptype _) cb rt st) asOfDay _
= CF.CashFlowFrame (cb,asOfDay,Nothing) flows
where
lastPayDate:cf_dates = lastN (rt+1) $ sd:getPaymentDates inst 0
Expand Down Expand Up @@ -103,30 +103,30 @@ instance Asset Installment where

getCurrentBal (Installment _ b _ _ ) = b

getOriginBal (Installment (LoanOriginalInfo ob _ _ _ _ _) _ _ _) = ob
getOriginBal (Installment (LoanOriginalInfo ob _ _ _ _ _ _) _ _ _) = ob

getOriginRate (Installment (LoanOriginalInfo _ or _ _ _ _) _ _ _)
getOriginRate (Installment (LoanOriginalInfo _ or _ _ _ _ _) _ _ _)
= case or of
Fix _ _r -> _r
Floater _ _ _ _r _ _ _ _ -> _r

isDefaulted (Installment _ _ _ (Defaulted _)) = True
isDefaulted (Installment {}) = False

getPaymentDates (Installment (LoanOriginalInfo _ _ ot p sd _) _ _ _) extra
getPaymentDates (Installment (LoanOriginalInfo _ _ ot p sd _ _) _ _ _) extra
= genDates sd p (ot+extra)

getOriginDate (Installment (LoanOriginalInfo _ _ ot p sd _) _ _ _) = sd
getOriginDate (Installment (LoanOriginalInfo _ _ ot p sd _ _) _ _ _) = sd

getRemainTerms (Installment (LoanOriginalInfo _ _ ot p sd _) _ rt _) = rt
getRemainTerms (Installment (LoanOriginalInfo _ _ ot p sd _ _) _ rt _) = rt

updateOriginDate (Installment (LoanOriginalInfo ob or ot p sd _type) cb rt st) nd
= Installment (LoanOriginalInfo ob or ot p nd _type) cb rt st
updateOriginDate (Installment (LoanOriginalInfo ob or ot p sd _type _obligor) cb rt st) nd
= Installment (LoanOriginalInfo ob or ot p nd _type _obligor) cb rt st

resetToOrig (Installment (LoanOriginalInfo ob or ot p sd _type) cb rt st)
= Installment (LoanOriginalInfo ob or ot p sd _type) ob ot st
resetToOrig (Installment (LoanOriginalInfo ob or ot p sd _type _obligor) cb rt st)
= Installment (LoanOriginalInfo ob or ot p sd _type _obligor) ob ot st

projCashflow inst@(Installment (LoanOriginalInfo ob or ot p sd pt) cb rt Current)
projCashflow inst@(Installment (LoanOriginalInfo ob or ot p sd pt _) cb rt Current)
asOfDay
pAssump@(A.InstallmentAssump defaultAssump prepayAssump recoveryAssump ams,_,_)
mRates
Expand All @@ -152,7 +152,7 @@ instance Asset Installment where


-- ^ project with defaulted at a date
projCashflow inst@(Installment (LoanOriginalInfo ob or ot p sd ptype) cb rt (Defaulted (Just defaultedDate)))
projCashflow inst@(Installment (LoanOriginalInfo ob or ot p sd ptype _) cb rt (Defaulted (Just defaultedDate)))
asOfDay
(_,_,(A.DefaultedRecovery rr lag timing))
mRates
Expand All @@ -171,7 +171,7 @@ instance Asset Installment where
projCashflow inst@(Installment _ cb rt (Defaulted Nothing)) asOfDay assumps _
= (CF.CashFlowFrame (cb, asOfDay, Nothing) $ [CF.LoanFlow asOfDay cb 0 0 0 0 0 0 (getOriginRate inst) Nothing],Map.empty)

splitWith (Installment (LoanOriginalInfo ob or ot p sd _type) cb rt st) rs
= [ Installment (LoanOriginalInfo (mulBR ob ratio) or ot p sd _type) (mulBR cb ratio) rt st | ratio <- rs ]
splitWith (Installment (LoanOriginalInfo ob or ot p sd _type _obligor) cb rt st) rs
= [ Installment (LoanOriginalInfo (mulBR ob ratio) or ot p sd _type _obligor) (mulBR cb ratio) rt st | ratio <- rs ]


Loading

0 comments on commit 3da607e

Please sign in to comment.