Skip to content

Commit

Permalink
add CI
Browse files Browse the repository at this point in the history
  • Loading branch information
joel-becker committed Aug 29, 2024
1 parent 20265d4 commit 244bd8d
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 83 deletions.
25 changes: 25 additions & 0 deletions .github/workflows/main.yml
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
90 changes: 7 additions & 83 deletions requirements.txt
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
70 changes: 70 additions & 0 deletions tests/personal_finance.py
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()

0 comments on commit 244bd8d

Please sign in to comment.