-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
20265d4
commit 244bd8d
Showing
3 changed files
with
102 additions
and
83 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
name: Python package | ||
|
||
on: [push] | ||
|
||
jobs: | ||
build: | ||
|
||
runs-on: ubuntu-latest | ||
strategy: | ||
matrix: | ||
python-version: [3.7, 3.8, 3.9] | ||
|
||
steps: | ||
- uses: actions/checkout@v2 | ||
- name: Set up Python ${{ matrix.python-version }} | ||
uses: actions/setup-python@v2 | ||
with: | ||
python-version: ${{ matrix.python-version }} | ||
- name: Install dependencies | ||
run: | | ||
python -m pip install --upgrade pip | ||
pip install -r requirements.txt | ||
- name: Run tests | ||
run: | | ||
python -m unittest discover tests |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,84 +1,8 @@ | ||
altair==5.0.1 | ||
appdirs==1.4.4 | ||
attrs==23.1.0 | ||
backports.zoneinfo==0.2.1 | ||
beautifulsoup4==4.12.2 | ||
blinker==1.6.2 | ||
cachetools==5.3.1 | ||
certifi==2023.5.7 | ||
cffi==1.15.1 | ||
charset-normalizer==3.1.0 | ||
click==8.1.3 | ||
codecov==2.1.13 | ||
contourpy==1.0.7 | ||
coverage==7.2.7 | ||
cryptography==41.0.1 | ||
cycler==0.11.0 | ||
decorator==5.1.1 | ||
dill==0.3.6 | ||
exceptiongroup==1.1.1 | ||
fonttools==4.39.4 | ||
fredapi==0.5.0 | ||
frozendict==2.3.8 | ||
gitdb==4.0.10 | ||
GitPython==3.1.31 | ||
html5lib==1.1 | ||
idna==3.4 | ||
importlib-metadata==6.6.0 | ||
importlib-resources==5.12.0 | ||
iniconfig==2.0.0 | ||
Jinja2==3.1.2 | ||
jsonschema==4.17.3 | ||
kiwisolver==1.4.4 | ||
lxml==4.9.2 | ||
markdown-it-py==2.2.0 | ||
MarkupSafe==2.1.3 | ||
matplotlib==3.7.1 | ||
mdurl==0.1.2 | ||
msgspec==0.15.1 | ||
multiprocess==0.70.14 | ||
multitasking==0.0.11 | ||
numpy==1.24.3 | ||
packaging==23.1 | ||
pandas==2.0.2 | ||
pathos==0.3.0 | ||
Pillow==9.5.0 | ||
pkgutil_resolve_name==1.3.10 | ||
pluggy==1.0.0 | ||
pox==0.3.2 | ||
ppft==1.7.6.6 | ||
protobuf==4.23.2 | ||
pyarrow==12.0.0 | ||
pycparser==2.21 | ||
pydeck==0.8.1b0 | ||
Pygments==2.15.1 | ||
Pympler==1.0.1 | ||
pyparsing==3.0.9 | ||
pyrsistent==0.19.3 | ||
pytest==7.3.1 | ||
pytest-cov==4.1.0 | ||
python-dateutil==2.8.2 | ||
pytz==2023.3 | ||
pytz-deprecation-shim==0.1.0.post0 | ||
requests==2.31.0 | ||
rich==13.4.1 | ||
scipy==1.10.1 | ||
six==1.16.0 | ||
smmap==5.0.0 | ||
soupsieve==2.4.1 | ||
squigglepy==0.25 | ||
streamlit==1.23.1 | ||
tenacity==8.2.2 | ||
fredapi==0.5.2 | ||
matplotlib==3.9.2 | ||
numpy==2.1.0 | ||
pandas==2.2.2 | ||
squigglepy==0.28 | ||
streamlit==1.38.0 | ||
toml==0.10.2 | ||
tomli==2.0.1 | ||
toolz==0.12.0 | ||
tornado==6.3.2 | ||
tqdm==4.65.0 | ||
typing_extensions==4.6.3 | ||
tzdata==2023.3 | ||
tzlocal==4.3 | ||
urllib3==2.0.2 | ||
validators==0.20.0 | ||
webencodings==0.5.1 | ||
yfinance==0.2.18 | ||
zipp==3.15.0 | ||
yfinance==0.2.43 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import unittest | ||
import numpy as np | ||
from models.personal_finance import PersonalFinanceModel | ||
|
||
class TestPersonalFinanceModel(unittest.TestCase): | ||
def setUp(self): | ||
# Set up a basic model for testing | ||
self.input_params = { | ||
"m": 1000, | ||
"years": 40, | ||
"r": 0.05, | ||
"years_until_retirement": 30, | ||
"years_until_death": 60, | ||
"retirement_income": 50000, | ||
"income_path": None, # You'll need to provide a mock or real income path | ||
"min_income": 20000, | ||
"inflation_rate": 0.02, | ||
"ar_inflation_coefficients": [0.5], | ||
"ar_inflation_sd": 0.01, | ||
"min_cash_threshold": 5000, | ||
"max_cash_threshold": 20000, | ||
"cash_start": 10000, | ||
"market_start": 50000, | ||
"tax_region": "US", | ||
"portfolio_weights": [1.0], # Simplified for testing | ||
"asset_returns": [0.07], | ||
"asset_volatilities": [0.15], | ||
"asset_correlations": [[1.0]] | ||
} | ||
self.model = PersonalFinanceModel(self.input_params) | ||
|
||
def test_initialization(self): | ||
self.assertEqual(self.model.m, 1000) | ||
self.assertEqual(self.model.years, 40) | ||
self.assertEqual(self.model.r, 0.05) | ||
|
||
def test_generate_market_returns(self): | ||
returns = self.model.generate_market_returns() | ||
self.assertEqual(returns.shape, (1000, 40)) | ||
self.assertTrue(np.all(returns > -1)) # Returns should be greater than -100% | ||
|
||
def test_generate_ar_inflation(self): | ||
inflation = self.model.generate_ar_inflation() | ||
self.assertEqual(inflation.shape, (1000, 40)) | ||
self.assertTrue(np.all(inflation > 0)) # Inflation should be positive | ||
|
||
def test_simulate(self): | ||
self.model.simulate() | ||
results = self.model.get_results() | ||
|
||
# Check that all result arrays have the correct shape | ||
for key, value in results.items(): | ||
self.assertEqual(value.shape, (1000, 40), f"{key} has incorrect shape") | ||
|
||
# Check that financial wealth is non-negative | ||
self.assertTrue(np.all(results['financial_wealth'] >= 0)) | ||
|
||
# Check that consumption is always positive | ||
self.assertTrue(np.all(results['consumption'] > 0)) | ||
|
||
def test_calculate_charitable_donations(self): | ||
self.model.charitable_giving_rate = 0.05 | ||
self.model.charitable_giving_cap = 10000 | ||
total_real_income = np.array([100000, 200000, 300000]) | ||
donations = self.model.calculate_charitable_donations(0, total_real_income) | ||
expected_donations = np.array([5000, 10000, 10000]) # Cap should be applied to last value | ||
np.testing.assert_array_almost_equal(donations, expected_donations) | ||
|
||
if __name__ == '__main__': | ||
unittest.main() |