Skip to content

Commit 19209d4

Browse files
committed
using ()
1 parent 8eb3926 commit 19209d4

File tree

5 files changed

+99
-7
lines changed

5 files changed

+99
-7
lines changed

absbox/local/component.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -993,15 +993,15 @@ def mkBookType(x: list):
993993

994994
def mkSupport(x:list):
995995
match x:
996-
case ["account", accName, (direction,ledgerName)] | ["suppportAccount", accName, (direction,ledgerName)] | ["支持账户", accName, (direction,ledgerName)] if direction in bookDirection.keys():
996+
case ("account", accName, (direction,ledgerName)) | ["account", accName, (direction,ledgerName)] | ["suppportAccount", accName, (direction,ledgerName)] | ["支持账户", accName, (direction,ledgerName)] if direction in bookDirection.keys():
997997
return mkTag(("SupportAccount", [vStr(accName), [vStr(bookDirection[direction]),vStr(ledgerName)]]))
998-
case ["account", accName] | ["suppportAccount", accName] | ["支持账户", accName]:
998+
case ("account", accName) | ["account", accName] | ["suppportAccount", accName] | ["支持账户", accName]:
999999
return mkTag(("SupportAccount", [vStr(accName), None]))
1000-
case ["facility", liqName] | ["suppportFacility", liqName] | ["支持机构", liqName]:
1000+
case ("facility", liqName) | ["facility", liqName] | ["suppportFacility", liqName] | ["支持机构", liqName]:
10011001
return mkTag(("SupportLiqFacility", vStr(liqName)))
1002-
case ["support", *supports] | ["multiSupport", *supports] | ["多重支持", *supports]:
1002+
case ("support", *supports) | ["support", *supports] | ["multiSupport", *supports] | ["多重支持", *supports]:
10031003
return mkTag(("MultiSupport", lmap(mkSupport, supports)))
1004-
case ["withCondition", pre, s] | ["条件支持", pre, s]:
1004+
case ("withCondition", pre, s) | ["withCondition", pre, s] | ["条件支持", pre, s]:
10051005
return mkTag(("WithCondition", [mkPre(pre), mkSupport(s)]))
10061006
case None:
10071007
return None
@@ -2003,7 +2003,7 @@ def mkAssetUnion(x):
20032003
return mkTag(("FA", mkAsset(x)))
20042004
case "应收帐款" | "Invoice" :
20052005
return mkTag(("RE", mkAsset(x)))
2006-
case "ProjectedFlowFix" | "ProjectedFlowMix" :
2006+
case "ProjectedByFactor" :
20072007
return mkTag(("PF", mkAsset(x)))
20082008
case _:
20092009
raise RuntimeError(f"Failed to match AssetUnion {x}")
@@ -2596,3 +2596,7 @@ def translate(y) -> dict:
25962596
return r
25972597
case [x,*rest]:
25982598
return mkNonPerfAssumps(r | translate(x),rest)
2599+
from enum import Enum
2600+
import itertools
2601+
import sys
2602+
import functools

