portopt 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.
- portopt-0.1.0/LICENSE +28 -0
- portopt-0.1.0/PKG-INFO +197 -0
- portopt-0.1.0/README.md +143 -0
- portopt-0.1.0/cli/__init__.py +61 -0
- portopt-0.1.0/cli/__main__.py +5 -0
- portopt-0.1.0/cli/client.py +282 -0
- portopt-0.1.0/cli/data_assembly.py +869 -0
- portopt-0.1.0/cli/db.py +121 -0
- portopt-0.1.0/cli/direct_fetch.py +226 -0
- portopt-0.1.0/cli/display.py +136 -0
- portopt-0.1.0/cli/macro.py +215 -0
- portopt-0.1.0/cli/portfolio.py +482 -0
- portopt-0.1.0/cli/universe.py +152 -0
- portopt-0.1.0/cli/yfinance.py +436 -0
- portopt-0.1.0/optimizer/__init__.py +71 -0
- portopt-0.1.0/optimizer/exceptions.py +25 -0
- portopt-0.1.0/optimizer/factors/__init__.py +193 -0
- portopt-0.1.0/optimizer/factors/_alpha.py +111 -0
- portopt-0.1.0/optimizer/factors/_config.py +523 -0
- portopt-0.1.0/optimizer/factors/_construction.py +490 -0
- portopt-0.1.0/optimizer/factors/_diagnostics.py +197 -0
- portopt-0.1.0/optimizer/factors/_integration.py +318 -0
- portopt-0.1.0/optimizer/factors/_mimicking.py +383 -0
- portopt-0.1.0/optimizer/factors/_ml_scoring.py +141 -0
- portopt-0.1.0/optimizer/factors/_oos_validation.py +285 -0
- portopt-0.1.0/optimizer/factors/_regime.py +162 -0
- portopt-0.1.0/optimizer/factors/_scoring.py +369 -0
- portopt-0.1.0/optimizer/factors/_selection.py +263 -0
- portopt-0.1.0/optimizer/factors/_standardization.py +298 -0
- portopt-0.1.0/optimizer/factors/_validation.py +671 -0
- portopt-0.1.0/optimizer/moments/__init__.py +59 -0
- portopt-0.1.0/optimizer/moments/_config.py +141 -0
- portopt-0.1.0/optimizer/moments/_dmm.py +422 -0
- portopt-0.1.0/optimizer/moments/_factory.py +151 -0
- portopt-0.1.0/optimizer/moments/_hmm.py +541 -0
- portopt-0.1.0/optimizer/moments/_scaling.py +154 -0
- portopt-0.1.0/optimizer/optimization/__init__.py +104 -0
- portopt-0.1.0/optimizer/optimization/_config.py +668 -0
- portopt-0.1.0/optimizer/optimization/_dr_cvar.py +253 -0
- portopt-0.1.0/optimizer/optimization/_factory.py +758 -0
- portopt-0.1.0/optimizer/optimization/_regime_risk.py +419 -0
- portopt-0.1.0/optimizer/optimization/_robust.py +440 -0
- portopt-0.1.0/optimizer/pipeline/__init__.py +27 -0
- portopt-0.1.0/optimizer/pipeline/_builder.py +64 -0
- portopt-0.1.0/optimizer/pipeline/_config.py +47 -0
- portopt-0.1.0/optimizer/pipeline/_orchestrator.py +635 -0
- portopt-0.1.0/optimizer/pre_selection/__init__.py +9 -0
- portopt-0.1.0/optimizer/pre_selection/_config.py +110 -0
- portopt-0.1.0/optimizer/pre_selection/_pipeline.py +131 -0
- portopt-0.1.0/optimizer/preprocessing/__init__.py +15 -0
- portopt-0.1.0/optimizer/preprocessing/_delisting.py +54 -0
- portopt-0.1.0/optimizer/preprocessing/_imputation.py +113 -0
- portopt-0.1.0/optimizer/preprocessing/_outliers.py +97 -0
- portopt-0.1.0/optimizer/preprocessing/_regression_imputer.py +207 -0
- portopt-0.1.0/optimizer/preprocessing/_validation.py +68 -0
- portopt-0.1.0/optimizer/py.typed +0 -0
- portopt-0.1.0/optimizer/rebalancing/__init__.py +35 -0
- portopt-0.1.0/optimizer/rebalancing/_config.py +154 -0
- portopt-0.1.0/optimizer/rebalancing/_rebalancer.py +169 -0
- portopt-0.1.0/optimizer/scoring/__init__.py +13 -0
- portopt-0.1.0/optimizer/scoring/_config.py +63 -0
- portopt-0.1.0/optimizer/scoring/_factory.py +137 -0
- portopt-0.1.0/optimizer/synthetic/__init__.py +21 -0
- portopt-0.1.0/optimizer/synthetic/_config.py +135 -0
- portopt-0.1.0/optimizer/synthetic/_factory.py +121 -0
- portopt-0.1.0/optimizer/tuning/__init__.py +18 -0
- portopt-0.1.0/optimizer/tuning/_config.py +104 -0
- portopt-0.1.0/optimizer/tuning/_factory.py +97 -0
- portopt-0.1.0/optimizer/universe/__init__.py +31 -0
- portopt-0.1.0/optimizer/universe/_config.py +159 -0
- portopt-0.1.0/optimizer/universe/_factory.py +58 -0
- portopt-0.1.0/optimizer/universe/_screener.py +370 -0
- portopt-0.1.0/optimizer/validation/__init__.py +29 -0
- portopt-0.1.0/optimizer/validation/_config.py +138 -0
- portopt-0.1.0/optimizer/validation/_factory.py +220 -0
- portopt-0.1.0/optimizer/views/__init__.py +25 -0
- portopt-0.1.0/optimizer/views/_config.py +223 -0
- portopt-0.1.0/optimizer/views/_factory.py +288 -0
- portopt-0.1.0/optimizer/views/_uncertainty.py +79 -0
- portopt-0.1.0/portopt.egg-info/PKG-INFO +197 -0
- portopt-0.1.0/portopt.egg-info/SOURCES.txt +86 -0
- portopt-0.1.0/portopt.egg-info/dependency_links.txt +1 -0
- portopt-0.1.0/portopt.egg-info/entry_points.txt +2 -0
- portopt-0.1.0/portopt.egg-info/requires.txt +34 -0
- portopt-0.1.0/portopt.egg-info/top_level.txt +2 -0
- portopt-0.1.0/pyproject.toml +180 -0
- portopt-0.1.0/setup.cfg +4 -0
- portopt-0.1.0/tests/test_properties.py +444 -0
portopt-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, Silvio Angelo Baratto Roldan
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
portopt-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: portopt
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Portfolio optimization library built on skfolio and scikit-learn
|
|
5
|
+
Author: Silvio Baratto
|
|
6
|
+
License: BSD-3-Clause
|
|
7
|
+
Project-URL: Homepage, https://github.com/SilvioBaratto/optimizer
|
|
8
|
+
Project-URL: Documentation, https://silviobaratto.github.io/optimizer
|
|
9
|
+
Project-URL: Repository, https://github.com/SilvioBaratto/optimizer
|
|
10
|
+
Project-URL: Issues, https://github.com/SilvioBaratto/optimizer/issues
|
|
11
|
+
Project-URL: Changelog, https://github.com/SilvioBaratto/optimizer/blob/main/CHANGELOG.md
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: numpy>=1.24
|
|
26
|
+
Requires-Dist: pandas>=2.0
|
|
27
|
+
Requires-Dist: scipy>=1.11
|
|
28
|
+
Requires-Dist: scikit-learn>=1.6
|
|
29
|
+
Requires-Dist: skfolio>=0.5
|
|
30
|
+
Requires-Dist: hmmlearn>=0.3.3
|
|
31
|
+
Requires-Dist: arch>=8.0.0
|
|
32
|
+
Provides-Extra: test
|
|
33
|
+
Requires-Dist: pytest>=7.4; extra == "test"
|
|
34
|
+
Requires-Dist: pytest-cov>=4.0; extra == "test"
|
|
35
|
+
Requires-Dist: hypothesis>=6.0; extra == "test"
|
|
36
|
+
Provides-Extra: lint
|
|
37
|
+
Requires-Dist: ruff>=0.1; extra == "lint"
|
|
38
|
+
Requires-Dist: pip-audit>=2.6; extra == "lint"
|
|
39
|
+
Provides-Extra: typecheck
|
|
40
|
+
Requires-Dist: mypy>=1.5; extra == "typecheck"
|
|
41
|
+
Requires-Dist: pyright[nodejs]==1.1.398; extra == "typecheck"
|
|
42
|
+
Provides-Extra: docs
|
|
43
|
+
Requires-Dist: mkdocs-material>=9.0; extra == "docs"
|
|
44
|
+
Requires-Dist: mkdocstrings[python]>=0.24; extra == "docs"
|
|
45
|
+
Requires-Dist: mkdocs-gen-files>=0.5; extra == "docs"
|
|
46
|
+
Requires-Dist: mkdocs-literate-nav>=0.6; extra == "docs"
|
|
47
|
+
Provides-Extra: dmm
|
|
48
|
+
Requires-Dist: torch>=2.0; extra == "dmm"
|
|
49
|
+
Requires-Dist: pyro-ppl>=1.9; extra == "dmm"
|
|
50
|
+
Provides-Extra: dev
|
|
51
|
+
Requires-Dist: portopt[docs,lint,test,typecheck]; extra == "dev"
|
|
52
|
+
Requires-Dist: pre-commit>=3.5; extra == "dev"
|
|
53
|
+
Dynamic: license-file
|
|
54
|
+
|
|
55
|
+
# Portfolio Optimizer
|
|
56
|
+
|
|
57
|
+
[](https://github.com/SilvioBaratto/optimizer/actions/workflows/ci.yml)
|
|
58
|
+

|
|
59
|
+
[](https://codecov.io/gh/SilvioBaratto/optimizer)
|
|
60
|
+

|
|
61
|
+
|
|
62
|
+
Quantitative portfolio construction and optimization platform built on [skfolio](https://skfolio.org/) and scikit-learn.
|
|
63
|
+
|
|
64
|
+
## Architecture
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
optimizer/ Pure-Python optimization library (DB-agnostic, sklearn/skfolio-based)
|
|
68
|
+
preprocessing/ Return data cleaning (validation, outlier treatment, sector imputation)
|
|
69
|
+
pre_selection/ Asset filtering pipeline (completeness, variance, correlation, dominance)
|
|
70
|
+
moments/ Expected return and covariance estimation
|
|
71
|
+
views/ Black-Litterman, Entropy Pooling, Opinion Pooling
|
|
72
|
+
optimization/ Mean-risk, risk budgeting, HRP/HERC/NCO, stacking
|
|
73
|
+
synthetic/ Vine copula scenario generation and stress testing
|
|
74
|
+
validation/ Walk-forward, combinatorial purged CV, randomized CV
|
|
75
|
+
scoring/ Performance scoring for model selection
|
|
76
|
+
tuning/ Grid search and randomized search with temporal CV
|
|
77
|
+
rebalancing/ Calendar and threshold-based rebalancing
|
|
78
|
+
pipeline/ End-to-end orchestration (prices → validated weights)
|
|
79
|
+
|
|
80
|
+
api/ FastAPI backend (PostgreSQL, BAML, Trading 212 integration)
|
|
81
|
+
cli/ Typer CLI (data fetching, universe management, macro regime analysis)
|
|
82
|
+
tests/ Test suite for the optimizer library
|
|
83
|
+
theory/ LaTeX/Markdown theoretical documentation
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Quick Start — Optimizer Library
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
pip install -e ".[dev]"
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
import pandas as pd
|
|
94
|
+
from optimizer.optimization import MeanRiskConfig, build_mean_risk
|
|
95
|
+
from optimizer.validation import WalkForwardConfig
|
|
96
|
+
from optimizer.pipeline import run_full_pipeline
|
|
97
|
+
|
|
98
|
+
# Load price data (DatetimeIndex, one column per asset)
|
|
99
|
+
prices = pd.read_csv("prices.csv", index_col=0, parse_dates=True)
|
|
100
|
+
|
|
101
|
+
# Configure and run
|
|
102
|
+
optimizer = build_mean_risk(MeanRiskConfig.for_max_sharpe())
|
|
103
|
+
cv_config = WalkForwardConfig.for_quarterly_rolling()
|
|
104
|
+
|
|
105
|
+
result = run_full_pipeline(
|
|
106
|
+
prices=prices,
|
|
107
|
+
optimizer=optimizer,
|
|
108
|
+
cv_config=cv_config,
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
print(result.weights)
|
|
112
|
+
print(result.summary)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Quick Start — API + CLI
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# Start PostgreSQL
|
|
119
|
+
docker compose up -d
|
|
120
|
+
|
|
121
|
+
# Set up the API
|
|
122
|
+
cd api
|
|
123
|
+
pip install -r requirements.txt
|
|
124
|
+
cp .env.example .env # Edit with your API keys
|
|
125
|
+
alembic upgrade head
|
|
126
|
+
uvicorn app.main:app --reload # http://localhost:8000
|
|
127
|
+
|
|
128
|
+
# CLI (from project root)
|
|
129
|
+
pip install -r requirements.txt
|
|
130
|
+
python -m cli --help
|
|
131
|
+
python -m cli db health
|
|
132
|
+
python -m cli universe stats
|
|
133
|
+
python -m cli yfinance fetch
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Development
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
# Install with dev dependencies
|
|
140
|
+
pip install -e ".[dev]"
|
|
141
|
+
|
|
142
|
+
# Run tests
|
|
143
|
+
pytest tests/ -v
|
|
144
|
+
|
|
145
|
+
# Lint
|
|
146
|
+
ruff check .
|
|
147
|
+
|
|
148
|
+
# Type check
|
|
149
|
+
mypy .
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Examples
|
|
153
|
+
|
|
154
|
+
Self-contained scripts using synthetic data (no API keys required):
|
|
155
|
+
|
|
156
|
+
| Script | Description |
|
|
157
|
+
|---|---|
|
|
158
|
+
| [`quickstart.py`](examples/quickstart.py) | MeanRisk optimization with walk-forward backtest |
|
|
159
|
+
| [`robust_optimization.py`](examples/robust_optimization.py) | Compare robust portfolios at different kappa values |
|
|
160
|
+
| [`regime_blending.py`](examples/regime_blending.py) | HMM fitting and regime-conditional moment estimation |
|
|
161
|
+
| [`factor_selection.py`](examples/factor_selection.py) | Factor construction, standardization, and stock selection |
|
|
162
|
+
| [`full_pipeline.py`](examples/full_pipeline.py) | End-to-end pipeline with pre-selection and rebalancing |
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
pip install -e ".[dev]"
|
|
166
|
+
python examples/quickstart.py
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Environment Variables
|
|
170
|
+
|
|
171
|
+
Copy `.env.example` to `.env` and fill in your API keys. Database defaults match `docker-compose.yml` and work out of the box.
|
|
172
|
+
|
|
173
|
+
| Variable | Description |
|
|
174
|
+
|---|---|
|
|
175
|
+
| `DATABASE_URL` | PostgreSQL connection string |
|
|
176
|
+
| `FRED_API_KEY` | Federal Reserve Economic Data |
|
|
177
|
+
| `TRADING_212_API_KEY` | Trading 212 portfolio access |
|
|
178
|
+
| `TRADING_ECONOMICS_API_KEY` | Trading Economics macro data |
|
|
179
|
+
| `OPENAI_KEY` | Azure OpenAI (for BAML chatbot) |
|
|
180
|
+
|
|
181
|
+
## Disclaimer
|
|
182
|
+
|
|
183
|
+
This software is provided for **educational and research purposes only**. It is not intended as, and shall not be understood or construed as, financial, investment, tax, or legal advice.
|
|
184
|
+
|
|
185
|
+
**No investment advice.** The authors and contributors are not registered investment advisors, broker-dealers, or financial planners. Nothing in this software or its documentation constitutes a recommendation to buy, sell, or hold any financial instrument.
|
|
186
|
+
|
|
187
|
+
**No liability for losses.** The authors and contributors accept no responsibility or liability whatsoever for any loss or damage arising from the use of this software. You may lose some or all of your invested capital. Use this software entirely at your own risk.
|
|
188
|
+
|
|
189
|
+
**Past performance is not indicative of future results.** Backtesting and historical analysis produced by this software do not guarantee future performance. Simulated results may not reflect the impact of real market conditions including liquidity, slippage, fees, and taxes.
|
|
190
|
+
|
|
191
|
+
**Seek professional advice.** Before making any investment decision, consult with a qualified, licensed financial advisor, accountant, or attorney.
|
|
192
|
+
|
|
193
|
+
By using this software, you acknowledge that you have read and understood this disclaimer and agree to be bound by its terms.
|
|
194
|
+
|
|
195
|
+
## License
|
|
196
|
+
|
|
197
|
+
[BSD-3-Clause](LICENSE)
|
portopt-0.1.0/README.md
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Portfolio Optimizer
|
|
2
|
+
|
|
3
|
+
[](https://github.com/SilvioBaratto/optimizer/actions/workflows/ci.yml)
|
|
4
|
+

|
|
5
|
+
[](https://codecov.io/gh/SilvioBaratto/optimizer)
|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
Quantitative portfolio construction and optimization platform built on [skfolio](https://skfolio.org/) and scikit-learn.
|
|
9
|
+
|
|
10
|
+
## Architecture
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
optimizer/ Pure-Python optimization library (DB-agnostic, sklearn/skfolio-based)
|
|
14
|
+
preprocessing/ Return data cleaning (validation, outlier treatment, sector imputation)
|
|
15
|
+
pre_selection/ Asset filtering pipeline (completeness, variance, correlation, dominance)
|
|
16
|
+
moments/ Expected return and covariance estimation
|
|
17
|
+
views/ Black-Litterman, Entropy Pooling, Opinion Pooling
|
|
18
|
+
optimization/ Mean-risk, risk budgeting, HRP/HERC/NCO, stacking
|
|
19
|
+
synthetic/ Vine copula scenario generation and stress testing
|
|
20
|
+
validation/ Walk-forward, combinatorial purged CV, randomized CV
|
|
21
|
+
scoring/ Performance scoring for model selection
|
|
22
|
+
tuning/ Grid search and randomized search with temporal CV
|
|
23
|
+
rebalancing/ Calendar and threshold-based rebalancing
|
|
24
|
+
pipeline/ End-to-end orchestration (prices → validated weights)
|
|
25
|
+
|
|
26
|
+
api/ FastAPI backend (PostgreSQL, BAML, Trading 212 integration)
|
|
27
|
+
cli/ Typer CLI (data fetching, universe management, macro regime analysis)
|
|
28
|
+
tests/ Test suite for the optimizer library
|
|
29
|
+
theory/ LaTeX/Markdown theoretical documentation
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Quick Start — Optimizer Library
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install -e ".[dev]"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
import pandas as pd
|
|
40
|
+
from optimizer.optimization import MeanRiskConfig, build_mean_risk
|
|
41
|
+
from optimizer.validation import WalkForwardConfig
|
|
42
|
+
from optimizer.pipeline import run_full_pipeline
|
|
43
|
+
|
|
44
|
+
# Load price data (DatetimeIndex, one column per asset)
|
|
45
|
+
prices = pd.read_csv("prices.csv", index_col=0, parse_dates=True)
|
|
46
|
+
|
|
47
|
+
# Configure and run
|
|
48
|
+
optimizer = build_mean_risk(MeanRiskConfig.for_max_sharpe())
|
|
49
|
+
cv_config = WalkForwardConfig.for_quarterly_rolling()
|
|
50
|
+
|
|
51
|
+
result = run_full_pipeline(
|
|
52
|
+
prices=prices,
|
|
53
|
+
optimizer=optimizer,
|
|
54
|
+
cv_config=cv_config,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
print(result.weights)
|
|
58
|
+
print(result.summary)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Quick Start — API + CLI
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# Start PostgreSQL
|
|
65
|
+
docker compose up -d
|
|
66
|
+
|
|
67
|
+
# Set up the API
|
|
68
|
+
cd api
|
|
69
|
+
pip install -r requirements.txt
|
|
70
|
+
cp .env.example .env # Edit with your API keys
|
|
71
|
+
alembic upgrade head
|
|
72
|
+
uvicorn app.main:app --reload # http://localhost:8000
|
|
73
|
+
|
|
74
|
+
# CLI (from project root)
|
|
75
|
+
pip install -r requirements.txt
|
|
76
|
+
python -m cli --help
|
|
77
|
+
python -m cli db health
|
|
78
|
+
python -m cli universe stats
|
|
79
|
+
python -m cli yfinance fetch
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Development
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# Install with dev dependencies
|
|
86
|
+
pip install -e ".[dev]"
|
|
87
|
+
|
|
88
|
+
# Run tests
|
|
89
|
+
pytest tests/ -v
|
|
90
|
+
|
|
91
|
+
# Lint
|
|
92
|
+
ruff check .
|
|
93
|
+
|
|
94
|
+
# Type check
|
|
95
|
+
mypy .
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Examples
|
|
99
|
+
|
|
100
|
+
Self-contained scripts using synthetic data (no API keys required):
|
|
101
|
+
|
|
102
|
+
| Script | Description |
|
|
103
|
+
|---|---|
|
|
104
|
+
| [`quickstart.py`](examples/quickstart.py) | MeanRisk optimization with walk-forward backtest |
|
|
105
|
+
| [`robust_optimization.py`](examples/robust_optimization.py) | Compare robust portfolios at different kappa values |
|
|
106
|
+
| [`regime_blending.py`](examples/regime_blending.py) | HMM fitting and regime-conditional moment estimation |
|
|
107
|
+
| [`factor_selection.py`](examples/factor_selection.py) | Factor construction, standardization, and stock selection |
|
|
108
|
+
| [`full_pipeline.py`](examples/full_pipeline.py) | End-to-end pipeline with pre-selection and rebalancing |
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
pip install -e ".[dev]"
|
|
112
|
+
python examples/quickstart.py
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Environment Variables
|
|
116
|
+
|
|
117
|
+
Copy `.env.example` to `.env` and fill in your API keys. Database defaults match `docker-compose.yml` and work out of the box.
|
|
118
|
+
|
|
119
|
+
| Variable | Description |
|
|
120
|
+
|---|---|
|
|
121
|
+
| `DATABASE_URL` | PostgreSQL connection string |
|
|
122
|
+
| `FRED_API_KEY` | Federal Reserve Economic Data |
|
|
123
|
+
| `TRADING_212_API_KEY` | Trading 212 portfolio access |
|
|
124
|
+
| `TRADING_ECONOMICS_API_KEY` | Trading Economics macro data |
|
|
125
|
+
| `OPENAI_KEY` | Azure OpenAI (for BAML chatbot) |
|
|
126
|
+
|
|
127
|
+
## Disclaimer
|
|
128
|
+
|
|
129
|
+
This software is provided for **educational and research purposes only**. It is not intended as, and shall not be understood or construed as, financial, investment, tax, or legal advice.
|
|
130
|
+
|
|
131
|
+
**No investment advice.** The authors and contributors are not registered investment advisors, broker-dealers, or financial planners. Nothing in this software or its documentation constitutes a recommendation to buy, sell, or hold any financial instrument.
|
|
132
|
+
|
|
133
|
+
**No liability for losses.** The authors and contributors accept no responsibility or liability whatsoever for any loss or damage arising from the use of this software. You may lose some or all of your invested capital. Use this software entirely at your own risk.
|
|
134
|
+
|
|
135
|
+
**Past performance is not indicative of future results.** Backtesting and historical analysis produced by this software do not guarantee future performance. Simulated results may not reflect the impact of real market conditions including liquidity, slippage, fees, and taxes.
|
|
136
|
+
|
|
137
|
+
**Seek professional advice.** Before making any investment decision, consult with a qualified, licensed financial advisor, accountant, or attorney.
|
|
138
|
+
|
|
139
|
+
By using this software, you acknowledge that you have read and understood this disclaimer and agree to be bound by its terms.
|
|
140
|
+
|
|
141
|
+
## License
|
|
142
|
+
|
|
143
|
+
[BSD-3-Clause](LICENSE)
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""Optimizer Platform CLI — Typer app factory and entry point."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
|
|
9
|
+
from cli.client import ApiClient
|
|
10
|
+
from cli.db import db_app
|
|
11
|
+
from cli.macro import macro_app
|
|
12
|
+
from cli.portfolio import portfolio_app
|
|
13
|
+
from cli.universe import universe_app
|
|
14
|
+
from cli.yfinance import yfinance_app
|
|
15
|
+
|
|
16
|
+
app = typer.Typer(
|
|
17
|
+
name="optimizer",
|
|
18
|
+
help="Optimizer Platform CLI — interact with the API from the terminal.",
|
|
19
|
+
no_args_is_help=True,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _version_callback(value: bool) -> None:
|
|
24
|
+
if value:
|
|
25
|
+
typer.echo("optimizer CLI 0.1.0")
|
|
26
|
+
raise typer.Exit()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@app.callback()
|
|
30
|
+
def main(
|
|
31
|
+
ctx: typer.Context,
|
|
32
|
+
base_url: str = typer.Option(
|
|
33
|
+
"http://localhost:8000",
|
|
34
|
+
"--base-url",
|
|
35
|
+
envvar="OPTIMIZER_API_URL",
|
|
36
|
+
help="Base URL of the Optimizer API server.",
|
|
37
|
+
),
|
|
38
|
+
version: bool | None = typer.Option(
|
|
39
|
+
None,
|
|
40
|
+
"--version",
|
|
41
|
+
"-v",
|
|
42
|
+
callback=_version_callback,
|
|
43
|
+
is_eager=True,
|
|
44
|
+
help="Show CLI version and exit.",
|
|
45
|
+
),
|
|
46
|
+
) -> None:
|
|
47
|
+
"""Global options applied before any sub-command."""
|
|
48
|
+
ctx.ensure_object(dict)
|
|
49
|
+
ctx.obj = ApiClient(base_url=base_url)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
# Register command groups
|
|
53
|
+
app.add_typer(db_app)
|
|
54
|
+
app.add_typer(macro_app)
|
|
55
|
+
app.add_typer(portfolio_app)
|
|
56
|
+
app.add_typer(universe_app)
|
|
57
|
+
app.add_typer(yfinance_app)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
if __name__ == "__main__":
|
|
61
|
+
app()
|