shadowprice 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. shadowprice-0.1.0/.gitattributes +4 -0
  2. shadowprice-0.1.0/.github/workflows/ci.yml +91 -0
  3. shadowprice-0.1.0/.github/workflows/release.yml +84 -0
  4. shadowprice-0.1.0/.gitignore +12 -0
  5. shadowprice-0.1.0/CHANGELOG.md +25 -0
  6. shadowprice-0.1.0/CITATION.cff +15 -0
  7. shadowprice-0.1.0/CONTRIBUTING.md +54 -0
  8. shadowprice-0.1.0/LICENSE +21 -0
  9. shadowprice-0.1.0/PKG-INFO +214 -0
  10. shadowprice-0.1.0/README.md +181 -0
  11. shadowprice-0.1.0/examples/water_network.py +171 -0
  12. shadowprice-0.1.0/pyproject.toml +63 -0
  13. shadowprice-0.1.0/src/shadowprice/__init__.py +75 -0
  14. shadowprice-0.1.0/src/shadowprice/_basis.py +62 -0
  15. shadowprice-0.1.0/src/shadowprice/_version.py +1 -0
  16. shadowprice-0.1.0/src/shadowprice/benefits.py +65 -0
  17. shadowprice-0.1.0/src/shadowprice/conversion.py +168 -0
  18. shadowprice-0.1.0/src/shadowprice/discounting.py +147 -0
  19. shadowprice-0.1.0/src/shadowprice/economic.py +211 -0
  20. shadowprice-0.1.0/src/shadowprice/financial.py +228 -0
  21. shadowprice-0.1.0/src/shadowprice/financing.py +128 -0
  22. shadowprice-0.1.0/src/shadowprice/lines.py +99 -0
  23. shadowprice-0.1.0/src/shadowprice/methods.py +120 -0
  24. shadowprice-0.1.0/src/shadowprice/presets/__init__.py +1 -0
  25. shadowprice-0.1.0/src/shadowprice/presets/adb_2017.toml +22 -0
  26. shadowprice-0.1.0/src/shadowprice/presets/eu_2014.toml +48 -0
  27. shadowprice-0.1.0/src/shadowprice/presets/wb_2016.toml +24 -0
  28. shadowprice-0.1.0/src/shadowprice/project.py +259 -0
  29. shadowprice-0.1.0/src/shadowprice/report.py +171 -0
  30. shadowprice-0.1.0/src/shadowprice/risk.py +275 -0
  31. shadowprice-0.1.0/src/shadowprice/timeline.py +94 -0
  32. shadowprice-0.1.0/tests/conftest.py +19 -0
  33. shadowprice-0.1.0/tests/test_benefits.py +23 -0
  34. shadowprice-0.1.0/tests/test_conversion_methods.py +69 -0
  35. shadowprice-0.1.0/tests/test_discounting.py +72 -0
  36. shadowprice-0.1.0/tests/test_economic.py +117 -0
  37. shadowprice-0.1.0/tests/test_financial.py +118 -0
  38. shadowprice-0.1.0/tests/test_readme.py +14 -0
  39. shadowprice-0.1.0/tests/test_report_and_example.py +37 -0
  40. shadowprice-0.1.0/tests/test_risk.py +108 -0
  41. shadowprice-0.1.0/tests/test_timeline.py +40 -0
