From 31ac79dd8832c851a87cc2c15279343749582e5c Mon Sep 17 00:00:00 2001 From: Xiaoyu Date: Sun, 30 Jun 2024 19:59:08 +0800 Subject: [PATCH] enable query --- ChangeLog.md | 6 ++++-- src/Deal/DealAction.hs | 4 +++- src/Deal/DealQuery.hs | 20 +++++++++++++++++--- src/Liability.hs | 3 ++- src/Util.hs | 5 +++++ swagger.json | 2 +- 6 files changed, 32 insertions(+), 8 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index ed4cd3d0..4435f74a 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,13 +1,15 @@ # Changelog for Hastructure -## 0.28.11 +## 0.28.13 ### 2024-06-30 * NEW: new assumption `issue bond` which allow funding by issuing new bonds during cashflow projection. -* FIX: `formula` will return `inf` if a `divide` with zero instead of just throw exception * NEW: new asset class `projectScheduleFlow` which can be divided projected cashflow with fix portion and float portions. The interest from the float portion will be affected by interest rate assumption. +* ENHANCE: enable formula `bondRate`/`bondWaRate` on `bondGroup` +* FIX: `formula` will return `inf` if a `divide` with zero instead of just throw exception * FIX: `financial reports` was failing because it can't access to `interest due` on bond group. * FIX: enable formula query on `bond groups` + ## 0.28.8 ### 2024-06 * FIX: `limit` on `payFee` was not working with `duePct` diff --git a/src/Deal/DealAction.hs b/src/Deal/DealAction.hs index 64de7a6d..7bd4345f 100644 --- a/src/Deal/DealAction.hs +++ b/src/Deal/DealAction.hs @@ -344,6 +344,7 @@ calcDueInt t calc_date mBal mRate b@(L.Bond bn bt bo bi _ bond_bal bond_rate _ i calcDuePrin :: Ast.Asset a => TestDeal a -> T.Day -> L.Bond -> L.Bond +calcDuePrin t calc_date b@(L.BondGroup bMap) = L.BondGroup $ Map.map (calcDuePrin t calc_date) bMap calcDuePrin t calc_date b@(L.Bond _ L.Sequential _ _ _ bondBal _ _ _ _ _ _ _ _) = b {L.bndDuePrin = bondBal } @@ -393,6 +394,7 @@ priceAssetUnion (ACM.LO m) d pm aps = Ast.priceAsset m d pm aps priceAssetUnion (ACM.IL m) d pm aps = Ast.priceAsset m d pm aps priceAssetUnion (ACM.LS m) d pm aps = Ast.priceAsset m d pm aps priceAssetUnion (ACM.RE m) d pm aps = Ast.priceAsset m d pm aps +priceAssetUnion (ACM.PF m) d pm aps = Ast.priceAsset m d pm aps priceAssetUnionList :: [ACM.AssetUnion] -> Date -> PricingMethod -> AP.ApplyAssumptionType -> Maybe [RateAssumption] -> [PriceResult] priceAssetUnionList assetList d pm (AP.PoolLevel assetPerf) mRates @@ -784,7 +786,7 @@ performAction d t@TestDeal{bonds=bndMap, accounts=accMap, liqProvider=liqMap} (W Just (DueCapAmt amt) -> min amt (accBal + supportAvail) _ -> error $ "Not support for limit when pay int by seq" ++ show mLimit bndsList = (Map.!) bndMap <$> bnds - dueAmts = L.bndDueIntOverInt<$> bndsList + dueAmts = L.bndDueIntOverInt <$> bndsList actualPaids = paySeqLiabilitiesAmt amtAvailable dueAmts -- update bond paid bondsPaid = uncurry (L.payInt d) <$> zip actualPaids bndsList diff --git a/src/Deal/DealQuery.hs b/src/Deal/DealQuery.hs index 1e77284c..e6252355 100644 --- a/src/Deal/DealQuery.hs +++ b/src/Deal/DealQuery.hs @@ -94,6 +94,7 @@ patchDateToStats d t _ -> t -- `debug` ("Failed to patch date to stats"++show t) + queryDealRate :: P.Asset a => TestDeal a -> DealStats -> Micro queryDealRate t s = fromRational $ @@ -125,14 +126,27 @@ queryDealRate t s = cumuPoolDefBal / originPoolBal -- `debug` (show idx ++" cumulative p def rate"++show cumuPoolDefBal++">>"++show originPoolBal) - BondRate bn -> toRational $ L.bndRate $ bonds t Map.! bn + BondRate bn -> case Map.lookup bn (bonds t) of + Just b@(L.Bond {}) -> toRational $ L.bndRate b + Just b@(L.BondGroup bSubMap) -> + let + bnds = Map.elems bSubMap + rates = toRational <$> L.bndRate <$> bnds + bals = L.getCurBalance <$> bnds + in + weightedBy bals rates + Nothing -> + case viewDealBondsByNames t [bn] of + [b] -> toRational $ L.bndRate b + _ -> error ("Failed to find bond by name"++bn) BondWaRate bns -> let rs = toRational <$> (\bn -> queryDealRate t (BondRate bn)) <$> bns - ws = toRational <$> (\bn -> queryDeal t (CurrentBondBalanceOf [bn])) <$> bns + ws = (\bn -> queryDeal t (CurrentBondBalanceOf [bn])) <$> bns in - toRational $ sum (zipWith (+) ws rs) / sum ws + -- toRational $ safeDivide $ sum (zipWith (*) ws rs) $ sum ws + weightedBy ws rs PoolWaRate mPns -> let diff --git a/src/Liability.hs b/src/Liability.hs index f4335add..9f9d8b6f 100644 --- a/src/Liability.hs +++ b/src/Liability.hs @@ -11,7 +11,8 @@ module Liability ,priceBond,PriceResult(..),pv,InterestInfo(..),RateReset(..) ,weightAverageBalance,calcZspread,payYield,scaleBond,totalDueInt ,buildRateResetDates,isAdjustble,StepUp(..),isStepUp,getDayCountFromInfo - ,calcWalBond,patchBondFactor,fundWith,writeOff,InterestOverInterestType(..)) + ,calcWalBond,patchBondFactor,fundWith,writeOff,InterestOverInterestType(..) + ,getCurBalance) where import Language.Haskell.TH diff --git a/src/Util.hs b/src/Util.hs index b28c52ef..e31a89e5 100644 --- a/src/Util.hs +++ b/src/Util.hs @@ -11,6 +11,7 @@ module Util ,maximum',minimum',roundingBy,roundingByM ,floorWith,slice,toPeriodRateByInterval, dropLastN ,lastOf,findBox + ,safeDivide -- for debug ,zyj ) @@ -27,6 +28,7 @@ import Lib import Types import DateUtil +import Numeric.Limits (infinity) import Text.Printf import Control.Exception @@ -305,6 +307,9 @@ findBox (Exc,Exc) x ((l,h):xs) | otherwise = findBox (Exc,Exc) x xs +safeDivide :: RealFloat a => a -> a -> a +safeDivide _ 0 = infinity +safeDivide x y = x / y ----- DEBUG/PRINT diff --git a/swagger.json b/swagger.json index 57d4e0c7..aa16bc39 100644 --- a/swagger.json +++ b/swagger.json @@ -17098,7 +17098,7 @@ "name": "BSD 3" }, "title": "Hastructure API", - "version": "0.28.11" + "version": "0.28.12" }, "openapi": "3.0.0", "paths": {