Skip to content

Commit 98d4eae

Browse files
committed
updated streamlit_app and cli
1 parent 42ec1cb commit 98d4eae

3 files changed

Lines changed: 573 additions & 415 deletions

File tree

.github/workflows/ci.yml

Lines changed: 1 addition & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
runs-on: ubuntu-latest
1212
strategy:
1313
matrix:
14-
python-version: [3.9, 3.10, 3.11, 3.12]
14+
python-version: ["3.9", "3.10", "3.11", "3.12"]
1515

1616
steps:
1717
- uses: actions/checkout@v4
@@ -40,105 +40,3 @@ jobs:
4040
with:
4141
files: coverage.xml
4242
fail_ci_if_error: true
43-
# Below is a **surgical to-do list** you can tackle one file at a time. I’ve ordered the fixes roughly by ROI: finish everything in **Step 0** first, then march down the file list.
44-
45-
# ---
46-
47-
# ## Step 0 – Repo-level hygiene (do once)
48-
49-
# | Action | Why it matters |
50-
# | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------ |
51-
# | **Create `pyproject.toml`** with-in `[project]` dependencies (`numpy`, `pandas`, `numpy-financial`, `pydantic`, `typer`, `streamlit`, `plotly`, `markdown2`, `weasyprint`) and an editable `src` layout. | Removes “works-on-my-machine” smell. |
52-
# | **Add `pre-commit`** (black, isort, flake8, mypy). | Static lint stops style drift. |
53-
# | **GitHub Actions**: matrix on 3.9 → 3.12 running `pytest -q`. | Shows green badge to recruiters. |
54-
# | **Codecov badge** (>90 % lines) | Signals test discipline. |
55-
56-
# ---
57-
58-
# ## File-by-file fixes
59-
60-
# ### 1. `src/modules/lbo_model.py`
61-
62-
# | 🔧 Fix | Detail |
63-
# | -------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- |
64-
# | **Parameterise hard-coded 70 / 30 split** of bullet vs amort debt; pass as kwargs with defaults. Right now they’re literals . | Makes model flexible for mezz / unitranche cases. |
65-
# | **Move `amort_schedule = [amort_amt/5]*5` to a helper** and allow custom schedules. | Models seven-year deals without code edits. |
66-
# | **Sweep hierarchy**: instead of paying only the first non-revolver tranche , iterate senior → subordinated until cash exhausted. | Reflects typical cash-waterfall. |
67-
# | **Implement LTV covenant** (`enterprise_value * exit_multiple`) vs total debt each year; raise `CovenantBreachError` like ICR. | Completes promised feature set. |
68-
# | **Exit cash & WC unwind**: add cash balance build-up and working-capital release in exit IRR calc. | Removes rosy bias in IRR. |
69-
# | **Docstrings & type hints** for every public method. | Reviewer readability. |
70-
71-
# ### 2. `src/modules/fund_waterfall.py`
72-
73-
# | 🔧 Fix | Detail |
74-
# | ------------------------------------------------------------------------------------------------------------------------------------------ | ------ |
75-
# | **Finish `reset_hurdle` logic** – after a tier is met, reduce base capital and recompute IRR; remove the stub comment . | |
76-
# | **True catch-up math**: calculate GP catch-up until GP gets X % of all distributed profit before moving to next tier. | |
77-
# | **Tier-by-tier carry** instead of “highest tier only”: loop through tiers and allocate incremental carry on the tranche above each hurdle. | |
78-
# | **Management-fee base**: make it choice of *committed* vs *drawn* capital; right now it’s always committed . | |
79-
# | **Annual fee offset**: subtract fees from distributions before hurdle tests; this is market practice. | |
80-
# | **Clawback polish**: compare *net* GP carry (paid – taxes) to final entitlement; accrue interest on excess. | |
81-
# | **Return vs paid-in capital test**: ensure LP gets 100 % of paid-in + pref before any carry. | |
82-
83-
# ### 3. `src/modules/sensitivity.py`
84-
85-
# | 🔧 Fix | Detail |
86-
# | ------------------------------------------------------------------------------------ | ------ |
87-
# | **Add confidence intervals** via bootstrap on IRR distribution. | |
88-
# | **Vectorise `run_2d_sensitivity`** with `itertools.product` + list-comp for speed. | |
89-
# | **Optional heat-map export** (`plotly.express.imshow`). | |
90-
# | **Test coverage**: assert runtime < 1 s for a 100×100 grid to flag perf regressions. | |
91-
92-
# ### 4. `cli.py`
93-
94-
# | 🔧 Fix | Detail |
95-
# | -------------------------------------------------------------------------------------------------- | ------ |
96-
# | **Typo in `Field(. gt=0)`** – the leading space breaks parsing; use `Field(gt=0, …)` | |
97-
# | . | |
98-
# | **`--years` global option** so users don’t edit JSON for horizon tweaks. | |
99-
# | **`typer.Option(Path(...), exists=True)`** is deprecated; switch to `FileText` or manual check. | |
100-
# | **Surfacing error codes**: exit 2 for covenant breach, 3 for insolvency; CI can grep return codes. | |
101-
102-
# ### 5. `streamlit_app.py`
103-
104-
# | 🔧 Fix | Detail |
105-
# | -------------------------------------------------------------------------------------------------------------------------- | ------ |
106-
# | **Sanitise user JSON** from `tiers_json` with `jsonschema.validate`; right now `eval()` risk is latent when you refactor . | |
107-
# | **Cache `convert_md_to_pdf`** with `@st.cache_data(ttl=3600)` to avoid heavy WeasyPrint re-runs. | |
108-
# | **Guard against large uploads** – max file size sidebar setting. | |
109-
# | **Accessibility**: add alt-text for Plotly traces via `hovertext`. | |
110-
111-
# ### 6. `cashflow.py`
112-
113-
# | 🔧 Fix | Detail |
114-
# | ------------------------------------------------------------------------------------- | ------ |
115-
# | **Remove duplicate logic with `lbo_model`** – keep in one place, import in the other. | |
116-
# | **Return `pd.DataFrame` directly** instead of dict-of-dicts for usability. | |
117-
118-
# ### 7. `exit.py`
119-
120-
# | 🔧 Fix | Detail |
121-
# | --------------------------------------------------------------------------------------------- | ------ |
122-
# | **Use `numpy_financial.irr`** instead of custom CAGR when cash flows aren’t annual lump sums. | |
123-
# | **Handle negative equity value** by returning `None` IRR, not −1 sentinel . | |
124-
# | **Add option for sale costs (%) and leverage recap**. | |
125-
126-
# ### 8. Tests (`tests/*.py`)
127-
128-
# | 🔧 Fix | Detail |
129-
# | ------------------------------------------------------------------------------------------------ | ------ |
130-
# | **Parametrise** pytest cases with `@pytest.mark.parametrize` instead of copy-paste blocks. | |
131-
# | **Add property-based tests** (`hypothesis`) to fuzz weird tiers, fee rates, and amort schedules. | |
132-
# | **Contract tests vs Excel**: load a simple spreadsheet waterfall, assert parity. | |
133-
134-
# ---
135-
136-
# ## Suggested implementation sequence
137-
138-
# 1. **Fund waterfall core fixes** (carry tiers, reset hurdle).
139-
# 2. **LBO model debt & covenant realism**.
140-
# 3. **Repo packaging + CI** (do once features stabilise).
141-
# 4. **Streamlit security & performance tweaks**.
142-
# 5. **Sensitivity visual extras & hypothesis tests**.
143-
144-
# Finishing items 1-3 gets you to the “minimum publishable model”; items 4-8 are polish that will impress reviewers but aren’t blocking the paper.

0 commit comments

Comments
 (0)