absbox/local/generic.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ def read(resp):
118118
if x[comp_v[0]]:
119119
ir = list(tz.pluck('contents', x[comp_v[0]]))
120120
output[comp_name][k] = pd.DataFrame(ir, columns=comp_v[1]).set_index("date")
121+
elif x[comp_v[0]] is None:
122+
output[comp_name][k] = pd.DataFrame([], columns=comp_v[1]).set_index("date")
123+
else:
124+
pass
121125
output[comp_name] = collections.OrderedDict(sorted(output[comp_name].items()))
122126
# aggregate fees
123127
output['fees'] = {f: v.groupby('date').agg({"balance": "min", "payment": "sum", "due": "min"})

absbox/local/util.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import functools,json,copy,logging,re,itertools
33
from functools import reduce
44
from datetime import datetime
5+
from dateutil.relativedelta import relativedelta
56
from lenses import lens, ui, optics
67
import toolz as tz
78

@@ -463,3 +464,32 @@ def patchDicts(dict1:dict,dict2:dict)-> dict:
463464
def getNumCols(df:pd.DataFrame)-> list:
464465
numeric_columns = [col for col in df.columns if pd.to_numeric(df[col], errors='coerce').notna().all()]
465466
return numeric_columns
467+
468+
def get_earlier_date(date_str, n_months, input_format="%Y-%m-%d", output_format="%Y-%m-%d"):
469+
"""
470+
Returns a date string that is n_months earlier than the input date.
471+
472+
Parameters:
473+
date_str (str): Input date string
474+
n_months (int): Number of months to subtract
475+
input_format (str): Format of input date string (default: YYYY-MM-DD)
476+
output_format (str): Format of output date string (default: YYYY-MM-DD)
477+
478+
Returns:
479+
str: Date string that is n_months earlier
480+
"""
481+
try:
482+
# Parse input date string to datetime
483+
input_date = datetime.strptime(date_str, input_format)
484+
485+
# Subtract n months
486+
earlier_date = input_date - relativedelta(months=n_months)
487+
488+
# Format output date
489+
return earlier_date.strftime(output_format)
490+
except ValueError as e:
491+
return f"Error: Invalid date format or value. {str(e)}"
492+
493+
494+
495+

absbox/tests/regression/test_main.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,60 @@ def test_revolving_01(setup_api):
539539
def test_06(setup_api):
540540
r = setup_api.run(test06 , read=True , runAssump = [])
541541
assert r['pool']['flow']['PoolConsol'].Principal.sum() == 2175, "Total principal should be 2175.0"
542+
543+
544+
@pytest.mark.waterfall
545+
def test_limit_01(setup_api):
546+
formulaPay = \
547+
["IfElse",["date","<=","2021-10-20"]
548+
,[['payPrin', 'acc01', ['A1'],{"limit":{"formula":("const",30)}}]]
549+
,[['payPrin', 'acc01', ['A1']]]
550+
]
551+
552+
test01_ = test01 & lens.waterfall['default'][1].set(formulaPay)
553+
r = setup_api.run(test01_,read=True)
554+
assert r['bonds']['A1'][:"2021-10-20"].principal.to_list() == [30.0, 30.0, 30.0, 30.0]
555+
assert r['bonds']['A1'].loc["2021-11-20"].principal.item() == 75.92
556+
557+
formulaPay = \
558+
["IfElse",["date","<=","2021-10-20"]
559+
,[['payPrin', 'acc01', ['A1'],{"limit":{"balPct":0.4}}]]
560+
,[['payPrin', 'acc01', ['A1']]]
561+
]
562+
563+
test01_ = test01 & lens.waterfall['default'][1].set(formulaPay)
564+
r = setup_api.run(test01_,read=True)
565+
assert r['bonds']['A1'][:"2021-11-20"].principal.to_list() == [122.01, 30.78, 30.44, 30.58, 76.48]
566+
567+
formulaPay = ['payPrin', 'acc01', ['A1'],{"limit":{"balCapAmt":75}}]
568+
569+
test01_ = test01 & lens.waterfall['default'][1].set(formulaPay)
570+
r = setup_api.run(test01_,read=True)
571+
r['bonds']['A1'].principal.to_list() == [75]*13+[25]
572+
573+
@pytest.mark.waterfall
574+
def test_support_account(setup_api):
575+
""" Test support account """
576+
test01_ = test01 & lens.accounts.set((('acc01', {'balance': 0}),('acc02', {'balance': 200})))\
577+
& lens.waterfall['default'][0].modify(lambda x: x+[{"support":["account","acc02"]}])
578+
r =setup_api.run(test01_,read=True
579+
,poolAssump = ("Pool",("Mortgage",{"CDR":0.75},None,None,None)
580+
,None
581+
,None))
582+
assert r['accounts']['acc01'].loc['2023-09-20'].change.item() == -2.56
583+
assert r['accounts']['acc02'].loc['2023-09-20'].change.item() == -0.13
584+
585+
test01_ = test01 & lens.accounts.set((('acc01', {'balance': 0}),('acc02', {'balance': 10}),('acc03', {'balance': 50})))\
586+
& lens.waterfall['default'][0].modify(lambda x: x+[{"support":["support",("account","acc02"),("account","acc03")]}])
587+
r = setup_api.run(test01_,read=True
588+
,poolAssump = ("Pool",("Mortgage",{"CDR":0.75},None,None,None)
589+
,None
590+
,None)
591+
)
592+
assert r['accounts']['acc01'].loc['2023-09-20'].change.item() == -2.56
593+
assert r['accounts']['acc02'].loc['2023-09-20'].change.item() == -0.13
594+
assert r['accounts']['acc02'].loc['2024-01-20'].change.item() == -1.96
595+
assert r['accounts']['acc03'].loc['2024-01-20'].change.item() == -0.73
542596
# @pytest.mark.analytics
543597
# def test_rootfinder_by_formula(setup_api):
544598
# poolPerf = ("Pool",("Mortgage",{"CDR":0.002},{"CPR":0.001},{"Rate":0.1,"Lag":18},None)

docs/source/analytics.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2404,7 +2404,7 @@ Bond Pricing Equals to Face
24042404
The search stop when a bond pricing equals to face value.
24052405
24062406
syntax
2407-
``("bondPricingEqToOrigin", <bondName>, <TestBondFlag>, <TestFeeFlag>)``
2407+
``("bondPricingEqOrigin", <bondName>, <TestBondFlag>, <TestFeeFlag>)``
24082408
24092409
Bond with target IRR
24102410
The search stop when a bond hit a target IRR.

0 commit comments

Comments
 (0)