Research system
Valuation App
A weekly research run that values groups of public companies six ways and keeps every result as history.
- Role
- Designed and built
- When
- 2026 – present
- Status
- Private
- Built with
- Python, SEC EDGAR, pytest, mypy, ruff
Research log, still running
Every Sunday at 06:00, the research runs again.
This is the real run history, week by week: when each run started, how far each company got through the pipeline, and why the rest were set aside. The findings stay private, so there are no company names, values or rankings here, and the groups being studied carry generic labels.
- Next run
- Last run
- Oct 18 Incomplete
- Log updated
- 9weeks on the log, since Sep 5
- 4/6scheduled runs completed in full
- 93companies tracked across 4 groups
- 6/8data issues found and fixed
Weeks start on Sunday. Each bar is the run of record for that week: the scheduled run when there was one, otherwise the last manual run.
Week of Aug 30
Completed with warningsHow far companies got
- In the groups93
- Identified86
- Filings loaded81
- Classified64
- Valued62
Why the rest were set aside
- No recent filing15
- Identifier could not be resolved6
- Reports in a non-USD currency5
- Fewer than two usable methods2
- Business type not supported1
- Exchange not supported1
- Negative book value1
By group
| Group | Companies | Valued |
|---|---|---|
| ETF holdings | 30 | 26 |
| Curated list A | 18 | 14 |
| Curated list B | 25 | 20 |
| Curated list C | 20 | 2 |
Warnings raised by the run
- Curated list C: classification success rate 16% is below the 70% threshold
Flagged afterwards
Later audits found problems in this week's data. The history is kept as it was and marked, not rewritten.
Other activity this week
- Manual run, Sat Sep 5 20:13: 59 valued · flagged DI-001, DI-002, DI-003, DI-004, DI-005
- Manual run, Sat Sep 5 20:30: incomplete
- Manual run, Sat Sep 5 20:35: 68 valued · flagged DI-001, DI-002, DI-003, DI-004, DI-005
- 1 configuration check (dry runs, no data)
Week of Sep 6
Completed with warningsHow far companies got
- In the groups93
- Identified86
- Filings loaded81
- Classified69
- Valued62
Why the rest were set aside
- Fewer than two usable methods7
- Identifier could not be resolved6
- No price available6
- Reports in a non-USD currency5
- Required figure missing from filings4
- Business type not supported1
- Exchange not supported1
- Negative book value1
By group
| Group | Companies | Valued |
|---|---|---|
| ETF holdings | 30 | 26 |
| Curated list A | 18 | 14 |
| Curated list B | 25 | 15 |
| Curated list C | 20 | 7 |
Warnings raised by the run
- Curated list C: classification success rate 68% is below the 70% threshold
Flagged afterwards
Later audits found problems in this week's data. The history is kept as it was and marked, not rewritten.
Other activity this week
- 3 configuration checks (dry runs, no data)
Week of Sep 13
Completed with warningsHow far companies got
- In the groups93
- Identified86
- Filings loaded81
- Classified65
- Valued63
Why the rest were set aside
- No price available13
- Identifier could not be resolved6
- Reports in a non-USD currency5
- Fewer than two usable methods2
- Business type not supported1
- Exchange not supported1
- Required figure missing from filings1
- Negative book value1
By group
| Group | Companies | Valued |
|---|---|---|
| ETF holdings | 30 | 26 |
| Curated list A | 18 | 14 |
| Curated list B | 25 | 20 |
| Curated list C | 20 | 3 |
Warnings raised by the run
- Curated list C: classification success rate 21% is below the 70% threshold
Flagged afterwards
Later audits found problems in this week's data. The history is kept as it was and marked, not rewritten.
Week of Sep 20
FailedNo network at run time (preflight could not reach SEC EDGAR).
Week of Sep 27
Completed with warningsHow far companies got
- In the groups93
- Identified86
- Filings loaded81
- Classified74
- Valued67
Why the rest were set aside
- Fewer than two usable methods7
- Identifier could not be resolved6
- Reports in a non-USD currency5
- Required figure missing from filings4
- Business type not supported1
- Exchange not supported1
- Negative book value1
- No price available1
By group
| Group | Companies | Valued |
|---|---|---|
| ETF holdings | 30 | 26 |
| Curated list A | 18 | 14 |
| Curated list B | 25 | 20 |
| Curated list C | 20 | 7 |
Warnings raised by the run
- Curated list C: classification success rate 68% is below the 70% threshold
Flagged afterwards
Later audits found problems in this week's data. The history is kept as it was and marked, not rewritten.
Week of Oct 4
Completed with warningsHow far companies got
- In the groups93
- Identified86
- Filings loaded79
- Classified56
- Valued53
Why the rest were set aside
- No price available19
- Identifier could not be resolved6
- Reports in a non-USD currency5
- Fewer than two usable methods3
- No recent filing2
- Required figure missing from filings2
- Business type not supported1
- Exchange not supported1
- Negative book value1
By group
| Group | Companies | Valued |
|---|---|---|
| ETF holdings | 30 | 24 |
| Curated list A | 18 | 14 |
| Curated list B | 25 | 11 |
| Curated list C | 20 | 4 |
Warnings raised by the run
- Curated list B: classification success rate 52% is below the 70% threshold
- Curated list C: classification success rate 32% is below the 70% threshold
Flagged afterwards
Later audits found problems in this week's data. The history is kept as it was and marked, not rewritten.
Week of Oct 11
Completed with warningsHow far companies got
- In the groups93
- Identified86
- Filings loaded81
- Classified56
- Valued53
Why the rest were set aside
- No price available22
- Identifier could not be resolved6
- Reports in a non-USD currency5
- Fewer than two usable methods3
- Business type not supported1
- Exchange not supported1
- Required figure missing from filings1
- Negative book value1
By group
| Group | Companies | Valued |
|---|---|---|
| ETF holdings | 30 | 26 |
| Curated list A | 18 | 14 |
| Curated list B | 25 | 9 |
| Curated list C | 20 | 4 |
Warnings raised by the run
- Curated list B: classification success rate 43% is below the 70% threshold
- Curated list C: classification success rate 32% is below the 70% threshold
Flagged afterwards
Later audits found problems in this week's data. The history is kept as it was and marked, not rewritten.
Week of Oct 18
IncompleteStopped before the last group finished; no run record was written.
How far companies got
- In the groups73
- Identified67
- Filings loaded62
- Classified50
- Valued49
Why the rest were set aside
- No price available11
- Identifier could not be resolved6
- Reports in a non-USD currency5
- Fewer than two usable methods1
- Business type not supported1
By group
| Group | Companies | Valued |
|---|---|---|
| ETF holdings | 30 | 26 |
| Curated list A | 18 | 14 |
| Curated list B | 25 | 9 |
| Curated list C | Not reached this week | |
Flagged afterwards
Later audits found problems in this week's data. The history is kept as it was and marked, not rewritten.
Week of Oct 25
ScheduledThe next run is set for . It will be the first with the fixes from the latest round of work: one shared price budget with a second provider as fallback, a stale-price gate, and negative estimates kept out of the consensus.
Show every week as a table
| Week of | Status | Started | Duration | Companies | Valued | Rate-limited |
|---|---|---|---|---|---|---|
| Aug 30 | Completed with warnings | Sat 21:00 | 63 min | 93 | 62 | 75 |
| Sep 6 | Completed with warnings | Wed 14:38 | 62 min | 93 | 62 | 20 |
| Sep 13 | Completed with warnings | Sun 15:14 | 51 min | 93 | 63 | 67 |
| Sep 20 | Failed | Sun 09:56 | 1 min | 0 | 0 | 0 |
| Sep 27 | Completed with warnings | Sun 11:40 | 26 min | 93 | 67 | 0 |
| Oct 4 | Completed with warnings | Sun 10:16 | 5 h 53 min | 93 | 53 | 95 |
| Oct 11 | Completed with warnings | Sun 10:57 | 72 min | 93 | 53 | 113 |
| Oct 18 | Incomplete | Sun 08:57 | 54 min | 73 | 49 | 106 |
| Oct 25 | Scheduled | — | — | — | — | — |
Data issues register
Problems found by auditing past runs. Each one is fixed at the root, and the affected history is flagged instead of rewritten.
DI-001high Fixed
A delisted company valued against its frozen final price
The price provider kept serving a final close after an acquisition. A stale-price gate now excludes any price more than seven days old.
DI-002high Fixed
Month-old cached prices served as "latest"
The first two baseline-day runs read prices from a month-old cache. Fixed the same day; the baseline run itself is unaffected.
DI-003high Fixed
Negative method estimates averaged into the consensus
A negative DCF could drag a consensus below every positive method. Non-positive estimates are now dropped before blending.
DI-004medium Fixed
Net income missed under alternative filing tags
Some filers report net income under less common XBRL tags. Tag fallbacks added; affected observations are kept but read with caution.
DI-005low Fixed
Data-quality scores understated for one company type
Some companies were marked down for figures their industry does not report. Required figures now depend on the company type.
DI-006medium Fixed
Companies lost to price-provider rate limiting
Each group started with its own request budget, so later groups ran out. One shared budget, no futile retries, and a second price provider as fallback.
DI-007low Open
Missing weeks from failed or interrupted runs
Gaps rather than errors. Runs now record themselves at start, so an interruption is flagged instead of leaving no trace.
DI-008medium Open
One group structurally under-covered
Most of one group never reaches two usable methods because of AFFO and share-count gaps in filings. Needs per-filer work.
Work on the system
- Research data audit
- Diagnose why the weekly scheduled runs were losing companies, fix Tiingo rate limiting
- A large, single-session build-out of two new layers on top of the S1–S6 scanner
- Documentation deliverable
Problem
Valuing a company properly means pulling filings, normalising the numbers and running several models. Doing that across a whole sector every week by hand isn't realistic, and a spreadsheet quietly overwrites last week's thinking with this week's.
Approach
Treat research as a repeatable run instead of a one-off analysis: gather the data, value every company with several methods, blend them into one consensus with a confidence score, and store each run as point-in-time history that can be compared and audited later. It never trades.
Implementation
A Python command-line pipeline. SEC EDGAR is the system of record for filings and fundamentals; a market data provider supplies prices, with a fallback when it's rate-limited. Six methods run per company (DCF, Graham, relative, residual income, DDM and AFFO), and non-positive estimates are dropped before blending. Scans can target curated lists, SIC sectors or ETF holdings. Stale prices are detected and excluded, known data issues are kept in a register, and affected runs are flagged rather than rewritten. Strict typing with mypy, a pytest suite and ruff.
Outcome
Runs unattended every week as a scheduled task, and the research log above is its real run history, refreshed after each run. The findings stay private; what's shown here is how the system runs, not what it found.