Hastructure 0.45.3 → 0.50.0
raw patch · 6 files changed
+34/−21 lines, 6 filesdep ~basedep ~lensdep ~template-haskellPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: base, lens, template-haskell
API changes (from Hackage documentation)
Files
- CHANGELOG.md +10/−0
- Hastructure.cabal +4/−4
- app/Main.hs +1/−1
- src/Cashflow.hs +8/−8
- src/Deal.hs +9/−6
- src/Deal/DealAction.hs +2/−2
CHANGELOG.md view
@@ -2,6 +2,16 @@ <!-- towncrier release notes start --> +## 0.50.0+### 2025-07-14+* NEW: add `stopBy` in run assumption ,which stop deal run by a list of `Condition`+* NEW: expose `asset level` cashflow ,with a toggle+* NEW: expose `Un-Used Pool cashflow`+* ENHANCE: parameterized the `tweaks`+* ENHANCE: update dependency to accomodate publishment to `Hackage`+* FIX: enable `Lease` deal for `Financial reports`++ ## 0.46.4 ### 2025-06-10 * ENHANCE: add error message when calculation IRR for bond with non cashflow
Hastructure.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: Hastructure-version: 0.45.3+version: 0.50.0 synopsis: Cashflow modeling library for structured finance description: Please see the README on GitHub at <https://github.com/yellowbean/Hastructure#readme> category: StructuredFinance,Securitisation,Cashflow@@ -76,11 +76,11 @@ src build-depends: Decimal >= 0.5.2 && < 0.6,- base >= 4.18.0 && < 4.20,+ base >= 4.18.0 && < 4.21, deepseq >= 1.5.1 && < 1.6, MissingH >= 1.6.0 && < 1.7, containers >= 0.6.8 && < 0.7,- template-haskell >= 2.20.0 && < 2.22,+ template-haskell >= 2.20.0 && < 2.21.1.0, bytestring >= 0.12.1 && < 0.13, exceptions >= 0.10.7 && < 0.11, mtl >= 2.3.1 && < 2.4,@@ -99,7 +99,7 @@ generic-lens >= 2.2.2 && < 2.3, http-types >= 0.12.4 && < 0.13, ieee754 >= 0.8.0 && < 0.9,- lens >= 5.2.3 && < 5.3.5,+ lens >= 5.2.3 && < 5.3.6, parallel >= 3.2.2 && < 3.3, math-functions >= 0.3.4 && < 0.4, monad-loops >= 0.4.3 && < 0.5,
app/Main.hs view
@@ -104,7 +104,7 @@ version1 :: Version -version1 = Version "0.46.4"+version1 = Version "0.50.0" wrapRun :: [D.ExpectReturn] -> DealType -> Maybe AP.ApplyAssumptionType -> AP.NonPerfAssumption -> RunResp
src/Cashflow.hs view
@@ -25,10 +25,10 @@ ,mergeCf,buildStartTsRow ,txnCumulativeStats,consolidateCashFlow, cfBeginStatus, getBegBalCashFlowFrame ,splitCashFlowFrameByDate, mergePoolCf2, buildBegBal, extendCashFlow, patchBalance- ,splitPoolCashflowByDate+ ,splitPoolCashflowByDate ,getAllDatesCashFlowFrame,splitCf, cutoffCashflow- ,AssetCashflow,PoolCashflow- ,emptyCashflow,isEmptyRow2+ ,AssetCashflow,PoolCashflow+ ,emptyCashflow,isEmptyRow2 ) where import Data.Time (Day)@@ -269,23 +269,23 @@ (ls,rs) = splitByDate txns d st newStatus = case rs of [] -> (0, d, Nothing)- (r:_) -> (mflowBegBalance r, d, Nothing)+ (r:_) -> (buildBegBal rs, d, Nothing) in (CashFlowFrame status ls,CashFlowFrame newStatus rs) + splitPoolCashflowByDate :: PoolCashflow -> Date -> SplitType -> (PoolCashflow,PoolCashflow) splitPoolCashflowByDate (poolCF, mAssetCfs) d st = let (lPoolCF,rPoolCF) = splitCashFlowFrameByDate poolCF d st mAssetSplited = (\xs -> [ splitCashFlowFrameByDate x d st | x <- xs ]) <$> mAssetCfs assetCfs = (\xs -> [ (lCf, rCf) | (lCf,rCf) <- xs ]) <$> mAssetSplited - lAssetCfs = (\xs -> fst <$> xs ) <$> assetCfs- rAssetCfs = (\xs -> snd <$> xs ) <$> assetCfs+ lAssetCfs = (fst <$>) <$> assetCfs+ rAssetCfs = (snd <$>) <$> assetCfs in ((lPoolCF, lAssetCfs) , (rPoolCF, rAssetCfs)) - getTxnLatestAsOf :: CashFlowFrame -> Date -> Maybe TsRow getTxnLatestAsOf (CashFlowFrame _ txn) d = L.find (\x -> getDate x <= d) $ reverse txn @@ -425,7 +425,7 @@ buildBegBal :: [TsRow] -> Balance buildBegBal [] = 0-buildBegBal (x:_) = mflowBegBalance x+buildBegBal (x:xs) = mflowBegBalance x sumTs :: [TsRow] -> Date -> TsRow
src/Deal.hs view
@@ -1020,15 +1020,16 @@ let poolFlowUsedNoEmpty = Map.map (over CF.cashflowTxn CF.dropTailEmptyTxns) (getAllCollectedFrame finalDeal Nothing)+ let poolFlowUnUsed = osPoolFlow & mapped . _1 . CF.cashflowTxn %~ CF.dropTailEmptyTxns+ & mapped . _2 . _Just . each . CF.cashflowTxn %~ CF.dropTailEmptyTxns bndPricing <- case mPricing of (Just p) -> priceBonds finalDeal p Nothing -> Right Map.empty return (finalDeal , poolFlowUsedNoEmpty- , getRunResult finalDeal ++ V.validateRun finalDeal ++ DL.toList (DL.append logs (unCollectedPoolFlowWarning osPoolFlow))+ , getRunResult finalDeal ++ V.validateRun finalDeal ++ DL.toList (DL.append logs (unCollectedPoolFlowWarning poolFlowUnUsed)) , bndPricing- , osPoolFlow & mapped . _1 . CF.cashflowTxn %~ CF.dropTailEmptyTxns- & mapped . _2 . _Just . each . CF.cashflowTxn %~ CF.dropTailEmptyTxns+ , poolFlowUnUsed ) -- `debug` ("run deal done with pool" ++ show poolFlowUsedNoEmpty) where (runFlag, valLogs) = V.validateReq t nonPerfAssumps @@ -1038,9 +1039,11 @@ Nothing -> Nothing Just (AP.AvailableAssets rp rperf) -> Just (Map.fromList [("Consol", (rp, rperf))]) Just (AP.AvailableAssetsBy rMap) -> Just rMap- -- TODO: need to add warning if uncollected pool flow is not empty- unCollectedPoolFlowWarning pMap = if sum (Map.elems (Map.map (CF.sizeCashFlowFrame . view _1) pMap)) > 0 then - DL.singleton $ WarningMsg "Oustanding pool cashflow hasn't been collected yet"+ unCollectedPoolFlowWarning pMap = let+ countMap = Map.map (CF.sizeCashFlowFrame . view _1) pMap + in + if sum (Map.elems countMap) > 0 then + DL.singleton $ WarningMsg $ "Oustanding pool cashflow hasn't been collected yet"++ show countMap else DL.empty
src/Deal/DealAction.hs view
@@ -573,7 +573,7 @@ boughtCfDates = getDate <$> view CF.cashflowTxn cfBought newAggDates = case (dsInterval,boughtCfDates) of ([],[]) -> []- (_,[]) -> [] -- `debug` ("hit with non cash date from bought"++ show dsInterval) + (_,[]) -> [] ([],_) -> boughtCfDates (oDs,bDs) -> let @@ -584,7 +584,7 @@ [] else sliceDates (SliceAfter lastOdate) bDs-+ -- TODO: the cfOrigin may not have correct beg balance ,which doesn't match all the amortization of cashflow txn mergedCf = CF.mergePoolCf2 cfOrigin cfBought in ((over CF.cashflowTxn (`CF.aggTsByDates` (dsInterval ++ newAggDates)) mergedCf), (++ [cfBought]) <$> mAflow)