sagan-trade 0.2.4__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.
- sagan_trade-0.2.4/CHANGELOG.md +60 -0
- sagan_trade-0.2.4/LICENSE +21 -0
- sagan_trade-0.2.4/MANIFEST.in +10 -0
- sagan_trade-0.2.4/PKG-INFO +171 -0
- sagan_trade-0.2.4/README.md +102 -0
- sagan_trade-0.2.4/docs/api/cli.md +78 -0
- sagan_trade-0.2.4/docs/api/config.md +73 -0
- sagan_trade-0.2.4/docs/api/data.md +52 -0
- sagan_trade-0.2.4/docs/api/ensemble.md +16 -0
- sagan_trade-0.2.4/docs/api/exceptions.md +77 -0
- sagan_trade-0.2.4/docs/api/index.md +55 -0
- sagan_trade-0.2.4/docs/api/logging.md +44 -0
- sagan_trade-0.2.4/docs/api/predict.md +39 -0
- sagan_trade-0.2.4/docs/api/registry.md +84 -0
- sagan_trade-0.2.4/docs/api/utils.md +59 -0
- sagan_trade-0.2.4/docs/architecture.md +226 -0
- sagan_trade-0.2.4/docs/changelog.md +34 -0
- sagan_trade-0.2.4/docs/contributing.md +116 -0
- sagan_trade-0.2.4/docs/getting-started.md +146 -0
- sagan_trade-0.2.4/docs/index.md +153 -0
- sagan_trade-0.2.4/docs/tutorials/custom_config.md +142 -0
- sagan_trade-0.2.4/docs/tutorials/parallel_training.md +133 -0
- sagan_trade-0.2.4/docs/tutorials/single_stock.md +133 -0
- sagan_trade-0.2.4/pyproject.toml +128 -0
- sagan_trade-0.2.4/requirements.txt +5 -0
- sagan_trade-0.2.4/sagan/__init__.py +86 -0
- sagan_trade-0.2.4/sagan/__main__.py +6 -0
- sagan_trade-0.2.4/sagan/app.py +291 -0
- sagan_trade-0.2.4/sagan/cli/auth.py +86 -0
- sagan_trade-0.2.4/sagan/cli/commands.py +137 -0
- sagan_trade-0.2.4/sagan/compliance/report.py +72 -0
- sagan_trade-0.2.4/sagan/config.py +73 -0
- sagan_trade-0.2.4/sagan/data.py +234 -0
- sagan_trade-0.2.4/sagan/database.py +60 -0
- sagan_trade-0.2.4/sagan/ensemble.py +112 -0
- sagan_trade-0.2.4/sagan/exceptions.py +100 -0
- sagan_trade-0.2.4/sagan/explain/formatter.py +39 -0
- sagan_trade-0.2.4/sagan/explain/gemma.py +63 -0
- sagan_trade-0.2.4/sagan/indicators.py +46 -0
- sagan_trade-0.2.4/sagan/logging_config.py +81 -0
- sagan_trade-0.2.4/sagan/metrics.py +151 -0
- sagan_trade-0.2.4/sagan/models/__init__.py +1 -0
- sagan_trade-0.2.4/sagan/models/llm_bridge.py +77 -0
- sagan_trade-0.2.4/sagan/models/manager.py +86 -0
- sagan_trade-0.2.4/sagan/models/math_engine.py +104 -0
- sagan_trade-0.2.4/sagan/models/pinn_loss.py +23 -0
- sagan_trade-0.2.4/sagan/models/tft.py +105 -0
- sagan_trade-0.2.4/sagan/models/xai_layer.py +38 -0
- sagan_trade-0.2.4/sagan/parallel.py +192 -0
- sagan_trade-0.2.4/sagan/portfolio/csv_import.py +29 -0
- sagan_trade-0.2.4/sagan/portfolio/snaptrade.py +18 -0
- sagan_trade-0.2.4/sagan/predict.py +112 -0
- sagan_trade-0.2.4/sagan/py.typed +1 -0
- sagan_trade-0.2.4/sagan/registry.py +259 -0
- sagan_trade-0.2.4/sagan/signals.py +51 -0
- sagan_trade-0.2.4/sagan/utils.py +152 -0
- sagan_trade-0.2.4/sagan_trade.egg-info/PKG-INFO +171 -0
- sagan_trade-0.2.4/sagan_trade.egg-info/SOURCES.txt +65 -0
- sagan_trade-0.2.4/sagan_trade.egg-info/dependency_links.txt +1 -0
- sagan_trade-0.2.4/sagan_trade.egg-info/entry_points.txt +2 -0
- sagan_trade-0.2.4/sagan_trade.egg-info/requires.txt +36 -0
- sagan_trade-0.2.4/sagan_trade.egg-info/top_level.txt +1 -0
- sagan_trade-0.2.4/setup.cfg +4 -0
- sagan_trade-0.2.4/setup.py +44 -0
- sagan_trade-0.2.4/tests/test_data.py +51 -0
- sagan_trade-0.2.4/tests/test_ensemble.py +54 -0
- sagan_trade-0.2.4/tests/test_utils.py +84 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to **Sagan XAI** will be documented here.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## [0.2.1] – 2026-04-15
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- Dashboard SyntaxError: Fixed `nonlocal` scoping issue in `sagan/app.py` that occurred when using certain Python versions or execution contexts.
|
|
14
|
+
|
|
15
|
+
## [0.2.0] – 2026-04-15
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- SEBI Compliance Engine: Dual export of signals to `.md` and `.json`.
|
|
19
|
+
- Automated Threshold Optimization: Model-generated RSI and Volatility boundaries for 2000+ NSE stocks.
|
|
20
|
+
- HITL Audit Logic: Local SQLite database (`sagan.db`) recording all actions and model justifications.
|
|
21
|
+
- Gating-Driven Conflict resolution: Using TFT Variable Selection Network (VSN) weights to manage signal discrepancies.
|
|
22
|
+
- Consolidated Typer CLI: New commands `userlogs`, `metrics`, and `dash`.
|
|
23
|
+
|
|
24
|
+
## [0.0.1] – 2026-04-15
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
- **Completely removed paywall and credit tracking**: Firestore-based billing and tiered feature gating have been stripped. The library is now fully open and free.
|
|
28
|
+
- **Fixed TensorFlow retracing issue**: Optimized prediction pipeline to use direct model calls and added an LRU cache for model loading, resolving expensive tracing warnings during inference.
|
|
29
|
+
- **Reset versioning**: Reset package version to `0.0.1` as per state transition.
|
|
30
|
+
|
|
31
|
+
### Removed
|
|
32
|
+
- `sagan.billing` module and all related Firestore/sync logic.
|
|
33
|
+
- `auth`, `sync`, and `usage` CLI commands.
|
|
34
|
+
- Dependencies: `authlib`, `python-jose`, `httpx`.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## [0.1.0] – 2024-04-11
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
- **`ExplainableEnsemble`** – three-head TFT model (buy / sell / hold) with PINN mean-reversion loss.
|
|
42
|
+
- **`train()`** – convenience wrapper that fetches, trains, and registers an ensemble in one call.
|
|
43
|
+
- **`predict()`** – generates a `LONG / SHORT / NEUTRAL` signal with confidence and XAI override flag.
|
|
44
|
+
- **`batch_predict()`** – compares signals across multiple saved model IDs.
|
|
45
|
+
- **`train_parallel()`** / **`train_parallel_from_fetch()`** – multiprocessing dispatch for training one model per ticker simultaneously.
|
|
46
|
+
- **`list_models()`** / **`delete_model()`** / **`export_model()`** – full registry lifecycle management.
|
|
47
|
+
- **`SaganConfig`** – centralised configuration dataclass with `from_env()` and `from_dict()` factory methods.
|
|
48
|
+
- **`setup_logging()`** – configurable logger helper.
|
|
49
|
+
- **`sharpe_ratio()`**, **`max_drawdown()`**, **`annualised_return()`**, **`calmar_ratio()`** – reusable financial metrics.
|
|
50
|
+
- **Custom exception hierarchy**: `SaganError`, `ModelNotFoundError`, `InsufficientDataError`, `FetchError`, `ConfigurationError`, `RegistryCorruptedError`.
|
|
51
|
+
- **CLI** (`sagan --train`, `--predict`, `--list`, `--parallel`, `--model-id`, `--epochs`, `--window`, `--horizon`).
|
|
52
|
+
- **Full MkDocs Material documentation** hosted at <https://sagan-docs.vercel.app>.
|
|
53
|
+
- **GitHub Actions** CI (lint + type-check + test) and PyPI publish workflows.
|
|
54
|
+
- `py.typed` marker for PEP 561 compliance.
|
|
55
|
+
|
|
56
|
+
### Notes
|
|
57
|
+
- Initial public alpha. API may evolve before `1.0.0`.
|
|
58
|
+
- TensorFlow ≥ 2.10 required; GPU is auto-detected but not required.
|
|
59
|
+
|
|
60
|
+
[0.1.0]: https://github.com/sagan-labs/sagan/releases/tag/v0.1.0
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Sagan Labs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
include README.md
|
|
2
|
+
include LICENSE
|
|
3
|
+
include CHANGELOG.md
|
|
4
|
+
include pyproject.toml
|
|
5
|
+
include requirements.txt
|
|
6
|
+
recursive-include sagan *.py py.typed
|
|
7
|
+
recursive-include docs *.md *.yml *.png *.svg
|
|
8
|
+
recursive-exclude * __pycache__
|
|
9
|
+
recursive-exclude * *.pyc
|
|
10
|
+
recursive-exclude * *.pyo
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sagan-trade
|
|
3
|
+
Version: 0.2.4
|
|
4
|
+
Summary: Strategic Symbolic Trading Engine with iterative R2 fitting and FunctionGemma discovery.
|
|
5
|
+
Home-page: https://github.com/sagan-labs/sagan-xai
|
|
6
|
+
Author: Sagan Labs
|
|
7
|
+
Author-email: Sagan Labs <hello@sagan-docs.vercel.app>
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Homepage, https://sagan-trade.vercel.app
|
|
10
|
+
Project-URL: Documentation, https://sagan-trade.vercel.app
|
|
11
|
+
Project-URL: Source, https://github.com/That-Tech-Geek/sagan-trade
|
|
12
|
+
Project-URL: Bug Tracker, https://github.com/That-Tech-Geek/sagan-trade/issues
|
|
13
|
+
Project-URL: Changelog, https://sagan-trade.vercel.app/changelog
|
|
14
|
+
Project-URL: PyPI, https://pypi.org/project/sagan-trade/
|
|
15
|
+
Keywords: trading,quantitative-finance,machine-learning,explainable-ai,pinn,temporal-fusion-transformer,mean-reversion,ensemble,deep-learning
|
|
16
|
+
Classifier: Development Status :: 3 - Alpha
|
|
17
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
18
|
+
Classifier: Intended Audience :: Science/Research
|
|
19
|
+
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
21
|
+
Classifier: Programming Language :: Python :: 3
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
26
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
27
|
+
Classifier: Operating System :: OS Independent
|
|
28
|
+
Classifier: Typing :: Typed
|
|
29
|
+
Requires-Python: >=3.8
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
License-File: LICENSE
|
|
32
|
+
Requires-Dist: tensorflow>=2.10
|
|
33
|
+
Requires-Dist: pandas>=1.5
|
|
34
|
+
Requires-Dist: numpy>=1.23
|
|
35
|
+
Requires-Dist: yfinance>=0.2
|
|
36
|
+
Requires-Dist: scikit-learn>=1.1
|
|
37
|
+
Requires-Dist: streamlit>=1.25
|
|
38
|
+
Requires-Dist: plotly>=5.15
|
|
39
|
+
Requires-Dist: cryptography
|
|
40
|
+
Requires-Dist: typer
|
|
41
|
+
Requires-Dist: snaptrade-python-sdk
|
|
42
|
+
Requires-Dist: schedule
|
|
43
|
+
Provides-Extra: dev
|
|
44
|
+
Requires-Dist: pytest>=7.4; extra == "dev"
|
|
45
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
46
|
+
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
47
|
+
Requires-Dist: mypy>=1.5; extra == "dev"
|
|
48
|
+
Requires-Dist: build>=1.0; extra == "dev"
|
|
49
|
+
Requires-Dist: twine>=4.0; extra == "dev"
|
|
50
|
+
Requires-Dist: mkdocs-material>=9.5; extra == "dev"
|
|
51
|
+
Requires-Dist: mkdocstrings[python]>=0.24; extra == "dev"
|
|
52
|
+
Provides-Extra: ci
|
|
53
|
+
Requires-Dist: pytest>=7.4; extra == "ci"
|
|
54
|
+
Requires-Dist: pytest-cov>=4.0; extra == "ci"
|
|
55
|
+
Requires-Dist: ruff>=0.4; extra == "ci"
|
|
56
|
+
Requires-Dist: mypy>=1.5; extra == "ci"
|
|
57
|
+
Requires-Dist: pandas>=1.5; extra == "ci"
|
|
58
|
+
Requires-Dist: numpy>=1.23; extra == "ci"
|
|
59
|
+
Requires-Dist: scikit-learn>=1.1; extra == "ci"
|
|
60
|
+
Requires-Dist: yfinance>=0.2; extra == "ci"
|
|
61
|
+
Provides-Extra: docs
|
|
62
|
+
Requires-Dist: mkdocs-material>=9.5; extra == "docs"
|
|
63
|
+
Requires-Dist: mkdocstrings[python]>=0.24; extra == "docs"
|
|
64
|
+
Requires-Dist: mkdocs-git-revision-date-localized-plugin>=1.2; extra == "docs"
|
|
65
|
+
Dynamic: author
|
|
66
|
+
Dynamic: home-page
|
|
67
|
+
Dynamic: license-file
|
|
68
|
+
Dynamic: requires-python
|
|
69
|
+
|
|
70
|
+
# Sagan Trade
|
|
71
|
+
|
|
72
|
+
> **High-throughput symbolic mathematical trading engine**
|
|
73
|
+
|
|
74
|
+
[](https://python.org)
|
|
75
|
+
[](LICENSE)
|
|
76
|
+
[](https://pypi.org/project/sagan-trade/)
|
|
77
|
+
|
|
78
|
+
Sagan Trade replaces black-box neural networks with transparent, human-readable mathematical equations discovered via **FunctionGemma** (via Ollama).
|
|
79
|
+
|
|
80
|
+
| Component | Role |
|
|
81
|
+
|---|---|
|
|
82
|
+
| **Symbolic Regressor** | Fits variables to R2 > 0.95 using Polynomial and Fourier basis functions. |
|
|
83
|
+
| **FunctionGemma** | AI architect that suggests optimal mathematical compositions of signals. |
|
|
84
|
+
| **Power Hub** | OS-level optimization for maximum throughput (Eco, Balanced, Turbo). |
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Installation
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
pip install sagan-trade
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Or in editable mode from source:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
git clone https://github.com/That-Tech-Geek/sagan-trade
|
|
98
|
+
cd sagan-trade
|
|
99
|
+
pip install -e ".[dev]"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Quick Start
|
|
105
|
+
|
|
106
|
+
### Python API
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
import sagan
|
|
110
|
+
|
|
111
|
+
# Train a symbolic ensemble with high-accuracy math fitting
|
|
112
|
+
model_id = sagan.train(
|
|
113
|
+
["AAPL"],
|
|
114
|
+
signals=["Close", "Volume", "RSI"],
|
|
115
|
+
target_r2=0.95,
|
|
116
|
+
profile="turbo"
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# Predict using the latest symbolic expression
|
|
120
|
+
result = sagan.predict()
|
|
121
|
+
print(result["signal"]) # "LONG" | "SHORT"
|
|
122
|
+
print(result["formula"]) # e.g. "(Close * 0.5) + log(Volume)"
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Command-Line Interface
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
# List available math signals for a ticker
|
|
129
|
+
sagan vars AAPL
|
|
130
|
+
|
|
131
|
+
# Train symbolic model
|
|
132
|
+
sagan train AAPL --signals Close,Volume --r2 0.95 --profile turbo
|
|
133
|
+
|
|
134
|
+
# Get Trading Signal
|
|
135
|
+
sagan predict
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Architecture
|
|
141
|
+
|
|
142
|
+
```
|
|
143
|
+
yfinance Data
|
|
144
|
+
│
|
|
145
|
+
▼
|
|
146
|
+
[Parallel Fitting] → Each variable fitted to R2 > 0.95
|
|
147
|
+
│
|
|
148
|
+
▼
|
|
149
|
+
[FunctionGemma] → Suggests composite math formula
|
|
150
|
+
│
|
|
151
|
+
▼
|
|
152
|
+
[Evaluation] → Trend-based signal generation
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Configuration
|
|
158
|
+
|
|
159
|
+
All defaults live in `sagan.config`:
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
from sagan import config
|
|
163
|
+
|
|
164
|
+
config.models_dir = "~/.sagan/models/"
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## License
|
|
170
|
+
|
|
171
|
+
[MIT](LICENSE) © 2024 Sagan Labs
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Sagan Trade
|
|
2
|
+
|
|
3
|
+
> **High-throughput symbolic mathematical trading engine**
|
|
4
|
+
|
|
5
|
+
[](https://python.org)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
[](https://pypi.org/project/sagan-trade/)
|
|
8
|
+
|
|
9
|
+
Sagan Trade replaces black-box neural networks with transparent, human-readable mathematical equations discovered via **FunctionGemma** (via Ollama).
|
|
10
|
+
|
|
11
|
+
| Component | Role |
|
|
12
|
+
|---|---|
|
|
13
|
+
| **Symbolic Regressor** | Fits variables to R2 > 0.95 using Polynomial and Fourier basis functions. |
|
|
14
|
+
| **FunctionGemma** | AI architect that suggests optimal mathematical compositions of signals. |
|
|
15
|
+
| **Power Hub** | OS-level optimization for maximum throughput (Eco, Balanced, Turbo). |
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install sagan-trade
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Or in editable mode from source:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
git clone https://github.com/That-Tech-Geek/sagan-trade
|
|
29
|
+
cd sagan-trade
|
|
30
|
+
pip install -e ".[dev]"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Quick Start
|
|
36
|
+
|
|
37
|
+
### Python API
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
import sagan
|
|
41
|
+
|
|
42
|
+
# Train a symbolic ensemble with high-accuracy math fitting
|
|
43
|
+
model_id = sagan.train(
|
|
44
|
+
["AAPL"],
|
|
45
|
+
signals=["Close", "Volume", "RSI"],
|
|
46
|
+
target_r2=0.95,
|
|
47
|
+
profile="turbo"
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
# Predict using the latest symbolic expression
|
|
51
|
+
result = sagan.predict()
|
|
52
|
+
print(result["signal"]) # "LONG" | "SHORT"
|
|
53
|
+
print(result["formula"]) # e.g. "(Close * 0.5) + log(Volume)"
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Command-Line Interface
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# List available math signals for a ticker
|
|
60
|
+
sagan vars AAPL
|
|
61
|
+
|
|
62
|
+
# Train symbolic model
|
|
63
|
+
sagan train AAPL --signals Close,Volume --r2 0.95 --profile turbo
|
|
64
|
+
|
|
65
|
+
# Get Trading Signal
|
|
66
|
+
sagan predict
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Architecture
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
yfinance Data
|
|
75
|
+
│
|
|
76
|
+
▼
|
|
77
|
+
[Parallel Fitting] → Each variable fitted to R2 > 0.95
|
|
78
|
+
│
|
|
79
|
+
▼
|
|
80
|
+
[FunctionGemma] → Suggests composite math formula
|
|
81
|
+
│
|
|
82
|
+
▼
|
|
83
|
+
[Evaluation] → Trend-based signal generation
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Configuration
|
|
89
|
+
|
|
90
|
+
All defaults live in `sagan.config`:
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from sagan import config
|
|
94
|
+
|
|
95
|
+
config.models_dir = "~/.sagan/models/"
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## License
|
|
101
|
+
|
|
102
|
+
[MIT](LICENSE) © 2024 Sagan Labs
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# CLI Reference
|
|
2
|
+
|
|
3
|
+
The `sagan` command-line tool is installed automatically with the package.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
sagan --help
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Commands
|
|
12
|
+
|
|
13
|
+
### `--train`
|
|
14
|
+
|
|
15
|
+
Train a new ensemble on one or more tickers.
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
sagan --train RELIANCE.NS TCS.NS HDFCBANK.NS
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
| Flag | Type | Default | Description |
|
|
22
|
+
|---|---|---|---|
|
|
23
|
+
| `--train TICKERS…` | `str+` | — | **Required.** Ticker symbols |
|
|
24
|
+
| `--years INT` | int | 5 | Years of historical data |
|
|
25
|
+
| `--window INT` | int | 10 | Look-back window (days) |
|
|
26
|
+
| `--horizon INT` | int | 3 | Forward horizon for labelling |
|
|
27
|
+
| `--epochs INT` | int | 30 | Max training epochs |
|
|
28
|
+
| `--parallel` | flag | off | Train one model per ticker in parallel |
|
|
29
|
+
| `--num-processes INT` | int | 12 | Parallel worker processes |
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
### `--predict`
|
|
34
|
+
|
|
35
|
+
Generate a trading signal using the latest (or a specific) saved model.
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
sagan --predict
|
|
39
|
+
sagan --predict --model-id sagan_20240411_120000_abc123
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
| Flag | Type | Default | Description |
|
|
43
|
+
|---|---|---|---|
|
|
44
|
+
| `--predict` | flag | — | **Required.** Activate predict mode |
|
|
45
|
+
| `--model-id STR` | str | latest | Specific model to query |
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
### `--list`
|
|
50
|
+
|
|
51
|
+
Display a table of all registered models.
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
sagan --list
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Output columns: `model_id`, `tickers`, `val_sharpe`, `override_fraction`, `created_at`.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Examples
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# Train on NSE blue-chips, 5 years
|
|
65
|
+
sagan --train RELIANCE.NS TCS.NS INFY.NS HDFCBANK.NS --years 5
|
|
66
|
+
|
|
67
|
+
# Parallel training on US tech (8 workers)
|
|
68
|
+
sagan --train AAPL MSFT GOOGL AMZN META --parallel --num-processes 8
|
|
69
|
+
|
|
70
|
+
# Aggressive hyper-params
|
|
71
|
+
sagan --train AAPL --window 20 --horizon 5 --epochs 100
|
|
72
|
+
|
|
73
|
+
# Predict with a specific model
|
|
74
|
+
sagan --predict --model-id sagan_20240411_120000_abc123
|
|
75
|
+
|
|
76
|
+
# List all models
|
|
77
|
+
sagan --list
|
|
78
|
+
```
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Config
|
|
2
|
+
|
|
3
|
+
The `sagan.config` module exposes the :class:`~sagan.config.SaganConfig` dataclass
|
|
4
|
+
and the module-level `config` singleton that all Sagan modules share.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## SaganConfig
|
|
9
|
+
|
|
10
|
+
::: sagan.config.SaganConfig
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## config (singleton)
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
from sagan import config
|
|
18
|
+
|
|
19
|
+
# Inspect defaults
|
|
20
|
+
print(config.default_window) # 10
|
|
21
|
+
print(config.xai_confidence_threshold) # 0.6
|
|
22
|
+
print(config.models_dir) # ~/.sagan/xai_models
|
|
23
|
+
|
|
24
|
+
# Mutate for the current session
|
|
25
|
+
config.default_epochs = 50
|
|
26
|
+
config.pinn_lambda = 0.005
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Environment Variables
|
|
32
|
+
|
|
33
|
+
`SaganConfig.from_env()` reads the following variables:
|
|
34
|
+
|
|
35
|
+
| Variable | Field | Type |
|
|
36
|
+
|---|---|---|
|
|
37
|
+
| `SAGAN_HOME_DIR` | `home_dir` | `Path` |
|
|
38
|
+
| `SAGAN_MODELS_DIR` | `models_dir` | `Path` |
|
|
39
|
+
| `SAGAN_DEFAULT_WINDOW` | `default_window` | `int` |
|
|
40
|
+
| `SAGAN_DEFAULT_HORIZON` | `default_horizon` | `int` |
|
|
41
|
+
| `SAGAN_DEFAULT_EPOCHS` | `default_epochs` | `int` |
|
|
42
|
+
| `SAGAN_DEFAULT_HEAD_DIM` | `default_head_dim` | `int` |
|
|
43
|
+
| `SAGAN_DEFAULT_NUM_HEADS` | `default_num_heads` | `int` |
|
|
44
|
+
| `SAGAN_DEFAULT_FF_DIM` | `default_ff_dim` | `int` |
|
|
45
|
+
| `SAGAN_DEFAULT_DROPOUT` | `default_dropout` | `float` |
|
|
46
|
+
| `SAGAN_DEFAULT_THRESHOLD` | `default_threshold` | `float` |
|
|
47
|
+
| `SAGAN_PINN_LAMBDA` | `pinn_lambda` | `float` |
|
|
48
|
+
| `SAGAN_XAI_CONFIDENCE_THRESHOLD` | `xai_confidence_threshold` | `float` |
|
|
49
|
+
| `SAGAN_REGIME_CHANGE_THRESHOLD` | `regime_change_threshold` | `float` |
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Example: Programmatic override
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
from sagan.config import SaganConfig
|
|
57
|
+
import sagan
|
|
58
|
+
|
|
59
|
+
# Override via dict
|
|
60
|
+
cfg = SaganConfig.from_dict({
|
|
61
|
+
"default_window": 20,
|
|
62
|
+
"default_epochs": 50,
|
|
63
|
+
"pinn_lambda": 0.005,
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
# Use with ExplainableEnsemble
|
|
67
|
+
from sagan import ExplainableEnsemble
|
|
68
|
+
ens = ExplainableEnsemble(
|
|
69
|
+
["AAPL"],
|
|
70
|
+
window=cfg.default_window,
|
|
71
|
+
epochs=cfg.default_epochs,
|
|
72
|
+
)
|
|
73
|
+
```
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Data
|
|
2
|
+
|
|
3
|
+
The `sagan.data` module handles price data acquisition and supervised dataset preparation.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## fetch_prices
|
|
8
|
+
|
|
9
|
+
::: sagan.data.fetch_prices
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## validate_tickers
|
|
14
|
+
|
|
15
|
+
::: sagan.data.validate_tickers
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## prepare_probabilistic_data
|
|
20
|
+
|
|
21
|
+
::: sagan.data.prepare_probabilistic_data
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Labelling scheme
|
|
26
|
+
|
|
27
|
+
Given a forward return $\bar{r}$ and a threshold $\delta$:
|
|
28
|
+
|
|
29
|
+
| Condition | Label | Class index |
|
|
30
|
+
|---|---|---|
|
|
31
|
+
| $\bar{r} > \delta$ | **BUY** | 0 |
|
|
32
|
+
| $\bar{r} < -\delta$ | **SELL** | 1 |
|
|
33
|
+
| $-\delta \le \bar{r} \le \delta$ | **HOLD** | 2 |
|
|
34
|
+
|
|
35
|
+
The one-hot label vector `y_probs[i]` has shape `(3,)` and sums to 1.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Example: Manual data preparation
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
from sagan.data import fetch_prices, prepare_probabilistic_data
|
|
43
|
+
|
|
44
|
+
prices = fetch_prices(["RELIANCE.NS", "TCS.NS"], years=3)
|
|
45
|
+
X, y_probs, y_ret, symbols, n_stocks = prepare_probabilistic_data(
|
|
46
|
+
prices, window=10, horizon=3, threshold=0.01
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
print(X.shape) # (N, 10, 2)
|
|
50
|
+
print(y_probs.shape) # (N, 3)
|
|
51
|
+
print(symbols) # ['RELIANCE.NS', 'TCS.NS']
|
|
52
|
+
```
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Ensemble
|
|
2
|
+
|
|
3
|
+
The `sagan.ensemble` module contains the :class:`~sagan.ensemble.ExplainableEnsemble`
|
|
4
|
+
class and the :func:`~sagan.ensemble.train` convenience function.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## ExplainableEnsemble
|
|
9
|
+
|
|
10
|
+
::: sagan.ensemble.ExplainableEnsemble
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## train
|
|
15
|
+
|
|
16
|
+
::: sagan.ensemble.train
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Exceptions
|
|
2
|
+
|
|
3
|
+
All Sagan exceptions inherit from :class:`~sagan.exceptions.SaganError`,
|
|
4
|
+
allowing callers to catch any library error with a single `except SaganError`.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Hierarchy
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
SaganError
|
|
12
|
+
├── ModelNotFoundError
|
|
13
|
+
├── InsufficientDataError
|
|
14
|
+
├── FetchError
|
|
15
|
+
├── ConfigurationError
|
|
16
|
+
└── RegistryCorruptedError
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## SaganError
|
|
22
|
+
|
|
23
|
+
::: sagan.exceptions.SaganError
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## ModelNotFoundError
|
|
28
|
+
|
|
29
|
+
::: sagan.exceptions.ModelNotFoundError
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## InsufficientDataError
|
|
34
|
+
|
|
35
|
+
::: sagan.exceptions.InsufficientDataError
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## FetchError
|
|
40
|
+
|
|
41
|
+
::: sagan.exceptions.FetchError
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## ConfigurationError
|
|
46
|
+
|
|
47
|
+
::: sagan.exceptions.ConfigurationError
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## RegistryCorruptedError
|
|
52
|
+
|
|
53
|
+
::: sagan.exceptions.RegistryCorruptedError
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Catching exceptions
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
from sagan.exceptions import (
|
|
61
|
+
SaganError,
|
|
62
|
+
ModelNotFoundError,
|
|
63
|
+
FetchError,
|
|
64
|
+
InsufficientDataError,
|
|
65
|
+
)
|
|
66
|
+
import sagan
|
|
67
|
+
|
|
68
|
+
# Catch all Sagan errors
|
|
69
|
+
try:
|
|
70
|
+
result = sagan.predict(model_id="bad_id")
|
|
71
|
+
except ModelNotFoundError as exc:
|
|
72
|
+
print(f"Model '{exc.model_id}' doesn't exist")
|
|
73
|
+
except FetchError as exc:
|
|
74
|
+
print(f"Data fetch failed for {exc.tickers}")
|
|
75
|
+
except SaganError as exc:
|
|
76
|
+
print(f"Sagan error: {exc}")
|
|
77
|
+
```
|