Skip to content

Commit 5327da7

Browse files
Added ConfigurationClass.py and ALM.ini so can create configurations.
1 parent 6529d8a commit 5327da7

23 files changed

+780
-533
lines changed

ALM.ini

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
3+
4+
[TRACE]
5+
enabled = True
6+
7+
# if you want to change the root folder so as not to use current working folder
8+
# [BASE]
9+
# base_folder = C:\\XXX\\XXX\\XXX\\GitHub\\Asset_Liability_Model_POC_python
10+
11+
[INTERMEDIATE]
12+
enabled = True
13+
file_path = Intermediate
14+
cash_portfolio_file = Cash_Portfolio_test.csv
15+
equity_portfolio_file = Equity_Portfolio_test.csv
16+
17+
18+
[INPUT]
19+
file_path = Input
20+
bonds = Bond Portfolio 2.csv
21+
cash = Cash_Portfolio_test.csv
22+
curves = Curves_no VA.csv
23+
equities = Equity_Portfolio_test.csv
24+
param_no_VA = Param_no_VA.csv
25+
sector_spread = Sector_Spread.csv
26+
parameters = Parameters.csv
27+
liability = Liability_Cashflow.csv

BondClasses.py

Lines changed: 43 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,14 @@
11
import numpy as np
22
from datetime import datetime as dt, timedelta
33
from datetime import date
4-
from enum import IntEnum
54
from dataclasses import dataclass
65
from dateutil.relativedelta import relativedelta
76
from typing import List, Dict, Any
7+
from FrequencyClass import Frequency
88

99

10-
class Frequency(IntEnum):
11-
ANNUAL = 1
12-
BIANNUAL = 2
13-
TRIANNUAL = 3
14-
QUARTERLY = 4
15-
MONTHLY = 12
1610

17-
18-
@dataclass
11+
@dataclass(frozen=True)
1912
class CorpBond:
2013
asset_id: int
2114
nace: str
@@ -29,6 +22,32 @@ class CorpBond:
2922
default_probability: float
3023
market_price: float
3124

25+
def __post_init__(self) -> None:
26+
if self.asset_id<=0:
27+
raise ValueError("Asset ID must be greater than 0")
28+
if self.coupon_rate < 0:
29+
raise ValueError("Coupon rate cannot be negative")
30+
if self.coupon_rate > 1:
31+
raise ValueError("Coupon rate cannot be greater than 1")
32+
if self.recovery_rate < 0:
33+
raise ValueError("Recovery rate cannot be negative")
34+
if self.recovery_rate > 1:
35+
raise ValueError("Recovery rate cannot be greater than 1")
36+
if self.default_probability < 0:
37+
raise ValueError("Default probability cannot be negative")
38+
if self.default_probability > 1:
39+
raise ValueError("Default probability cannot be greater than 1")
40+
if self.market_price < 0:
41+
raise ValueError("Market price cannot be negative")
42+
if self.frequency not in [Frequency.MONTHLY, Frequency.QUARTERLY,Frequency.TRIANNUAL, Frequency.BIANNUAL, Frequency.ANNUAL]:
43+
raise ValueError("Frequency must be either Monthly, Quarterly,Triannual, SemiAnnual or Annual")
44+
if self.notional_amount <= 0:
45+
raise ValueError("Notional amount must be greater than 0")
46+
if self.maturity_date <= self.issue_date:
47+
raise ValueError("Maturity date cannot be before issue date")
48+
49+
50+
3251
@property
3352
def dividend_amount(self) -> float:
3453
return self.coupon_rate * self.notional_amount
@@ -69,7 +88,7 @@ def __init__(self, corporate_bonds: dict[int,CorpBond] = None):
6988
self.corporate_bonds = corporate_bonds
7089

7190
def IsEmpty(self)-> bool:
72-
if self.corporate_bonds == None:
91+
if self.corporate_bonds is None:
7392
return True
7493
if len(self.corporate_bonds) == 0:
7594
return True
@@ -80,14 +99,12 @@ def add(self,corp_bond: CorpBond) :
8099
81100
:type corp_bond: CorpBond
82101
"""
83-
if self.corporate_bonds == None:
84-
self.corporate_bonds = {corp_bond.asset_id: corp_bond}
85-
else:
102+
if self.corporate_bonds is not None:
86103
self.corporate_bonds.update({corp_bond.asset_id: corp_bond})
104+
else:
105+
self.corporate_bonds = {corp_bond.asset_id: corp_bond}
87106

88-
89-
90-
def create_coupon_dates(self, modelling_date)->dict:
107+
def create_aggregate_coupon_dates(self, modelling_date)->dict:
91108
"""
92109
Create the vector of dates at which the coupons are paid out and the total amounts for
93110
all corporate bonds in the portfolio, for dates on or after the modelling date
@@ -109,13 +126,18 @@ def create_coupon_dates(self, modelling_date)->dict:
109126
coupon_date: date
110127
for asset_id in self.corporate_bonds:
111128
corp_bond = self.corporate_bonds[asset_id]
112-
dividend_amount = corp_bond.dividend_amount
113129
for coupon_date in corp_bond.generate_coupon_dates(modelling_date):
114130
if coupon_date in coupons:
115-
coupons[coupon_date] = dividend_amount + coupons[coupon_date]
131+
coupons[coupon_date] += corp_bond.dividend_amount
116132
else:
117-
coupons.update({coupon_date:dividend_amount})
133+
coupons.update({coupon_date:corp_bond.dividend_amount})
118134
return coupons
135+
136+
"""
137+
def create_coupon_dates(self, modelling_date: date):
138+
for corp_bond in self.corporate_bonds.values() :
139+
corp_bond.generate_coupon_dates(modelling_date)
140+
"""
119141

