Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
yellowbean committed Oct 26, 2023
2 parents 7776ddd + 3061906 commit f21a7c6
Show file tree
Hide file tree
Showing 19 changed files with 675 additions and 340 deletions.
1 change: 0 additions & 1 deletion .ghcid

This file was deleted.

11 changes: 10 additions & 1 deletion ChangeLog.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
# Changelog for Hastructure

## 0.22.1
### 2023-11-1



## 0.22.0
### 2023-10-15
* BREAK: cashflow now with `Cumulative Stats` ( cumulative default/delinq/loss/prepayment/principal/recovery)
* NEW: expose `inspect` in waterfall action to observe variables during a waterfall execution
* NEW: `stepup` now accpet a `pre` instead of a `date` to switch rate
* ENHANCE: auto patch `issuance balance` for `PreClosing` Deal
* ENHANCE: implement `pre-run check` and `post-run check`, patch check logs in result
* ENHANCE: implement `pre-run check` and `post-run check`
* IssuanceBalance check : `Ongoing Deal` shall have a IssuanceBalance value in Pool
* Interest Rate check : index required by deal should be found in assumption
* Waterfall action check : actions in waterfall ( source/target) should exist in deal object
* FIX: fix bug on `prepay penalty` when using `stepDown`
* FIX: fix project cashflow for `Loan`

## 0.21.5
### 2023-10-8
Expand Down
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,28 @@

# What is Hastructure ?

``Hastructure`` names after ``Haskell`` and ``Structured Finance``, aims to provide cashflow projection for deal/transactions describled in either Haskell structure or ``JSON`` via REST Service, with inputs:
``Hastructure`` names after ``Haskell`` and ``Structured Finance``, targets to provide cashflow projection for deal/transactions describled in either Haskell structure or ``JSON`` via RESTful Service, given inputs from below:

* deal components (bonds,assets,accounts,waterfall,trigger,fees etc.)
* pool performance prediction input as well as interest rate assumption
* pool performance assumption input as well as interest rate assumption

the engine will yields outputs:
``Hastructure`` will generate outputs:

* cashflow of bonds/accounts/fees
* pricing of bonds
* or other outputs make your lose all of the money faster :sunglasses:
* or other outputs make your lose money faster :sunglasses:

# Why Hastructure ?

* :bricks: A building block engine to model cashflows of structured product, all the formula and variables are exposed.
* :bricks: A collection of building blocks to build cashflows model for structured product. User just need to `compose` them together.
* :car: In-house and white-label friendly.
* :flags: No lock-in risk, all JSONs input/output, no proprietary file formats.

# I'm using language XXX

