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.
Files changed (88) hide show
  1. portopt-0.1.0/LICENSE +28 -0
  2. portopt-0.1.0/PKG-INFO +197 -0
  3. portopt-0.1.0/README.md +143 -0
  4. portopt-0.1.0/cli/__init__.py +61 -0
  5. portopt-0.1.0/cli/__main__.py +5 -0
  6. portopt-0.1.0/cli/client.py +282 -0
  7. portopt-0.1.0/cli/data_assembly.py +869 -0
  8. portopt-0.1.0/cli/db.py +121 -0
  9. portopt-0.1.0/cli/direct_fetch.py +226 -0
  10. portopt-0.1.0/cli/display.py +136 -0
  11. portopt-0.1.0/cli/macro.py +215 -0
  12. portopt-0.1.0/cli/portfolio.py +482 -0
  13. portopt-0.1.0/cli/universe.py +152 -0
  14. portopt-0.1.0/cli/yfinance.py +436 -0
  15. portopt-0.1.0/optimizer/__init__.py +71 -0
  16. portopt-0.1.0/optimizer/exceptions.py +25 -0
  17. portopt-0.1.0/optimizer/factors/__init__.py +193 -0
  18. portopt-0.1.0/optimizer/factors/_alpha.py +111 -0
  19. portopt-0.1.0/optimizer/factors/_config.py +523 -0
  20. portopt-0.1.0/optimizer/factors/_construction.py +490 -0
  21. portopt-0.1.0/optimizer/factors/_diagnostics.py +197 -0
  22. portopt-0.1.0/optimizer/factors/_integration.py +318 -0
  23. portopt-0.1.0/optimizer/factors/_mimicking.py +383 -0
  24. portopt-0.1.0/optimizer/factors/_ml_scoring.py +141 -0
  25. portopt-0.1.0/optimizer/factors/_oos_validation.py +285 -0
  26. portopt-0.1.0/optimizer/factors/_regime.py +162 -0
  27. portopt-0.1.0/optimizer/factors/_scoring.py +369 -0
  28. portopt-0.1.0/optimizer/factors/_selection.py +263 -0
  29. portopt-0.1.0/optimizer/factors/_standardization.py +298 -0
  30. portopt-0.1.0/optimizer/factors/_validation.py +671 -0
  31. portopt-0.1.0/optimizer/moments/__init__.py +59 -0
  32. portopt-0.1.0/optimizer/moments/_config.py +141 -0
  33. portopt-0.1.0/optimizer/moments/_dmm.py +422 -0
  34. portopt-0.1.0/optimizer/moments/_factory.py +151 -0
  35. portopt-0.1.0/optimizer/moments/_hmm.py +541 -0
  36. portopt-0.1.0/optimizer/moments/_scaling.py +154 -0
  37. portopt-0.1.0/optimizer/optimization/__init__.py +104 -0
  38. portopt-0.1.0/optimizer/optimization/_config.py +668 -0
  39. portopt-0.1.0/optimizer/optimization/_dr_cvar.py +253 -0
  40. portopt-0.1.0/optimizer/optimization/_factory.py +758 -0
  41. portopt-0.1.0/optimizer/optimization/_regime_risk.py +419 -0
  42. portopt-0.1.0/optimizer/optimization/_robust.py +440 -0
  43. portopt-0.1.0/optimizer/pipeline/__init__.py +27 -0
  44. portopt-0.1.0/optimizer/pipeline/_builder.py +64 -0
  45. portopt-0.1.0/optimizer/pipeline/_config.py +47 -0
  46. portopt-0.1.0/optimizer/pipeline/_orchestrator.py +635 -0
  47. portopt-0.1.0/optimizer/pre_selection/__init__.py +9 -0
  48. portopt-0.1.0/optimizer/pre_selection/_config.py +110 -0
  49. portopt-0.1.0/optimizer/pre_selection/_pipeline.py +131 -0
  50. portopt-0.1.0/optimizer/preprocessing/__init__.py +15 -0
  51. portopt-0.1.0/optimizer/preprocessing/_delisting.py +54 -0
  52. portopt-0.1.0/optimizer/preprocessing/_imputation.py +113 -0
  53. portopt-0.1.0/optimizer/preprocessing/_outliers.py +97 -0
  54. portopt-0.1.0/optimizer/preprocessing/_regression_imputer.py +207 -0
  55. portopt-0.1.0/optimizer/preprocessing/_validation.py +68 -0
  56. portopt-0.1.0/optimizer/py.typed +0 -0
  57. portopt-0.1.0/optimizer/rebalancing/__init__.py +35 -0
  58. portopt-0.1.0/optimizer/rebalancing/_config.py +154 -0
  59. portopt-0.1.0/optimizer/rebalancing/_rebalancer.py +169 -0
  60. portopt-0.1.0/optimizer/scoring/__init__.py +13 -0
  61. portopt-0.1.0/optimizer/scoring/_config.py +63 -0
  62. portopt-0.1.0/optimizer/scoring/_factory.py +137 -0
  63. portopt-0.1.0/optimizer/synthetic/__init__.py +21 -0
  64. portopt-0.1.0/optimizer/synthetic/_config.py +135 -0
  65. portopt-0.1.0/optimizer/synthetic/_factory.py +121 -0
  66. portopt-0.1.0/optimizer/tuning/__init__.py +18 -0
  67. portopt-0.1.0/optimizer/tuning/_config.py +104 -0
  68. portopt-0.1.0/optimizer/tuning/_factory.py +97 -0
  69. portopt-0.1.0/optimizer/universe/__init__.py +31 -0
  70. portopt-0.1.0/optimizer/universe/_config.py +159 -0
  71. portopt-0.1.0/optimizer/universe/_factory.py +58 -0
  72. portopt-0.1.0/optimizer/universe/_screener.py +370 -0
  73. portopt-0.1.0/optimizer/validation/__init__.py +29 -0
  74. portopt-0.1.0/optimizer/validation/_config.py +138 -0
  75. portopt-0.1.0/optimizer/validation/_factory.py +220 -0
  76. portopt-0.1.0/optimizer/views/__init__.py +25 -0
  77. portopt-0.1.0/optimizer/views/_config.py +223 -0
  78. portopt-0.1.0/optimizer/views/_factory.py +288 -0
  79. portopt-0.1.0/optimizer/views/_uncertainty.py +79 -0
  80. portopt-0.1.0/portopt.egg-info/PKG-INFO +197 -0
  81. portopt-0.1.0/portopt.egg-info/SOURCES.txt +86 -0
  82. portopt-0.1.0/portopt.egg-info/dependency_links.txt +1 -0
  83. portopt-0.1.0/portopt.egg-info/entry_points.txt +2 -0
  84. portopt-0.1.0/portopt.egg-info/requires.txt +34 -0
  85. portopt-0.1.0/portopt.egg-info/top_level.txt +2 -0
  86. portopt-0.1.0/pyproject.toml +180 -0
  87. portopt-0.1.0/setup.cfg +4 -0
  88. 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
