Metadata-Version: 2.5
Name: openvaluation
Version: 0.1.0
Summary: Startup valuation methods as auditable code: Berkus, Scorecard, Risk Factor Summation, VC Method, First Chicago and market multiples.
Project-URL: Homepage, https://github.com/yagebin79386/openvaluation
Project-URL: Documentation, https://github.com/yagebin79386/openvaluation/blob/main/docs/README.md
Project-URL: Source, https://github.com/yagebin79386/openvaluation
Project-URL: Issues, https://github.com/yagebin79386/openvaluation/issues
Project-URL: Changelog, https://github.com/yagebin79386/openvaluation/blob/main/CHANGELOG.md
Author: Ruiqi Tan
License: MIT License
        
        Copyright (c) 2026 Ruiqi Tan
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Keywords: angel-investing,berkus,finance,fundraising,pre-revenue,scorecard,startup,valuation,venture-capital
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Office/Business :: Financial
Classifier: Typing :: Typed
Requires-Python: >=3.9
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == 'dev'
Provides-Extra: mcp
Requires-Dist: mcp>=2.0; extra == 'mcp'
Description-Content-Type: text/markdown

# openvaluation

**Startup valuation methods as auditable code.** Berkus, Scorecard, Risk Factor Summation, the VC
Method, First Chicago and market multiples — implemented, tested, and able to show their working.

Free and open source, MIT licensed. Pure Python, **no dependencies**, no API keys, no network calls.

```bash
pip install openvaluation
```

The pre-revenue methods angel groups actually use live in textbooks, worksheets and spreadsheets,
but not in maintained software. Search GitHub for "Berkus method" and you find a scatter of
zero-star scripts; every commercial tool that implements these keeps the arithmetic closed. This
package is that missing piece: a library an agent, a script or a notebook can call and get a
defensible number back, with the derivation attached.

```python
from openvaluation import Engine

company = {
    "company": {"sector": "saas", "stage": "seed", "region": "us"},
    "financials": {"revenue": {"arr": 480_000}},
    "berkus": {"sound_idea": 1.0, "prototype": 1.0, "management_team": 0.8,
               "strategic_relationships": 0.4, "product_rollout": 0.6},
    "scorecard": {"management_team": 1.25, "opportunity_size": 1.4},
}

print(Engine().run_all(company, stage="seed").summary())
```

```
4 methods ran; median 4,420,000 USD (range 1,400,000–6,462,500)

  berkus                         1,900,000  [1,400,000 – 2,400,000]
  ev_arr                         3,840,000  [2,400,000 – 5,760,000]
  risk_factor_summation          5,000,000  [4,750,000 – 5,250,000]
  scorecard                      5,875,000  [5,287,500 – 6,462,500]

  2 methods could not run:
    vc_method: vc_method needs exit.value, exit.revenue (supply an exit value, or
      projected revenue at exit to apply a multiple to)
    first_chicago: first_chicago needs scenarios.success.probability, ...
```

## Extraction is probabilistic; arithmetic should not be

Language models get asked what a startup is worth constantly, and they are bad at it — not at the
reasoning, at the arithmetic and at remembering which method needs which input. They are, however,
very good at reading a pitch deck and pulling out structured facts.

This package draws the line between those two jobs. The model reads the documents and fills in the
fields. The engine does the arithmetic, deterministically, and reports exactly how it got there.
Same input, same output, every time — with no model in the loop to drift.

```python
result = Engine().run(company, "berkus")
print(result.explain())
```

```
berkus: 1,900,000 USD (range 1,400,000–2,400,000)

Steps
  1. Sound idea — basic value, product risk: 500,000  — rating 1.00
  2. Prototype — technology risk: 500,000  — rating 1.00
  3. Quality management team — execution risk: 400,000  — rating 0.80
  4. Strategic relationships — market risk: 200,000  — rating 0.40
  5. Product rollout or sales — production risk: 300,000  — rating 0.60
  6. Pre-money valuation: 1,900,000  — sum of five elements

Assumptions
  cap_per_element: 500000.0

Limitations
  - Berkus caps pre-revenue value and ignores market size, growth and financials.
  - Ratings are judgements, not measurements; this run capped at 2,500,000.
  - This company reports revenue; Berkus was designed for pre-revenue companies
    and a revenue-based method will usually say more.

Sources
  - Dave Berkus, 'The Berkus Method: Valuing an Early Stage Investment' (berkonomics.com)
```