@@ -0,0 +1,4 @@
1
+ # Normalise line endings so commits from Windows and Unix match.
2
+ * text=auto eol=lf
3
+ *.xlsx binary
4
+ *.png binary
@@ -0,0 +1,91 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_dispatch:
8
+
9
+ defaults:
10
+ run:
11
+ shell: bash
12
+
13
+ jobs:
14
+ lint:
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ - uses: actions/setup-python@v5
19
+ with:
20
+ python-version: "3.13"
21
+ - run: pip install ruff
22
+ - run: ruff check .
23
+ - run: ruff format --check .
24
+
25
+ test:
26
+ name: test (${{ matrix.os }}, Python ${{ matrix.python-version }})
27
+ runs-on: ${{ matrix.os }}
28
+ strategy:
29
+ fail-fast: false
30
+ matrix:
31
+ os: [ubuntu-latest, windows-latest, macos-latest]
32
+ python-version: ["3.11", "3.12", "3.13", "3.14"]
33
+ steps:
34
+ - uses: actions/checkout@v4
35
+ - uses: actions/setup-python@v5
36
+ with:
37
+ python-version: ${{ matrix.python-version }}
38
+ - run: pip install -e ".[dev]"
39
+ - run: pytest --cov=shadowprice --cov-report=term-missing
40
+
41
+ oldest-dependencies:
42
+ # The lowest versions declared in pyproject.toml must keep working.
43
+ runs-on: ubuntu-latest
44
+ steps:
45
+ - uses: actions/checkout@v4
46
+ - uses: actions/setup-python@v5
47
+ with:
48
+ python-version: "3.11"
49
+ - name: Install with oldest supported dependencies
50
+ run: |
51
+ printf 'numpy==1.24.*\npandas==2.0.*\nopenpyxl==3.1.0\n' > oldest.txt
52
+ pip install -e ".[dev]" -c oldest.txt
53
+ python -c "import numpy, pandas; print('numpy', numpy.__version__, 'pandas', pandas.__version__)"
54
+ - run: pytest
55
+
56
+ installed-package:
57
+ # Build the wheel and test it the way users install it (not editable).
58
+ name: installed package (${{ matrix.os }})
59
+ runs-on: ${{ matrix.os }}
60
+ strategy:
61
+ fail-fast: false
62
+ matrix:
63
+ os: [ubuntu-latest, windows-latest]
64
+ steps:
65
+ - uses: actions/checkout@v4
66
+ - uses: actions/setup-python@v5
67
+ with:
68
+ python-version: "3.13"
69
+ - name: Build sdist and wheel
70
+ run: |
71
+ pip install build twine
72
+ python -m build
73
+ twine check dist/*
74
+ - name: Install the wheel into a clean environment
75
+ run: |
76
+ python -m venv /tmp/clean || python -m venv clean-env
77
+ if [ -d /tmp/clean/bin ]; then PY=/tmp/clean/bin/python; \
78
+ elif [ -d /tmp/clean/Scripts ]; then PY=/tmp/clean/Scripts/python; \
79
+ else PY=clean-env/Scripts/python; fi
80
+ echo "PY=$PY" >> "$GITHUB_ENV"
81
+ WHEEL=$(ls dist/*.whl)
82
+ "$PY" -m pip install "${WHEEL}[excel]" pytest
83
+ - name: Check the installed copy is used
84
+ run: |
85
+ "$PY" -c "import shadowprice as sp; assert 'site-packages' in sp.__file__, sp.__file__; print(sp.__version__, sp.available_methods())"
86
+ - name: Run tests against the installed package
87
+ run: '"$PY" -m pytest -p no:cacheprovider'
88
+ - name: Run the worked example
89
+ run: |
90
+ mkdir -p run && cd run
91
+ "$PY" ../examples/water_network.py
@@ -0,0 +1,84 @@
1
+ name: Release
2
+
3
+ # Publishing a GitHub Release (tag vX.Y.Z) uploads the package to PyPI.
4
+ # "Run workflow" in the Actions tab can upload to TestPyPI for a trial.
5
+ # Authentication uses PyPI trusted publishing: no passwords or tokens are stored.
6
+
7
+ on:
8
+ release:
9
+ types: [published]
10
+ workflow_dispatch:
11
+ inputs:
12
+ target:
13
+ description: "Where to publish"
14
+ type: choice
15
+ options: [testpypi, pypi]
16
+ default: testpypi
17
+
18
+ jobs:
19
+ build:
20
+ name: Build distributions
21
+ runs-on: ubuntu-latest
22
+ steps:
23
+ - uses: actions/checkout@v4
24
+ - uses: actions/setup-python@v5
25
+ with:
26
+ python-version: "3.13"
27
+ - name: Check that the release tag matches the package version
28
+ if: github.event_name == 'release'
29
+ run: |
30
+ version=$(python -c "import re; print(re.search(r'\"(.+)\"', open('src/shadowprice/_version.py').read()).group(1))")
31
+ if [ "${GITHUB_REF_NAME}" != "v${version}" ]; then
32
+ echo "::error::Tag ${GITHUB_REF_NAME} does not match package version v${version}"
33
+ exit 1
34
+ fi
35
+ - name: Build and check
36
+ run: |
37
+ pip install build twine
38
+ python -m build
39
+ twine check --strict dist/*
40
+ - name: Test the built wheel
41
+ run: |
42
+ python -m venv /tmp/clean
43
+ /tmp/clean/bin/pip install "$(ls dist/*.whl)[excel]" pytest
44
+ /tmp/clean/bin/python -m pytest -q -p no:cacheprovider
45
+ - uses: actions/upload-artifact@v4
46
+ with:
47
+ name: dist
48
+ path: dist/
49
+
50
+ publish-testpypi:
51
+ name: Publish to TestPyPI
52
+ if: github.event_name == 'workflow_dispatch' && inputs.target == 'testpypi'
53
+ needs: build
54
+ runs-on: ubuntu-latest
55
+ environment:
56
+ name: testpypi
57
+ url: https://test.pypi.org/p/shadowprice
58
+ permissions:
59
+ id-token: write
60
+ steps:
61
+ - uses: actions/download-artifact@v4
62
+ with:
63
+ name: dist
64
+ path: dist/
65
+ - uses: pypa/gh-action-pypi-publish@release/v1
66
+ with:
67
+ repository-url: https://test.pypi.org/legacy/
68
+
69
+ publish-pypi:
70
+ name: Publish to PyPI
71
+ if: github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && inputs.target == 'pypi')
72
+ needs: build
73
+ runs-on: ubuntu-latest
74
+ environment:
75
+ name: pypi
76
+ url: https://pypi.org/p/shadowprice
77
+ permissions:
78
+ id-token: write
79
+ steps:
80
+ - uses: actions/download-artifact@v4
81
+ with:
82
+ name: dist
83
+ path: dist/
84
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,12 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .venv/
5
+ build/
6
+ dist/
7
+ .pytest_cache/
8
+ .ruff_cache/
9
+ .coverage
10
+ htmlcov/
11
+ *.xlsx
12
+ .ipynb_checkpoints/
@@ -0,0 +1,25 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 — 2026-11-15
4
+
5
+ First public release (alpha).
6
+
7
+ * CI: tests on Linux, Windows and macOS with Python 3.11–3.14, a job with the oldest
8
+ supported dependencies, and a job that builds the wheel and tests the installed package.
9
+ * README: install without git; note on installing into an IDE's environment.
10
+ * Release workflow: publishing a GitHub Release uploads to PyPI via trusted publishing;
11
+ manual runs can upload to TestPyPI.
12
+
13
+ * Project and scenario model with incremental (with/without) analysis.
14
+ * Financial analysis: FNPV/FRR on investment (C) and on national capital (K), financial
15
+ sustainability, funding gap rate; loan schedules (annuity/linear, grace periods).
16
+ * Economic analysis: fiscal corrections, tariff exclusion, conversion factors under
17
+ domestic or world numeraire, ENPV, EIRR, B/C, ENPV profile, distribution of net benefits
18
+ by stakeholder.
19
+ * National parameters: SCF, SERF, shadow wage factor, traded-input CF, Ramsey SDR.
20
+ * Method presets: `eu_2014`, `adb_2017`, `wb_2016`; custom presets from TOML files.
21
+ * Risk analysis: sensitivity elasticities, critical variables, switching values, scenario
22
+ NPV, Monte Carlo (triangular, uniform, normal, discrete; Gaussian-copula correlation).
23
+ * Benefit helpers: willingness to pay, consumer surplus (rule of half), time savings,
24
+ avoided costs, emissions, price paths.
25
+ * Reporting: summary and flow tables, Excel export with English and Russian labels.
@@ -0,0 +1,15 @@
1
+ cff-version: 1.2.0
2
+ message: "If you use this software, please cite it as below."
3
+ title: "shadowprice: economic cost-benefit analysis of investment projects in Python"
4
+ type: software
5
+ authors:
6
+ - family-names: Iskakov
7
+ given-names: Serik
8
+ version: 0.1.0
9
+ license: MIT
10
+ repository-code: "https://github.com/iskakovs/shadowprice"
11
+ keywords:
12
+ - cost-benefit analysis
13
+ - project appraisal
14
+ - shadow prices
15
+ - public investment
@@ -0,0 +1,54 @@
1
+ # Contributing to shadowprice
2
+
3
+ ## Development setup
4
+
5
+ ```bash
6
+ git clone https://github.com/iskakovs/shadowprice
7
+ cd shadowprice
8
+ python -m venv .venv && source .venv/bin/activate
9
+ pip install -e ".[dev]"
10
+ pytest
11
+ ruff check . && ruff format --check .
12
+ ```
13
+
14
+ ## Ground rules
15
+
16
+ * **Every parameter has a source.** Discount rates, conversion factors and reference
17
+ periods must cite the guideline, edition and section they come from.
18
+ * **Every formula has a test** with an expected value computed by hand or taken from a
19
+ published worked example.
20
+ * Keep the core dependencies to `numpy` and `pandas`.
21
+
22
+ ## Adding a method preset
23
+
24
+ Presets live in `src/shadowprice/presets/<id>.toml`. Top-level keys must come before any
25
+ table (`[sdr_options]`, `[reference_periods]`).
26
+
27
+ ```toml
28
+ id = "kz_example" # file name without .toml
29
+ title = "Short title"
30
+ source = "Full reference: issuer, document, date, section"
31
+ year = 2025
32
+ numeraire = "domestic" # "domestic" or "world"
33
+ financial_discount_rate = 0.05 # optional
34
+ social_discount_rate = 0.08 # or use [sdr_options] / sdr_rule = "ramsey"
35
+ default_cf = 1.0
36
+ critical_threshold = 0.01
37
+ notes = ["Anything users must know when applying the method."]
38
+
39
+ [sdr_options] # optional alternative rates
40
+ general = 0.08
41
+
42
+ [reference_periods] # years, [min, max]
43
+ water_supply_sanitation = [25, 30]
44
+ ```
45
+
46
+ Add a test in `tests/test_conversion_methods.py` that loads the preset and checks its
47
+ values, and list it in the README table.
48
+
49
+ ## Pull requests
50
+
51
+ 1. Open an issue describing the change.
52
+ 2. Add tests and documentation.
53
+ 3. Make sure `pytest` and `ruff` pass.
54
+ 4. Add a line to `CHANGELOG.md`.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Serik Iskakov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,214 @@
1
+ Metadata-Version: 2.5
2
+ Name: shadowprice
3
+ Version: 0.1.0
4
+ Summary: Economic cost-benefit analysis of investment projects: financial analysis, shadow prices, ENPV/EIRR and risk analysis following EU, ADB and World Bank methods.
5
+ Project-URL: Homepage, https://github.com/iskakovs/shadowprice
6
+ Project-URL: Issues, https://github.com/iskakovs/shadowprice/issues
7
+ Author: Serik Iskakov
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Keywords: EIRR,ENPV,conversion factors,cost-benefit analysis,economic analysis,infrastructure,project appraisal,public investment,shadow prices
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Financial and Insurance Industry
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Classifier: Topic :: Office/Business :: Financial
21
+ Classifier: Topic :: Scientific/Engineering
22
+ Requires-Python: >=3.11
23
+ Requires-Dist: numpy>=1.24
24
+ Requires-Dist: pandas>=2.0
25
+ Provides-Extra: dev
26
+ Requires-Dist: openpyxl>=3.1; extra == 'dev'
27
+ Requires-Dist: pytest-cov>=5; extra == 'dev'
28
+ Requires-Dist: pytest>=8; extra == 'dev'
29
+ Requires-Dist: ruff>=0.5; extra == 'dev'
30
+ Provides-Extra: excel
31
+ Requires-Dist: openpyxl>=3.1; extra == 'excel'
32
+ Description-Content-Type: text/markdown
33
+
34
+ # shadowprice
35
+
36
+ [![CI](https://github.com/iskakovs/shadowprice/actions/workflows/ci.yml/badge.svg)](https://github.com/iskakovs/shadowprice/actions/workflows/ci.yml)
37
+ [![PyPI](https://img.shields.io/pypi/v/shadowprice.svg)](https://pypi.org/project/shadowprice/)
38
+ [![Python](https://img.shields.io/pypi/pyversions/shadowprice.svg)](https://pypi.org/project/shadowprice/)
39
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
40
+
41
+ **Economic cost-benefit analysis of investment projects in Python** — financial analysis,
42
+ shadow prices and conversion factors, ENPV/EIRR/B-C and risk analysis, following the
43
+ methods of the European Commission, the Asian Development Bank and the World Bank.
44
+
45
+ > Status: alpha (v0.1.0). The API may change before 1.0.
46
+
47
+ ## Why
48
+
49
+ Economic appraisal of public investment (roads, water, energy, municipal infrastructure,
50
+ PPPs) is still done almost entirely in spreadsheets: discount factors, conversion factors
51
+ and risk simulations are rebuilt by hand for every project, and results are hard to audit
52
+ or reproduce. Open-source tools cover only fragments — a road-only CBA module, the UK
53
+ Green Book in R, health-economics packages — but not the EU / development-bank method.
54
+
55
+ `shadowprice` turns that method into tested, reusable code:
56
+
57
+ * **Methods as data** – EU 2014 guide, ADB 2017 and World Bank 2016 rules ship as versioned
58
+ presets with their sources. Run the same project under different methods, or add your
59
+ own national rules as a TOML file.
60
+ * **Full pipeline** – with/without (incremental) scenarios → financial analysis →
61
+ fiscal corrections → conversion to economic prices → ENPV, EIRR, B/C → risk analysis →
62
+ distribution of net benefits.
63
+ * **Risk analysis without add-ins** – exact sensitivity elasticities, critical variables,
64
+ switching values and vectorised Monte Carlo with correlated inputs.
65
+ * **Auditable output** – every line keeps its conversion factor, tax share and source;
66
+ results export to Excel with English or Russian labels.
67
+
68
+ ## Install
69
+
70
+ From PyPI:
71
+
72
+ ```bash
73
+ pip install "shadowprice[excel]"
74
+ ```
75
+
76
+ The latest development version from GitHub (requires [git](https://git-scm.com)):
77
+
78
+ ```bash
79
+ pip install "shadowprice[excel] @ git+https://github.com/iskakovs/shadowprice"
80
+ ```
81
+
82
+ Without git, from the source archive:
83
+
84
+ ```bash
85
+ pip install "shadowprice[excel] @ https://github.com/iskakovs/shadowprice/archive/refs/heads/main.zip"
86
+ ```
87
+
88
+ Python 3.11+. Core dependencies: `numpy` (≥ 1.24) and `pandas` (≥ 2.0); the `excel` extra adds
89
+ `openpyxl`. CI runs the test suite on Linux, Windows and macOS with Python 3.11–3.14, with
90
+ the oldest supported dependencies, and against the built wheel.
91
+
92
+ > **Using an IDE (PyCharm, VS Code)?** Install into the interpreter your project uses — e.g.
93
+ > from the IDE's terminal, where the project's virtual environment is already active.
94
+
95
+ ## Quick start
96
+
97
+ ```python
98
+ import shadowprice as sp
99
+ from shadowprice import benefits as bf
100
+
101
+ p = sp.Project(
102
+ "Water network",
103
+ start_year=2026,
104
+ horizon=30,
105
+ currency="mln KZT",
106
+ sector="water_supply_sanitation",
107
+ )
108
+
109
+ # With-project scenario (market prices, constant 2026 prices)
110
+ w = p.scenario("with")
111
+ w.investment("Imported pipes", {2026: 1800, 2027: 1200}, cf="traded", tax_share=0.12, group="capex")
112
+ w.investment("Civil works", {2026: 900, 2027: 700}, cf="non_traded", tax_share=0.12, group="capex")
113
+ w.om("Operation", 215, start=2028, group="opex")
114
+ w.revenue("Tariffs", 570, start=2028, group="demand") # excluded from economic analysis
115
+ w.benefit("Willingness to pay", bf.willingness_to_pay(6.0, 160), start=2028, group="demand")
116
+ w.residual_straight_line(45)
117
+
118
+ # Counterfactual (business as usual); the analysis uses with - without
119
+ wo = p.scenario("without")
120
+ wo.om("Emergency repairs", 290, group="opex")
121
+ wo.revenue("Tariffs (current)", 430, group="demand")
122
+ wo.benefit("Willingness to pay (current)", bf.willingness_to_pay(4.5, 160), group="demand")
123
+
124
+ fin = p.financial(rate=0.04) # FNPV/FRR(C), funding gap
125
+ eco = p.economic("adb_2017", national=sp.NationalParameters(serf=1.05))
126
+
127
+ print(fin.summary())
128
+ print(eco.summary()) # ENPV, EIRR, B/C
129
+ print(sp.sensitivity(eco)) # critical variables, switching values
130
+
131
+ mc = sp.monte_carlo(
132
+ eco, {"capex": sp.Triangular(-0.05, 0, 0.35), "demand": sp.Normal(0, 0.15)}, n=10_000, seed=1
133
+ )
134
+ print(f"P(ENPV < 0) = {mc.prob_negative:.1%}")
135
+
136
+ sp.report.to_excel("cba.xlsx", financial=fin, economic=eco, montecarlo=mc, lang="ru")
137
+ ```
138
+
139
+ A complete worked example (financing, loans, sustainability, distribution analysis) is in
140
+ [`examples/water_network.py`](examples/water_network.py).
141
+
142
+ ## Core concepts
143
+
144
+ **Lines.** Every cash flow is a line with a *kind* — `investment`, `replacement`, `om`,
145
+ `revenue`, `residual` (financial analysis) or `benefit`, `external_cost` (economic only).
146
+ Values are positive magnitudes in market prices; the sign follows the kind.
147
+
148
+ **Scenarios.** Lines live in a `"with"` scenario and, optionally, a `"without"`
149
+ counterfactual. All indicators are computed on the increment, so avoided costs in the
150
+ counterfactual become benefits automatically.
151
+
152
+ **Economic prices.** For each line: `economic = market × (1 − tax_share) × CF`. Revenues
153
+ (tariffs) are transfers and are dropped unless flagged `as_benefit=True`; benefits are
154
+ entered directly at economic prices.
155
+
156
+ | CF tag | Domestic numeraire (ADB, WB) | World numeraire (EU 2014) |
157
+ |---|---|---|
158
+ | `"default"` | method default (1.0) | method default (1.0) |
159
+ | `"traded"` | SERF | 1.0 (border prices) |
160
+ | `"non_traded"` | 1.0 | SCF |
161
+ | `"labour_*"` | shadow wage factor | shadow wage factor × SCF |
162
+ | any other tag | `NationalParameters(factors=...)` | same |
163
+ | a number | used as is | used as is |
164
+
165
+ **Methods vs national parameters.** A `Method` holds a guideline's rules (discount rates,
166
+ numeraire, reference periods, critical-variable threshold). Country values (SCF/SERF,
167
+ shadow wages, specific CFs) go in `NationalParameters`. Helpers estimate them:
168
+ `sp.scf(...)`, `sp.shadow_wage_factor(...)`, `sp.ramsey_sdr(...)`.
169
+
170
+ **Risk groups.** Each line has a `group` (default: its kind). Sensitivity and Monte Carlo
171
+ vary groups as relative changes; because NPV is linear in each group, elasticities and
172
+ switching values are exact.
173
+
174
+ ## Bundled methods
175
+
176
+ | id | Source | Numeraire | Discount rates |
177
+ |---|---|---|---|
178
+ | `eu_2014` | EC DG REGIO, *Guide to CBA of Investment Projects* (2014) | world | financial 4% real; social 5% (Cohesion) / 3% (other) |
179
+ | `adb_2017` | ADB, *Guidelines for the Economic Analysis of Projects* (2017) | domestic | 9% (EOCC) |
180
+ | `wb_2016` | World Bank, *Discounting Costs and Benefits in Economic Analysis* (2016) | domestic | Ramsey rule: SDR = 2 × per-capita growth |
181
+
182
+ `sp.method("eu_2014").reference_period("roads")` returns the recommended reference period
183
+ `(25, 30)`. Custom or national methods load from a TOML file: `sp.method("path/to/kz.toml")`.
184
+
185
+ ## Conventions
186
+
187
+ * The first year of the reference period is `t = 0` and is not discounted.
188
+ * Use constant (real) prices with real discount rates; `sp.discounting.deflate` converts
189
+ nominal series.
190
+ * B/C = PV of lines with positive economic PV ÷ PV of lines with negative economic PV.
191
+ * When cash flows have several IRRs, the lowest is returned with a warning; rely on NPV.
192
+
193
+ ## Roadmap
194
+
195
+ * **v0.2** – validation suite reproducing published worked examples (EU guide case
196
+ studies, ADB conversion-factor water example); Kazakh labels; live-formula Excel export;
197
+ estimation of national parameters (SCF/SERF, shadow wage) from trade and labour data.
198
+ * **v0.3** – `ppp` module: public sector comparator, shadow bid, risk transfer, value for
199
+ money, fiscal commitments.
200
+ * **v0.4** – `rab` module: regulatory asset base roll-forward, WACC, building blocks,
201
+ tariff path.
202
+
203
+ ## Contributing
204
+
205
+ Contributions are welcome, especially new method presets and national parameters with
206
+ documented sources. See [CONTRIBUTING.md](CONTRIBUTING.md).
207
+
208
+ ## Citation
209
+
210
+ If you use `shadowprice` in research, please cite it (see [CITATION.cff](CITATION.cff)).
211
+
212
+ ## License
213
+
214
+ MIT © 2026 Serik Iskakov