Skip to content

Commit

Permalink
Pre 0.21.x (#90)
Browse files Browse the repository at this point in the history
* seperate assump by status
* deprecate on fee due on end of collection
* implement haircut
* add new query on deal status
* missing asset stats to pool level stats
* include missing-stats when project cashflow
* fix rate use
* fix rate adjust reset dates for bonds
* include st change on closing date
* fix query on origin pool balance logic
* create a new DateUtil ns
* Fix delinq cf back to performing status
* use current rate to start for fixed rate asset
* support mix of dlinq mortgage flow with mortgage flow
* update borrower num
* bump version to-> < 0.21.9 >

---------

Co-authored-by: yellowbean <always.zhang@gmail>
  • Loading branch information
yellowbean and yellowbean authored Oct 12, 2023
1 parent 3cb434e commit b8eba42
Show file tree
Hide file tree
Showing 48 changed files with 1,222 additions and 727 deletions.
1 change: 1 addition & 0 deletions .clj-kondo/.cache/v1/cljs/agency.config.transit.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
["^ ","~$debug?",["^ ","~:row",3,"~:col",1,"~:name","^0","~:ns","~$agency.config","~:top-ns","^5"],"~:filename","/Users/xiaoyu/Projects/absbox.work/agency/src/agency/config.cljs"]
1 change: 1 addition & 0 deletions .clj-kondo/.cache/v1/cljs/agency.core.transit.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
["^ ","~$dev-setup",["^ ","~:row",11,"~:col",1,"~:fixed-arities",["~#set",[0]],"~:name","^0","~:ns","~$agency.core","~:top-ns","^7","~:arities",["^ ","~i0",["^ ","~:ret",["^4",["~:nil"]],"~:arglist-str","[]"]],"~:type","~:fn"],"~$mount-root",["^ ","^1",15,"^2",1,"^3",["^4",[0]],"^5","^?","^6","^7","^8","^7","^=","^>"],"~$init",["^ ","^1",21,"^2",1,"^3",["^4",[0]],"^5","^@","^6","^7","^8","^7","^=","^>"],"~:filename","/Users/xiaoyu/Projects/absbox.work/agency/src/agency/core.cljs"]
1 change: 1 addition & 0 deletions .clj-kondo/.cache/v1/cljs/agency.db.transit.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
["^ ","~$default-db",["^ ","~:row",3,"~:col",1,"~:name","^0","~:ns","~$agency.db","~:top-ns","^5","~:type",["^ ","^7","~:map","~:val",["^ ","^3",["^ ","^1",4,"^2",10,"~:end-row",4,"~:end-col",20,"~:tag","~:string"]]]],"~:filename","/Users/xiaoyu/Projects/absbox.work/agency/src/agency/db.cljs"]
1 change: 1 addition & 0 deletions .clj-kondo/.cache/v1/cljs/agency.views.transit.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
["^ ","~$main-panel",["^ ","~:row",6,"~:col",1,"~:fixed-arities",["~#set",[0]],"~:name","^0","~:ns","~$agency.views","~:top-ns","^7","~:arities",["^ ","~i0",["^ ","~:ret","~:vector","~:arglist-str","[]"]],"~:type","~:fn"],"~:filename","/Users/xiaoyu/Projects/absbox.work/agency/src/agency/views.cljs"]
1 change: 1 addition & 0 deletions .clj-kondo/.cache/v1/cljs/structuring.views.transit.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
["^ ","~$get-values-from-list",["^ ","~:row",65,"~:col",1,"~:fixed-arities",["~#set",[1]],"~:name","^0","~:ns","~$structuring.views","~:top-ns","^7","~:arities",["^ ","~i1",["^ ","~:ret","~:seq","~:arglist-str","[x]"]],"~:type","~:fn"],"~$bond-editor",["^ ","^1",510,"^2",1,"^3",["^4",[1]],"^5","^?","^6","^7","^8","^7","^9",["^ ","~i1",["^ ","^:","~:vector","^<","[x]"]],"^=","^>"],"~$dropdown-options",["^ ","^1",19,"^2",1,"^3",["^4",[1,2]],"^5","^A","^6","^7","^8","^7","^9",["^ ","~i1",["^ ","^:","^@","^<","[xs]"],"~i2",["^ ","^:","^@","^<","[xs default]"]],"^=","^>"],"~$to-keywords",["^ ","^1",68,"^2",1,"^3",["^4",[1]],"^5","^B","^6","^7","^8","^7","^9",["^ ","~i1",["^ ","^:","^;","^<","[x]"]],"^=","^>"],"~$add-evt",["^ ","^1",108,"^2",1,"^3",["^4",[5]],"^5","^C","^6","^7","^8","^7","^=","^>"],"~$comp-call",["^ ","^1",480,"^2",1,"^3",["^4",[0]],"^5","^D","^6","^7","^8","^7","^=","^>"],"~$main-panel",["^ ","^1",626,"^2",1,"^3",["^4",[0]],"^5","^E","^6","^7","^8","^7","^9",["^ ","~i0",["^ ","^:","^@","^<","[]"]],"^=","^>"],"~$stmtView",["^ ","^1",587,"^2",1,"^3",["^4",[2]],"^5","^F","^6","^7","^8","^7","^=","^>"],"~$comp-pool",["^ ","^1",261,"^2",1,"^3",["^4",[1]],"^5","^G","^6","^7","^8","^7","^9",["^ ","~i1",["^ ","^:","^@","^<","[xs]"]],"^=","^>"],"~$wrap-on-change",["^ ","^1",71,"^2",1,"^3",["^4",[4]],"^5","^H","^6","^7","^8","^7","^=","^>"],"~$checkbox-shape?",["^ ","^1",60,"^2",1,"^3",["^4",[1]],"^5","^I","^6","^7","^8","^7","^=","^>"],"~$deal-run-result-comp",["^ ","^1",592,"^2",1,"^3",["^4",[0]],"^5","^J","^6","^7","^8","^7","^=","^>"],"~$comp-fees",["^ ","^1",282,"^2",1,"^3",["^4",[1]],"^5","^K","^6","^7","^8","^7","^9",["^ ","~i1",["^ ","^:","^@","^<","[xs]"]],"^=","^>"],"~$pool-editor",["^ ","^1",570,"^2",1,"^3",["^4",[1]],"^5","^L","^6","^7","^8","^7","^9",["^ ","~i1",["^ ","^:","^@","^<","[x]"]],"^=","^>"],"~$build-bond",["^ ","^3",["^4",[4]],"~:private",true,"^6","^7","^5","^M","^=","^>","^2",1,"^8","^7","^1",407],"~$render-notice",["^ ","^1",618,"^2",1,"^3",["^4",[1]],"^5","^O","^6","^7","^8","^7","^=","^>"],"~$palette",["^ ","^1",130,"^2",1,"^3",["^4",[1]],"^5","^P","^6","^7","^8","^7","^9",["^ ","~i1",["^ ","^:","^@","^<","[x]"]],"^=","^>"],"~:filename","/Users/xiaoyu/Projects/absbox.work/deal-bench/src/structuring/views.cljs","~$input-builder",["^ ","^1",183,"^2",1,"^3",["^4",[1]],"^5","^R","^6","^7","^8","^7","^=","^>"],"~$fee-editor",["^ ","^1",525,"^2",1,"^3",["^4",[1]],"^5","^S","^6","^7","^8","^7","^9",["^ ","~i1",["^ ","^:","^@","^<","[x]"]],"^=","^>"],"~$wrap-on-change2",["^ ","^1",47,"^2",1,"^3",["^4",[4]],"^5","^T","^6","^7","^8","^7","^9",["^ ","~i4",["^ ","^:","^@","^<","[tag evt-name params tf]"]],"^=","^>"],"~$comp-waterfall",["^ ","^1",343,"^2",1,"^3",["^4",[1]],"^5","^U","^6","^7","^8","^7","^9",["^ ","~i1",["^ ","^:","^@","^<","[xs]"]],"^=","^>"],"~$comp-bonds",["^ ","^1",422,"^2",1,"^3",["^4",[1]],"^5","^V","^6","^7","^8","^7","^9",["^ ","~i1",["^ ","^:","^@","^<","[xs]"]],"^=","^>"],"~$dispatch-to",["^ ","^1",125,"^2",1,"^3",["^4",[1]],"^5","^W","^6","^7","^8","^7","^9",["^ ","~i1",["^ ","^:","^>","^<","[dispatch-path]"]],"^=","^>"],"~$-build-input",["^ ","^1",489,"^2",1,"^3",["^4",[3]],"^5","^X","^6","^7","^8","^7","^=","^>"],"~$waterfall-editor",["^ ","^1",555,"^2",1,"^3",["^4",[1]],"^5","^Y","^6","^7","^8","^7","^9",["^ ","~i1",["^ ","^:","^@","^<","[x]"]],"^=","^>"],"~$checkbox-options",["^ ","^1",33,"^2",1,"^3",["^4",[1,2]],"^5","^Z","^6","^7","^8","^7","^9",["^ ","~i1",["^ ","^:","^@","^<","[xs]"],"~i2",["^ ","^:","^@","^<","[xs selected]"]],"^=","^>"],"~$account-editor",["^ ","^1",540,"^2",1,"^3",["^4",[1]],"^5","^[","^6","^7","^8","^7","^9",["^ ","~i1",["^ ","^:","^@","^<","[x]"]],"^=","^>"],"~$comp-options",["^ ","^1",459,"^2",1,"^3",["^4",[0]],"^5","^10","^6","^7","^8","^7","^=","^>"],"~$comp-accounts",["^ ","^1",306,"^2",1,"^3",["^4",[1]],"^5","^11","^6","^7","^8","^7","^9",["^ ","~i1",["^ ","^:","^@","^<","[xs]"]],"^=","^>"],"~$deal-edit",["^ ","^1",580,"^2",1,"^3",["^4",[1]],"^5","^12","^6","^7","^8","^7","^9",["^ ","~i1",["^ ","^:","^@","^<","[x]"]],"^=","^>"],"~$call-assump-comp",["^ ","^1",141,"^2",1,"^3",["^4",[2]],"^5","^13","^6","^7","^8","^7","^9",["^ ","~i2",["^ ","^:","^@","^<","[opts p]"]],"^=","^>"],"~$comp-assump",["^ ","^1",190,"^2",1,"^3",["^4",[0]],"^5","^14","^6","^7","^8","^7","^9",["^ ","~i0",["^ ","^:","^@","^<","[]"]],"^=","^>"],"~$comp-dates",["^ ","^1",170,"^2",1,"^3",["^4",[1]],"^5","^15","^6","^7","^8","^7","^=","^>"],"~$-convert",["^ ","^1",120,"^2",1,"^3",["^4",[1]],"^5","^16","^6","^7","^8","^7","^=","^>"]]
Empty file added .clj-kondo/.cache/v1/lock
Empty file.
1 change: 1 addition & 0 deletions .lsp/.cache/db.transit.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
["^ ","~:classpath",["~#set",[]],"~:project-hash","","~:project-root","/Users/xiaoyu/Projects/Hastructure","~:kondo-config-hash","8130318a7ed6c88a5f0fea1e88da4b97f2ce388a2115384ee7ff0112aa12c899","~:dependency-scheme","jar","~:analysis",null,"~:analysis-checksums",["^ "],"~:project-analysis-type","~:project-and-full-dependencies","~:version",11,"~:stubs-generation-namespaces",["^1",[]]]
14 changes: 13 additions & 1 deletion ChangeLog.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
# Changelog for Hastructure

## 0.21.5
### 2023-10-8
* ENHANCE: in the revolving buy , now buy amount is no longer a multipler of revolving assets face value
* FIX: now revolving asset may have remtain term == original term

## 0.21.4
### 2023-9-27
* ENHANCE: require a new status when defining a deal in `preClosing` stage
* FIX: fix a bug when reading financial report logs


## 0.21.3
### 2023-9-26
* NEW: include a default/delinq/loss status map when projecting cashflow
* NEW: include a `default`/`delinq`/`loss` status map when projecting cashflow
* NEW: implement `haircut` as extra stress projecting `mortgage`
* ENHANCE: include `called` deal status, which will be set when deal was triggered with a clean up call assumption
* ENHANCE: expose `runAsset` endpoint
* ENHANCE: expose formula query on `deal status` as well as `trigger status`
* ENHANCE: add `rampUp` deal status
* FIX: adjust bond reset date from `cutoff date` to `closing date`

## 0.21.1
Expand Down
1 change: 1 addition & 0 deletions Hastructure.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ library
Call
Cashflow
CreditEnhancement
DateUtil
Deal
Deal.DealAction
Deal.DealBase
Expand Down
36 changes: 36 additions & 0 deletions Hastructure.code-workspace
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"folders": [
{
"path": "."
},
{
"path": "../PyABS"
},
{
"path": "../pyabs-doc"
},
{
"path": "../absbox-doc"
},
{
"path": "../absbox.work"
},
{
"path": "../absbox.org"
}
],
"settings": {
"esbonio.sphinx.confDir": "",
"sqltools.connections": [
{
"previewLimit": 50,
"driver": "SQLite",
"name": "a",
"database": "${workspaceFolder:absbox.work}/data/chinabond/DB.db"
}
],
"files.exclude": {
"**/.ipynb": true
}
}
}
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
[![Actions Status](https://github.com/yellowbean/Hastructure/workflows/Haskell%20CI/badge.svg)](https://github.com/yellowbean/Hastructure/actions)
[![Docker Build](https://img.shields.io/docker/v/yellowbean/hastructure?color=green&label=docker)](https://hub.docker.com/r/yellowbean/hastructure)

# 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:

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

the engine will yields outputs:

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

# Why Hastructure ?
* :dollar: A structured finance cashflow engine written in Haskell
* :coffee: Easy integration with Java/C#/C++/JavaScript/Python with RESTful interface and Docker image ready
* :bricks: A building block engine to model cashflows of structured product, all the formula and variables are exposed.
* :car: In-house and white-label friendly.
* :flags: No lock-in risk, all JSONs input/output, no proprietary file formats.
* :snake: [Python wrapper](https://github.com/yellowbean/PyABS) on the way
* :snake: [Python wrapper](https://github.com/yellowbean/PyABS) is in ``Beta`` now !

### Features
* Integration
Expand Down
39 changes: 34 additions & 5 deletions app/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE OverloadedStrings #-}
module Main where
Expand All @@ -30,7 +31,7 @@ import qualified Data.Text as T
--import Data.Swagger
import Data.Maybe
import Data.Yaml as Y
import Data.OpenApi hiding (Server)
import Data.OpenApi hiding (Server,contentType)
import qualified Data.Map as Map
import Data.String.Conversions
import Data.Time.Calendar
Expand All @@ -41,14 +42,15 @@ import qualified Data.ByteString.Char8 as BS
import Lucid hiding (type_)
import Network.Wai
import Network.Wai.Handler.Warp
import Network.Wai.Middleware.Servant.Errors (errorMwDefJson, HasErrorBody(..))
import Network.Wai.Middleware.Servant.Errors (errorMw, HasErrorBody(..),errorMwDefJson)
import qualified Data.Aeson.Parser
import Language.Haskell.TH

--import Data.OpenApi hiding(Server)
import Servant.OpenApi
import Servant
import Servant.Types.SourceT (source)
import Servant.API.ContentTypes (contentType)

import Types
import qualified Deal as D
Expand Down Expand Up @@ -76,6 +78,7 @@ import qualified Triggers as TRG
import qualified Revolving as RV
import qualified Lib
import qualified Util as U
import qualified DateUtil as DU


import Debug.Trace
Expand All @@ -89,7 +92,7 @@ $(deriveJSON defaultOptions ''Version)
instance ToSchema Version

version1 :: Version
version1 = Version "0.21.3"
version1 = Version "0.21.9"

data PoolType = MPool (P.Pool AB.Mortgage)
| LPool (P.Pool AB.Loan)
Expand Down Expand Up @@ -331,15 +334,40 @@ myServer = return engineSwagger
runMultiDeals (MultiDealRunReq mDts assump nonPerfAssump)
= return $ Map.map (\singleDealType -> wrapRun singleDealType assump nonPerfAssump) mDts
runDate (RunDateReq sd dp)
= return $ U.genSerialDatesTill2 IE sd dp (Lib.toDate "20990101")
= return $ DU.genSerialDatesTill2 IE sd dp (Lib.toDate "20990101")


writeSwaggerJSON :: IO ()
writeSwaggerJSON = BL8.writeFile "swagger.json" (encodePretty engineSwagger)

data Config = Config { port :: Int} deriving (Show,Generic)
data Config = Config { port :: Int}
deriving (Show,Generic)

instance FromJSON Config

-- data Ctyp a
--
-- {-
-- if you are using GHC 8.6 and above you can make use of deriving Via
-- for creating the Accept Instance
--
-- >> data Ctyp a
-- >> deriving Accept via JSON
-- -}
--
-- instance Accept (Ctyp JSON) where
-- contentType _ = contentType (Proxy @JSON)
--
-- instance HasErrorBody (Ctyp JSON) '[] where
-- encodeError = undefined -- write your custom implementation
--
-- -- | Example Middleware with a different 'HasErrorBody' instance for JSON
-- errorMwJson :: Application -> Application
-- errorMwJson = errorMw @(Ctyp JSON) @'[]

--instance HasErrorBody (Ctyp JSON) '["error","warning","resp"] where
-- encodeError = error

main :: IO ()
main =
do
Expand All @@ -350,6 +378,7 @@ main =
Left exp -> Config 8081
Right c -> c
run _p
-- $ errorMwJson @JSON @'["error","warning","status"]
$ errorMwDefJson
$ serve (Proxy :: Proxy API) myServer

Expand Down
4 changes: 3 additions & 1 deletion config.yml
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
port: 8081
port: 8081
maxScenario : 10
maxDealNum : 10
27 changes: 27 additions & 0 deletions ghcid.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/Users/xiaoyu/Projects/Hastructure/src/AssetClass/Loan.hs:86:10-19: warning: [-Wmissing-methods]
• No explicit implementation for
‘getBorrowerNum’
• In the instance declaration for ‘Asset Loan’
|
86 | instance Asset Loan where
| ^^^^^^^^^^
/Users/xiaoyu/Projects/Hastructure/src/AssetClass/Lease.hs:166:10-20: warning: [-Wmissing-methods]
• No explicit implementation for
‘getBorrowerNum’
• In the instance declaration for ‘Asset Lease’
|
166 | instance Asset Lease where
| ^^^^^^^^^^^
/Users/xiaoyu/Projects/Hastructure/src/AssetClass/Installment.hs:102:10-26: warning: [-Wmissing-methods]
• No explicit implementation for
‘getBorrowerNum’
• In the instance declaration for ‘Asset Installment’
|
102 | instance Asset Installment where
| ^^^^^^^^^^^^^^^^^
/Users/xiaoyu/Projects/Hastructure/src/Deal.hs:966:10-64: warning: [-Woverlapping-patterns]
Pattern match is redundant
In a case alternative: _ -> ...
|
966 | _ -> error $ "Failed to match action on Date"++ show ad
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2 changes: 2 additions & 0 deletions publish.sh
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ fi
echo "<PUBLISH> Tagging"
git add app/Main.hs
git add swagger.json
git add Hastructure.cabal
git add ChangeLog.md
git commit -m "bump version to-> < $2 >"
git tag -a $1$2 -m "$3"

Expand Down
21 changes: 9 additions & 12 deletions src/Accounts.hs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import Stmt (Statement(..),appendStmt,Txn(..),getTxnBegBalance,getDate
import Types
import Lib
import Util
import DateUtil
import Data.Aeson hiding (json)
import Language.Haskell.TH
import Data.Aeson.TH
Expand All @@ -22,7 +23,7 @@ import Debug.Trace
debug = flip trace

data InterestInfo = BankAccount IRate Date DatePattern -- ^ fix reinvest return rate
| InvestmentAccount Index Spread Date DatePattern -- ^ float reinvest return rate
| InvestmentAccount Index Spread Date DatePattern -- ^ float reinvest return rate (index,spread, dp)
deriving (Show, Generic)

data ReserveAmount = PctReserve DealStats Rate -- ^ target amount with reference to % of formula
Expand Down Expand Up @@ -81,33 +82,29 @@ depositIntByCurve a@(Account bal _ (Just (InvestmentAccount idx spd lastCollectD
rc
ed
= a {accBalance = newBal
,accStmt= new_stmt
,accStmt= newStmt
,accInterest = Just (InvestmentAccount idx spd ed dp)}
where
accrued_int = case stmt of
accruedInt = case stmt of
Nothing ->
let
curve_ds = [lastCollectDate] ++ subDates EE lastCollectDate ed (getTsDates rc) ++ [ed]
curve_vs = map
(\x -> toRational (getValByDate rc Exc x) + toRational spd)
(init curve_ds)
curve_vs = (\x -> toRational (getValByDate rc Exc x) + toRational spd) <$> (init curve_ds)
ds_factor = getIntervalFactors curve_ds
weightInt = sum $ zipWith (*) curve_vs ds_factor -- `debug` ("ds"++show curve_ds++"vs"++show curve_vs++"factors"++show ds_factor)
in
mulBR bal weightInt
Just (Statement _txns) ->
let
curve_ds = [lastCollectDate] ++ subDates EE lastCollectDate ed (getTsDates rc) ++ [ed]
curve_vs = map
(\x -> toRational (getValByDate rc Exc x) + toRational spd)
(init curve_ds)
curve_vs = (\x -> toRational (getValByDate rc Exc x) + toRational spd) <$> (init curve_ds)
bals = weightAvgBalanceByDates curve_ds _txns
in
sum $ zipWith mulBR bals curve_vs -- `debug` ("cds"++show curve_ds++"vs"++ show curve_vs++"bs"++show bals)

newBal = accrued_int + bal
new_txn = AccTxn ed newBal accrued_int BankInt
new_stmt = appendStmt stmt new_txn
newBal = accruedInt + bal
newTxn = AccTxn ed newBal accruedInt BankInt
newStmt = appendStmt stmt newTxn


-- | move cash from account A to account B
Expand Down
1 change: 1 addition & 0 deletions src/Analytics.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ module Analytics (calcDuration,pv,calcWAL,pv2,pv3)
import Types
import Lib
import Util
import DateUtil
import Data.Aeson hiding (json)
import Language.Haskell.TH
import Data.Aeson.TH
Expand Down
Loading

0 comments on commit b8eba42

Please sign in to comment.