squarequant 0.2.2__tar.gz → 0.4.0.dev1__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.
- squarequant-0.4.0.dev1/CHANGELOG.md +21 -0
- {squarequant-0.2.2 → squarequant-0.4.0.dev1}/LICENSE +20 -20
- squarequant-0.4.0.dev1/MANIFEST.in +8 -0
- squarequant-0.4.0.dev1/PKG-INFO +114 -0
- squarequant-0.4.0.dev1/README.md +72 -0
- squarequant-0.4.0.dev1/docs/api.md +16 -0
- squarequant-0.4.0.dev1/docs/audit.md +67 -0
- squarequant-0.4.0.dev1/docs/conf.py +8 -0
- squarequant-0.4.0.dev1/docs/index.md +9 -0
- squarequant-0.4.0.dev1/docs/usage.md +201 -0
- squarequant-0.4.0.dev1/examples/risk_metrics_demo.py +63 -0
- squarequant-0.4.0.dev1/pyproject.toml +76 -0
- {squarequant-0.2.2 → squarequant-0.4.0.dev1}/squarequant/__init__.py +60 -52
- squarequant-0.4.0.dev1/squarequant/api.py +927 -0
- {squarequant-0.2.2 → squarequant-0.4.0.dev1}/squarequant/constants.py +42 -35
- {squarequant-0.2.2 → squarequant-0.4.0.dev1}/squarequant/core/__init__.py +6 -6
- squarequant-0.4.0.dev1/squarequant/core/base.py +132 -0
- squarequant-0.4.0.dev1/squarequant/core/metrics.py +1113 -0
- {squarequant-0.2.2 → squarequant-0.4.0.dev1}/squarequant/data/__init__.py +6 -6
- {squarequant-0.2.2 → squarequant-0.4.0.dev1}/squarequant/data/data.py +245 -250
- squarequant-0.4.0.dev1/squarequant/monte_carlo/__init__.py +6 -0
- squarequant-0.4.0.dev1/squarequant/monte_carlo/montecarlo.py +489 -0
- {squarequant-0.2.2 → squarequant-0.4.0.dev1}/squarequant/utils/__init__.py +6 -6
- {squarequant-0.2.2 → squarequant-0.4.0.dev1}/squarequant/utils/helpers.py +91 -85
- squarequant-0.4.0.dev1/squarequant/utils/validation.py +28 -0
- {squarequant-0.2.2 → squarequant-0.4.0.dev1}/squarequant/var/__init__.py +6 -6
- squarequant-0.4.0.dev1/squarequant/var/valueatrisk.py +183 -0
- squarequant-0.4.0.dev1/squarequant.egg-info/PKG-INFO +114 -0
- {squarequant-0.2.2 → squarequant-0.4.0.dev1}/squarequant.egg-info/SOURCES.txt +19 -3
- squarequant-0.4.0.dev1/squarequant.egg-info/requires.txt +21 -0
- squarequant-0.4.0.dev1/tests/conftest.py +11 -0
- squarequant-0.4.0.dev1/tests/test_data_adapters.py +89 -0
- squarequant-0.4.0.dev1/tests/test_example.py +12 -0
- squarequant-0.4.0.dev1/tests/test_numerics.py +210 -0
- squarequant-0.4.0.dev1/tests/test_public_api.py +117 -0
- squarequant-0.4.0.dev1/tests/test_regressions.py +177 -0
- squarequant-0.2.2/PKG-INFO +0 -269
- squarequant-0.2.2/README.md +0 -210
- squarequant-0.2.2/setup.py +0 -60
- squarequant-0.2.2/squarequant/api.py +0 -554
- squarequant-0.2.2/squarequant/core/base.py +0 -166
- squarequant-0.2.2/squarequant/core/metrics.py +0 -1405
- squarequant-0.2.2/squarequant/var/tetstvar.py +0 -241
- squarequant-0.2.2/squarequant/var/valueatrisk.py +0 -482
- squarequant-0.2.2/squarequant.egg-info/PKG-INFO +0 -269
- squarequant-0.2.2/squarequant.egg-info/requires.txt +0 -21
- {squarequant-0.2.2 → squarequant-0.4.0.dev1}/setup.cfg +0 -0
- {squarequant-0.2.2 → squarequant-0.4.0.dev1}/squarequant.egg-info/dependency_links.txt +0 -0
- {squarequant-0.2.2 → squarequant-0.4.0.dev1}/squarequant.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Changes
|
|
2
|
+
|
|
3
|
+
## 0.4.0.dev1
|
|
4
|
+
|
|
5
|
+
This edition retains the original risk statistics, VaR, simulations, data adapters
|
|
6
|
+
and utilities. Contract definitions, trade capture, persistence, payment
|
|
7
|
+
schedules, valuation/scenario layers, their tests, examples, benchmarks and
|
|
8
|
+
associated documentation have been removed from the source distribution.
|
|
9
|
+
|
|
10
|
+
Retained numerical corrections and new consistency/validation improvements are
|
|
11
|
+
described in `docs/audit.md`.
|
|
12
|
+
The portfolio VaR column remains part of the statistical API.
|
|
13
|
+
|
|
14
|
+
The package requires Python 3.11+. The function-level default VaR horizon remains
|
|
15
|
+
10 observations; users should pass their chosen horizon explicitly. Supplied
|
|
16
|
+
risk-free rates remain daily unless the annual convention is selected.
|
|
17
|
+
Delta-gamma VaR requires an explicit Hessian and retains the documented
|
|
18
|
+
moment-matching approximation. Invalid numerical/grid inputs now fail clearly.
|
|
19
|
+
|
|
20
|
+
Data-provider dependencies remain optional. Complete install/build/API checks
|
|
21
|
+
and their actual outcomes are recorded in `VALIDATION_REPORT.md`.
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 Gabriel Bosch
|
|
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
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Gabriel Bosch
|
|
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
21
|
SOFTWARE.
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: squarequant
|
|
3
|
+
Version: 0.4.0.dev1
|
|
4
|
+
Summary: Financial risk metrics, Monte Carlo simulations, and optional market-data adapters
|
|
5
|
+
Author-email: Gabriel Bosch <contact@squarequant.org>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Documentation, https://www.squarequant.org
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/SquareQuant/squarequant-package/issues
|
|
9
|
+
Project-URL: Homepage, https://github.com/SquareQuant/squarequant-package
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
16
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
17
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
18
|
+
Classifier: Intended Audience :: Science/Research
|
|
19
|
+
Classifier: Development Status :: 4 - Beta
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: pandas>=2.0
|
|
24
|
+
Requires-Dist: numpy>=1.24
|
|
25
|
+
Requires-Dist: scipy>=1.10
|
|
26
|
+
Provides-Extra: data
|
|
27
|
+
Requires-Dist: yfinance>=0.2.0; extra == "data"
|
|
28
|
+
Requires-Dist: requests>=2.25.0; extra == "data"
|
|
29
|
+
Provides-Extra: optimization
|
|
30
|
+
Requires-Dist: cvxpy>=1.0.0; extra == "optimization"
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
33
|
+
Requires-Dist: ruff>=0.11; extra == "dev"
|
|
34
|
+
Requires-Dist: mypy>=1.15; extra == "dev"
|
|
35
|
+
Requires-Dist: hypothesis>=6; extra == "dev"
|
|
36
|
+
Requires-Dist: build>=1; extra == "dev"
|
|
37
|
+
Requires-Dist: requests>=2.25.0; extra == "dev"
|
|
38
|
+
Requires-Dist: sphinx>=4.0.0; extra == "dev"
|
|
39
|
+
Requires-Dist: myst-parser>=1.0.0; extra == "dev"
|
|
40
|
+
Requires-Dist: pytest-cov>=2.12.0; extra == "dev"
|
|
41
|
+
Dynamic: license-file
|
|
42
|
+
|
|
43
|
+
# SquareQuant — financial risk statistics
|
|
44
|
+
|
|
45
|
+
Version `0.4.0.dev1` provides rolling financial risk metrics, historical/parametric
|
|
46
|
+
VaR, Monte Carlo simulations, and optional market-data downloads. Python 3.11+
|
|
47
|
+
is required.
|
|
48
|
+
|
|
49
|
+
## Install and run
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
python -m venv .venv
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
On Windows:
|
|
56
|
+
|
|
57
|
+
```powershell
|
|
58
|
+
.\.venv\Scripts\python.exe -m pip install -e ".[dev]"
|
|
59
|
+
.\.venv\Scripts\python.exe -m pytest -q
|
|
60
|
+
.\.venv\Scripts\python.exe examples\risk_metrics_demo.py
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
On macOS/Linux:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
.venv/bin/python -m pip install -e '.[dev]'
|
|
67
|
+
.venv/bin/python -m pytest -q
|
|
68
|
+
.venv/bin/python examples/risk_metrics_demo.py
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Example
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
import pandas as pd
|
|
75
|
+
import squarequant as sq
|
|
76
|
+
|
|
77
|
+
returns = pd.DataFrame({'Asset': [-0.04, -0.02, 0.01, 0.02]})
|
|
78
|
+
var = sq.var(returns, ['Asset'], window=4, holding_period=1)
|
|
79
|
+
es = sq.cvar(returns, ['Asset'], window=4, holding_period=1, confidence=0.625)
|
|
80
|
+
print(var['Portfolio'].iloc[-1]) # 0.037
|
|
81
|
+
print(es['Asset'].iloc[-1]) # 0.03333333333333333
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The public API contains `DownloadConfig`, `download_tickers`, `sharpe`, `sortino`,
|
|
85
|
+
`vol`, `mdd`, `calmar`, `var`, `cvar`, `semidev`, `avgdd`, `ulcer`, `mad`, `erm`,
|
|
86
|
+
`evar`, `cdar`, `simplemc`, `brownian`, `correlated_brownian`, `gbm_paths`, and
|
|
87
|
+
`gbm_correlated_paths`.
|
|
88
|
+
|
|
89
|
+
The `data` extra installs yfinance/requests for optional downloads. It is not
|
|
90
|
+
needed to import SquareQuant or run the offline statistics example. The
|
|
91
|
+
`optimization` extra is retained for installation compatibility.
|
|
92
|
+
|
|
93
|
+
## Documentation and validation
|
|
94
|
+
|
|
95
|
+
- [Usage, assumptions and numerical examples](docs/usage.md)
|
|
96
|
+
- [Public API reference](docs/api.md)
|
|
97
|
+
- [Audit and corrections](docs/audit.md)
|
|
98
|
+
- [Release changes](CHANGELOG.md)
|
|
99
|
+
- [Executed verification results](VALIDATION_REPORT.md)
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
python -m ruff check squarequant tests examples/risk_metrics_demo.py
|
|
103
|
+
python -m ruff format --check squarequant tests examples/risk_metrics_demo.py
|
|
104
|
+
python -m mypy --no-incremental
|
|
105
|
+
python -m sphinx -W -b html docs docs/_build/html
|
|
106
|
+
python -m build
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
CI is configured for Python 3.11/3.12/3.13. Actual local validation versions and
|
|
110
|
+
results are recorded in `VALIDATION_REPORT.md`. Legacy `examples/*_test.py` files
|
|
111
|
+
are vendor/plotting scripts; the isolated offline suite is under `tests/`.
|
|
112
|
+
Those legacy scripts require optional provider packages and matplotlib.
|
|
113
|
+
|
|
114
|
+
Code is licensed under MIT. See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# SquareQuant — financial risk statistics
|
|
2
|
+
|
|
3
|
+
Version `0.4.0.dev1` provides rolling financial risk metrics, historical/parametric
|
|
4
|
+
VaR, Monte Carlo simulations, and optional market-data downloads. Python 3.11+
|
|
5
|
+
is required.
|
|
6
|
+
|
|
7
|
+
## Install and run
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
python -m venv .venv
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
On Windows:
|
|
14
|
+
|
|
15
|
+
```powershell
|
|
16
|
+
.\.venv\Scripts\python.exe -m pip install -e ".[dev]"
|
|
17
|
+
.\.venv\Scripts\python.exe -m pytest -q
|
|
18
|
+
.\.venv\Scripts\python.exe examples\risk_metrics_demo.py
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
On macOS/Linux:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
.venv/bin/python -m pip install -e '.[dev]'
|
|
25
|
+
.venv/bin/python -m pytest -q
|
|
26
|
+
.venv/bin/python examples/risk_metrics_demo.py
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Example
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
import pandas as pd
|
|
33
|
+
import squarequant as sq
|
|
34
|
+
|
|
35
|
+
returns = pd.DataFrame({'Asset': [-0.04, -0.02, 0.01, 0.02]})
|
|
36
|
+
var = sq.var(returns, ['Asset'], window=4, holding_period=1)
|
|
37
|
+
es = sq.cvar(returns, ['Asset'], window=4, holding_period=1, confidence=0.625)
|
|
38
|
+
print(var['Portfolio'].iloc[-1]) # 0.037
|
|
39
|
+
print(es['Asset'].iloc[-1]) # 0.03333333333333333
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The public API contains `DownloadConfig`, `download_tickers`, `sharpe`, `sortino`,
|
|
43
|
+
`vol`, `mdd`, `calmar`, `var`, `cvar`, `semidev`, `avgdd`, `ulcer`, `mad`, `erm`,
|
|
44
|
+
`evar`, `cdar`, `simplemc`, `brownian`, `correlated_brownian`, `gbm_paths`, and
|
|
45
|
+
`gbm_correlated_paths`.
|
|
46
|
+
|
|
47
|
+
The `data` extra installs yfinance/requests for optional downloads. It is not
|
|
48
|
+
needed to import SquareQuant or run the offline statistics example. The
|
|
49
|
+
`optimization` extra is retained for installation compatibility.
|
|
50
|
+
|
|
51
|
+
## Documentation and validation
|
|
52
|
+
|
|
53
|
+
- [Usage, assumptions and numerical examples](docs/usage.md)
|
|
54
|
+
- [Public API reference](docs/api.md)
|
|
55
|
+
- [Audit and corrections](docs/audit.md)
|
|
56
|
+
- [Release changes](CHANGELOG.md)
|
|
57
|
+
- [Executed verification results](VALIDATION_REPORT.md)
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
python -m ruff check squarequant tests examples/risk_metrics_demo.py
|
|
61
|
+
python -m ruff format --check squarequant tests examples/risk_metrics_demo.py
|
|
62
|
+
python -m mypy --no-incremental
|
|
63
|
+
python -m sphinx -W -b html docs docs/_build/html
|
|
64
|
+
python -m build
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
CI is configured for Python 3.11/3.12/3.13. Actual local validation versions and
|
|
68
|
+
results are recorded in `VALIDATION_REPORT.md`. Legacy `examples/*_test.py` files
|
|
69
|
+
are vendor/plotting scripts; the isolated offline suite is under `tests/`.
|
|
70
|
+
Those legacy scripts require optional provider packages and matplotlib.
|
|
71
|
+
|
|
72
|
+
Code is licensed under MIT. See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Public API reference
|
|
2
|
+
|
|
3
|
+
## Risk statistics and simulations
|
|
4
|
+
|
|
5
|
+
```{automodule} squarequant.api
|
|
6
|
+
:members:
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Optional data configuration and retrieval
|
|
10
|
+
|
|
11
|
+
```{autoclass} squarequant.data.data.DownloadConfig
|
|
12
|
+
:members:
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```{autofunction} squarequant.data.data.download_tickers
|
|
16
|
+
```
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Statistics audit and corrections
|
|
2
|
+
|
|
3
|
+
This source edition contains the financial statistics, Monte Carlo and optional
|
|
4
|
+
data-download components. The upstream audit baseline is commit
|
|
5
|
+
`024363059e7af6a23e0e95167a6294b5d449e33a`.
|
|
6
|
+
|
|
7
|
+
## Retained corrections
|
|
8
|
+
|
|
9
|
+
| Component | Confirmed issue | Correction |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| Drawdowns | A boolean was compared with the string `absolute`; double rolling leaked an earlier peak outside the window; return inputs omitted initial losses. | Explicit return conventions and a within-window path with an initial wealth baseline. |
|
|
12
|
+
| Shared preprocessing | Whole-frame missing-value removal discarded unrelated valid observations; forward filling manufactured zero price returns. | Process selected columns, retain dates/per-asset missing values, use price conversion without imputation. |
|
|
13
|
+
| Risk-free rates | The risk-free column could be price-converted; daily versus annual inputs were implicit. | Preserve the rate series; add explicit annual effective conversion while retaining daily explicit-input defaults. |
|
|
14
|
+
| Delta-gamma VaR | Squared returns/correlations did not identify instrument price curvature, and the expected gamma term was added to volatility. | Explicit supplied portfolio Hessian, Gaussian quadratic P&L moments and covariance-level horizon scaling. |
|
|
15
|
+
| Historical VaR | Multiple-period results relied on square-root scaling. | Preserve/document the approximation and add overlapping empirical horizon returns. |
|
|
16
|
+
| Calmar | Log annual returns and simple annual returns were inconsistent. | Convert annualized log returns with `expm1`. |
|
|
17
|
+
| CVaR/ES | Tail counts were rounded up; parametric mean was scaled with square-root time. | Fractional empirical tail mass; separate mean/volatility horizon scaling. |
|
|
18
|
+
| Entropic statistics | The fixed-z formula mixed z and its reciprocal, could overflow and normal EVaR ignored the horizon. | Stable log-sum-exp bound with documented legacy naming; normal EVaR horizon scaling. |
|
|
19
|
+
| Monte Carlo | Default multi-factor GBM reused one factor; fitted log drift was presented as price drift; parameter checks were incomplete. | Correct default correlation dimension, half-variance drift correction and validation. |
|
|
20
|
+
| Data/packaging | Date defaults were fixed at import; single-ticker MultiIndexes were mishandled; optional provider imports blocked numerical use; Python/version metadata disagreed. | Per-instance defaults, response normalization, lazy provider imports and one version source with an explicit Python baseline. |
|
|
21
|
+
|
|
22
|
+
## Additional corrections in 0.4.0.dev1
|
|
23
|
+
|
|
24
|
+
- Calmar now calculates both numerator and drawdown denominator from the same
|
|
25
|
+
return window. Equivalent price and return inputs are regression-tested.
|
|
26
|
+
- Relative/log drawdowns use log-wealth differences to avoid overflowing a long
|
|
27
|
+
compounded wealth path; a -100% simple return remains a valid total loss.
|
|
28
|
+
- Confidence, z, grids and holding periods reject non-finite values, booleans and
|
|
29
|
+
inappropriate non-integer counts. NumPy integer counts are accepted.
|
|
30
|
+
- VaR aligns labelled Series weights by asset name and retains zero-net
|
|
31
|
+
exposures. Invalid/missing gamma labels have explicit errors. The reserved
|
|
32
|
+
aggregate result label cannot overwrite an input factor.
|
|
33
|
+
- Nullable pandas numeric data are supported; complex observations are rejected.
|
|
34
|
+
- Monte Carlo instance methods delegate to their static implementations,
|
|
35
|
+
reducing duplicate code and making API equivalence directly testable.
|
|
36
|
+
- Date helpers enforce ISO format and date ordering. Downloaded symbols retain
|
|
37
|
+
requested order; `Count` is accepted, `Adj Close` is retrieved coherently, and
|
|
38
|
+
intraday requests are rejected by the EOD-only adapter.
|
|
39
|
+
- Optional annotations, public VaR documentation, supported-method constants,
|
|
40
|
+
fixtures, build manifests and CI targets are aligned with the retained API.
|
|
41
|
+
Static checks cover all package source modules rather than a selected subset.
|
|
42
|
+
|
|
43
|
+
## Validation approach and remaining assumptions
|
|
44
|
+
|
|
45
|
+
The suite exercises every public export with offline inputs. It includes
|
|
46
|
+
analytical VaR/ES/ratio examples, price-versus-return consistency, drawdown
|
|
47
|
+
properties, simulation moments/correlations, seeded API equivalence, bad-input
|
|
48
|
+
checks, and provider-response fixtures. A network guard forbids outbound
|
|
49
|
+
connections. Provider tests use deterministic doubles rather than credentials or
|
|
50
|
+
live subscriptions. The complete example is an executable numerical regression.
|
|
51
|
+
|
|
52
|
+
Delta-gamma VaR uses Gaussian moment matching, so it is an approximate quantile
|
|
53
|
+
of generally non-Gaussian quadratic P&L. Delta-normal uses a zero-mean convention.
|
|
54
|
+
Square-root historical risk scaling is an approximation. The `erm` legacy name
|
|
55
|
+
refers to a fixed-z tail bound; it is not an optimized empirical EVaR or the
|
|
56
|
+
confidence-independent entropic risk measure. The assumptions and units are
|
|
57
|
+
specified in [usage.md](usage.md).
|
|
58
|
+
|
|
59
|
+
Minimum observations and window sizes remain metric-specific. Strict rolling
|
|
60
|
+
drawdown calculation costs O(observations × window × assets), while historical
|
|
61
|
+
quantiles and standard moments use pandas rolling methods. No universal
|
|
62
|
+
performance claim is made for arbitrary data sizes.
|
|
63
|
+
|
|
64
|
+
Python 3.11/3.12/3.13 are configured in CI. Executed interpreter/dependency
|
|
65
|
+
versions, test counts, coverage, build and installed-artifact results are
|
|
66
|
+
recorded in the accompanying validation report. CI configuration is distinct
|
|
67
|
+
from having executed every interpreter locally.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
project = "SquareQuant"
|
|
2
|
+
author = "SquareQuant contributors"
|
|
3
|
+
extensions = ["myst_parser", "sphinx.ext.autodoc"]
|
|
4
|
+
source_suffix = {".md": "markdown"}
|
|
5
|
+
master_doc = "index"
|
|
6
|
+
exclude_patterns = ["_build"]
|
|
7
|
+
html_theme = "alabaster"
|
|
8
|
+
myst_enable_extensions = ["colon_fence"]
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# Using SquareQuant
|
|
2
|
+
|
|
3
|
+
## Inputs and output conventions
|
|
4
|
+
|
|
5
|
+
Risk functions accept a pandas DataFrame and an explicit sequence of asset column
|
|
6
|
+
names. Inputs must be real numeric observations with a unique, increasing index.
|
|
7
|
+
Missing observations are retained per asset; unrelated columns are not processed.
|
|
8
|
+
A requested missing asset produces a warning and a NaN output column. Date filters
|
|
9
|
+
require a DatetimeIndex. Calculations return DataFrames indexed by observation
|
|
10
|
+
date; output columns retain the requested names. VaR adds a `Portfolio` column,
|
|
11
|
+
so that name is reserved as an input asset name for VaR.
|
|
12
|
+
|
|
13
|
+
Set `use_returns=True` for returns/P&L and `False` for prices. Return conventions:
|
|
14
|
+
|
|
15
|
+
| `returns_type` | Price conversion | Multi-period aggregation |
|
|
16
|
+
|---|---|---|
|
|
17
|
+
| `relative` | `P_t / P_(t-1) - 1` | Compound `(1+r)` |
|
|
18
|
+
| `log` | `log(P_t/P_(t-1))`, requiring positive prices | Sum |
|
|
19
|
+
| `absolute` | `P_t-P_(t-1)` | Sum |
|
|
20
|
+
|
|
21
|
+
Relative price returns use no forward filling. A missing price leaves adjacent
|
|
22
|
+
returns unknown. Nullable pandas numeric columns are supported. Use integer
|
|
23
|
+
observation windows/horizons; booleans, fractions, NaN and infinite counts/risk
|
|
24
|
+
parameters are rejected where applicable. Annualization uses 252 observations
|
|
25
|
+
per year. Change data frequency before interpreting annualized outputs.
|
|
26
|
+
|
|
27
|
+
## Core metrics
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
import pandas as pd
|
|
31
|
+
import squarequant as sq
|
|
32
|
+
|
|
33
|
+
returns = pd.DataFrame({'A': [-0.04, -0.02, 0.01, 0.02]})
|
|
34
|
+
vol = sq.vol(returns, ['A'], window=4)
|
|
35
|
+
sharpe = sq.sharpe(returns, ['A'], window=4, freerate_value=0)
|
|
36
|
+
var = sq.var(returns, ['A'], window=4, holding_period=1)
|
|
37
|
+
es = sq.cvar(returns, ['A'], window=4, holding_period=1, confidence=0.625)
|
|
38
|
+
assert abs(var['Portfolio'].iloc[-1] - 0.037) < 1e-12
|
|
39
|
+
assert abs(es['A'].iloc[-1] - 1/30) < 1e-12
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Volatility uses sample standard deviation and square-root annualization. Sharpe
|
|
43
|
+
uses annualized mean excess return divided by annualized standard deviation.
|
|
44
|
+
Sortino/downside deviation count all observations in the denominator and set
|
|
45
|
+
positive excess returns to zero. Semi-deviation's default target is estimated
|
|
46
|
+
inside each rolling window; an explicit target stays constant.
|
|
47
|
+
|
|
48
|
+
Explicit `freerate_value` or `freerate` columns are **daily** by default. Select
|
|
49
|
+
`risk_free_period='annual'` for annual effective rates. Relative returns subtract
|
|
50
|
+
`(1+r_annual)^(1/252)-1`; log returns subtract `log(1+r_annual)/252`. A risk-free
|
|
51
|
+
column is not price-converted. With no explicit risk-free input, the default is
|
|
52
|
+
2% annual effective. Absolute P&L needs a compatible daily currency risk-free
|
|
53
|
+
amount, such as an explicitly supplied zero, rather than an annual percentage.
|
|
54
|
+
|
|
55
|
+
Drawdowns are calculated entirely within the rolling window. Return inputs
|
|
56
|
+
include initial wealth of one (zero for absolute P&L), so a first-period loss is
|
|
57
|
+
captured. Relative/log drawdowns use stable log-wealth differences. MDD and
|
|
58
|
+
average drawdown are nonpositive; ulcer and CDaR are nonnegative. CDaR is the
|
|
59
|
+
conditional mean of observed drawdowns at/below the empirical lower-tail
|
|
60
|
+
quantile, with observations tied at the threshold included.
|
|
61
|
+
|
|
62
|
+
A price-input drawdown window contains that many price observations. Calmar
|
|
63
|
+
instead uses a window of converted returns for both its annualized numerator and
|
|
64
|
+
its maximum drawdown denominator, requiring the preceding price observation.
|
|
65
|
+
Relative and log inputs yield equivalent Calmar ratios. Absolute inputs define
|
|
66
|
+
annualized P&L divided by absolute-currency maximum drawdown. Zero drawdown or
|
|
67
|
+
zero standard/downside deviation yields NaN where a ratio is undefined.
|
|
68
|
+
|
|
69
|
+
MAD/downside square-root annualization is a retained daily-return convention;
|
|
70
|
+
it is not a distribution-free identity for multi-period P&L.
|
|
71
|
+
|
|
72
|
+
## VaR and expected shortfall
|
|
73
|
+
|
|
74
|
+
VaR is reported in input return/P&L units; positive numbers denote losses. A VaR
|
|
75
|
+
quantile may be negative when the relevant outcome is a gain; it is not floored
|
|
76
|
+
at zero. The package-level `sq.var` default horizon is **10 observations**, while
|
|
77
|
+
`ValueAtRisk` directly defaults to **1**. Specify `holding_period` explicitly in
|
|
78
|
+
research code.
|
|
79
|
+
|
|
80
|
+
- `historical`: negative empirical lower-tail return quantile.
|
|
81
|
+
- `delta-normal` (`parametric` alias): zero-mean Gaussian linear approximation.
|
|
82
|
+
- `delta-gamma-normal`: supplied-Hessian quadratic P&L with moment-matched normal
|
|
83
|
+
quantiles.
|
|
84
|
+
|
|
85
|
+
VaR supports `sqrt_time`, `linear`, `none`, and historical `overlapping` scaling.
|
|
86
|
+
`sqrt_time` is a modelling approximation and warns when applied to historical
|
|
87
|
+
VaR for multiple periods. `overlapping` first constructs the observed horizon
|
|
88
|
+
returns, then uses the requested rolling number of those horizon observations.
|
|
89
|
+
Adjacent horizon observations overlap and are dependent. No false independence
|
|
90
|
+
assumption is needed to calculate their empirical quantile.
|
|
91
|
+
|
|
92
|
+
Weights may be a sequence, dictionary or labelled pandas Series. Series are
|
|
93
|
+
aligned to asset labels; positive-net weights normalize to sum to one. Zero-net
|
|
94
|
+
or negative-net vectors are retained as supplied. Missing active-factor values
|
|
95
|
+
make that portfolio observation unknown; a zero-weight factor does not remove
|
|
96
|
+
it. For log/absolute inputs, aggregation is a linear factor combination, not a
|
|
97
|
+
claim about an exact discrete buy-and-hold wealth process.
|
|
98
|
+
|
|
99
|
+
For zero-mean Gaussian factors and quadratic P&L:
|
|
100
|
+
|
|
101
|
+
```{math}
|
|
102
|
+
X\sim N(0,\Sigma),\quad P=w^\top X+\tfrac12 X^\top G X,
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
```{math}
|
|
106
|
+
m=\tfrac12\operatorname{tr}(G\Sigma),\quad
|
|
107
|
+
v=w^\top\Sigma w+\tfrac12\operatorname{tr}(G\Sigma G\Sigma),\quad
|
|
108
|
+
\operatorname{VaR}_\alpha\approx z_\alpha\sqrt{v}-m.
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
`gamma_matrix` must be finite, symmetric, labelled/dimensioned for the selected
|
|
112
|
+
factors, in the same input units and already position-weighted. It cannot be
|
|
113
|
+
inferred from squared historical factor returns. Per-asset delta-gamma columns
|
|
114
|
+
are unit-delta single-factor diagnostics using the supplied `G_ii`; the
|
|
115
|
+
`Portfolio` result uses the full weights and Hessian. These columns are not an
|
|
116
|
+
additive risk allocation. The quadratic P&L generally has a non-Gaussian
|
|
117
|
+
distribution, so this is an approximation. Under default horizon scaling, use
|
|
118
|
+
`Sigma_h=h*Sigma`; gamma effects are calculated after this covariance change.
|
|
119
|
+
`linear` scales factor shocks by h and therefore covariance by h squared.
|
|
120
|
+
|
|
121
|
+
The old `market_regime_threshold` and `vol_scaling_factor` arguments remain for
|
|
122
|
+
call compatibility. They do not modify the result and nondefault values emit a
|
|
123
|
+
deprecation warning. Missing gamma emits a deprecation warning and raises an
|
|
124
|
+
error when delta-gamma is selected.
|
|
125
|
+
|
|
126
|
+
Historical CVaR/ES integrates the fractional empirical tail mass, avoiding a
|
|
127
|
+
rounded-up count bias. Parametric ES/normal EVaR scale the mean by h and volatility
|
|
128
|
+
by square-root h (or by h under linear scaling). Historical ES square-root
|
|
129
|
+
scaling remains an approximation. The legacy `erm` function is a fixed-z
|
|
130
|
+
Chernoff tail bound `(log mean exp(-z*R) - log(1-confidence))/z`; it is not the
|
|
131
|
+
confidence-independent conventional entropic risk measure. `evar` implements
|
|
132
|
+
normal-distribution EVaR. No optimized empirical EVaR or alternate distribution
|
|
133
|
+
calibration is implied.
|
|
134
|
+
|
|
135
|
+
## Simulations and historical GBM fitting
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
import numpy as np
|
|
139
|
+
from squarequant.monte_carlo.montecarlo import MonteCarloSimulator
|
|
140
|
+
import squarequant as sq
|
|
141
|
+
|
|
142
|
+
w = sq.brownian(T=1, N=32, nsims=100, seed=42)
|
|
143
|
+
gbm = sq.gbm_paths(S0=100, mu=0.05, sigma=0.2, N=32, nsims=100, seed=42)
|
|
144
|
+
correlated = sq.gbm_correlated_paths(
|
|
145
|
+
np.array([100., 100.]), np.array([0.05, 0.03]), np.array([0.2, 0.15]),
|
|
146
|
+
N=32, nsims=100, seed=42, correlation_matrix=np.array([[1., 0.5], [0.5, 1.]]),
|
|
147
|
+
)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Paths include time zero. N is the number of grid points, so `dt=T/(N-1)`.
|
|
151
|
+
Correlation matrices must be finite, symmetric, positive definite and have unit
|
|
152
|
+
diagonals. The default multi-asset correlation is the identity matrix. Instance
|
|
153
|
+
and static entry points share the same implementations and preserve seeded
|
|
154
|
+
reproducibility. Zero volatility gives deterministic exponential growth.
|
|
155
|
+
|
|
156
|
+
`MonteCarloSimulator.fit_params` estimates historical GBM parameters from one
|
|
157
|
+
positive price series using population-variance MLE:
|
|
158
|
+
`sigma=std(log_returns, ddof=0)/sqrt(dt)` and
|
|
159
|
+
`mu=mean(log_returns)/dt + sigma**2/2`. This estimates the drift of price under
|
|
160
|
+
the historical sampling measure; it does not impose a risk-neutral drift or
|
|
161
|
+
perform a change of measure. A user may supply another drift to the path
|
|
162
|
+
simulator for another specified modelling measure.
|
|
163
|
+
|
|
164
|
+
`simplemc` reports the sample mean, unbiased sample variance and an interval
|
|
165
|
+
formed using the selected distribution's quantile times the estimated standard
|
|
166
|
+
error. The normal interval is an asymptotic approximation with estimated
|
|
167
|
+
variance; the t option uses the supplied degrees of freedom. The Laplace option
|
|
168
|
+
is a distribution-quantile heuristic, not an exact finite-sample confidence
|
|
169
|
+
interval for a mean. Invalid samples and degrees of freedom are rejected.
|
|
170
|
+
|
|
171
|
+
## Optional data downloads
|
|
172
|
+
|
|
173
|
+
Install `python -m pip install -e '.[data]'` from source. Both a ticker string and
|
|
174
|
+
a list of unique, nonempty ticker strings are accepted. Results use names such
|
|
175
|
+
as `AAPL_Close`.
|
|
176
|
+
|
|
177
|
+
The yfinance adapter handles single-level columns and both ticker/field and
|
|
178
|
+
field/ticker MultiIndexes. It requests adjusted data by default; explicitly
|
|
179
|
+
requesting `Adj Close` disables automatic adjustment so the named adjusted-close
|
|
180
|
+
field can be retrieved. If `Close` is requested alongside `Adj Close`, `Close`
|
|
181
|
+
is then the unadjusted field. Missing symbols/fields are logged; reconcile your
|
|
182
|
+
requested output when completeness is required.
|
|
183
|
+
|
|
184
|
+
The Theta adapter targets the existing v2 EOD endpoint and supports `interval='1d'`
|
|
185
|
+
only; it requires a compatible local Theta terminal. It normalizes fields,
|
|
186
|
+
including `Count`, and keeps requested ticker order even with parallel fetching.
|
|
187
|
+
Partial failures are logged and successful symbols remain available. Live
|
|
188
|
+
terminal compatibility, subscriptions and option-specific request parameters
|
|
189
|
+
are outside the offline adapter checks; no live-vendor validation is claimed.
|
|
190
|
+
|
|
191
|
+
`DownloadConfig` date defaults are evaluated per instance. Explicit dates require
|
|
192
|
+
zero-padded ISO format and ordered endpoints. Provider dependencies are lazy
|
|
193
|
+
imports, so the numerical API remains usable without them.
|
|
194
|
+
|
|
195
|
+
## Executable example
|
|
196
|
+
|
|
197
|
+
`python examples/risk_metrics_demo.py` uses no network or credentials. Its JSON
|
|
198
|
+
output exercises all metric groups and all simulation wrappers. Key expected
|
|
199
|
+
values are historical VaR `0.037`, 62.5% historical ES `0.03333333333333333`,
|
|
200
|
+
sample mean `2.5`, Brownian shape `[3, 8]`, and correlated Brownian/GBM shapes
|
|
201
|
+
`[2, 3, 8]`.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""Deterministic, offline demonstration of every statistics/simulation API group.
|
|
2
|
+
|
|
3
|
+
Install from the project root with: python -m pip install -e '.[dev]'
|
|
4
|
+
Then run: python examples/risk_metrics_demo.py
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
import pandas as pd
|
|
11
|
+
|
|
12
|
+
import squarequant as sq
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def run() -> dict:
|
|
16
|
+
returns = pd.DataFrame({"A": [-0.04, -0.02, 0.01, 0.02], "B": [0.01, -0.01, 0.03, -0.02]})
|
|
17
|
+
result = {}
|
|
18
|
+
for name in [
|
|
19
|
+
"sharpe",
|
|
20
|
+
"sortino",
|
|
21
|
+
"vol",
|
|
22
|
+
"mdd",
|
|
23
|
+
"calmar",
|
|
24
|
+
"cvar",
|
|
25
|
+
"semidev",
|
|
26
|
+
"avgdd",
|
|
27
|
+
"ulcer",
|
|
28
|
+
"mad",
|
|
29
|
+
"erm",
|
|
30
|
+
"evar",
|
|
31
|
+
"cdar",
|
|
32
|
+
]:
|
|
33
|
+
kwargs = dict(window=4)
|
|
34
|
+
if name in {"sharpe", "sortino"}:
|
|
35
|
+
kwargs["freerate_value"] = 0
|
|
36
|
+
if name == "cvar":
|
|
37
|
+
kwargs.update(holding_period=1, confidence=0.625)
|
|
38
|
+
frame = getattr(sq, name)(returns, ["A"], **kwargs)
|
|
39
|
+
result[name] = float(frame.iloc[-1, 0])
|
|
40
|
+
for method in ["historical", "delta-normal", "delta-gamma-normal"]:
|
|
41
|
+
kwargs = {"gamma_matrix": np.array([[2.0]])} if method == "delta-gamma-normal" else {}
|
|
42
|
+
frame = sq.var(returns, ["A"], window=4, holding_period=1, method=method, **kwargs)
|
|
43
|
+
result["var_" + method] = float(frame.Portfolio.iloc[-1])
|
|
44
|
+
prices = pd.DataFrame({"A": [100.0, 80.0, 90.0, 95.0]})
|
|
45
|
+
result["calmar_from_prices"] = float(sq.calmar(prices, ["A"], window=3, use_returns=False).iloc[-1, 0])
|
|
46
|
+
result["sample_mean"] = sq.simplemc([1.0, 2.0, 3.0, 4.0])["sample_mean"]
|
|
47
|
+
result["brownian_shape"] = list(sq.brownian(N=8, nsims=3, seed=42).shape)
|
|
48
|
+
result["correlated_brownian_shape"] = list(
|
|
49
|
+
sq.correlated_brownian(N=8, nsims=3, seed=42, correlation_matrix=np.eye(2)).shape
|
|
50
|
+
)
|
|
51
|
+
result["gbm_shape"] = list(sq.gbm_paths(N=8, nsims=3, seed=42).shape)
|
|
52
|
+
result["correlated_gbm_shape"] = list(
|
|
53
|
+
sq.gbm_correlated_paths(np.ones(2), np.zeros(2), np.ones(2) * 0.2, N=8, nsims=3, seed=42).shape
|
|
54
|
+
)
|
|
55
|
+
result["version"] = sq.__version__
|
|
56
|
+
assert abs(result["var_historical"] - 0.037) < 1e-12
|
|
57
|
+
assert abs(result["cvar"] - 1 / 30) < 1e-12
|
|
58
|
+
print(json.dumps(result, indent=2, allow_nan=False))
|
|
59
|
+
return result
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
if __name__ == "__main__":
|
|
63
|
+
run()
|