quantvolt 0.1.0__tar.gz → 0.2.1__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.
- {quantvolt-0.1.0 → quantvolt-0.2.1}/Cargo.lock +1 -1
- {quantvolt-0.1.0 → quantvolt-0.2.1}/Cargo.toml +1 -2
- {quantvolt-0.1.0 → quantvolt-0.2.1}/PKG-INFO +35 -11
- {quantvolt-0.1.0 → quantvolt-0.2.1}/README.md +31 -9
- {quantvolt-0.1.0 → quantvolt-0.2.1}/pyproject.toml +23 -5
- {quantvolt-0.1.0 → quantvolt-0.2.1}/rust/src/paths.rs +2 -2
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/__init__.py +73 -1
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/_validation.py +1 -1
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/assets/dispatch_approx.py +43 -43
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/assets/dispatch_deterministic.py +9 -11
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/assets/dispatch_sdp.py +62 -56
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/assets/long_dated.py +83 -88
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/assets/plant.py +4 -4
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/assets/storage.py +34 -34
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/cli.py +43 -4
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/curvemodels/__init__.py +1 -1
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/curvemodels/multifactor.py +13 -13
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/curvemodels/schwartz_smith.py +35 -38
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/curves/arbitrage.py +8 -10
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/curves/builder.py +10 -11
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/data/__init__.py +2 -2
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/data/base.py +12 -12
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/data/commercial.py +3 -3
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/data/datasets.py +2 -1
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/data/entsoe.py +11 -11
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/data/entsog.py +5 -6
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/data/netztransparenz.py +4 -12
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/data/open_meteo.py +5 -5
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/exceptions.py +1 -1
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/hedging/__init__.py +3 -4
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/hedging/hybrid.py +11 -11
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/hedging/mean_variance.py +5 -5
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/hedging/ppa_nomination.py +4 -12
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/hedging/variance_min.py +11 -11
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/market/outages.py +80 -83
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/market/transmission.py +2 -2
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/market/weather.py +1 -1
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/models/__init__.py +72 -0
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/models/commodity.py +20 -5
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/models/curve.py +4 -4
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/models/discount_curve.py +1 -1
- quantvolt-0.2.1/src/quantvolt/models/instruments.py +507 -0
- quantvolt-0.2.1/src/quantvolt/models/ppa.py +89 -0
- quantvolt-0.2.1/src/quantvolt/models/ppa_terms.py +444 -0
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/models/schedule.py +1 -1
- quantvolt-0.2.1/src/quantvolt/models/units.py +224 -0
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/models/vol_surface.py +1 -1
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/numerics/__init__.py +4 -0
- quantvolt-0.2.1/src/quantvolt/numerics/_degenerate.py +75 -0
- quantvolt-0.2.1/src/quantvolt/numerics/bachelier.py +316 -0
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/numerics/black76.py +8 -21
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/numerics/daycount.py +1 -1
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/numerics/interpolation.py +1 -1
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/numerics/monte_carlo.py +14 -13
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/numerics/risk_adjustment.py +3 -3
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/numerics/rootfind.py +1 -1
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/numerics/spread_models.py +1 -1
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/portfolio/model.py +37 -9
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/portfolio/settlement.py +2 -6
- quantvolt-0.2.1/src/quantvolt/portfolio/valuation.py +626 -0
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/pricing/__init__.py +26 -0
- quantvolt-0.2.1/src/quantvolt/pricing/bachelier.py +108 -0
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/pricing/exotic.py +44 -46
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/pricing/futures.py +7 -7
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/pricing/implied_vol.py +7 -8
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/pricing/mark_to_market.py +8 -8
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/pricing/power_hedge.py +1 -3
- quantvolt-0.2.1/src/quantvolt/pricing/ppa.py +852 -0
- quantvolt-0.2.1/src/quantvolt/pricing/ppa_valuation.py +370 -0
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/pricing/spread_option.py +13 -13
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/pricing/spreads.py +85 -90
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/pricing/swap.py +6 -6
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/pricing/tolling.py +52 -55
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/pricing/transmission_right.py +11 -12
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/pricing/vanilla.py +35 -24
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/risk/aggregation.py +3 -3
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/risk/cashflow_metrics.py +1 -3
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/risk/cfar.py +9 -9
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/risk/covariance.py +2 -2
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/risk/credit_var.py +15 -15
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/risk/engine.py +9 -9
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/risk/mc_var.py +60 -61
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/risk/parametric_var.py +56 -59
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/risk/scenarios.py +7 -6
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/stats/correlation.py +2 -2
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/stats/descriptive.py +3 -3
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/stats/mean_reversion.py +1 -1
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/stats/normality.py +1 -1
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/stats/stationarity.py +1 -1
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/testing.py +6 -2
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/workflow/criteria.py +3 -3
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/workflow/modeling.py +18 -19
- quantvolt-0.1.0/src/quantvolt/models/instruments.py +0 -221
- quantvolt-0.1.0/src/quantvolt/models/ppa.py +0 -54
- quantvolt-0.1.0/src/quantvolt/portfolio/valuation.py +0 -231
- quantvolt-0.1.0/src/quantvolt/pricing/ppa.py +0 -377
- {quantvolt-0.1.0 → quantvolt-0.2.1}/.gitignore +0 -0
- {quantvolt-0.1.0 → quantvolt-0.2.1}/LICENSE +0 -0
- {quantvolt-0.1.0 → quantvolt-0.2.1}/rust/src/asian_mc.rs +0 -0
- {quantvolt-0.1.0 → quantvolt-0.2.1}/rust/src/lib.rs +0 -0
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/_core.pyi +0 -0
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/assets/__init__.py +0 -0
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/assets/_tolerance.py +0 -0
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/curves/__init__.py +0 -0
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/data/dataset_catalog.json +0 -0
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/data/smard.py +0 -0
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/hedging/_conditioning.py +0 -0
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/hedging/ppa_walk_forward.py +0 -0
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/market/__init__.py +0 -0
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/models/greeks.py +0 -0
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/models/interval.py +0 -0
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/models/power_hedge.py +0 -0
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/numerics/_normal.py +0 -0
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/numerics/exotic.py +0 -0
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/portfolio/__init__.py +0 -0
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/pricing/_dates.py +0 -0
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/py.typed +0 -0
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/risk/__init__.py +0 -0
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/risk/_levels.py +0 -0
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/stats/__init__.py +0 -0
- {quantvolt-0.1.0 → quantvolt-0.2.1}/src/quantvolt/workflow/__init__.py +0 -0
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: quantvolt
|
|
3
|
-
Version: 0.1
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Classifier: Development Status :: 3 - Alpha
|
|
5
5
|
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
6
6
|
Classifier: Intended Audience :: Science/Research
|
|
7
7
|
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
8
9
|
Classifier: Programming Language :: Python :: 3.12
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
9
11
|
Classifier: Programming Language :: Rust
|
|
10
12
|
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
11
13
|
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
@@ -28,7 +30,7 @@ Summary: Quantitative analysis of European power and energy markets
|
|
|
28
30
|
Keywords: energy,power,gas,carbon,quant,derivatives,risk-management,pricing,monte-carlo,forward-curve
|
|
29
31
|
Author-email: Nima Bahrami <nima@skillmix.nl>
|
|
30
32
|
License-Expression: MIT
|
|
31
|
-
Requires-Python: >=3.
|
|
33
|
+
Requires-Python: >=3.11
|
|
32
34
|
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
33
35
|
Project-URL: Documentation, https://nimabahrami.github.io/quantvolt/
|
|
34
36
|
Project-URL: Homepage, https://nimabahrami.github.io/quantvolt/
|
|
@@ -51,9 +53,24 @@ Covered markets: EEX Phelix DE/AT power, EPEX SPOT power (DE, FR, NL, BE, GB), T
|
|
|
51
53
|
natural gas (ICE Endex), and EUA carbon allowances — extensible by the caller without editing
|
|
52
54
|
library source. See [docs/european-markets.md](docs/european-markets.md).
|
|
53
55
|
|
|
56
|
+
## Why QuantVolt?
|
|
57
|
+
|
|
58
|
+
A typical desk assembles a curve spreadsheet, a standalone options pricer, a storage/dispatch
|
|
59
|
+
optimizer and a bolted-on VaR tool, each with its own units, sign conventions and delivery-period
|
|
60
|
+
identity — hand-reconciling between them is slow and a recurring source of quiet errors. QuantVolt
|
|
61
|
+
instead moves the same immutable `ForwardCurve` / `DeliveryPeriod` / `MarketData` / `Greeks` value
|
|
62
|
+
objects through curve construction, pricing, portfolio valuation, risk, realized settlement and
|
|
63
|
+
physical-asset valuation, with determinism, eager validation and serializability enforced
|
|
64
|
+
structurally rather than left to convention. It is equally explicit about scope: a PPA stays
|
|
65
|
+
`unpriced` until you register a forward-looking pricer, storage/dispatch results are brought into
|
|
66
|
+
a portfolio explicitly, no market data ships with the package, and approximations (Kirk,
|
|
67
|
+
Turnbull-Wakeman, `bang_bang`) are labelled, never hidden. See
|
|
68
|
+
[the "Why QuantVolt?" page](https://nimabahrami.github.io/quantvolt/#/guide/why) and the
|
|
69
|
+
[external validation evidence](docs/validation.md) for the checkable version of these claims.
|
|
70
|
+
|
|
54
71
|
## Install
|
|
55
72
|
|
|
56
|
-
Requires Python 3.
|
|
73
|
+
Requires Python 3.11+.
|
|
57
74
|
|
|
58
75
|
```bash
|
|
59
76
|
uv add quantvolt # or: pip install quantvolt
|
|
@@ -113,10 +130,11 @@ Call premium: 45,663 EUR (delta 5,288 EUR per EUR/MWh)
|
|
|
113
130
|
Book NPV: 9,133 EUR, VaR(95): 11,715 EUR
|
|
114
131
|
```
|
|
115
132
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
that last invariant in
|
|
133
|
+
Repeated calls with the same inputs, seed, QuantVolt version, architecture, and native build
|
|
134
|
+
produce identical results. Monte Carlo honours a `seed`, inputs are validated eagerly (no silent
|
|
135
|
+
partial results), results round-trip through plain dicts / JSON, and the library never mutates
|
|
136
|
+
caller data — `quantvolt.testing.assert_input_unchanged` lets you verify that last invariant in
|
|
137
|
+
your own tests.
|
|
120
138
|
|
|
121
139
|
### Settle a PPA with your own interval data
|
|
122
140
|
|
|
@@ -295,7 +313,7 @@ specialised names stay on their sub-package. Full reference with a runnable exam
|
|
|
295
313
|
| `quantvolt.stats` | Descriptive statistics, normality tests, ADF/KPSS stationarity with Samuelson-effect detection, correlation, Ornstein-Uhlenbeck mean reversion |
|
|
296
314
|
| `quantvolt.market` | Transmission cost, temperature/degree-day utilities, generation outage / reliability KPIs |
|
|
297
315
|
| `quantvolt.workflow` | 7-step model-selection workflow for structured products |
|
|
298
|
-
| `quantvolt.portfolio` | `Portfolio`/`Position` book assembly,
|
|
316
|
+
| `quantvolt.portfolio` | `Portfolio`/`Position` book assembly; `value_portfolio` natively prices futures, forwards, swaps, transmission/pipeline rights, vanilla options, spread options and tolling agreements via the caller-extensible `DEFAULT_PRICERS` registry (PPAs and realized hedges are valued via a caller-registered pricer, e.g. `make_ppa_pricer` — deliberately not a default); realized interval `settle_energy_portfolio` aggregation is kept structurally separate from that forward-looking NPV |
|
|
299
317
|
| `quantvolt.data` | Optional (`quantvolt[data]`): provider adapters behind a `DataSource` protocol — the only package that performs I/O |
|
|
300
318
|
| `quantvolt.testing` | `assert_input_unchanged` — shipped test utility for the no-mutation invariant |
|
|
301
319
|
| `quantvolt.exceptions` | The `EnergyQuantError` hierarchy (`ValidationError`, `ArbitrageError`, `MissingTenorError`, …) |
|
|
@@ -317,14 +335,20 @@ positions. See [docs/risk-and-assets.md](docs/risk-and-assets.md).
|
|
|
317
335
|
|
|
318
336
|
## Documentation
|
|
319
337
|
|
|
338
|
+
- [Why QuantVolt?](https://nimabahrami.github.io/quantvolt/#/guide/why) — the integration problem,
|
|
339
|
+
the shared computational model, the extensible pricer registry, and an honest "what QuantVolt is
|
|
340
|
+
not" section
|
|
320
341
|
- [docs/api.md](docs/api.md) — module-by-module API reference with runnable examples
|
|
321
342
|
- [docs/risk-and-assets.md](docs/risk-and-assets.md) — the VaR family, the physical-vs-risk-neutral
|
|
322
343
|
drift rule, incomplete-market hedging, dispatch & storage, and the long-dated / liquidity caveats
|
|
323
344
|
- [docs/european-markets.md](docs/european-markets.md) — market coverage, power-vs-gas
|
|
324
345
|
statistics, negative prices, Samuelson effect, carbon costs, data-source policy
|
|
325
|
-
-
|
|
326
|
-
|
|
327
|
-
|
|
346
|
+
- [docs/validation.md](docs/validation.md) — external validation evidence: QuantVolt's pricers
|
|
347
|
+
checked against QuantLib 1.43 golden fixtures, with honest caveats and regeneration instructions
|
|
348
|
+
- Three complete, runnable end-to-end tutorials (site, each backed by a `site/examples/
|
|
349
|
+
verify_tutorial_*.py` script): [spark spread to hedge](https://nimabahrami.github.io/quantvolt/#/guide/tutorial-spark),
|
|
350
|
+
[renewable PPA to CFaR](https://nimabahrami.github.io/quantvolt/#/guide/tutorial-ppa), and
|
|
351
|
+
[storage intrinsic to hedge](https://nimabahrami.github.io/quantvolt/#/guide/tutorial-storage)
|
|
328
352
|
|
|
329
353
|
## Development
|
|
330
354
|
|
|
@@ -14,9 +14,24 @@ Covered markets: EEX Phelix DE/AT power, EPEX SPOT power (DE, FR, NL, BE, GB), T
|
|
|
14
14
|
natural gas (ICE Endex), and EUA carbon allowances — extensible by the caller without editing
|
|
15
15
|
library source. See [docs/european-markets.md](docs/european-markets.md).
|
|
16
16
|
|
|
17
|
+
## Why QuantVolt?
|
|
18
|
+
|
|
19
|
+
A typical desk assembles a curve spreadsheet, a standalone options pricer, a storage/dispatch
|
|
20
|
+
optimizer and a bolted-on VaR tool, each with its own units, sign conventions and delivery-period
|
|
21
|
+
identity — hand-reconciling between them is slow and a recurring source of quiet errors. QuantVolt
|
|
22
|
+
instead moves the same immutable `ForwardCurve` / `DeliveryPeriod` / `MarketData` / `Greeks` value
|
|
23
|
+
objects through curve construction, pricing, portfolio valuation, risk, realized settlement and
|
|
24
|
+
physical-asset valuation, with determinism, eager validation and serializability enforced
|
|
25
|
+
structurally rather than left to convention. It is equally explicit about scope: a PPA stays
|
|
26
|
+
`unpriced` until you register a forward-looking pricer, storage/dispatch results are brought into
|
|
27
|
+
a portfolio explicitly, no market data ships with the package, and approximations (Kirk,
|
|
28
|
+
Turnbull-Wakeman, `bang_bang`) are labelled, never hidden. See
|
|
29
|
+
[the "Why QuantVolt?" page](https://nimabahrami.github.io/quantvolt/#/guide/why) and the
|
|
30
|
+
[external validation evidence](docs/validation.md) for the checkable version of these claims.
|
|
31
|
+
|
|
17
32
|
## Install
|
|
18
33
|
|
|
19
|
-
Requires Python 3.
|
|
34
|
+
Requires Python 3.11+.
|
|
20
35
|
|
|
21
36
|
```bash
|
|
22
37
|
uv add quantvolt # or: pip install quantvolt
|
|
@@ -76,10 +91,11 @@ Call premium: 45,663 EUR (delta 5,288 EUR per EUR/MWh)
|
|
|
76
91
|
Book NPV: 9,133 EUR, VaR(95): 11,715 EUR
|
|
77
92
|
```
|
|
78
93
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
that last invariant in
|
|
94
|
+
Repeated calls with the same inputs, seed, QuantVolt version, architecture, and native build
|
|
95
|
+
produce identical results. Monte Carlo honours a `seed`, inputs are validated eagerly (no silent
|
|
96
|
+
partial results), results round-trip through plain dicts / JSON, and the library never mutates
|
|
97
|
+
caller data — `quantvolt.testing.assert_input_unchanged` lets you verify that last invariant in
|
|
98
|
+
your own tests.
|
|
83
99
|
|
|
84
100
|
### Settle a PPA with your own interval data
|
|
85
101
|
|
|
@@ -258,7 +274,7 @@ specialised names stay on their sub-package. Full reference with a runnable exam
|
|
|
258
274
|
| `quantvolt.stats` | Descriptive statistics, normality tests, ADF/KPSS stationarity with Samuelson-effect detection, correlation, Ornstein-Uhlenbeck mean reversion |
|
|
259
275
|
| `quantvolt.market` | Transmission cost, temperature/degree-day utilities, generation outage / reliability KPIs |
|
|
260
276
|
| `quantvolt.workflow` | 7-step model-selection workflow for structured products |
|
|
261
|
-
| `quantvolt.portfolio` | `Portfolio`/`Position` book assembly,
|
|
277
|
+
| `quantvolt.portfolio` | `Portfolio`/`Position` book assembly; `value_portfolio` natively prices futures, forwards, swaps, transmission/pipeline rights, vanilla options, spread options and tolling agreements via the caller-extensible `DEFAULT_PRICERS` registry (PPAs and realized hedges are valued via a caller-registered pricer, e.g. `make_ppa_pricer` — deliberately not a default); realized interval `settle_energy_portfolio` aggregation is kept structurally separate from that forward-looking NPV |
|
|
262
278
|
| `quantvolt.data` | Optional (`quantvolt[data]`): provider adapters behind a `DataSource` protocol — the only package that performs I/O |
|
|
263
279
|
| `quantvolt.testing` | `assert_input_unchanged` — shipped test utility for the no-mutation invariant |
|
|
264
280
|
| `quantvolt.exceptions` | The `EnergyQuantError` hierarchy (`ValidationError`, `ArbitrageError`, `MissingTenorError`, …) |
|
|
@@ -280,14 +296,20 @@ positions. See [docs/risk-and-assets.md](docs/risk-and-assets.md).
|
|
|
280
296
|
|
|
281
297
|
## Documentation
|
|
282
298
|
|
|
299
|
+
- [Why QuantVolt?](https://nimabahrami.github.io/quantvolt/#/guide/why) — the integration problem,
|
|
300
|
+
the shared computational model, the extensible pricer registry, and an honest "what QuantVolt is
|
|
301
|
+
not" section
|
|
283
302
|
- [docs/api.md](docs/api.md) — module-by-module API reference with runnable examples
|
|
284
303
|
- [docs/risk-and-assets.md](docs/risk-and-assets.md) — the VaR family, the physical-vs-risk-neutral
|
|
285
304
|
drift rule, incomplete-market hedging, dispatch & storage, and the long-dated / liquidity caveats
|
|
286
305
|
- [docs/european-markets.md](docs/european-markets.md) — market coverage, power-vs-gas
|
|
287
306
|
statistics, negative prices, Samuelson effect, carbon costs, data-source policy
|
|
288
|
-
-
|
|
289
|
-
|
|
290
|
-
|
|
307
|
+
- [docs/validation.md](docs/validation.md) — external validation evidence: QuantVolt's pricers
|
|
308
|
+
checked against QuantLib 1.43 golden fixtures, with honest caveats and regeneration instructions
|
|
309
|
+
- Three complete, runnable end-to-end tutorials (site, each backed by a `site/examples/
|
|
310
|
+
verify_tutorial_*.py` script): [spark spread to hedge](https://nimabahrami.github.io/quantvolt/#/guide/tutorial-spark),
|
|
311
|
+
[renewable PPA to CFaR](https://nimabahrami.github.io/quantvolt/#/guide/tutorial-ppa), and
|
|
312
|
+
[storage intrinsic to hedge](https://nimabahrami.github.io/quantvolt/#/guide/tutorial-storage)
|
|
291
313
|
|
|
292
314
|
## Development
|
|
293
315
|
|
|
@@ -4,10 +4,10 @@ build-backend = "maturin"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "quantvolt"
|
|
7
|
-
version = "0.1
|
|
7
|
+
version = "0.2.1"
|
|
8
8
|
description = "Quantitative analysis of European power and energy markets"
|
|
9
9
|
readme = "README.md"
|
|
10
|
-
requires-python = ">=3.
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
11
|
license = "MIT"
|
|
12
12
|
license-files = ["LICENSE"]
|
|
13
13
|
authors = [{ name = "Nima Bahrami", email = "nima@skillmix.nl" }]
|
|
@@ -28,7 +28,9 @@ classifiers = [
|
|
|
28
28
|
"Intended Audience :: Financial and Insurance Industry",
|
|
29
29
|
"Intended Audience :: Science/Research",
|
|
30
30
|
"Programming Language :: Python :: 3",
|
|
31
|
+
"Programming Language :: Python :: 3.11",
|
|
31
32
|
"Programming Language :: Python :: 3.12",
|
|
33
|
+
"Programming Language :: Python :: 3.13",
|
|
32
34
|
"Programming Language :: Rust",
|
|
33
35
|
"Topic :: Office/Business :: Financial :: Investment",
|
|
34
36
|
"Topic :: Scientific/Engineering :: Mathematics",
|
|
@@ -61,12 +63,20 @@ dev = [
|
|
|
61
63
|
"maturin>=1.7,<2.0",
|
|
62
64
|
]
|
|
63
65
|
|
|
66
|
+
# PEP 735 dependency group for OFFLINE external-validation fixture generation only.
|
|
67
|
+
# NOT a [project.optional-dependencies] extra and NOT a core/runtime dependency: the
|
|
68
|
+
# analytics core never imports QuantLib, CI never installs this group, and the generator
|
|
69
|
+
# scripts under scripts/ (wheel-excluded above) are the only consumers. See
|
|
70
|
+
# .kiro/specs/external-validation/ and docs/validation.md for the regeneration workflow.
|
|
71
|
+
[dependency-groups]
|
|
72
|
+
validation = ["QuantLib>=1.34"]
|
|
73
|
+
|
|
64
74
|
[tool.maturin]
|
|
65
75
|
python-source = "src"
|
|
66
76
|
module-name = "quantvolt._core"
|
|
67
|
-
# abi3-
|
|
77
|
+
# abi3-py311: build a single stable-ABI wheel that works on CPython 3.11+
|
|
68
78
|
# (one compile per platform instead of one per Python version).
|
|
69
|
-
features = ["pyo3/extension-module", "pyo3/abi3-
|
|
79
|
+
features = ["pyo3/extension-module", "pyo3/abi3-py311"]
|
|
70
80
|
# Keep the sdist to the buildable package only. The docs site, rendered docs,
|
|
71
81
|
# research data, helper scripts, and the logo are not part of the installable
|
|
72
82
|
# library and would only bloat the distribution.
|
|
@@ -90,12 +100,20 @@ exclude = [
|
|
|
90
100
|
[tool.ruff]
|
|
91
101
|
line-length = 100
|
|
92
102
|
src = ["src", "tests"]
|
|
103
|
+
target-version = "py311"
|
|
93
104
|
|
|
94
105
|
[tool.ruff.lint]
|
|
95
106
|
select = ["E", "F", "I", "UP", "B", "SIM", "RUF"]
|
|
96
107
|
|
|
108
|
+
[tool.ruff.lint.per-file-ignores]
|
|
109
|
+
# Authored documentation text (AUTHORED_DOCS) carries long human-readable lines;
|
|
110
|
+
# RUF001 flags the en-dashes used deliberately in that prose.
|
|
111
|
+
"site/build_api.py" = ["E501", "RUF001"]
|
|
112
|
+
# One-off internal refactoring tool, not shipped code.
|
|
113
|
+
"site/tools/refactor_reference_design.py" = ["E501"]
|
|
114
|
+
|
|
97
115
|
[tool.mypy]
|
|
98
|
-
python_version = "3.
|
|
116
|
+
python_version = "3.11"
|
|
99
117
|
strict = true
|
|
100
118
|
files = ["src/quantvolt"]
|
|
101
119
|
|
|
@@ -490,11 +490,11 @@ pub fn simulate_correlated_forwards_term_core(
|
|
|
490
490
|
if antithetic {
|
|
491
491
|
write_record(&mut data, p_minus, 0, rec, dim, &minus);
|
|
492
492
|
}
|
|
493
|
-
for step in
|
|
493
|
+
for (step, factor) in factors.iter().enumerate().take(steps) {
|
|
494
494
|
for e in &mut eps {
|
|
495
495
|
*e = rng.sample::<f64, _>(StandardNormal);
|
|
496
496
|
}
|
|
497
|
-
matvec_lower(
|
|
497
|
+
matvec_lower(factor, &eps, dim, &mut incr);
|
|
498
498
|
let offset = step * dim;
|
|
499
499
|
for d in 0..dim {
|
|
500
500
|
if active_steps[offset + d] {
|
|
@@ -22,6 +22,7 @@ from .assets import (
|
|
|
22
22
|
PhysicalFactorMapping,
|
|
23
23
|
PlantModel,
|
|
24
24
|
StorageModel,
|
|
25
|
+
ValuationSource,
|
|
25
26
|
bang_bang,
|
|
26
27
|
dispatch_deterministic,
|
|
27
28
|
dispatch_value,
|
|
@@ -70,7 +71,12 @@ from .hedging import (
|
|
|
70
71
|
)
|
|
71
72
|
from .models import (
|
|
72
73
|
BUILT_IN_COMMODITIES,
|
|
74
|
+
CachedAssetValuation,
|
|
75
|
+
CapFloorStripContract,
|
|
76
|
+
CapFloorType,
|
|
77
|
+
ChangeInLawAllocation,
|
|
73
78
|
CommodityConfig,
|
|
79
|
+
CurtailmentTreatment,
|
|
74
80
|
CurveNode,
|
|
75
81
|
DeliveryPeriod,
|
|
76
82
|
DeliverySchedule,
|
|
@@ -81,24 +87,43 @@ from .models import (
|
|
|
81
87
|
Granularity,
|
|
82
88
|
Greeks,
|
|
83
89
|
Hub,
|
|
90
|
+
IndexationStep,
|
|
84
91
|
InstrumentPriceRecord,
|
|
85
92
|
Moneyness,
|
|
93
|
+
NegativePriceClause,
|
|
94
|
+
NegativePriceTreatment,
|
|
95
|
+
OptionSide,
|
|
96
|
+
OptionType,
|
|
86
97
|
PipelineRight,
|
|
87
98
|
PlantConfig,
|
|
88
99
|
PowerDeliveryInterval,
|
|
89
100
|
PowerHedgeContract,
|
|
90
101
|
PowerHedgePosition,
|
|
91
102
|
PowerHedgeType,
|
|
103
|
+
PpaAvailabilityGuarantee,
|
|
92
104
|
PpaContract,
|
|
105
|
+
PpaContractMetadata,
|
|
106
|
+
PpaCreditSupportType,
|
|
107
|
+
PpaPriceTerms,
|
|
108
|
+
PpaReconciliationPeriod,
|
|
109
|
+
PpaReconciliationTerms,
|
|
93
110
|
PpaSettlementType,
|
|
111
|
+
PpaTerms,
|
|
112
|
+
PpaToleranceBand,
|
|
94
113
|
PpaVolumeBasis,
|
|
114
|
+
PpaVolumeTerms,
|
|
115
|
+
PriceUnit,
|
|
95
116
|
RiskType,
|
|
96
117
|
SettlementType,
|
|
118
|
+
SpreadOptionContract,
|
|
97
119
|
SwapContract,
|
|
120
|
+
TollingAgreement,
|
|
98
121
|
TransmissionRight,
|
|
99
122
|
TransportDirection,
|
|
123
|
+
VanillaOptionContract,
|
|
100
124
|
VolatilitySurface,
|
|
101
125
|
VolatilityTenor,
|
|
126
|
+
convert_price,
|
|
102
127
|
)
|
|
103
128
|
from .portfolio import (
|
|
104
129
|
Instrument,
|
|
@@ -114,6 +139,8 @@ from .portfolio import (
|
|
|
114
139
|
)
|
|
115
140
|
from .pricing import (
|
|
116
141
|
AsianOptionRequest,
|
|
142
|
+
BachelierOptionRequest,
|
|
143
|
+
BachelierOptionResult,
|
|
117
144
|
BarrierOptionRequest,
|
|
118
145
|
CapFloorRequest,
|
|
119
146
|
CapFloorResult,
|
|
@@ -129,6 +156,11 @@ from .pricing import (
|
|
|
129
156
|
PowerHedgeSettlement,
|
|
130
157
|
PpaDataColumns,
|
|
131
158
|
PpaIntervalSettlement,
|
|
159
|
+
PpaPeriodValuation,
|
|
160
|
+
PpaPeriodVolume,
|
|
161
|
+
PpaReconciliationColumns,
|
|
162
|
+
PpaValuationResult,
|
|
163
|
+
PpaVolumeProfile,
|
|
132
164
|
SpreadOptionRequest,
|
|
133
165
|
SpreadOptionResult,
|
|
134
166
|
SwapPricingResult,
|
|
@@ -147,19 +179,23 @@ from .pricing import (
|
|
|
147
179
|
futures_delta,
|
|
148
180
|
implied_heat_rate,
|
|
149
181
|
implied_vol,
|
|
182
|
+
make_ppa_pricer,
|
|
150
183
|
mark_to_market,
|
|
151
184
|
power_cap_payoff,
|
|
152
185
|
power_floor_payoff,
|
|
153
186
|
price_asian,
|
|
187
|
+
price_bachelier_option,
|
|
154
188
|
price_barrier,
|
|
155
189
|
price_cap_floor,
|
|
156
190
|
price_futures,
|
|
157
191
|
price_lookback,
|
|
192
|
+
price_ppa,
|
|
158
193
|
price_spark_spread_option,
|
|
159
194
|
price_spread_option,
|
|
160
195
|
price_swap,
|
|
161
196
|
price_tolling_agreement,
|
|
162
197
|
price_vanilla_option,
|
|
198
|
+
reconcile_ppa_ledger,
|
|
163
199
|
settle_power_hedge_interval,
|
|
164
200
|
settle_power_hedges_frame,
|
|
165
201
|
settle_ppa_frame,
|
|
@@ -188,7 +224,7 @@ from .risk import (
|
|
|
188
224
|
parametric_var,
|
|
189
225
|
)
|
|
190
226
|
|
|
191
|
-
__version__ = "0.1
|
|
227
|
+
__version__ = "0.2.1"
|
|
192
228
|
|
|
193
229
|
__all__ = [
|
|
194
230
|
"BUILT_IN_COMMODITIES",
|
|
@@ -197,13 +233,20 @@ __all__ = [
|
|
|
197
233
|
"ArbitrageWarning",
|
|
198
234
|
"AsianOptionRequest",
|
|
199
235
|
"AuthenticationError",
|
|
236
|
+
"BachelierOptionRequest",
|
|
237
|
+
"BachelierOptionResult",
|
|
200
238
|
"BangBangHedgeWarning",
|
|
201
239
|
"BarrierOptionRequest",
|
|
240
|
+
"CachedAssetValuation",
|
|
202
241
|
"CapFloorRequest",
|
|
203
242
|
"CapFloorResult",
|
|
243
|
+
"CapFloorStripContract",
|
|
244
|
+
"CapFloorType",
|
|
204
245
|
"CashflowStrategyComparison",
|
|
205
246
|
"CashflowStrategyMetrics",
|
|
247
|
+
"ChangeInLawAllocation",
|
|
206
248
|
"CommodityConfig",
|
|
249
|
+
"CurtailmentTreatment",
|
|
207
250
|
"CurveBuildResult",
|
|
208
251
|
"CurveBuilder",
|
|
209
252
|
"CurveNode",
|
|
@@ -229,6 +272,7 @@ __all__ = [
|
|
|
229
272
|
"Greeks",
|
|
230
273
|
"Hub",
|
|
231
274
|
"ImpliedVolResult",
|
|
275
|
+
"IndexationStep",
|
|
232
276
|
"Instrument",
|
|
233
277
|
"InstrumentPriceRecord",
|
|
234
278
|
"InsufficientDataError",
|
|
@@ -243,8 +287,12 @@ __all__ = [
|
|
|
243
287
|
"MtMResult",
|
|
244
288
|
"MultifactorForwardModel",
|
|
245
289
|
"NativeExtensionError",
|
|
290
|
+
"NegativePriceClause",
|
|
291
|
+
"NegativePriceTreatment",
|
|
246
292
|
"NoPricingDataError",
|
|
247
293
|
"NumericalError",
|
|
294
|
+
"OptionSide",
|
|
295
|
+
"OptionType",
|
|
248
296
|
"PhysicalFactorMapping",
|
|
249
297
|
"PipelineRight",
|
|
250
298
|
"PlantConfig",
|
|
@@ -259,16 +307,31 @@ __all__ = [
|
|
|
259
307
|
"PowerHedgePosition",
|
|
260
308
|
"PowerHedgeSettlement",
|
|
261
309
|
"PowerHedgeType",
|
|
310
|
+
"PpaAvailabilityGuarantee",
|
|
262
311
|
"PpaContract",
|
|
312
|
+
"PpaContractMetadata",
|
|
313
|
+
"PpaCreditSupportType",
|
|
263
314
|
"PpaDataColumns",
|
|
264
315
|
"PpaIntervalSettlement",
|
|
265
316
|
"PpaNominationCandidate",
|
|
266
317
|
"PpaNominationColumns",
|
|
267
318
|
"PpaNominationFit",
|
|
268
319
|
"PpaNominationObjective",
|
|
320
|
+
"PpaPeriodValuation",
|
|
321
|
+
"PpaPeriodVolume",
|
|
322
|
+
"PpaPriceTerms",
|
|
323
|
+
"PpaReconciliationColumns",
|
|
324
|
+
"PpaReconciliationPeriod",
|
|
325
|
+
"PpaReconciliationTerms",
|
|
269
326
|
"PpaSettlementType",
|
|
327
|
+
"PpaTerms",
|
|
328
|
+
"PpaToleranceBand",
|
|
329
|
+
"PpaValuationResult",
|
|
270
330
|
"PpaVolumeBasis",
|
|
331
|
+
"PpaVolumeProfile",
|
|
332
|
+
"PpaVolumeTerms",
|
|
271
333
|
"PpaWalkForwardResult",
|
|
334
|
+
"PriceUnit",
|
|
272
335
|
"PricedPosition",
|
|
273
336
|
"RateLimitError",
|
|
274
337
|
"RiskEngine",
|
|
@@ -281,16 +344,20 @@ __all__ = [
|
|
|
281
344
|
"SchwartzSmithParams",
|
|
282
345
|
"SettledPortfolioPosition",
|
|
283
346
|
"SettlementType",
|
|
347
|
+
"SpreadOptionContract",
|
|
284
348
|
"SpreadOptionRequest",
|
|
285
349
|
"SpreadOptionResult",
|
|
286
350
|
"StorageModel",
|
|
287
351
|
"SwapContract",
|
|
288
352
|
"SwapPricingResult",
|
|
353
|
+
"TollingAgreement",
|
|
289
354
|
"TollingResult",
|
|
290
355
|
"TransmissionRight",
|
|
291
356
|
"TransportDirection",
|
|
292
357
|
"TransportRightResult",
|
|
293
358
|
"ValidationError",
|
|
359
|
+
"ValuationSource",
|
|
360
|
+
"VanillaOptionContract",
|
|
294
361
|
"VanillaOptionRequest",
|
|
295
362
|
"VanillaOptionResult",
|
|
296
363
|
"VolatilitySurface",
|
|
@@ -307,6 +374,7 @@ __all__ = [
|
|
|
307
374
|
"classify_moneyness",
|
|
308
375
|
"clean_spread",
|
|
309
376
|
"compare_cashflow_strategies",
|
|
377
|
+
"convert_price",
|
|
310
378
|
"crack_spread",
|
|
311
379
|
"credit_var",
|
|
312
380
|
"dark_spread",
|
|
@@ -321,21 +389,25 @@ __all__ = [
|
|
|
321
389
|
"implied_heat_rate",
|
|
322
390
|
"implied_vol",
|
|
323
391
|
"linear_cross_hedge",
|
|
392
|
+
"make_ppa_pricer",
|
|
324
393
|
"mark_to_market",
|
|
325
394
|
"monte_carlo_var",
|
|
326
395
|
"parametric_var",
|
|
327
396
|
"power_cap_payoff",
|
|
328
397
|
"power_floor_payoff",
|
|
329
398
|
"price_asian",
|
|
399
|
+
"price_bachelier_option",
|
|
330
400
|
"price_barrier",
|
|
331
401
|
"price_cap_floor",
|
|
332
402
|
"price_futures",
|
|
333
403
|
"price_lookback",
|
|
404
|
+
"price_ppa",
|
|
334
405
|
"price_spark_spread_option",
|
|
335
406
|
"price_spread_option",
|
|
336
407
|
"price_swap",
|
|
337
408
|
"price_tolling_agreement",
|
|
338
409
|
"price_vanilla_option",
|
|
410
|
+
"reconcile_ppa_ledger",
|
|
339
411
|
"settle_energy_portfolio",
|
|
340
412
|
"settle_power_hedge_interval",
|
|
341
413
|
"settle_power_hedges_frame",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""Reusable boundary-validation guards. Public entry points validate through these before any
|
|
2
|
-
computation
|
|
2
|
+
computation, raising ``ValidationError`` on the first violated constraint."""
|
|
3
3
|
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
|