tycheon 0.1.0__py3-none-any.whl
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.
- tycheon/__init__.py +32 -0
- tycheon/_svg.py +55 -0
- tycheon/_vendor/kronos/LICENSE +21 -0
- tycheon/_vendor/kronos/README.md +39 -0
- tycheon/_vendor/kronos/UPSTREAM.json +12 -0
- tycheon/_vendor/kronos/model/kronos.py +662 -0
- tycheon/_vendor/kronos/model/module.py +570 -0
- tycheon/agents/README.md +33 -0
- tycheon/agents/__init__.py +7 -0
- tycheon/backtest/__init__.py +57 -0
- tycheon/backtest/costs.py +121 -0
- tycheon/backtest/factories.py +145 -0
- tycheon/backtest/guards.py +142 -0
- tycheon/backtest/metrics.py +381 -0
- tycheon/backtest/walk_forward.py +246 -0
- tycheon/calibration/__init__.py +33 -0
- tycheon/calibration/conformal.py +411 -0
- tycheon/calibration/diagnostics.py +227 -0
- tycheon/calibration/forecaster.py +110 -0
- tycheon/calibration/metrics.py +125 -0
- tycheon/calibration/plots.py +87 -0
- tycheon/calibration/scores.py +288 -0
- tycheon/covariates/__init__.py +27 -0
- tycheon/covariates/features.py +149 -0
- tycheon/covariates/residual.py +349 -0
- tycheon/covariates/store.py +164 -0
- tycheon/data/__init__.py +23 -0
- tycheon/data/actions.py +140 -0
- tycheon/data/asof.py +84 -0
- tycheon/data/providers/__init__.py +1 -0
- tycheon/data/providers/base.py +128 -0
- tycheon/data/providers/file.py +86 -0
- tycheon/data/providers/licensed.py +91 -0
- tycheon/data/providers/yfinance.py +109 -0
- tycheon/data/sample.py +194 -0
- tycheon/data/schema.py +143 -0
- tycheon/data/store.py +205 -0
- tycheon/errors.py +45 -0
- tycheon/governance/README.md +37 -0
- tycheon/governance/__init__.py +9 -0
- tycheon/models/__init__.py +23 -0
- tycheon/models/base.py +563 -0
- tycheon/models/baselines/__init__.py +20 -0
- tycheon/models/baselines/_common.py +29 -0
- tycheon/models/baselines/arima.py +68 -0
- tycheon/models/baselines/drift.py +49 -0
- tycheon/models/baselines/garch.py +80 -0
- tycheon/models/baselines/random_walk.py +48 -0
- tycheon/models/baselines/seasonal_naive.py +57 -0
- tycheon/models/chronos/__init__.py +5 -0
- tycheon/models/chronos/forecaster.py +113 -0
- tycheon/models/devices.py +37 -0
- tycheon/models/kronos/__init__.py +10 -0
- tycheon/models/kronos/forecaster.py +306 -0
- tycheon/models/kronos/sampling.py +172 -0
- tycheon/models/kronos/specs.py +83 -0
- tycheon/models/kronos/vendor.py +139 -0
- tycheon/models/kronos/windowing.py +121 -0
- tycheon/models/timesfm/__init__.py +5 -0
- tycheon/models/timesfm/forecaster.py +133 -0
- tycheon/py.typed +0 -0
- tycheon/risk/__init__.py +68 -0
- tycheon/risk/measures.py +283 -0
- tycheon/risk/plots.py +112 -0
- tycheon/risk/portfolio.py +362 -0
- tycheon/risk/report.py +556 -0
- tycheon/risk/scenarios.py +261 -0
- tycheon/routing/__init__.py +25 -0
- tycheon/routing/ensemble.py +396 -0
- tycheon/routing/regimes.py +157 -0
- tycheon/serve/__init__.py +1 -0
- tycheon-0.1.0.dist-info/METADATA +319 -0
- tycheon-0.1.0.dist-info/RECORD +76 -0
- tycheon-0.1.0.dist-info/WHEEL +4 -0
- tycheon-0.1.0.dist-info/licenses/LICENSE +202 -0
- tycheon-0.1.0.dist-info/licenses/third_party/kronos/LICENSE +21 -0
tycheon/__init__.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Tycheon — calibrated financial forecasting and risk.
|
|
2
|
+
|
|
3
|
+
Kronos forecasts the path; Tycheon tells you how much to trust it.
|
|
4
|
+
|
|
5
|
+
Tycheon is the forecasting and risk layer: conformal prediction intervals and
|
|
6
|
+
reliability diagnostics, exogenous covariates beyond OHLCV, regime-weighted
|
|
7
|
+
routing across Kronos / TimesFM / Chronos and honest baselines, translation of
|
|
8
|
+
forecasts into VaR, Expected Shortfall and drawdown probabilities, and
|
|
9
|
+
leakage-proof walk-forward evaluation.
|
|
10
|
+
|
|
11
|
+
Three invariants hold everywhere in this package:
|
|
12
|
+
|
|
13
|
+
* **Point-in-time.** Every data read takes an ``as_of`` and refuses anything
|
|
14
|
+
published after it. Leakage tests are mandatory for every data path.
|
|
15
|
+
* **Uncertainty is not optional.** Every forecast carries intervals or
|
|
16
|
+
quantiles, calibration status, the model mix, its ``as_of`` and a model card
|
|
17
|
+
reference.
|
|
18
|
+
* **Baselines are published honestly.** Every evaluation reports the
|
|
19
|
+
random-walk baseline and a Diebold-Mariano test, including when the baseline
|
|
20
|
+
wins.
|
|
21
|
+
|
|
22
|
+
For research and risk analytics. Not investment advice.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
26
|
+
|
|
27
|
+
try:
|
|
28
|
+
__version__ = version("tycheon")
|
|
29
|
+
except PackageNotFoundError: # pragma: no cover - only when run from a bare tree
|
|
30
|
+
__version__ = "0.0.0.dev0"
|
|
31
|
+
|
|
32
|
+
__all__ = ["__version__"]
|
tycheon/_svg.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""Shared helpers for the diagnostic plots: matplotlib is optional, output is inline SVG.
|
|
2
|
+
|
|
3
|
+
Plots are returned as SVG *strings* so an HTML report can embed them with no external files,
|
|
4
|
+
no scripts and no network access. Text and lines use ``currentColor`` so a figure follows the
|
|
5
|
+
page's light or dark theme.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import importlib
|
|
11
|
+
import io
|
|
12
|
+
import re
|
|
13
|
+
from typing import TYPE_CHECKING, Any
|
|
14
|
+
|
|
15
|
+
from tycheon.errors import OptionalDependencyError
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from matplotlib.figure import Figure
|
|
19
|
+
|
|
20
|
+
#: Colours chosen to read on both light and dark backgrounds.
|
|
21
|
+
BLUE = "#3b82c4"
|
|
22
|
+
ORANGE = "#e08a2c"
|
|
23
|
+
RED = "#d1495b"
|
|
24
|
+
GREEN = "#3aa17e"
|
|
25
|
+
GREY = "#8a8f98"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def require_matplotlib() -> Any:
|
|
29
|
+
"""Import ``matplotlib`` or explain which extra installs it."""
|
|
30
|
+
try:
|
|
31
|
+
return importlib.import_module("matplotlib")
|
|
32
|
+
except ImportError as exc:
|
|
33
|
+
raise OptionalDependencyError(
|
|
34
|
+
"plots need matplotlib. Install the extra: pip install 'tycheon[report]'"
|
|
35
|
+
) from exc
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def new_figure(width: float = 6.0, height: float = 3.6) -> Figure:
|
|
39
|
+
"""A figure not attached to pyplot (no global state, safe in servers and tests)."""
|
|
40
|
+
require_matplotlib()
|
|
41
|
+
from matplotlib.figure import Figure
|
|
42
|
+
|
|
43
|
+
return Figure(figsize=(width, height), layout="constrained")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def figure_to_svg(fig: Figure) -> str:
|
|
47
|
+
"""Serialise ``fig`` to an inline-able SVG string that follows the page colour scheme."""
|
|
48
|
+
buffer = io.StringIO()
|
|
49
|
+
fig.savefig(buffer, format="svg", transparent=True)
|
|
50
|
+
svg = buffer.getvalue()
|
|
51
|
+
start = svg.find("<svg")
|
|
52
|
+
body = svg[start:] if start >= 0 else svg
|
|
53
|
+
body = re.sub(r"<metadata>.*?</metadata>\s*", "", body, flags=re.DOTALL)
|
|
54
|
+
# black text and axes become the surrounding text colour (light and dark themes)
|
|
55
|
+
return body.replace("#000000", "currentColor").replace("rgb(0%, 0%, 0%)", "currentColor")
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 ShiYu
|
|
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,39 @@
|
|
|
1
|
+
# Vendored: Kronos
|
|
2
|
+
|
|
3
|
+
Upstream: <https://github.com/shiyu-coder/Kronos> at commit
|
|
4
|
+
`67b630e67f6a18c9e9be918d9b4337c960db1e9a`, MIT licensed
|
|
5
|
+
(Copyright (c) 2025 ShiYu). The licence file is retained here verbatim and ships
|
|
6
|
+
inside the wheel.
|
|
7
|
+
|
|
8
|
+
## What is here
|
|
9
|
+
|
|
10
|
+
| File | Why |
|
|
11
|
+
|---|---|
|
|
12
|
+
| `model/kronos.py` | `KronosTokenizer`, `Kronos`, the sampling helpers. |
|
|
13
|
+
| `model/module.py` | The transformer building blocks they import. |
|
|
14
|
+
| `LICENSE` | Upstream MIT licence. Must travel with the code. |
|
|
15
|
+
| `UPSTREAM.json` | Commit and SHA-256 of every file above. |
|
|
16
|
+
|
|
17
|
+
Upstream's `model/__init__.py`, predictor examples, fine-tuning pipeline and web
|
|
18
|
+
UI are deliberately **not** vendored. Tycheon does not call upstream's
|
|
19
|
+
`KronosPredictor`: its sampler averages the sample paths away, and Tycheon needs
|
|
20
|
+
them (see ADR 0002).
|
|
21
|
+
|
|
22
|
+
## Rules
|
|
23
|
+
|
|
24
|
+
1. **Do not edit these files.** `tests/test_vendored_kronos.py` hashes them
|
|
25
|
+
against `UPSTREAM.json` and fails on any difference, so an accidental edit,
|
|
26
|
+
an editor reformat or a line-ending change cannot slip in.
|
|
27
|
+
2. Everything Tycheon adds lives in `src/tycheon/models/kronos/`, never here.
|
|
28
|
+
3. To update, vendor the new upstream commit in a PR of its own, regenerate
|
|
29
|
+
`UPSTREAM.json`, and re-run the slow Kronos tests. Read upstream's diff
|
|
30
|
+
first: a changed sampler or normalisation is a changed model.
|
|
31
|
+
4. Excluded from ruff, mypy and every pre-commit hook, because reformatting
|
|
32
|
+
vendored code makes it impossible to diff against upstream.
|
|
33
|
+
|
|
34
|
+
## How it is imported
|
|
35
|
+
|
|
36
|
+
Upstream does `from model.module import *` behind a `sys.path.append("../")`.
|
|
37
|
+
Putting a top-level package called `model` on `sys.path` would shadow anything
|
|
38
|
+
else with that name, so `tycheon.models.kronos.vendor` loads the two files by
|
|
39
|
+
path and resolves that one import itself, then removes every trace of it.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"repository": "https://github.com/shiyu-coder/Kronos",
|
|
3
|
+
"commit": "67b630e67f6a18c9e9be918d9b4337c960db1e9a",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"copyright": "Copyright (c) 2025 ShiYu",
|
|
6
|
+
"note": "Byte-identical copies. Do not edit; see third_party/kronos/README.md.",
|
|
7
|
+
"files": {
|
|
8
|
+
"LICENSE": "acb2d194d378204e5f2be4dcd24d39ecac437903620c790c3315a96dab388fdc",
|
|
9
|
+
"model/kronos.py": "0a5f90282e2039c2de0771473419715c845def154896dbd0f5747837e6241032",
|
|
10
|
+
"model/module.py": "a4df669998fa8115ac219b06687abaff2fac0fce9da762007dd142038949eee5"
|
|
11
|
+
}
|
|
12
|
+
}
|