qlib-sync 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.
- qlib_sync-0.1.0/.gitignore +10 -0
- qlib_sync-0.1.0/LICENSE +21 -0
- qlib_sync-0.1.0/PKG-INFO +219 -0
- qlib_sync-0.1.0/README.md +190 -0
- qlib_sync-0.1.0/README.zh-CN.md +156 -0
- qlib_sync-0.1.0/docs/scheduling.md +81 -0
- qlib_sync-0.1.0/mcpb/.mcpbignore +6 -0
- qlib_sync-0.1.0/mcpb/manifest.json +60 -0
- qlib_sync-0.1.0/mcpb/pyproject.toml +6 -0
- qlib_sync-0.1.0/mcpb/src/server.py +6 -0
- qlib_sync-0.1.0/pyproject.toml +76 -0
- qlib_sync-0.1.0/server.json +33 -0
- qlib_sync-0.1.0/skills/qlib-sync/SKILL.md +78 -0
- qlib_sync-0.1.0/src/qlib_sync/__init__.py +13 -0
- qlib_sync-0.1.0/src/qlib_sync/api.py +67 -0
- qlib_sync-0.1.0/src/qlib_sync/cli.py +81 -0
- qlib_sync-0.1.0/src/qlib_sync/cn/__init__.py +1 -0
- qlib_sync-0.1.0/src/qlib_sync/cn/market.py +381 -0
- qlib_sync-0.1.0/src/qlib_sync/cn/update.py +609 -0
- qlib_sync-0.1.0/src/qlib_sync/mcp_server.py +249 -0
- qlib_sync-0.1.0/src/qlib_sync/txn.py +71 -0
- qlib_sync-0.1.0/tests/test_api.py +35 -0
- qlib_sync-0.1.0/tests/test_cli.py +25 -0
- qlib_sync-0.1.0/tests/test_cn_market.py +544 -0
- qlib_sync-0.1.0/tests/test_mcp_server.py +144 -0
- qlib_sync-0.1.0/tests/test_release_metadata.py +44 -0
- qlib_sync-0.1.0/tests/test_txn.py +91 -0
- qlib_sync-0.1.0/tools/demo/README.md +25 -0
qlib_sync-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 randyy179
|
|
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.
|
qlib_sync-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: qlib-sync
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Safely install and update a local Qlib China A-share dataset, with an MCP server for AI assistants.
|
|
5
|
+
Project-URL: Homepage, https://github.com/randyy179/qlib-sync
|
|
6
|
+
Project-URL: Issues, https://github.com/randyy179/qlib-sync/issues
|
|
7
|
+
Project-URL: Changelog, https://github.com/randyy179/qlib-sync/releases
|
|
8
|
+
Author: randyy179
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: a-share,china,market-data,mcp,qlib,quant,stock
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: MacOS
|
|
17
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
23
|
+
Requires-Python: <3.13,>=3.10
|
|
24
|
+
Requires-Dist: mcp<3,>=2.3
|
|
25
|
+
Requires-Dist: pyqlib>=0.9.6
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
# qlib-sync
|
|
31
|
+
|
|
32
|
+
[](https://github.com/randyy179/qlib-sync/actions/workflows/ci.yml)
|
|
33
|
+
[](https://pypi.org/project/qlib-sync/)
|
|
34
|
+
[](https://github.com/randyy179/qlib-sync/blob/main/LICENSE)
|
|
35
|
+
|
|
36
|
+
[中文说明](https://github.com/randyy179/qlib-sync/blob/main/README.zh-CN.md)
|
|
37
|
+
|
|
38
|
+
**Website:** [randyy179.github.io/qlib-sync](https://randyy179.github.io/qlib-sync/)
|
|
39
|
+
|
|
40
|
+
<!-- mcp-name: io.github.randyy179/qlib-sync -->
|
|
41
|
+
|
|
42
|
+
**One command to install and keep current a local [Qlib](https://github.com/microsoft/qlib) China A-share dataset, and an MCP server so AI assistants can read it.**
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install qlib-sync
|
|
46
|
+
qlib-sync cn update
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Or without installing anything first: `uvx qlib-sync cn update`.
|
|
50
|
+
|
|
51
|
+

|
|
52
|
+
|
|
53
|
+
That installs the daily community release from
|
|
54
|
+
[chenditc/investment_data](https://github.com/chenditc/investment_data) into
|
|
55
|
+
`~/.qlib/qlib_data/cn_data`, the location Qlib reads by default. Run the same command again
|
|
56
|
+
any time; when the data is already current it finishes in about a second.
|
|
57
|
+
|
|
58
|
+
## Why not just `wget` and `tar`?
|
|
59
|
+
|
|
60
|
+
<img src="https://raw.githubusercontent.com/randyy179/qlib-sync/main/docs/assets/comic.jpg" width="560" alt="Four-panel comic: a download dies at 99% at night; the next day 550 MB arrive and nothing changed; the qlib-sync robot checks the data and stamps it verified, keeping the old copy safe; the researcher sips tea and asks an AI for Moutai's recent closes">
|
|
61
|
+
|
|
62
|
+
Qlib's README points A-share users to the community release with a `wget` and `tar` one-liner.
|
|
63
|
+
That works until it doesn't:
|
|
64
|
+
|
|
65
|
+
- **An interrupted or truncated download** extracts into a half-written dataset, or fails
|
|
66
|
+
after the old one has already been overwritten.
|
|
67
|
+
- **Upstream republishes releases.** In November 2026 a data error was found and corrected
|
|
68
|
+
([investment_data#163](https://github.com/chenditc/investment_data/issues/163)) and releases
|
|
69
|
+
were republished under the same date. A date check alone never sees the fix.
|
|
70
|
+
- **Every check downloads 550 MB**, even when nothing changed.
|
|
71
|
+
|
|
72
|
+
The investment_data README itself describes a careful manual process: download the release
|
|
73
|
+
manifest, check the archive with its `validate_archive.py`, then extract. qlib-sync runs the
|
|
74
|
+
same checks automatically on every update and adds what a manual process cannot: it skips the
|
|
75
|
+
download when nothing changed, extracts beside the live data and swaps it in with rollback
|
|
76
|
+
(rather than extracting on top of the existing folder), and picks up republished releases.
|
|
77
|
+
|
|
78
|
+
qlib-sync treats the dataset like a production system:
|
|
79
|
+
|
|
80
|
+
<picture>
|
|
81
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/randyy179/qlib-sync/main/docs/assets/update-flow-dark.svg">
|
|
82
|
+
<img alt="Update flow: check the manifest, download, verify, stage, swap; any failure puts the previous dataset back" src="https://raw.githubusercontent.com/randyy179/qlib-sync/main/docs/assets/update-flow-light.svg">
|
|
83
|
+
</picture>
|
|
84
|
+
|
|
85
|
+
| Step | What happens |
|
|
86
|
+
|---|---|
|
|
87
|
+
| Check | Reads the release's 500-byte manifest. Already current: done, nothing downloaded. |
|
|
88
|
+
| Download | Resumes interrupted downloads; shows progress; optional mirror for slow links to GitHub. |
|
|
89
|
+
| Verify | Size and sha256 from the manifest; the same release checks as upstream's `validate_archive.py` (every index pool and the future calendar reach the manifest's dates, release marked publishable); archive paths and links are checked before extraction. |
|
|
90
|
+
| Stage | Extracts next to the active dataset; refuses downgrades. |
|
|
91
|
+
| Swap | Renames the new dataset into place, then runs a real Qlib read. |
|
|
92
|
+
| Roll back | Any failure after the swap moves the previous dataset back. |
|
|
93
|
+
| Report | New trading days, newly listed and delisted symbols. |
|
|
94
|
+
|
|
95
|
+
The checks catch broken, truncated, or tampered packages. They cannot catch wrong values inside a
|
|
96
|
+
correctly published release (like the one in #163); for that, keep a rollback copy with
|
|
97
|
+
`--keep-backup`.
|
|
98
|
+
|
|
99
|
+
## Commands
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
qlib-sync status # every local Qlib dataset at a glance
|
|
103
|
+
qlib-sync cn status # local date, pools, and whether a newer release exists
|
|
104
|
+
qlib-sync cn update # install or update (add --json for machine-readable output)
|
|
105
|
+
qlib-sync cn health-check # structure checks plus a real Qlib read
|
|
106
|
+
qlib-sync cn restore --list # rollback backups; restore --yes switches back
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Useful options for `cn update`:
|
|
110
|
+
|
|
111
|
+
| Option | Effect |
|
|
112
|
+
|---|---|
|
|
113
|
+
| `--data-dir PATH` | Install somewhere other than `~/.qlib/qlib_data/cn_data` |
|
|
114
|
+
| `--mirror URL` | Download through a prefix-style GitHub proxy such as `https://ghfast.top` (or set `QLIB_SYNC_MIRROR`) |
|
|
115
|
+
| `--keep-backup` | Keep the previous dataset for one rollback |
|
|
116
|
+
| `--protect FILE` | Carry a custom stock pool in `instruments/` across updates (repeatable) |
|
|
117
|
+
| `--force` | Reinstall even when the dates match |
|
|
118
|
+
|
|
119
|
+
**The update replaces the whole `cn_data` folder.** Anything you added there is lost unless you
|
|
120
|
+
pass it with `--protect`.
|
|
121
|
+
|
|
122
|
+
### Mirrors
|
|
123
|
+
|
|
124
|
+
From mainland China, GitHub downloads can be slow or fail. Pass a mirror and qlib-sync downloads
|
|
125
|
+
the package through it while still reading the manifest from GitHub directly when it can, so the
|
|
126
|
+
checksum does not depend on the mirror. Mirrors are third-party services; qlib-sync does not
|
|
127
|
+
endorse any of them.
|
|
128
|
+
|
|
129
|
+
## Python
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
from qlib_sync import update_cn, status_cn, health_check_cn
|
|
133
|
+
|
|
134
|
+
result = update_cn() # raises qlib_sync.UpdateError on failure; data unchanged
|
|
135
|
+
print("\n".join(result.summary_lines()))
|
|
136
|
+
print(result.new_trading_days, result.added_symbols)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Use it from your AI assistant
|
|
140
|
+
|
|
141
|
+
qlib-sync includes an [MCP](https://modelcontextprotocol.io) server, the open standard most AI
|
|
142
|
+
tools use to call local tools. Any MCP client that can start a local command works, whichever
|
|
143
|
+
model it runs: Claude, GPT, Gemini, DeepSeek, Qwen, Kimi, GLM, or a local model. The server
|
|
144
|
+
runs on your machine and reads the dataset there; there is no service to host and nothing
|
|
145
|
+
leaves your computer. It is listed in the [MCP Registry](https://registry.modelcontextprotocol.io)
|
|
146
|
+
as `io.github.randyy179/qlib-sync`.
|
|
147
|
+
|
|
148
|
+
Every client needs the same two things: the command `uvx` and the arguments `qlib-sync mcp`.
|
|
149
|
+
|
|
150
|
+
| Client | How to add qlib-sync |
|
|
151
|
+
|---|---|
|
|
152
|
+
| Claude Desktop | Download `qlib-sync.mcpb` from the [latest release](https://github.com/randyy179/qlib-sync/releases/latest) and open it |
|
|
153
|
+
| Claude Code | `claude mcp add qlib-sync -- uvx qlib-sync mcp` |
|
|
154
|
+
| OpenAI Codex CLI | `codex mcp add qlib-sync -- uvx qlib-sync mcp` |
|
|
155
|
+
| Cursor | The JSON below, in `~/.cursor/mcp.json` |
|
|
156
|
+
| Gemini CLI | The JSON below, in `~/.gemini/settings.json` |
|
|
157
|
+
| Qwen Code | The JSON below, in `~/.qwen/settings.json` |
|
|
158
|
+
| Tencent CodeBuddy, ByteDance Trae, Alibaba Tongyi Lingma | MCP settings, add a server manually, paste the JSON below |
|
|
159
|
+
| Cherry Studio | Settings, MCP servers, add: type STDIO, command `uvx`, arguments `qlib-sync` and `mcp` on separate lines |
|
|
160
|
+
| VS Code (Copilot agent mode) | `.vscode/mcp.json`: `{ "servers": { "qlib-sync": { "type": "stdio", "command": "uvx", "args": ["qlib-sync", "mcp"] } } }` |
|
|
161
|
+
|
|
162
|
+
```json
|
|
163
|
+
{ "mcpServers": { "qlib-sync": { "command": "uvx", "args": ["qlib-sync", "mcp"] } } }
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Menu names and file locations change between versions; check your client's MCP documentation
|
|
167
|
+
if a path above has moved. Tested with Claude Code and OpenAI Codex CLI.
|
|
168
|
+
|
|
169
|
+
Web chat apps such as ChatGPT connect only to remote MCP servers over the internet, so they
|
|
170
|
+
cannot start this local server.
|
|
171
|
+
|
|
172
|
+
Set `QLIB_SYNC_DATA_DIR` to use a dataset outside `~/.qlib/qlib_data/cn_data`, and
|
|
173
|
+
`QLIB_SYNC_MIRROR` to download through a mirror.
|
|
174
|
+
|
|
175
|
+
| Tool | Does |
|
|
176
|
+
|---|---|
|
|
177
|
+
| `cn_status` | Local latest date, pools, and whether an update is available |
|
|
178
|
+
| `cn_update` | Install or update (safe to call: failures restore the previous data) |
|
|
179
|
+
| `cn_health_check` | Structure checks plus a real Qlib read |
|
|
180
|
+
| `cn_get_prices` | Daily bars for up to 20 symbols; real traded prices by default, adjusted on request |
|
|
181
|
+
| `cn_list_pool` | Members of csi300, csi500, and other pools on a date |
|
|
182
|
+
|
|
183
|
+
Then ask things like *"Is my A-share data current? What did Moutai close at over the last
|
|
184
|
+
week?"* Symbols accept `600519`, `SH600519`, or `600519.SH`.
|
|
185
|
+
|
|
186
|
+

|
|
187
|
+
|
|
188
|
+
[`skills/qlib-sync/SKILL.md`](https://github.com/randyy179/qlib-sync/blob/main/skills/qlib-sync/SKILL.md) teaches an assistant when to update,
|
|
189
|
+
how to read each failure, and the price conventions. It uses the open `SKILL.md` format that
|
|
190
|
+
Claude, Codex, and other agents load from their skills folder; any assistant can also simply
|
|
191
|
+
be pointed at the file.
|
|
192
|
+
|
|
193
|
+
## Daily updates
|
|
194
|
+
|
|
195
|
+
A run that finds nothing new costs one small request, so schedule it daily. See
|
|
196
|
+
[docs/scheduling.md](https://github.com/randyy179/qlib-sync/blob/main/docs/scheduling.md) for cron and launchd examples.
|
|
197
|
+
|
|
198
|
+
## Data and credits
|
|
199
|
+
|
|
200
|
+
All data comes from [chenditc/investment_data](https://github.com/chenditc/investment_data)
|
|
201
|
+
(Apache-2.0). qlib-sync only downloads the public release; it does not host or redistribute
|
|
202
|
+
data. Prices follow Qlib's convention: `$close` is adjusted and the real price is
|
|
203
|
+
`$close / $factor`.
|
|
204
|
+
|
|
205
|
+
qlib-sync is an independent project, not affiliated with Microsoft or the Qlib team.
|
|
206
|
+
|
|
207
|
+
Supported: macOS and Linux, Python 3.10 to 3.12 (pyqlib does not publish wheels for newer
|
|
208
|
+
versions yet; `uvx` picks a compatible Python automatically).
|
|
209
|
+
|
|
210
|
+
## Development
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
uv venv && uv pip install -e ".[dev]"
|
|
214
|
+
.venv/bin/python -m pytest
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## License
|
|
218
|
+
|
|
219
|
+
MIT
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# qlib-sync
|
|
2
|
+
|
|
3
|
+
[](https://github.com/randyy179/qlib-sync/actions/workflows/ci.yml)
|
|
4
|
+
[](https://pypi.org/project/qlib-sync/)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
[中文说明](README.zh-CN.md)
|
|
8
|
+
|
|
9
|
+
**Website:** [randyy179.github.io/qlib-sync](https://randyy179.github.io/qlib-sync/)
|
|
10
|
+
|
|
11
|
+
<!-- mcp-name: io.github.randyy179/qlib-sync -->
|
|
12
|
+
|
|
13
|
+
**One command to install and keep current a local [Qlib](https://github.com/microsoft/qlib) China A-share dataset, and an MCP server so AI assistants can read it.**
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install qlib-sync
|
|
17
|
+
qlib-sync cn update
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Or without installing anything first: `uvx qlib-sync cn update`.
|
|
21
|
+
|
|
22
|
+

|
|
23
|
+
|
|
24
|
+
That installs the daily community release from
|
|
25
|
+
[chenditc/investment_data](https://github.com/chenditc/investment_data) into
|
|
26
|
+
`~/.qlib/qlib_data/cn_data`, the location Qlib reads by default. Run the same command again
|
|
27
|
+
any time; when the data is already current it finishes in about a second.
|
|
28
|
+
|
|
29
|
+
## Why not just `wget` and `tar`?
|
|
30
|
+
|
|
31
|
+
<img src="docs/assets/comic.jpg" width="560" alt="Four-panel comic: a download dies at 99% at night; the next day 550 MB arrive and nothing changed; the qlib-sync robot checks the data and stamps it verified, keeping the old copy safe; the researcher sips tea and asks an AI for Moutai's recent closes">
|
|
32
|
+
|
|
33
|
+
Qlib's README points A-share users to the community release with a `wget` and `tar` one-liner.
|
|
34
|
+
That works until it doesn't:
|
|
35
|
+
|
|
36
|
+
- **An interrupted or truncated download** extracts into a half-written dataset, or fails
|
|
37
|
+
after the old one has already been overwritten.
|
|
38
|
+
- **Upstream republishes releases.** In November 2026 a data error was found and corrected
|
|
39
|
+
([investment_data#163](https://github.com/chenditc/investment_data/issues/163)) and releases
|
|
40
|
+
were republished under the same date. A date check alone never sees the fix.
|
|
41
|
+
- **Every check downloads 550 MB**, even when nothing changed.
|
|
42
|
+
|
|
43
|
+
The investment_data README itself describes a careful manual process: download the release
|
|
44
|
+
manifest, check the archive with its `validate_archive.py`, then extract. qlib-sync runs the
|
|
45
|
+
same checks automatically on every update and adds what a manual process cannot: it skips the
|
|
46
|
+
download when nothing changed, extracts beside the live data and swaps it in with rollback
|
|
47
|
+
(rather than extracting on top of the existing folder), and picks up republished releases.
|
|
48
|
+
|
|
49
|
+
qlib-sync treats the dataset like a production system:
|
|
50
|
+
|
|
51
|
+
<picture>
|
|
52
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/assets/update-flow-dark.svg">
|
|
53
|
+
<img alt="Update flow: check the manifest, download, verify, stage, swap; any failure puts the previous dataset back" src="docs/assets/update-flow-light.svg">
|
|
54
|
+
</picture>
|
|
55
|
+
|
|
56
|
+
| Step | What happens |
|
|
57
|
+
|---|---|
|
|
58
|
+
| Check | Reads the release's 500-byte manifest. Already current: done, nothing downloaded. |
|
|
59
|
+
| Download | Resumes interrupted downloads; shows progress; optional mirror for slow links to GitHub. |
|
|
60
|
+
| Verify | Size and sha256 from the manifest; the same release checks as upstream's `validate_archive.py` (every index pool and the future calendar reach the manifest's dates, release marked publishable); archive paths and links are checked before extraction. |
|
|
61
|
+
| Stage | Extracts next to the active dataset; refuses downgrades. |
|
|
62
|
+
| Swap | Renames the new dataset into place, then runs a real Qlib read. |
|
|
63
|
+
| Roll back | Any failure after the swap moves the previous dataset back. |
|
|
64
|
+
| Report | New trading days, newly listed and delisted symbols. |
|
|
65
|
+
|
|
66
|
+
The checks catch broken, truncated, or tampered packages. They cannot catch wrong values inside a
|
|
67
|
+
correctly published release (like the one in #163); for that, keep a rollback copy with
|
|
68
|
+
`--keep-backup`.
|
|
69
|
+
|
|
70
|
+
## Commands
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
qlib-sync status # every local Qlib dataset at a glance
|
|
74
|
+
qlib-sync cn status # local date, pools, and whether a newer release exists
|
|
75
|
+
qlib-sync cn update # install or update (add --json for machine-readable output)
|
|
76
|
+
qlib-sync cn health-check # structure checks plus a real Qlib read
|
|
77
|
+
qlib-sync cn restore --list # rollback backups; restore --yes switches back
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Useful options for `cn update`:
|
|
81
|
+
|
|
82
|
+
| Option | Effect |
|
|
83
|
+
|---|---|
|
|
84
|
+
| `--data-dir PATH` | Install somewhere other than `~/.qlib/qlib_data/cn_data` |
|
|
85
|
+
| `--mirror URL` | Download through a prefix-style GitHub proxy such as `https://ghfast.top` (or set `QLIB_SYNC_MIRROR`) |
|
|
86
|
+
| `--keep-backup` | Keep the previous dataset for one rollback |
|
|
87
|
+
| `--protect FILE` | Carry a custom stock pool in `instruments/` across updates (repeatable) |
|
|
88
|
+
| `--force` | Reinstall even when the dates match |
|
|
89
|
+
|
|
90
|
+
**The update replaces the whole `cn_data` folder.** Anything you added there is lost unless you
|
|
91
|
+
pass it with `--protect`.
|
|
92
|
+
|
|
93
|
+
### Mirrors
|
|
94
|
+
|
|
95
|
+
From mainland China, GitHub downloads can be slow or fail. Pass a mirror and qlib-sync downloads
|
|
96
|
+
the package through it while still reading the manifest from GitHub directly when it can, so the
|
|
97
|
+
checksum does not depend on the mirror. Mirrors are third-party services; qlib-sync does not
|
|
98
|
+
endorse any of them.
|
|
99
|
+
|
|
100
|
+
## Python
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
from qlib_sync import update_cn, status_cn, health_check_cn
|
|
104
|
+
|
|
105
|
+
result = update_cn() # raises qlib_sync.UpdateError on failure; data unchanged
|
|
106
|
+
print("\n".join(result.summary_lines()))
|
|
107
|
+
print(result.new_trading_days, result.added_symbols)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Use it from your AI assistant
|
|
111
|
+
|
|
112
|
+
qlib-sync includes an [MCP](https://modelcontextprotocol.io) server, the open standard most AI
|
|
113
|
+
tools use to call local tools. Any MCP client that can start a local command works, whichever
|
|
114
|
+
model it runs: Claude, GPT, Gemini, DeepSeek, Qwen, Kimi, GLM, or a local model. The server
|
|
115
|
+
runs on your machine and reads the dataset there; there is no service to host and nothing
|
|
116
|
+
leaves your computer. It is listed in the [MCP Registry](https://registry.modelcontextprotocol.io)
|
|
117
|
+
as `io.github.randyy179/qlib-sync`.
|
|
118
|
+
|
|
119
|
+
Every client needs the same two things: the command `uvx` and the arguments `qlib-sync mcp`.
|
|
120
|
+
|
|
121
|
+
| Client | How to add qlib-sync |
|
|
122
|
+
|---|---|
|
|
123
|
+
| Claude Desktop | Download `qlib-sync.mcpb` from the [latest release](https://github.com/randyy179/qlib-sync/releases/latest) and open it |
|
|
124
|
+
| Claude Code | `claude mcp add qlib-sync -- uvx qlib-sync mcp` |
|
|
125
|
+
| OpenAI Codex CLI | `codex mcp add qlib-sync -- uvx qlib-sync mcp` |
|
|
126
|
+
| Cursor | The JSON below, in `~/.cursor/mcp.json` |
|
|
127
|
+
| Gemini CLI | The JSON below, in `~/.gemini/settings.json` |
|
|
128
|
+
| Qwen Code | The JSON below, in `~/.qwen/settings.json` |
|
|
129
|
+
| Tencent CodeBuddy, ByteDance Trae, Alibaba Tongyi Lingma | MCP settings, add a server manually, paste the JSON below |
|
|
130
|
+
| Cherry Studio | Settings, MCP servers, add: type STDIO, command `uvx`, arguments `qlib-sync` and `mcp` on separate lines |
|
|
131
|
+
| VS Code (Copilot agent mode) | `.vscode/mcp.json`: `{ "servers": { "qlib-sync": { "type": "stdio", "command": "uvx", "args": ["qlib-sync", "mcp"] } } }` |
|
|
132
|
+
|
|
133
|
+
```json
|
|
134
|
+
{ "mcpServers": { "qlib-sync": { "command": "uvx", "args": ["qlib-sync", "mcp"] } } }
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Menu names and file locations change between versions; check your client's MCP documentation
|
|
138
|
+
if a path above has moved. Tested with Claude Code and OpenAI Codex CLI.
|
|
139
|
+
|
|
140
|
+
Web chat apps such as ChatGPT connect only to remote MCP servers over the internet, so they
|
|
141
|
+
cannot start this local server.
|
|
142
|
+
|
|
143
|
+
Set `QLIB_SYNC_DATA_DIR` to use a dataset outside `~/.qlib/qlib_data/cn_data`, and
|
|
144
|
+
`QLIB_SYNC_MIRROR` to download through a mirror.
|
|
145
|
+
|
|
146
|
+
| Tool | Does |
|
|
147
|
+
|---|---|
|
|
148
|
+
| `cn_status` | Local latest date, pools, and whether an update is available |
|
|
149
|
+
| `cn_update` | Install or update (safe to call: failures restore the previous data) |
|
|
150
|
+
| `cn_health_check` | Structure checks plus a real Qlib read |
|
|
151
|
+
| `cn_get_prices` | Daily bars for up to 20 symbols; real traded prices by default, adjusted on request |
|
|
152
|
+
| `cn_list_pool` | Members of csi300, csi500, and other pools on a date |
|
|
153
|
+
|
|
154
|
+
Then ask things like *"Is my A-share data current? What did Moutai close at over the last
|
|
155
|
+
week?"* Symbols accept `600519`, `SH600519`, or `600519.SH`.
|
|
156
|
+
|
|
157
|
+

|
|
158
|
+
|
|
159
|
+
[`skills/qlib-sync/SKILL.md`](skills/qlib-sync/SKILL.md) teaches an assistant when to update,
|
|
160
|
+
how to read each failure, and the price conventions. It uses the open `SKILL.md` format that
|
|
161
|
+
Claude, Codex, and other agents load from their skills folder; any assistant can also simply
|
|
162
|
+
be pointed at the file.
|
|
163
|
+
|
|
164
|
+
## Daily updates
|
|
165
|
+
|
|
166
|
+
A run that finds nothing new costs one small request, so schedule it daily. See
|
|
167
|
+
[docs/scheduling.md](docs/scheduling.md) for cron and launchd examples.
|
|
168
|
+
|
|
169
|
+
## Data and credits
|
|
170
|
+
|
|
171
|
+
All data comes from [chenditc/investment_data](https://github.com/chenditc/investment_data)
|
|
172
|
+
(Apache-2.0). qlib-sync only downloads the public release; it does not host or redistribute
|
|
173
|
+
data. Prices follow Qlib's convention: `$close` is adjusted and the real price is
|
|
174
|
+
`$close / $factor`.
|
|
175
|
+
|
|
176
|
+
qlib-sync is an independent project, not affiliated with Microsoft or the Qlib team.
|
|
177
|
+
|
|
178
|
+
Supported: macOS and Linux, Python 3.10 to 3.12 (pyqlib does not publish wheels for newer
|
|
179
|
+
versions yet; `uvx` picks a compatible Python automatically).
|
|
180
|
+
|
|
181
|
+
## Development
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
uv venv && uv pip install -e ".[dev]"
|
|
185
|
+
.venv/bin/python -m pytest
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## License
|
|
189
|
+
|
|
190
|
+
MIT
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# qlib-sync
|
|
2
|
+
|
|
3
|
+
[English](README.md)
|
|
4
|
+
|
|
5
|
+
**网站:**[randyy179.github.io/qlib-sync](https://randyy179.github.io/qlib-sync/)
|
|
6
|
+
|
|
7
|
+
**一条命令安装并保持更新本地 [Qlib](https://github.com/microsoft/qlib) A 股数据,并提供 MCP server,让 AI 助手直接读取。**
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install qlib-sync
|
|
11
|
+
qlib-sync cn update
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
也可以不预先安装,直接运行:`uvx qlib-sync cn update`。
|
|
15
|
+
|
|
16
|
+

|
|
17
|
+
|
|
18
|
+
数据来自 [chenditc/investment_data](https://github.com/chenditc/investment_data) 每天的社区发布,安装到 Qlib 默认读取的位置 `~/.qlib/qlib_data/cn_data`。原来的 Qlib 代码不用改。之后随时再运行同一条命令,数据已是最新时大约 1 秒结束。
|
|
19
|
+
|
|
20
|
+
## 为什么不直接 `wget` 加 `tar`?
|
|
21
|
+
|
|
22
|
+
<img src="docs/assets/comic.jpg" width="560" alt="四格漫画:深夜下载 A 股数据断在 99%;第二天又下了 550MB 结果啥也没变;qlib-sync 机器人先校验再替换、出错自动回滚;研究员喝着茶让 AI 直接读最新数据">
|
|
23
|
+
|
|
24
|
+
Qlib 的 README 推荐用 `wget` 下载社区数据包再用 `tar` 解压。平时没问题,但会遇到这些情况:
|
|
25
|
+
|
|
26
|
+
- **下载中断或不完整**:解压出半截数据,或者旧数据已经被覆盖了才发现失败。
|
|
27
|
+
- **上游会重新发布**:2026 年 11 月,上游发现并修正了一处数据错误([investment_data#163](https://github.com/chenditc/investment_data/issues/163)),用同一个日期重新发布了数据包。只比较日期的话,永远拿不到修复后的数据。
|
|
28
|
+
- **每次检查都要下载 550MB**,即使什么都没变。
|
|
29
|
+
|
|
30
|
+
investment_data 自己的 README 也给出了一套严谨的手动流程:下载发布清单(manifest),用它的 `validate_archive.py` 校验数据包,再解压。qlib-sync 每次更新都自动执行同样的校验,并补上手动流程做不到的部分:没有新数据时不下载;在旧数据旁边解压,校验通过后整体切换、失败回滚(而不是直接解压覆盖到现有目录);能拿到上游重新发布的修复版。
|
|
31
|
+
|
|
32
|
+
qlib-sync 把本地数据当生产系统来管理:
|
|
33
|
+
|
|
34
|
+
<picture>
|
|
35
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/assets/update-flow-dark.svg">
|
|
36
|
+
<img alt="更新流程:读 manifest、下载、校验、准备、切换;任何一步失败都会恢复原有数据" src="docs/assets/update-flow-light.svg">
|
|
37
|
+
</picture>
|
|
38
|
+
|
|
39
|
+
| 步骤 | 做什么 |
|
|
40
|
+
|---|---|
|
|
41
|
+
| 检查 | 先读发布附带的 500 字节 manifest。已是最新就结束,不下载 |
|
|
42
|
+
| 下载 | 支持断点续传、显示进度;网络慢时可走镜像 |
|
|
43
|
+
| 校验 | 核对大小和 sha256;执行与上游 `validate_archive.py` 相同的发布检查(各指数成分和未来交易日历都与 manifest 日期一致、发布标记为可发布);解压前检查路径和链接是否安全 |
|
|
44
|
+
| 准备 | 解压到旧数据旁边的临时目录;拒绝降级 |
|
|
45
|
+
| 切换 | 把新数据换上去,再用 Qlib 实际读一次 |
|
|
46
|
+
| 回滚 | 切换后任何一步失败,自动换回旧数据 |
|
|
47
|
+
| 汇报 | 新增了哪些交易日、新上市和退市的股票 |
|
|
48
|
+
|
|
49
|
+
这些校验能挡住损坏、不完整或被篡改的数据包,**挡不住上游正常发布的数据里本身的数值错误**(比如 #163 那种)。需要防这类问题时,可以加 `--keep-backup` 保留一份可回滚的旧数据。
|
|
50
|
+
|
|
51
|
+
## 命令
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
qlib-sync status # 所有本地 Qlib 数据集一览
|
|
55
|
+
qlib-sync cn status # 本地到哪天、有哪些股票池、远端有没有更新
|
|
56
|
+
qlib-sync cn update # 安装或更新(加 --json 输出机器可读结果)
|
|
57
|
+
qlib-sync cn health-check # 结构检查加一次真实的 Qlib 读取
|
|
58
|
+
qlib-sync cn restore --list # 查看备份;restore --yes 换回备份
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`cn update` 的常用选项:
|
|
62
|
+
|
|
63
|
+
| 选项 | 作用 |
|
|
64
|
+
|---|---|
|
|
65
|
+
| `--data-dir 路径` | 安装到 `~/.qlib/qlib_data/cn_data` 以外的位置 |
|
|
66
|
+
| `--mirror 地址` | 通过前缀式 GitHub 代理下载,如 `https://ghfast.top`(也可设环境变量 `QLIB_SYNC_MIRROR`) |
|
|
67
|
+
| `--keep-backup` | 保留一份旧数据用于回滚 |
|
|
68
|
+
| `--protect 文件名` | 更新后保留 `instruments/` 里自定义的股票池文件(可重复使用) |
|
|
69
|
+
| `--force` | 日期相同也重新安装 |
|
|
70
|
+
|
|
71
|
+
**注意:更新会替换整个 `cn_data` 目录。** 你自己放进去的文件,除非用 `--protect` 指定,否则会丢失。
|
|
72
|
+
|
|
73
|
+
### 国内镜像
|
|
74
|
+
|
|
75
|
+
在国内访问 GitHub 下载经常很慢甚至失败。指定镜像后,数据包走镜像下载,manifest 仍尽量直接从 GitHub 读取,这样校验值不依赖镜像本身。镜像是第三方服务,qlib-sync 不对任何镜像做担保。
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
qlib-sync cn update --mirror https://ghfast.top
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## 在 Python 里使用
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
from qlib_sync import update_cn, status_cn, health_check_cn
|
|
85
|
+
|
|
86
|
+
result = update_cn() # 失败时抛出 qlib_sync.UpdateError,原有数据不受影响
|
|
87
|
+
print("\n".join(result.summary_lines()))
|
|
88
|
+
print(result.new_trading_days, result.added_symbols)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## 在你的 AI 助手中使用
|
|
92
|
+
|
|
93
|
+
qlib-sync 自带一个 [MCP](https://modelcontextprotocol.io) server。MCP 是大多数 AI 工具调用本地工具的开放标准,所以只要你用的工具能启动本地命令,就能接入,不管它背后用的是哪个模型:Claude、GPT、Gemini、DeepSeek、通义千问、Kimi、智谱 GLM,或者本地部署的开源模型都可以。
|
|
94
|
+
|
|
95
|
+
MCP server 在你本机运行,读取你电脑上的数据,不需要搭建任何服务器,数据也不会离开你的电脑。也可以在 [MCP Registry](https://registry.modelcontextprotocol.io) 搜索 `io.github.randyy179/qlib-sync`。
|
|
96
|
+
|
|
97
|
+
各个工具需要填的内容都一样:命令 `uvx`,参数 `qlib-sync mcp`。
|
|
98
|
+
|
|
99
|
+
| 工具 | 接入方式 |
|
|
100
|
+
|---|---|
|
|
101
|
+
| Claude Desktop | 从[最新发布](https://github.com/randyy179/qlib-sync/releases/latest)下载 `qlib-sync.mcpb`,双击安装 |
|
|
102
|
+
| Claude Code | `claude mcp add qlib-sync -- uvx qlib-sync mcp` |
|
|
103
|
+
| OpenAI Codex CLI | `codex mcp add qlib-sync -- uvx qlib-sync mcp` |
|
|
104
|
+
| 腾讯 CodeBuddy、字节 Trae、阿里通义灵码 | 在 MCP 设置里手动添加服务器,粘贴下面的 JSON |
|
|
105
|
+
| Cherry Studio | 设置 → MCP 服务器 → 添加:类型选 STDIO,命令填 `uvx`,参数分两行填 `qlib-sync` 和 `mcp` |
|
|
106
|
+
| 通义千问 Qwen Code | 把下面的 JSON 写进 `~/.qwen/settings.json` |
|
|
107
|
+
| Cursor | 把下面的 JSON 写进 `~/.cursor/mcp.json` |
|
|
108
|
+
| Gemini CLI | 把下面的 JSON 写进 `~/.gemini/settings.json` |
|
|
109
|
+
| VS Code(Copilot Agent 模式) | `.vscode/mcp.json`:`{ "servers": { "qlib-sync": { "type": "stdio", "command": "uvx", "args": ["qlib-sync", "mcp"] } } }` |
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{ "mcpServers": { "qlib-sync": { "command": "uvx", "args": ["qlib-sync", "mcp"] } } }
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
各工具的菜单名称和配置文件位置会随版本变化,找不到时以该工具的 MCP 官方文档为准。已实测:Claude Code、OpenAI Codex CLI。
|
|
116
|
+
|
|
117
|
+
ChatGPT 这类网页聊天应用只能连接互联网上的远程 MCP server,无法启动本地程序,所以暂时用不了。
|
|
118
|
+
|
|
119
|
+
数据不在默认位置时设置环境变量 `QLIB_SYNC_DATA_DIR`;需要走镜像时设置 `QLIB_SYNC_MIRROR`。
|
|
120
|
+
|
|
121
|
+
| 工具 | 作用 |
|
|
122
|
+
|---|---|
|
|
123
|
+
| `cn_status` | 本地数据到哪天、有哪些股票池、有没有更新 |
|
|
124
|
+
| `cn_update` | 安装或更新(可放心调用:失败会自动恢复旧数据) |
|
|
125
|
+
| `cn_health_check` | 结构检查加一次真实的 Qlib 读取 |
|
|
126
|
+
| `cn_get_prices` | 最多 20 只股票的日线;默认返回真实成交价,可选复权价 |
|
|
127
|
+
| `cn_list_pool` | 某天沪深 300、中证 500 等股票池的成分股 |
|
|
128
|
+
|
|
129
|
+
接好之后可以直接问:"我的 A 股数据是最新的吗?茅台最近一周收盘价多少?" 股票代码写 `600519`、`SH600519`、`600519.SH` 都可以。
|
|
130
|
+
|
|
131
|
+

|
|
132
|
+
|
|
133
|
+
[`skills/qlib-sync/SKILL.md`](skills/qlib-sync/SKILL.md) 教 AI 什么时候该更新、每种错误怎么处理、价格口径是什么。它采用开放的 `SKILL.md` 格式,Claude、Codex 等工具可以直接从 skills 目录加载;其他 AI 助手也可以直接让它读这个文件。
|
|
134
|
+
|
|
135
|
+
## 每天自动更新
|
|
136
|
+
|
|
137
|
+
没有新数据时只花一次很小的请求,所以每天定时跑就行。cron 和 launchd 的配置示例见 [docs/scheduling.md](docs/scheduling.md)。
|
|
138
|
+
|
|
139
|
+
## 数据来源与致谢
|
|
140
|
+
|
|
141
|
+
全部数据来自 [chenditc/investment_data](https://github.com/chenditc/investment_data)(Apache-2.0 协议)。qlib-sync 只下载其公开发布的文件,不托管、不分发数据。价格遵循 Qlib 的约定:`$close` 是复权价,真实价格是 `$close / $factor`。
|
|
142
|
+
|
|
143
|
+
qlib-sync 是独立项目,与微软及 Qlib 团队无关。
|
|
144
|
+
|
|
145
|
+
支持 macOS 和 Linux,Python 3.10 到 3.12(pyqlib 暂未发布更新版本的安装包;用 `uvx` 时会自动选择兼容的 Python)。
|
|
146
|
+
|
|
147
|
+
## 开发
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
uv venv && uv pip install -e ".[dev]"
|
|
151
|
+
.venv/bin/python -m pytest
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## 协议
|
|
155
|
+
|
|
156
|
+
MIT
|