All projects
Featured ProjectFeb 2026 – Present

AXIOM: Honest Equity Valuation Engine

A browser-based equity valuation tool. Type a US ticker, AXIOM routes the company through one of 9 archetype frameworks (DCF for mature businesses, P/B for banks, P/FFO for REITs), runs the math, and shows the fair value alongside multiples-as-context, never blended in. Originally shipped with ML correction multipliers stacked on the headline; tore it down when I realised the displayed fair value didn't match the underlying DCF. Rebuilt around one rule: the headline number has to mean what it says.

One DCF formula · 9 archetype frameworks · 54-tag multiplier table · factor model in research mode · every magic number inventoried in HARDCODED_VALUES.md
10-Year DCF9 Archetype Frameworks54-Tag Sub-Sector TableFactor Model (Research)HARDCODED_VALUES.md
PythonFlaskPostgreSQLyfinanceCAPM + Credit-Spread WACC9-Archetype Router54-Tag Multiplier TableV/M/Q Factor Model (research)IC · Walk-Forward Monitor
axiom.app/dashboard

Live ticker, circular gauge, portfolio stats, the state the app sits in.

Three short clips. Watch them in order and you’ve seen the whole product.

axiom.app

01 · Type a ticker, get a fair value

AXIOM fair value, Wall Street consensus, and live price, side by side, never blended.

axiom.app

02 · A clean 10-year DCF

Change one assumption, the headline recalculates live. Same math, no fudge factors.

axiom.app

03 · Multiples as labelled context

Drag the multiple slider, comp moves, DCF headline stays put. The two views never blend.

Fundamentals from Yahoo Finance · archetype router selects the formula (DCF / P/B / P/FFO depending on business type) · clean 10-year DCF produces the headline · multiples sit beside it as context · factor model in research mode tracks IC and t-stat walk-forward · output is a fair value plus a bear/base/bull range.

Yahoo FinanceFundamentals + priceArchetype Router9 frameworksClean DCFCAPM + credit spreadsComp Multiples54-tag tableFactor ModelResearch modeFair ValueBear / Base / Bull

Each stage is explained twice, first for the finance reader, then for the engineer.

1. The Pivot: Tearing Down the Dishonest Version

Finance lens

Axiom shipped first as a typical retail valuation tool: pull a company's financials, run a DCF, blend it with EV/EBITDA and P/E multiples, layer an ML "correction multiplier" on top, and call the output "DCF Fair Value." It wasn't. The displayed fair value could read $531 while the underlying DCF was $380, the gap was ML fudging and silent multiple expansion, and the sensitivity table inside the same app contradicted the headline. So I tore it down and rebuilt around one rule: the number has to mean what it says.

Engineering lens

The blending pipeline, the ML correction multiplier applied to fair value, and the headline-vs-internals inconsistency were all removed in one pass. The DCF became a single deterministic Python function with an audited input contract; comparables were pulled out of the headline number entirely and re-rendered as labelled side context. A HARDCODED_VALUES.md file was added inventorying every remaining hand-set constant in the codebase, with a phased plan to migrate them to live peer-comp estimates, so what's assumed is auditable, and what's computed is real.

2. Clean 10-Year DCF with a Credit-Spread WACC

Finance lens

The core is a 10-year Discounted Cash Flow, the same instrument a banker builds in Excel for an IPO pitch, but coded as a deterministic pipeline. Free cash flow is projected with a three-stage growth fade (current → industry → terminal), discounted at a WACC built from CAPM equity costs and a synthetic credit-rating spread (Damodaran-style interest-coverage-to-rating mapping, so highly-covered firms automatically get cheaper debt, no hand-typed numbers in the spread table). Net debt comes off enterprise value, divide by shares, done.

Engineering lens

Terminal growth is capped strictly below WACC so Gordon Growth can't blow up. The same DCF math powers both the headline number and the sensitivity table, every figure rendered in the UI is internally consistent. One formula, no blending, no ML on the output.

3. 9-Archetype Router + 54-Tag Sub-Sector Table

Finance lens

A vanilla DCF works for Microsoft and dies on Tesla, banks, REITs, distressed names, hyper-growth, and "story stocks" don't share a single valuation language. Axiom routes every ticker through one of 9 archetype frameworks (FINANCIAL, GROWTH, MATURE, CYCLICAL, HIGH_CAPEX, HYPER_GROWTH, TURNAROUND, DISTRESSED, STABLE_GROWTH) which decides the formula: banks get P/B, REITs get P/FFO, mature operators get a clean DCF. On top of that, a 54-tag sub-sector table calibrates the multiples shown alongside.