Every result carries its steps, its assumptions, its limitations, and a citation for the method.
A valuation nobody can check is not worth defending.

## What can I even run?

Usually the question comes before the valuation: given what is known about this company, which
methods are available, and what one missing fact would unlock the most?

```python
report = Engine().readiness(company)

[m.method for m in report.ready]     # ['berkus', 'scorecard', 'risk_factor_summation', 'ev_arr']
report.unlocks()
# {'exit.value|exit.revenue': ('vc_method',),
#  'financials.ebitda': ('ev_ebitda',),
#  'financials.revenue.annual': ('ev_revenue',)}
```

`unlocks()` is ordered by how many methods each missing field frees up, so the first entry is the
most useful thing to go and find out. A `|` in a path means either field will do.

A method reported ready always runs — that invariant is tested, because a readiness report that
lies is worse than none.

## The methods

| id | Method | Applies when | Needs |
|---|---|---|---|
| `berkus` | Berkus Method | Pre-revenue | Ratings for five risk elements |
| `scorecard` | Scorecard Method | Pre-revenue | A sector, plus ratings against comparable companies |
| `risk_factor_summation` | Risk Factor Summation | Pre-revenue | A sector, plus ratings across twelve risks |
| `vc_method` | Venture Capital Method | Raising, with a credible exit | An exit value or exit revenue |
| `first_chicago` | First Chicago Method | Outcomes are genuinely bimodal | Three scenarios with probabilities |
| `ev_arr` | EV / ARR | Subscription revenue | ARR and a sector |
| `ev_revenue` | EV / Revenue | Revenue, not yet profitable | Annual revenue and a sector |
| `ev_ebitda` | EV / EBITDA | Profitable | Positive EBITDA and a sector |

**[Full documentation for each method](docs/README.md)** — formula, worked example, limitations and
source, one page each. Every example on those pages is executed by the test suite, so none of it
can drift from the code.

Each is implemented from its published description and cites it. The Scorecard weights are Bill
Payne's (30% team, 25% opportunity, 15% product, 10% competition, 10% sales, 5% investment need,
5% other); Berkus caps five elements at 500,000 each; Risk Factor Summation moves a comparable
average by 250,000 a step across twelve factors. Every one of those constants is a constructor
argument, not a magic number buried in the arithmetic.

```python
from openvaluation import Berkus, RiskFactorSummation

Berkus(cap_per_element=300_000)          # a market where 500k is too rich
RiskFactorSummation(step=100_000)        # finer-grained risk adjustments
```

## Benchmark data is your problem, and the package says so

Three methods need outside numbers: what comparable companies are worth, what multiple a sector
trades on, what rate a fund underwrites to. Those numbers go stale and no library should pretend
otherwise, so they arrive through a provider you supply.

The default provider ships **illustrative placeholders** — round, undated figures so that examples
run. Any valuation that touches them says so in its limitations:

```
  - Benchmark figures are illustrative placeholders, not market data; replace
    StaticBenchmarks with a real source before relying on this figure
```

Methods that never consult market data, like Berkus, do not carry that caveat. Supply real figures
and it goes away:

```python
from openvaluation import Engine, Multiple, TableBenchmarks

benchmarks = TableBenchmarks(
    seed_valuations={"saas": 4_200_000},
    multiple_table={("saas", "ARR"): Multiple(4.1, 6.8, 11.2, basis="ARR",
                                              source="Our comp set", sample_size=180,
                                              as_of="2026-06-30")},
    rate_table={"seed": 0.5},
    citations=("Our comp set, n=180, June 2026",),
)

engine = Engine(benchmarks=benchmarks)
```

Or implement `BenchmarkProvider` over whatever you have — a database, an API, a spreadsheet. Three
methods, all synchronous. Sector multiples and costs of capital published by Aswath Damodaran at
NYU Stern are the usual free starting point.

