mlquantx 0.2.6__tar.gz → 0.3.1__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.
- {mlquantx-0.2.6/src/mlquantx.egg-info → mlquantx-0.3.1}/PKG-INFO +6 -3
- {mlquantx-0.2.6 → mlquantx-0.3.1}/PYPI_README.md +5 -2
- mlquantx-0.3.1/README.md +208 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/pyproject.toml +2 -1
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/__init__.py +1 -1
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/cli/main.py +57 -2
- mlquantx-0.3.1/src/mlquant/systemone.py +355 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1/src/mlquantx.egg-info}/PKG-INFO +6 -3
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquantx.egg-info/SOURCES.txt +3 -0
- mlquantx-0.3.1/tests/test_benchmark_tensor_factors.py +61 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/tests/test_cli.py +8 -5
- {mlquantx-0.2.6 → mlquantx-0.3.1}/tests/test_public_data_validation.py +7 -0
- mlquantx-0.3.1/tests/test_systemone.py +201 -0
- mlquantx-0.3.1/tests/test_technical_pipeline_audit.py +34 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/tests/test_tensor_factors.py +64 -1
- mlquantx-0.2.6/README.md +0 -526
- mlquantx-0.2.6/tests/test_benchmark_tensor_factors.py +0 -15
- {mlquantx-0.2.6 → mlquantx-0.3.1}/LICENSE +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/NOTICE.md +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/setup.cfg +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/backtest/__init__.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/backtest/engine.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/backtest/metrics.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/cli/__init__.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/configs/__init__.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/configs/small.yaml +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/data/__init__.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/data/akshare_loader.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/data/baostock_loader.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/data/loaders.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/data/panel.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/data/synthetic.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/data/yfinance_loader.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/features/__init__.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/features/_factors_add.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/features/_factors_alpha101.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/features/_factors_best.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/features/_factors_better.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/features/_factors_change.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/features/_factors_extra.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/features/_factors_market.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/features/_factors_old.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/features/_factors_original.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/features/_factors_stock.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/features/alpha101.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/features/bias.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/features/legacy_factors.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/features/market_breadth.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/features/neutralize.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/features/target.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/features/tensor_factors.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/features.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/models/__init__.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/models/losses.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/models/nets.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/portfolio/__init__.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/portfolio/frontier.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/portfolio/markowitz.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/training/__init__.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/training/augment.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/training/dataset.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/training/trainer.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/utils/__init__.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/utils/config.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquant/utils/seed.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquantx.egg-info/dependency_links.txt +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquantx.egg-info/entry_points.txt +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquantx.egg-info/requires.txt +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/src/mlquantx.egg-info/top_level.txt +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/tests/test_aggregate_validation_reports.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/tests/test_akshare.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/tests/test_akshare_csi300_full_pipeline.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/tests/test_alpha101.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/tests/test_audit_validation_report.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/tests/test_augment.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/tests/test_baostock.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/tests/test_bias.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/tests/test_cost_drag_units.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/tests/test_export_huggingface_artifacts.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/tests/test_losses.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/tests/test_markowitz.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/tests/test_metrics.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/tests/test_neutralize.py +0 -0
- {mlquantx-0.2.6 → mlquantx-0.3.1}/tests/test_synthetic.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mlquantx
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Reference implementation of ‘ML-Enhanced Multi-Factor Quantitative Trading’ (arXiv:2507.07107).
|
|
5
5
|
Author: Yimin Du
|
|
6
6
|
License-Expression: MIT
|
|
@@ -56,8 +56,8 @@ Dynamic: license-file
|
|
|
56
56
|
# mlquant
|
|
57
57
|
|
|
58
58
|
**A reproducible PyTorch research stack for machine-learning multi-factor
|
|
59
|
-
trading: 213 factors, bias correction, portfolio optimization,
|
|
60
|
-
backtesting.**
|
|
59
|
+
trading: 213 factors, bias correction, portfolio optimization, vectorized
|
|
60
|
+
backtesting, and System-One-style portfolio decisions.**
|
|
61
61
|
|
|
62
62
|
[](https://github.com/initial-d/ml-quant-trading/actions/workflows/ci.yml)
|
|
63
63
|
[](https://arxiv.org/abs/2507.07107)
|
|
@@ -102,12 +102,15 @@ If the demo saves you setup time, consider
|
|
|
102
102
|
- vectorized backtesting with turnover and transaction costs
|
|
103
103
|
- AkShare, Baostock, yfinance, and deterministic synthetic data paths
|
|
104
104
|
- auditable public-data validation reports, including negative results
|
|
105
|
+
- `mlquant systemone decide` for typed portfolio-intent decisions from
|
|
106
|
+
structured research state
|
|
105
107
|
|
|
106
108
|
## Start here
|
|
107
109
|
|
|
108
110
|
- [Source and full documentation](https://github.com/initial-d/ml-quant-trading)
|
|
109
111
|
- [Google Colab quick start](https://colab.research.google.com/github/initial-d/ml-quant-trading/blob/main/notebooks/quickstart_colab.ipynb)
|
|
110
112
|
- [Public validation dashboard](https://github.com/initial-d/ml-quant-trading/blob/main/docs/validation_dashboard.md)
|
|
113
|
+
- [System-One-compatible portfolio decisions](https://github.com/initial-d/ml-quant-trading/blob/main/docs/systemone_adapter.md)
|
|
111
114
|
- [Research card and limitations](https://github.com/initial-d/ml-quant-trading/blob/main/docs/research_card.md)
|
|
112
115
|
- [100,000-row synthetic dataset](https://huggingface.co/datasets/dddyym/ml-quant-trading-synthetic)
|
|
113
116
|
- [213-input MLP checkpoint](https://huggingface.co/dddyym/ml-quant-trading-synthetic-mlp)
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# mlquant
|
|
2
2
|
|
|
3
3
|
**A reproducible PyTorch research stack for machine-learning multi-factor
|
|
4
|
-
trading: 213 factors, bias correction, portfolio optimization,
|
|
5
|
-
backtesting.**
|
|
4
|
+
trading: 213 factors, bias correction, portfolio optimization, vectorized
|
|
5
|
+
backtesting, and System-One-style portfolio decisions.**
|
|
6
6
|
|
|
7
7
|
[](https://github.com/initial-d/ml-quant-trading/actions/workflows/ci.yml)
|
|
8
8
|
[](https://arxiv.org/abs/2507.07107)
|
|
@@ -47,12 +47,15 @@ If the demo saves you setup time, consider
|
|
|
47
47
|
- vectorized backtesting with turnover and transaction costs
|
|
48
48
|
- AkShare, Baostock, yfinance, and deterministic synthetic data paths
|
|
49
49
|
- auditable public-data validation reports, including negative results
|
|
50
|
+
- `mlquant systemone decide` for typed portfolio-intent decisions from
|
|
51
|
+
structured research state
|
|
50
52
|
|
|
51
53
|
## Start here
|
|
52
54
|
|
|
53
55
|
- [Source and full documentation](https://github.com/initial-d/ml-quant-trading)
|
|
54
56
|
- [Google Colab quick start](https://colab.research.google.com/github/initial-d/ml-quant-trading/blob/main/notebooks/quickstart_colab.ipynb)
|
|
55
57
|
- [Public validation dashboard](https://github.com/initial-d/ml-quant-trading/blob/main/docs/validation_dashboard.md)
|
|
58
|
+
- [System-One-compatible portfolio decisions](https://github.com/initial-d/ml-quant-trading/blob/main/docs/systemone_adapter.md)
|
|
56
59
|
- [Research card and limitations](https://github.com/initial-d/ml-quant-trading/blob/main/docs/research_card.md)
|
|
57
60
|
- [100,000-row synthetic dataset](https://huggingface.co/datasets/dddyym/ml-quant-trading-synthetic)
|
|
58
61
|
- [213-input MLP checkpoint](https://huggingface.co/dddyym/ml-quant-trading-synthetic-mlp)
|
mlquantx-0.3.1/README.md
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# ml-quant-trading
|
|
2
|
+
|
|
3
|
+
**A reproducible PyTorch research stack for cross-sectional factor research:
|
|
4
|
+
213 mask-aware factors, public-data validation, cost-aware backtests, and
|
|
5
|
+
System-One-style portfolio decisions.**
|
|
6
|
+
|
|
7
|
+
[](https://github.com/initial-d/ml-quant-trading/actions/workflows/ci.yml)
|
|
8
|
+
[](https://github.com/initial-d/ml-quant-trading/stargazers)
|
|
9
|
+
[](https://github.com/initial-d/ml-quant-trading/releases)
|
|
10
|
+
[](https://pypi.org/project/mlquantx/)
|
|
11
|
+
[](https://arxiv.org/abs/2507.07107)
|
|
12
|
+
[](https://www.python.org/downloads/)
|
|
13
|
+
[](LICENSE)
|
|
14
|
+
|
|
15
|
+
Languages: [English](README.md) | [简体中文](README.zh-CN.md) | [繁體中文](README.zh-TW.md)
|
|
16
|
+
|
|
17
|
+
[Run in Colab](https://colab.research.google.com/github/initial-d/ml-quant-trading/blob/main/notebooks/quickstart_colab.ipynb)
|
|
18
|
+
| [System-One Portfolio Decisions](docs/systemone_adapter.md)
|
|
19
|
+
| [Validation Dashboard](docs/validation_dashboard.md)
|
|
20
|
+
| [Project Facts](docs/answer_index.md)
|
|
21
|
+
| [Citation Guide](docs/citation_conversion.md)
|
|
22
|
+
| [Research Card](docs/research_card.md)
|
|
23
|
+
|
|
24
|
+
## What This Is
|
|
25
|
+
|
|
26
|
+
`ml-quant-trading` is a research baseline, not a live trading system. It gives
|
|
27
|
+
students, researchers, engineers, and agent harnesses a concrete way to run and
|
|
28
|
+
inspect a full factor-to-backtest workflow:
|
|
29
|
+
|
|
30
|
+
```text
|
|
31
|
+
data -> masks -> 213 factors -> model scores -> portfolio weights -> cost-aware backtest
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The paper-specific contribution is the mask-first factor-computation protocol:
|
|
35
|
+
non-tradable limit-move prices should be masked before rolling-window factors,
|
|
36
|
+
not only filtered later at the portfolio layer.
|
|
37
|
+
|
|
38
|
+
New in the current direction is a System-One-compatible portfolio decision
|
|
39
|
+
adapter. It wraps pipeline state as typed asset decisions in a Jev-style shape:
|
|
40
|
+
|
|
41
|
+
```text
|
|
42
|
+
portfolio state + typed questions -> typed portfolio-intent answers
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
It answers research questions such as `asset_action`, `target_weight`,
|
|
46
|
+
`trade_allowed`, `risk_bucket`, and `max_participation_rate`. It does not create
|
|
47
|
+
broker orders, connect to accounts, or run live execution.
|
|
48
|
+
|
|
49
|
+
## Quick Start
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
python -m pip install mlquantx
|
|
53
|
+
mlquant demo
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The demo needs no market-data account or API key. It runs a deterministic
|
|
57
|
+
synthetic pipeline and writes shareable Markdown and JSON reports under
|
|
58
|
+
`artifacts/small/`.
|
|
59
|
+
|
|
60
|
+
For development:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
git clone https://github.com/initial-d/ml-quant-trading.git
|
|
64
|
+
cd ml-quant-trading
|
|
65
|
+
python -m pip install -e '.[dev]'
|
|
66
|
+
python -m pytest
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## System-One Portfolio Decisions
|
|
70
|
+
|
|
71
|
+
The decision adapter is the project's first step toward a quant-specific
|
|
72
|
+
System One model surface. The analogy to Jev is the interface style: a structured
|
|
73
|
+
state plus typed questions returns typed answers. This repository does not claim
|
|
74
|
+
official Jev certification or calibrated probabilities.
|
|
75
|
+
|
|
76
|
+
Example state:
|
|
77
|
+
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"as_of": "2024-12-31",
|
|
81
|
+
"universe": ["600519", "000001"],
|
|
82
|
+
"predictions": {
|
|
83
|
+
"score": {"600519": 0.018, "000001": -0.006},
|
|
84
|
+
"rank": {"600519": 0.91, "000001": 0.23}
|
|
85
|
+
},
|
|
86
|
+
"tradability": {
|
|
87
|
+
"600519": {"tradable": true, "halted": false, "limit_up": false, "limit_down": false}
|
|
88
|
+
},
|
|
89
|
+
"liquidity": {
|
|
90
|
+
"600519": {"amount": 1523000000, "adv20": 1340000000}
|
|
91
|
+
},
|
|
92
|
+
"portfolio": {
|
|
93
|
+
"current_weight": {"600519": 0.02},
|
|
94
|
+
"target_weight_baseline": {"600519": 0.04}
|
|
95
|
+
},
|
|
96
|
+
"risk": {
|
|
97
|
+
"asset_volatility_20d": {"600519": 0.021},
|
|
98
|
+
"max_position_weight": 0.05
|
|
99
|
+
},
|
|
100
|
+
"cost_model": {
|
|
101
|
+
"effective_cost_bps": 7,
|
|
102
|
+
"max_participation_rate": 0.1
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Run typed decisions:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
mlquant systemone decide \
|
|
111
|
+
--state artifacts/systemone/decision_state.json \
|
|
112
|
+
--output artifacts/systemone/portfolio_decision.json
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Default questions expand over every asset in `universe`. A custom question file
|
|
116
|
+
can ask only for selected assets or fields. See
|
|
117
|
+
[docs/systemone_adapter.md](docs/systemone_adapter.md).
|
|
118
|
+
|
|
119
|
+
## Why It Matters
|
|
120
|
+
|
|
121
|
+
| Capability | Why it matters |
|
|
122
|
+
|---|---|
|
|
123
|
+
| 213 factor dimensions | A broad mask-aware factor surface for cross-sectional research |
|
|
124
|
+
| Mask-first pipeline | Avoids upstream contamination from non-tradable limit-move observations |
|
|
125
|
+
| Public and synthetic data paths | Start without private data, then test AkShare, Baostock, or yfinance |
|
|
126
|
+
| Cost-aware validation | Keeps turnover, costs, drawdown, baselines, and caveats close to results |
|
|
127
|
+
| Typed decision adapter | Exposes portfolio intent as a callable System-One/Jev-style interface |
|
|
128
|
+
| Auditable reports | Preserves commands, environment, data source, assumptions, and failures |
|
|
129
|
+
|
|
130
|
+
## Public Validation Snapshot
|
|
131
|
+
|
|
132
|
+
Latest maintained public-data snapshot:
|
|
133
|
+
[AkShare CSI 300 Daily 213-Factor Validation](docs/validation_dashboard.md).
|
|
134
|
+
|
|
135
|
+
| Strategy | Annual return | Sharpe | Turnover | Final equity | Note |
|
|
136
|
+
|---|---:|---:|---:|---:|---|
|
|
137
|
+
| `equal_weight_daily` | 17.75% | 0.882 | 0.0010 | 1.8744 | Public-data baseline |
|
|
138
|
+
| `factor_mean_daily` | 15.80% | 0.701 | 0.3627 | 1.7579 | Gross edge, high turnover |
|
|
139
|
+
| `factor_mean_buffered_daily` | 22.20% | 0.919 | 0.1397 | 2.1616 | Buffered daily factor rule |
|
|
140
|
+
|
|
141
|
+
This is a public-data approximation using current CSI 300 constituents, not an
|
|
142
|
+
exact paper reproduction or investment claim. The useful point is framework
|
|
143
|
+
level: factor scores need tradability, turnover, and cost-aware portfolio
|
|
144
|
+
construction before backtests are interpreted.
|
|
145
|
+
|
|
146
|
+
## Core Modules
|
|
147
|
+
|
|
148
|
+
| Module | Role |
|
|
149
|
+
|---|---|
|
|
150
|
+
| `mlquant.data` | Synthetic, yfinance, Baostock, and AkShare panel loaders |
|
|
151
|
+
| `mlquant.features` | Mask-aware tensor primitives, Alpha101 subset, and 204 legacy factors |
|
|
152
|
+
| `mlquant.training` | Factor dataset, augmentation, and trainer |
|
|
153
|
+
| `mlquant.models` | MLP, Transformer, AdjMSE, IC, and RankIC losses |
|
|
154
|
+
| `mlquant.portfolio` | Long-only Markowitz-style portfolio construction |
|
|
155
|
+
| `mlquant.backtest` | Vectorized backtest and metrics |
|
|
156
|
+
| `mlquant.systemone` | Typed portfolio-intent decisions from structured state |
|
|
157
|
+
|
|
158
|
+
## Common Paths
|
|
159
|
+
|
|
160
|
+
| Goal | Start here |
|
|
161
|
+
|---|---|
|
|
162
|
+
| Run the zero-account demo | `mlquant demo` |
|
|
163
|
+
| Try public data | [Public-Data Validation](docs/public_data_validation.md) |
|
|
164
|
+
| Inspect maintained results | [Validation Dashboard](docs/validation_dashboard.md) |
|
|
165
|
+
| Use typed portfolio decisions | [System-One Adapter](docs/systemone_adapter.md) |
|
|
166
|
+
| Cite the project | [Citation Conversion Guide](docs/citation_conversion.md) |
|
|
167
|
+
| Understand boundaries | [Research Card](docs/research_card.md) and [Reality Check](docs/reality_check.md) |
|
|
168
|
+
| Benchmark tensor factors | [Benchmarking Guide](docs/benchmarking.md) |
|
|
169
|
+
| Evaluate an agent | [Agent Quant Benchmark Challenge](docs/agent_quant_benchmark_challenge.md) |
|
|
170
|
+
|
|
171
|
+
## Data Sources
|
|
172
|
+
|
|
173
|
+
| Source | Market | Access | Notes |
|
|
174
|
+
|---|---|---|---|
|
|
175
|
+
| Synthetic | N/A | Zero-config | Deterministic smoke tests and CI |
|
|
176
|
+
| AkShare | A-shares | Public, no API key | Useful public A-share path, endpoints may change |
|
|
177
|
+
| Baostock | A-shares | Free registration | Account-backed public data route |
|
|
178
|
+
| yfinance | US equities / ETFs | Public, rate-limited | Convenient validation and notebook examples |
|
|
179
|
+
|
|
180
|
+
The repository does not redistribute market data.
|
|
181
|
+
|
|
182
|
+
## Citation
|
|
183
|
+
|
|
184
|
+
If you write about A-share factor pipelines, cite the mask-first treatment of
|
|
185
|
+
non-tradable limit-move observations and rolling-window contamination:
|
|
186
|
+
|
|
187
|
+
```bibtex
|
|
188
|
+
@article{du2025mlquant,
|
|
189
|
+
title = {Machine Learning Enhanced Multi-Factor Quantitative Trading:
|
|
190
|
+
A Cross-Sectional Portfolio Optimization Approach with Bias Correction},
|
|
191
|
+
author = {Du, Yimin},
|
|
192
|
+
journal= {arXiv preprint arXiv:2507.07107},
|
|
193
|
+
year = {2025},
|
|
194
|
+
doi = {10.48550/arXiv.2507.07107},
|
|
195
|
+
url = {https://arxiv.org/abs/2507.07107}
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## Boundary
|
|
200
|
+
|
|
201
|
+
This project is for research and engineering experimentation. It is not
|
|
202
|
+
financial advice, not investment advice, not a broker-connected system, and not
|
|
203
|
+
a claim of live deployable alpha. Synthetic demos, public-data validations, and
|
|
204
|
+
typed portfolio decisions are research artifacts.
|
|
205
|
+
|
|
206
|
+
## License
|
|
207
|
+
|
|
208
|
+
MIT. See [LICENSE](LICENSE).
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "mlquantx"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.1"
|
|
8
8
|
description = "Reference implementation of ‘ML-Enhanced Multi-Factor Quantitative Trading’ (arXiv:2507.07107)."
|
|
9
9
|
readme = "PYPI_README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -72,6 +72,7 @@ where = ["src"]
|
|
|
72
72
|
|
|
73
73
|
[tool.pytest.ini_options]
|
|
74
74
|
testpaths = ["tests"]
|
|
75
|
+
pythonpath = ["src"]
|
|
75
76
|
addopts = "-ra -q --strict-markers"
|
|
76
77
|
filterwarnings = [
|
|
77
78
|
"ignore::DeprecationWarning",
|
|
@@ -24,6 +24,9 @@ from ..features.bias import limit_move_mask
|
|
|
24
24
|
from ..models.losses import AdjMSELoss
|
|
25
25
|
from ..models.nets import MLPRegressor
|
|
26
26
|
from ..portfolio.markowitz import MarkowitzConfig, MarkowitzOptimizer
|
|
27
|
+
from ..systemone import decide as systemone_decide
|
|
28
|
+
from ..systemone import load_questions as load_systemone_questions
|
|
29
|
+
from ..systemone import load_state as load_systemone_state
|
|
27
30
|
from ..training.dataset import FactorDataset
|
|
28
31
|
from ..training.trainer import TrainConfig, Trainer
|
|
29
32
|
from ..utils.config import load_config
|
|
@@ -67,7 +70,10 @@ def _write_backtest_summary(
|
|
|
67
70
|
),
|
|
68
71
|
}
|
|
69
72
|
json_path = output_dir / "summary.json"
|
|
70
|
-
json_path.write_text(
|
|
73
|
+
json_path.write_text(
|
|
74
|
+
json.dumps(payload, indent=2, sort_keys=True) + "\n",
|
|
75
|
+
encoding="utf-8",
|
|
76
|
+
)
|
|
71
77
|
|
|
72
78
|
rows = []
|
|
73
79
|
for key, value in clean_metrics.items():
|
|
@@ -102,7 +108,7 @@ def _write_backtest_summary(
|
|
|
102
108
|
]
|
|
103
109
|
)
|
|
104
110
|
markdown_path = output_dir / "summary.md"
|
|
105
|
-
markdown_path.write_text(markdown)
|
|
111
|
+
markdown_path.write_text(markdown, encoding="utf-8")
|
|
106
112
|
return markdown_path, json_path
|
|
107
113
|
|
|
108
114
|
|
|
@@ -301,6 +307,55 @@ def cmd_backtest(config_path: str) -> None:
|
|
|
301
307
|
click.echo(f"\nShareable reports: {markdown_path} {json_path}")
|
|
302
308
|
|
|
303
309
|
|
|
310
|
+
@cli.group("systemone")
|
|
311
|
+
def cmd_systemone() -> None:
|
|
312
|
+
"""Typed decision adapter for research evidence artifacts."""
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
@cmd_systemone.command("decide")
|
|
316
|
+
@click.option(
|
|
317
|
+
"--state",
|
|
318
|
+
"state_path",
|
|
319
|
+
required=True,
|
|
320
|
+
type=click.Path(exists=True, path_type=Path),
|
|
321
|
+
help="Path to a validation summary.json or compatible state JSON.",
|
|
322
|
+
)
|
|
323
|
+
@click.option(
|
|
324
|
+
"--questions",
|
|
325
|
+
"questions_path",
|
|
326
|
+
default=None,
|
|
327
|
+
type=click.Path(exists=True, path_type=Path),
|
|
328
|
+
help="Optional JSON/YAML file with typed question definitions.",
|
|
329
|
+
)
|
|
330
|
+
@click.option(
|
|
331
|
+
"--output",
|
|
332
|
+
"output_path",
|
|
333
|
+
default=None,
|
|
334
|
+
type=click.Path(path_type=Path),
|
|
335
|
+
help="Optional path for the typed decision JSON.",
|
|
336
|
+
)
|
|
337
|
+
def cmd_systemone_decide(
|
|
338
|
+
state_path: Path,
|
|
339
|
+
questions_path: Path | None,
|
|
340
|
+
output_path: Path | None,
|
|
341
|
+
) -> None:
|
|
342
|
+
"""Convert a research report into System-One-style typed decisions."""
|
|
343
|
+
state = load_systemone_state(state_path)
|
|
344
|
+
questions = (
|
|
345
|
+
load_systemone_questions(questions_path)
|
|
346
|
+
if questions_path is not None
|
|
347
|
+
else None
|
|
348
|
+
)
|
|
349
|
+
payload = systemone_decide(state, questions=questions, source_path=state_path)
|
|
350
|
+
text = json.dumps(payload, indent=2, sort_keys=True) + "\n"
|
|
351
|
+
if output_path is not None:
|
|
352
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
353
|
+
output_path.write_text(text, encoding="utf-8")
|
|
354
|
+
click.echo(f"wrote {output_path}")
|
|
355
|
+
else:
|
|
356
|
+
click.echo(text, nl=False)
|
|
357
|
+
|
|
358
|
+
|
|
304
359
|
def main() -> None:
|
|
305
360
|
cli()
|
|
306
361
|
|