Engineering lens

Archetype routing maps revenue profile, margin shape, leverage, and sector tags at request time. Each archetype has its own DCF inputs (terminal growth, fade schedule, reinvestment assumptions); financials and REITs route to entirely separate model functions. The 54-tag multiplier table lives in subsector_multiples.json and acts as a Bayesian prior on the comp multiples, not the answer, the starting point.

4. V/M/Q Factor Model: In Research Mode

Finance lens

The original ML layer learned to patch its own past errors, a circular feedback loop that doesn't actually predict the cross-section of returns. The rebuilt version works the way a real quant shop would: it scores every company on three independent factors, Value (DCF upside vs. market), Momentum (Jegadeesh-Titman 12-1 month sector-relative return), and Quality (FCF yield), Z-scored within sub-sector so Google is compared to internet peers, not oil majors. Crucially: this signal is not yet shown to users. It's being measured first.

Engineering lens

Information Coefficient + quintile hit rates are computed walk-forward in ml/monitor.py, the metrics quant funds actually use to evaluate predictive signals, not MAE. A "✓ SKILL SIGNAL" annotation appears in the monitoring output once t-stat ≥ 2 holds across enough OOS periods. The factor model exists in the codebase but is intentionally absent from the user-facing UI until it earns its place there. The model is allowed to say "I don't have a signal yet."

5. Honest by Default: Including the Limits

Finance lens

Layperson reading: the app gives "is this stock cheap or expensive" with a number, a colour, and a comparison to Wall Street. Finance reading: a fully-instrumented DCF + multi-factor research pipeline. Same product, two reading levels. The demo site has a dedicated "What this isn't (yet)" section that names the limitations: yfinance can be stale, several constants are still hand-set, the factor model isn't live, US-only coverage. Owning the gaps is part of the product.

Engineering lens

Architecturally a Flask + Postgres app with a vanilla-JS frontend, yfinance as the data spine, and an XGBoost-style walk-forward evaluation harness behind the scenes. Deployable on a single container. Every hand-set constant is named in HARDCODED_VALUES.md. Yahoo balance-sheet ratios known to be unreliable (ROE, ROIC, D/E, Altman Z) are currently hidden from the UI rather than shown wrong, visible-honest beats invisible-broken.

Clean 10-year DCF as one deterministic Python function: three-stage growth fade, CAPM equity cost, credit-spread debt cost, terminal growth strictly below WACC. The same math drives the headline fair value and the sensitivity table, no separate "display" number.

9-archetype router selects the framework (DCF for mature, P/B for banks, P/FFO for REITs, separate inputs for hyper-growth and distressed). On top, a 54-tag sub-sector table calibrates comp multiples as a Bayesian prior, not as the answer.

Factor model (Value / Momentum / Quality) is wired up but lives in research mode: IC, std, t-stat, and quintile hit rates are computed walk-forward in ml/monitor.py. The user-facing recommendation pill is driven by the DCF output, not the factor model, until the model demonstrates skill OOS.

HARDCODED_VALUES.md inventories every hand-set constant with a phased plan (P2 → P6) to replace each with live peer-comp computation, ML correction-layer changes, scenario parameters, or panel-regression-derived values. What's assumed is auditable; what's computed is real.

The honest limits. A page called “honest” with no limitations would be a credibility own-goal.

Data quality

Fundamentals come from yfinance, free, but rate-limited and occasionally stale. Several Yahoo balance-sheet ratios (ROE, ROIC, D/E, Altman Z) return on a wrong scale and are currently hidden from the UI rather than displayed inaccurately.

Hardcoded constants

Sub-sector multiples and a handful of WACC inputs are still hand-set. Every one is named in HARDCODED_VALUES.md alongside the phase plan to replace it with live peer-comp computation.

Factor model status

The V/M/Q signal exists in the codebase. It is not yet a user-facing recommendation. IC and t-stat tracking run walk-forward in ml/monitor.py; the model is held back from the UI until it clears the gate.

Coverage

US-listed equities only. International tickers, ADRs without US listings, and derivatives are out of scope. Banks and REITs use simpler P/B and P/FFO models, no full DCF for those archetypes.

Not investment advice

The fair value depends entirely on the assumptions. Change one input and the headline changes. AXIOM is a tool for thinking through valuation, not a recommendation engine.