120142
def create_maturity_cashflow(self, modelling_date: date) -> dict:
121143
"""
@@ -128,12 +150,10 @@ def create_maturity_cashflow(self, modelling_date: date) -> dict:
128150

129151
for asset_id in self.corporate_bonds:
130152
corp_bond = self.corporate_bonds[asset_id]
131-
maturity_amount = corp_bond.notional_amount
132-
maturity_date = corp_bond.maturity_date
133153
if maturity_date in maturities:
134-
maturities[maturity_date] = maturity_amount + maturities[maturity_date]
154+
maturities[maturity_date] += corp_bond.notional_amount
135155
else:
136-
maturities.update({maturity_date:maturity_amount})
156+
maturities.update({corp_bond.maturity_date:corp_bond.notional_amount})
137157
return maturities
138158

139159
class CorporateBond:

ConfigurationClass.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
class Configuration:
2+
def __init__(self) -> None:
3+
self.bond_portfolio: str = ""
4+
self.trace_enabled: bool = False
5+
self.intermediate_path: str = ""
6+
self.intermediate_enabled: bool = False
7+
self.intermediate_equity_portfolio: str = ""
8+
self.intermediate_cash_portfolio: str = ""
9+
self.input_path: str = ""
10+
self.input_cash_portfolio: str = ""
11+
self.input_curves: str = ""
12+
self.input_equity_portfolio: str = ""
13+
self.input_bond_portfolio: str = ""
14+
self.input_param_no_VA: str = ""
15+
self.input_spread: str = ""
16+
self.input_parameters: str = ""
17+
self.input_liability_cashflow: str = ""

Documentation/Equity_Class_Dev.ipynb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@
100100
"id": "49d48e43",
101101
"metadata": {},
102102
"source": [
103-
"GetEquityShare generator imports the portfolio of equities from the csv file and correctly saves them in the EquityShare objects."
103+
"get_EquityShare generator imports the portfolio of equities from the csv file and correctly saves them in the EquityShare objects."
104104
]
105105
},
106106
{
@@ -110,7 +110,7 @@
110110
"metadata": {},
111111
"outputs": [],
112112
"source": [
113-
"def GetEquityShare(filename:str) -> EquityShare:\n",
113+
"def get_EquityShare(filename:str) -> EquityShare:\n",
114114
" \"\"\"\n",
115115
" :type filename: str\n",
116116
" \"\"\"\n",
@@ -308,7 +308,7 @@
308308
"# Test is Portfolio constructor\n",
309309
"a = EquitySharePortfolio()\n",
310310
"\n",
311-
"test_equity_import = GetEquityShare(\"Input\\Equity_Portfolio_test.csv\")\n",
311+
"test_equity_import = get_EquityShare(\"Input\\Equity_Portfolio_test.csv\")\n",
312312
"\n",
313313
"#test_Not_IsEmpty\n",
314314
"b = EquitySharePortfolio({test_share_1.asset_id: test_share_1}) "

Documentation/PROTOTYPE BOND PRICING.ipynb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"outputs": [],
2121
"source": [
2222
"from Curves import Curves\n",
23-
"from ImportData import importSWEiopa\n",
23+
"from ImportData import import_SWEiopa\n",
2424
"from BondClasses import CorporateBond"
2525
]
2626
},
@@ -298,7 +298,7 @@
298298
"metadata": {},
299299
"outputs": [],
300300
"source": [
301-
"[maturities_country, curve_country, extra_param, Qb]= importSWEiopa(selected_param_file, selected_curves_file, country)"
301+
"[maturities_country, curve_country, extra_param, Qb]= import_SWEiopa(selected_param_file, selected_curves_file, country)"
302302
]
303303
},
304304
{

Documentation/PROTOTYPE CALIBRATION AND PROJECTION.ipynb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
"metadata": {},
3030
"outputs": [],
3131
"source": [
32-
"from ImportData import importSWEiopa\n",
32+
"from ImportData import import_SWEiopa\n",
3333
"from Curves import Curves"
3434
]
3535
},
@@ -74,7 +74,7 @@
7474
"selected_curves_file = paramfile.loc[\"EIOPA_curves_file\"][0]\n",
7575
"country = paramfile.loc[\"country\"][0]\n",
7676
"\n",
77-
"[maturities_country, curve_country, extra_param, Qb]= importSWEiopa(selected_param_file, selected_curves_file, country)"
77+
"[maturities_country, curve_country, extra_param, Qb]= import_SWEiopa(selected_param_file, selected_curves_file, country)"
7878
]
7979
},
8080
{

Documentation/PROTOTYPE EQUITY PRICING.ipynb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"outputs": [],
2121
"source": [
2222
"from Curves import Curves\n",
23-
"from ImportData import importSWEiopa\n",
23+
"from ImportData import import_SWEiopa\n",
2424
"from EquityClasses import Equity, EquityPriced"
2525
]
2626
},
@@ -106,7 +106,7 @@
106106
"outputs": [],
107107
"source": [
108108
"# Model parameters\n",
109-
"[maturities_country, curve_country, extra_param, Qb]= importSWEiopa(selected_param_file, selected_curves_file, country)"
109+
"[maturities_country, curve_country, extra_param, Qb]= import_SWEiopa(selected_param_file, selected_curves_file, country)"
110110
]
111111
},
112112
{

0 commit comments

Comments
 (0)