A provider that has no figure raises `UnknownBenchmark` rather than substituting a guess, because a
valuation built on an invented multiple is worse than no valuation.

## Give it to an AI agent

Ship the methods to whatever model you already talk to. The MCP server exposes four tools, and
because the arithmetic happens in Python the model cannot get the sums wrong:

```bash
pip install "openvaluation[mcp]"
```

```json
{"mcpServers": {"openvaluation": {"command": "openvaluation-mcp"}}}
```

| Tool | What it does |
|---|---|
| `list_valuation_methods` | Every method, and the exact input format, so the model fills in real field names |
| `check_valuation_readiness` | What the data already supports, and which missing field unlocks the most — so the model asks rather than invents |
| `value_company` | Every applicable method at once, with a range and the ones that could not run |
| `explain_valuation` | One method's full derivation, for the write-up |

The server's instructions tell the model the things it would otherwise get wrong: that Berkus and
Scorecard ratings are judgements needing evidence, that the shipped benchmark figures are
placeholders whose caveat must be passed on, and that the median alone is not the answer.

The same four functions are importable without MCP, for an HTTP handler or a notebook:

```python
from openvaluation.tools import check_readiness, value_company

check_readiness(company)   # plain dicts in, plain dicts out
```

## From the command line

```bash
openvaluation company.json                     # every applicable method
openvaluation company.json --readiness         # what can run, what is missing
openvaluation company.json --method berkus --explain
openvaluation company.json --json              # for piping onward
openvaluation --list-methods
```

## Input format

A plain nested dict — whatever your extraction step produced. Fields are read by dotted path, so
nothing needs to be complete:

```json
{
  "company":    {"sector": "saas", "stage": "seed", "region": "us"},
  "financials": {"revenue": {"arr": 480000, "annual": 520000}, "ebitda": 90000},
  "product":    {"stage": "mvp"},
  "berkus":     {"sound_idea": 1.0, "prototype": 0.8},
  "scorecard":  {"management_team": 1.25, "opportunity_size": 1.4},
  "risk":       {"management": 2, "competition": -1},
  "exit":       {"revenue": 40000000, "years": 5, "dilution": 0.3},
  "funding":    {"round_size": 2000000},
  "scenarios":  {"success": {"value": 80000000, "probability": 0.15},
                 "base":    {"value": 15000000, "probability": 0.35},
                 "failure": {"value": 0,        "probability": 0.50}}
}
```

Amounts may be bare numbers, numeric strings, or `{"value": 480000, "currency": "USD"}` objects.
Rates may be `0.4` or `40`. Zero counts as absent for quantities like revenue, because zero revenue
and unknown revenue are the same input to these methods.

## What this is not

- **Not investment advice, and not a 409A valuation.** These methods produce negotiating anchors
  and sanity checks. A valuation with legal or tax standing needs a qualified appraiser.
- **Not an extractor.** It takes structured facts; getting them out of a pitch deck is a separate
  job, and a good one for a language model.
- **Not a source of market data.** See above.
- **Not a judgement engine.** Berkus ratings and Scorecard factors are judgements about a company.
  The package records and applies them; it does not form them.

When methods disagree by more than the median, the report says so — because that disagreement is
information, and averaging it away destroys it.

## Requirements

Python 3.9+ (developed and tested on 3.11). No runtime dependencies.

## Where this came from

I built the valuation engine behind [Wakeworth](https://wakeworth.app), which values startups from
uploaded documents. The methods themselves are public knowledge and belong in public code; what
stays proprietary there is the document extraction and reporting around them. This package is the
methods layer, rebuilt standalone from the published descriptions, with the constants exposed and
every result made to show its working.

## Contributing

Issues and pull requests are welcome. I maintain this on a best-effort basis alongside other work,
so expect considered replies rather than fast ones. The most useful contributions are a method
implemented from a citable source, or a case where the arithmetic here disagrees with a worked
example in the literature.

```bash
git clone https://github.com/yagebin79386/openvaluation
cd openvaluation
pip install -e ".[dev]"
pytest
```

## License

MIT — see [LICENSE](LICENSE).

---

*Last updated: 2026-08-20 · [Changelog](CHANGELOG.md)*