* :snake: [Python wrapper](https://github.com/yellowbean/PyABS) is in ``Beta`` now !
* :coffee: Easy integration with ``Java/C#/C++/JavaScript/Python`` with ``RESTful`` interface and Docker image are ready.
* C/Cpp wrapper : Working on this !
* Java : Just use JNI and call C Api
* C/Java : [here](https://github.com/yellowbean/Hastructure/issues/106)

### Features
* Integration
Expand Down Expand Up @@ -63,7 +62,8 @@ the engine will yields outputs:
* Base on Pool performance, like Cumulative Default Rate, last 3 periods delinquency rates.
* Base on any combination above
* Interest Swap
* Float to Float/ Fix to Float support
* Float to Float/ Fix to Float
* formula based notional balance
* Scenario Analysis
* Running multiple scenarios on single deal
* Pricing on single asset
Expand Down
27 changes: 0 additions & 27 deletions ghcid.txt

This file was deleted.

32 changes: 16 additions & 16 deletions src/Accounts.hs
Original file line number Diff line number Diff line change
Expand Up @@ -83,22 +83,22 @@ depositIntByCurve a@(Account bal _ (Just (InvestmentAccount idx spd lastCollectD
ed
= a {accBalance = newBal ,accStmt= newStmt ,accInterest = Just (InvestmentAccount idx spd ed dp)}
where
accruedInt = case stmt of
Nothing ->
let
curveDs = [lastCollectDate] ++ subDates EE lastCollectDate ed (getTsDates rc) ++ [ed]
curveVs = (\x -> toRational (getValByDate rc Exc x) + toRational spd) <$> init curveDs
dsFactor = getIntervalFactors curveDs
weightInt = sum $ zipWith (*) curveVs dsFactor -- `debug` ("ds"++show curve_ds++"vs"++show curve_vs++"factors"++show ds_factor)
in
mulBR bal weightInt
Just (Statement txns) ->
let
curveDs = [lastCollectDate] ++ subDates EE lastCollectDate ed (getTsDates rc) ++ [ed]
curveVs = (\x -> toRational (getValByDate rc Exc x) + toRational spd) <$> init curveDs
bals = weightAvgBalanceByDates curveDs txns
in
sum $ zipWith mulBR bals curveVs -- `debug` ("cds"++show curve_ds++"vs"++ show curve_vs++"bs"++show bals)
accruedInt = let
curveDs = [lastCollectDate] ++ subDates EE lastCollectDate ed (getTsDates rc) ++ [ed]
curveVs = (\x -> toRational (getValByDate rc Exc x) + toRational spd) <$> init curveDs
in
case stmt of
Nothing ->
let
dsFactor = getIntervalFactors curveDs
weightInt = sum $ zipWith (*) curveVs dsFactor -- `debug` ("ds"++show curve_ds++"vs"++show curve_vs++"factors"++show ds_factor)
in
mulBR bal weightInt
Just (Statement txns) ->
let
bals = weightAvgBalanceByDates curveDs txns
in
sum $ zipWith mulBR bals curveVs -- `debug` ("cds"++show curve_ds++"vs"++ show curve_vs++"bs"++show bals)

newBal = accruedInt + bal
newTxn = AccTxn ed newBal accruedInt BankInt
Expand Down
58 changes: 6 additions & 52 deletions src/Asset.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ module Asset (Pool(..),aggPool
,calcPiFlow,calc_p_i_flow_even,calc_p_i_flow_i_p
,buildAssumptionPpyDefRecRate,buildAssumptionPpyDelinqDefRecRate
,calcRecoveriesFromDefault
,priceAsset,applyHaircut
,priceAsset,applyHaircut,buildPrepayRates,buildDefaultRates
) where

import qualified Data.Time as T
Expand All @@ -23,6 +23,7 @@ import Lib (Period(..)
import qualified Cashflow as CF -- (Cashflow,Amount,Interests,Principals)
import qualified Assumptions as A
import qualified AssetClass.AssetBase as ACM
import AssetClass.AssetCashflow

import qualified Data.Map as Map
import Analytics
Expand Down Expand Up @@ -67,6 +68,8 @@ class (Show a,IR.UseRate a) => Asset a where
getRemainTerms :: a -> Int
-- | project asset cashflow under credit stress and interest assumptions
projCashflow :: a -> Date -> A.AssetPerf -> Maybe [RateAssumption] -> (CF.CashFlowFrame, Map.Map CutoffFields Balance)
-- | project cashflow under user input sequence
runCashflow :: a -> Date -> A.AssumpReceipes -> [RateAssumption] -> (CF.CashFlowFrame, Map.Map CutoffFields Balance)
-- | Get possible number of borrower
getBorrowerNum :: a -> Int
-- | Split asset per rates passed in
Expand Down Expand Up @@ -128,60 +131,12 @@ applyExtraStress (Just ExtraStress{A.defaultFactors= mDefFactor
,getTsVals $ multiplyTs Exc (zipTs ds def) defFactor)


-- | apply haircuts to cashflow from a stress map

applyHaircut :: Maybe A.ExtraStress -> CF.CashFlowFrame -> CF.CashFlowFrame
applyHaircut Nothing cf = cf
applyHaircut (Just ExtraStress{A.poolHairCut = Nothing}) cf = cf
applyHaircut (Just ExtraStress{A.poolHairCut = Just haircuts}) (CF.CashFlowFrame txns)
= CF.CashFlowFrame $
(\txn -> foldr
(\fn acc -> fn acc )
txn
(applyHaircutTxn <$> haircuts) ) <$> txns
where
applyHaircutTxn (CollectedInterest,r)
(CF.MortgageDelinqFlow d bal prin interest ppy delinq def recovery loss irate mbn mppn mst)
= CF.MortgageDelinqFlow d bal prin (mulBR interest (1-r)) ppy delinq def recovery loss irate mbn mppn mst
applyHaircutTxn (CollectedPrincipal,r)
(CF.MortgageDelinqFlow d bal prin interest ppy delinq def recovery loss irate mbn mppn mst)
= CF.MortgageDelinqFlow d bal (mulBR prin (1-r)) interest ppy delinq def recovery loss irate mbn mppn mst
applyHaircutTxn (CollectedRecoveries,r)
(CF.MortgageDelinqFlow d bal prin interest ppy delinq def recovery loss irate mbn mppn mst)
= CF.MortgageDelinqFlow d bal prin interest ppy delinq def (mulBR recovery (1-r)) loss irate mbn mppn mst
applyHaircutTxn (CollectedPrepayment,r)
(CF.MortgageDelinqFlow d bal prin interest ppy delinq def recovery loss irate mbn mppn mst)
= CF.MortgageDelinqFlow d bal prin interest (mulBR ppy (1-r)) delinq def recovery loss irate mbn mppn mst
applyHaircutTxn (CollectedPrepaymentPenalty,r)
(CF.MortgageDelinqFlow d bal prin interest ppy delinq def recovery loss irate mbn mppn mst)
= CF.MortgageDelinqFlow d bal prin interest ppy delinq def recovery loss irate mbn ((\x -> mulBR x (1-r) ) <$> mppn) mst

applyHaircutTxn (CollectedInterest,r)
(CF.MortgageFlow d bal prin interest ppy def recovery loss irate mbn mppn mst)
= CF.MortgageFlow d bal prin (mulBR interest (1-r)) ppy def recovery loss irate mbn mppn mst
applyHaircutTxn (CollectedPrincipal,r)
(CF.MortgageFlow d bal prin interest ppy def recovery loss irate mbn mppn mst)
= CF.MortgageFlow d bal (mulBR prin (1-r)) interest ppy def recovery loss irate mbn mppn mst
applyHaircutTxn (CollectedRecoveries,r)
(CF.MortgageFlow d bal prin interest ppy def recovery loss irate mbn mppn mst)
= CF.MortgageFlow d bal prin interest ppy def (mulBR recovery (1-r)) loss irate mbn mppn mst
applyHaircutTxn (CollectedPrepayment,r)
(CF.MortgageFlow d bal prin interest ppy def recovery loss irate mbn mppn mst)
= CF.MortgageFlow d bal prin interest (mulBR ppy (1-r)) def recovery loss irate mbn mppn mst
applyHaircutTxn (CollectedPrepaymentPenalty,r)
(CF.MortgageFlow d bal prin interest ppy def recovery loss irate mbn mppn mst)
= CF.MortgageFlow d bal prin interest ppy def recovery loss irate mbn ((\x -> mulBR x (1-r) ) <$> mppn) mst

applyHaircutTxn _ _ = error "Not implemented"


buildPrepayRates :: [Date] -> Maybe A.AssetPrepayAssumption -> [Rate]
buildPrepayRates ds Nothing = replicate (pred (length ds)) 0.0
buildPrepayRates ds mPa =
case mPa of
Just (A.PrepaymentConstant r) -> replicate size r
Just (A.PrepaymentCPR r) -> (map (Util.toPeriodRateByInterval r)
(getIntervalDays ds))
Just (A.PrepaymentCPR r) -> Util.toPeriodRateByInterval r <$> getIntervalDays ds
Just (A.PrepaymentVec vs) -> zipWith
Util.toPeriodRateByInterval
(paddingDefault 0.0 vs (pred size))
Expand All @@ -195,8 +150,7 @@ buildDefaultRates ds Nothing = replicate (pred (length ds)) 0.0
buildDefaultRates ds mDa =
case mDa of
Just (A.DefaultConstant r) -> replicate size r
Just (A.DefaultCDR r) -> (map (Util.toPeriodRateByInterval r)
(getIntervalDays ds))
Just (A.DefaultCDR r) -> Util.toPeriodRateByInterval r <$> getIntervalDays ds
Just (A.DefaultVec vs) -> zipWith
Util.toPeriodRateByInterval
(paddingDefault 0.0 vs (pred size))
Expand Down
Loading

0 comments on commit f21a7c6

Please sign in to comment.