Portfolio spreadsheets in. A Shadow Variables report out.
A Python backend that reads institutional asset schedules and cash-flow ledgers the way they arrive, cross-references them against macro series, scores fifteen hidden-risk variables per asset, and writes the executive PDF. Password-protected tenants, encrypted at rest.
The fifteen variables
- DSCR today
- DSCR at refinance
- Months to maturity
- Refinance shortfall (equity check)
- DSCR at +200 bps (floating)
- Rent expiring in 24 months
- Largest tenant share
- NOI trend, T12 vs prior 12
- NOI volatility
- Expense drift vs revenue
- Insurance cost change
- Equity erosion at market cap rates
- LTV at market value
- Occupancy cushion over break-even
- Market softness
Each variable carries a severity from 0 to 100, a weight, and the sentence that explains it. Variables the data cannot support are shown grey and drop out of the weighting instead of being guessed.
Test access
Two tenants, two portfolios, strict isolation: a run id from one tenant returns 404 in the other, and the stored blob would not decrypt with the other tenant's key.
| Tenant | Id | Password | Seeded portfolio |
|---|---|---|---|
| Harrow Point Capital | harrowpoint | harrow-demo-2026 | Core Plus Fund II, 14 assets, 24-month ledger |
| Meridian Lane Holdings | meridianlane | meridian-demo-2026 | Sunbelt Value-Add I, 8 assets, floating-rate heavy |
Try an upload
A third fictional fund in a different layout (CSV with a title row and a "Portfolio Total" line) plus its ledger. Upload both inside either tenant and the report is ready in a few seconds.
- trailhead-portfolio.csv (6 assets)
- trailhead-ledger.csv (24 months, mixed date and amount formats)
- harrowpoint-portfolio.xlsx and ledger: the seeded files, to see what the pipeline had to fix
Under the hood
Python 3.12, FastAPI, pandas and openpyxl for ingest, ReportLab for the PDF, Jinja for the portal. Passwords PBKDF2-HMAC-SHA256 at 210,000 iterations; sessions are signed, time-limited cookies; tenant data is envelope-encrypted (HKDF per tenant, AES-128-CBC with HMAC) before it reaches the store, which is Redis here and S3 or GCS with a KMS-held master key in production. Deployed as one serverless function; the same code runs offline with a local encrypted file store.
Everything on this page is fictional: the tenants, the assets, the tenants' tenants. The macro snapshot is a frozen sample series so every run is reproducible.