+ [![CI](https://github.com/SilvioBaratto/optimizer/actions/workflows/ci.yml/badge.svg)](https://github.com/SilvioBaratto/optimizer/actions/workflows/ci.yml)
58
+ ![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue)
59
+ [![codecov](https://codecov.io/gh/SilvioBaratto/optimizer/branch/main/graph/badge.svg)](https://codecov.io/gh/SilvioBaratto/optimizer)
60
+ ![License](https://img.shields.io/badge/license-BSD--3--Clause-green)
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)
@@ -0,0 +1,143 @@
1
+ # Portfolio Optimizer
2
+
3
+ [![CI](https://github.com/SilvioBaratto/optimizer/actions/workflows/ci.yml/badge.svg)](https://github.com/SilvioBaratto/optimizer/actions/workflows/ci.yml)
4
+ ![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue)
5
+ [![codecov](https://codecov.io/gh/SilvioBaratto/optimizer/branch/main/graph/badge.svg)](https://codecov.io/gh/SilvioBaratto/optimizer)
6
+ ![License](https://img.shields.io/badge/license-BSD--3--Clause-green)
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()
@@ -0,0 +1,5 @@
1
+ """Allow ``python -m app.cli`` invocation."""
2
+
3
+ from cli import app
4
+
5
+ app()