deeptrade-quant 0.2.0__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.
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/PKG-INFO +48 -47
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/README.md +47 -46
- deeptrade_quant-0.3.1/deeptrade/__init__.py +6 -0
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/deeptrade/cli.py +5 -3
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/deeptrade/cli_config.py +8 -10
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/deeptrade/cli_plugin.py +6 -18
- deeptrade_quant-0.3.1/deeptrade/core/__init__.py +7 -0
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/deeptrade/core/config.py +12 -3
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/deeptrade/core/config_migrations.py +65 -6
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/deeptrade/core/db.py +6 -0
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/deeptrade/core/github_fetch.py +9 -25
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/deeptrade/core/llm_manager.py +2 -4
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/deeptrade/core/migrations/core/20260509_001_init.sql +1 -1
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/deeptrade/core/plugin_manager.py +4 -7
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/deeptrade/core/plugin_source.py +3 -8
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/deeptrade/core/registry.py +8 -22
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/deeptrade/core/tushare_client.py +173 -17
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/deeptrade/plugins_api/__init__.py +0 -12
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/deeptrade/plugins_api/base.py +2 -6
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/deeptrade/plugins_api/metadata.py +1 -3
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/pyproject.toml +1 -1
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/tests/cli/test_plugin_cmd.py +21 -16
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/tests/core/test_config.py +2 -6
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/tests/core/test_config_migrations.py +77 -3
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/tests/core/test_db.py +1 -0
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/tests/core/test_github_fetch.py +3 -3
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/tests/core/test_llm_client.py +6 -18
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/tests/core/test_llm_manager.py +1 -3
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/tests/core/test_plugin_install.py +4 -12
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/tests/core/test_plugin_source.py +3 -1
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/tests/core/test_plugin_upgrade.py +3 -3
- deeptrade_quant-0.3.1/tests/core/test_tushare_classifier.py +274 -0
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/tests/core/test_tushare_client.py +14 -28
- deeptrade_quant-0.3.1/tests/core/test_tushare_retry_r1.py +234 -0
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/tests/plugins_api/test_protocol.py +3 -20
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/tests/test_smoke.py +1 -2
- deeptrade_quant-0.2.0/deeptrade/__init__.py +0 -8
- deeptrade_quant-0.2.0/deeptrade/core/__init__.py +0 -8
- deeptrade_quant-0.2.0/deeptrade/core/notifier.py +0 -305
- deeptrade_quant-0.2.0/deeptrade/plugins_api/channel.py +0 -42
- deeptrade_quant-0.2.0/deeptrade/plugins_api/notify.py +0 -67
- deeptrade_quant-0.2.0/tests/core/test_notifier.py +0 -189
- deeptrade_quant-0.2.0/tests/plugins_api/test_notify.py +0 -94
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/.gitignore +0 -0
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/LICENSE +0 -0
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/deeptrade/cli_data.py +0 -0
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/deeptrade/core/llm_client.py +0 -0
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/deeptrade/core/logging_config.py +0 -0
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/deeptrade/core/migrations/__init__.py +0 -0
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/deeptrade/core/migrations/core/__init__.py +0 -0
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/deeptrade/core/paths.py +0 -0
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/deeptrade/core/run_status.py +0 -0
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/deeptrade/core/secrets.py +0 -0
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/deeptrade/plugins_api/events.py +0 -0
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/deeptrade/plugins_api/llm.py +0 -0
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/deeptrade/theme.py +0 -0
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/tests/__init__.py +0 -0
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/tests/cli/__init__.py +0 -0
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/tests/cli/test_config_cmd.py +0 -0
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/tests/cli/test_routing.py +0 -0
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/tests/conftest.py +0 -0
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/tests/core/__init__.py +0 -0
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/tests/core/test_paths.py +0 -0
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/tests/core/test_registry.py +0 -0
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/tests/core/test_secrets.py +0 -0
- {deeptrade_quant-0.2.0 → deeptrade_quant-0.3.1}/tests/plugins_api/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deeptrade-quant
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: LLM-driven A-share (Shanghai/Shenzhen main board) stock screening CLI
|
|
5
5
|
Project-URL: Homepage, https://github.com/ty19880929/deeptrade
|
|
6
6
|
Project-URL: Repository, https://github.com/ty19880929/deeptrade
|
|
@@ -34,23 +34,24 @@ Description-Content-Type: text/markdown
|
|
|
34
34
|
|
|
35
35
|
# DeepTrade
|
|
36
36
|
|
|
37
|
-
> 本地运行的 A 股(沪深主板)选股 CLI
|
|
37
|
+
> 本地运行的 A 股(沪深主板)选股 CLI 框架:tushare 行情 + OpenAI 兼容 LLM(DeepSeek / Qwen / Kimi …)+ DuckDB 单机仓库 + 纯透传式插件 CLI。框架不携带任何业务策略,所有策略按需从官方注册表安装。
|
|
38
38
|
|
|
39
|
-
[
|
|
39
|
+
> 📖 **在线文档**:[deeptrade.tiey.ai](https://deeptrade.tiey.ai) — 用户手册 + 开发者手册 + 官方插件目录
|
|
40
|
+
|
|
41
|
+
[](#) [](#) [](LICENSE) [](CHANGELOG.md)
|
|
40
42
|
|
|
41
43
|
## ✨ 主要特性
|
|
42
44
|
|
|
43
45
|
- **轻量本地化**:单文件 DuckDB + uv,一条命令跑完,无需服务进程或容器。
|
|
44
|
-
-
|
|
46
|
+
- **框架与插件物理解耦**:`deeptrade-quant` wheel 只含框架(`init / config / plugin / data`),所有策略走 `deeptrade plugin install <短名>` 从注册表安装。
|
|
47
|
+
- **纯透传式插件 CLI**:未知首词一律按 `deeptrade <plugin_id> <argv...>` 透传给插件,插件自管 `--help`、子命令、参数、持久化。
|
|
45
48
|
- **数据隔离(Plan A)**:每个插件在自己的 migrations 里声明并拥有自己的表(含 tushare 派生数据),框架不持有任何业务表。`tushare_sync_state` / `tushare_calls` / `llm_calls` 都按 `plugin_id` 维度隔离。
|
|
46
|
-
- **顶层通知 API**:`from deeptrade import notify, notification_session` 一行发推送;框架根据已安装的 channel 插件自动路由,无 channel 时自动 noop。
|
|
47
49
|
- **多 LLM Provider 共存**:`llm.providers` 字典化配置,多个 OpenAI 兼容服务并存;插件通过 `LLMManager.get_client(name=...)` 按名取用,单次 run 内可调多家。
|
|
48
50
|
- **LLM 强约束**:JSON 模式 + Pydantic 双层校验;**永远**不传 tools / function calls。
|
|
49
|
-
- **盘中数据隔离**:`--allow-intraday` 模式下同步的不完整数据写入 `data_completeness='intraday'`,日终模式严格拒绝命中。
|
|
50
51
|
|
|
51
52
|
## 🚀 5 分钟上手
|
|
52
53
|
|
|
53
|
-
###
|
|
54
|
+
### 安装框架
|
|
54
55
|
|
|
55
56
|
```bash
|
|
56
57
|
# 推荐:pipx 隔离环境(命令名仍是 deeptrade)
|
|
@@ -73,7 +74,7 @@ pip install -e ".[dev]"
|
|
|
73
74
|
### 初始化与配置
|
|
74
75
|
|
|
75
76
|
```bash
|
|
76
|
-
deeptrade init # 建库 + 应用 core migrations
|
|
77
|
+
deeptrade init # 建库 + 应用 core migrations(交互式可选配 tushare / LLM)
|
|
77
78
|
deeptrade config set-tushare # 交互式输入 tushare token
|
|
78
79
|
deeptrade config set-llm # 交互式增/改/删 LLM provider(deepseek / qwen / kimi …)
|
|
79
80
|
deeptrade config list-llm # 列出已配置且可用的 provider
|
|
@@ -83,16 +84,16 @@ deeptrade config show # 表格展示当前配置(密钥脱
|
|
|
83
84
|
|
|
84
85
|
### 安装官方插件并运行
|
|
85
86
|
|
|
86
|
-
官方插件维护在 [DeepTradePluginOfficial](https://github.com/ty19880929/DeepTradePluginOfficial)
|
|
87
|
+
官方插件维护在 [DeepTradePluginOfficial](https://github.com/ty19880929/DeepTradePluginOfficial),框架按短名查注册表 → 拉 GitHub release tarball 自动安装。
|
|
87
88
|
|
|
88
89
|
```bash
|
|
89
90
|
# 浏览注册表
|
|
90
|
-
deeptrade plugin search
|
|
91
|
+
deeptrade plugin search # 全量列出
|
|
92
|
+
deeptrade plugin search anomaly # 关键词过滤
|
|
91
93
|
|
|
92
|
-
# 按短名安装(注册表 →
|
|
94
|
+
# 按短名安装(注册表 → 该插件最新 release tag)
|
|
93
95
|
deeptrade plugin install limit-up-board
|
|
94
96
|
deeptrade plugin install volume-anomaly
|
|
95
|
-
deeptrade plugin install stdout-channel
|
|
96
97
|
|
|
97
98
|
deeptrade plugin list # 查看已安装
|
|
98
99
|
|
|
@@ -101,16 +102,18 @@ deeptrade limit-up-board --help
|
|
|
101
102
|
deeptrade limit-up-board run # 默认日终模式
|
|
102
103
|
deeptrade limit-up-board run --allow-intraday --force-sync
|
|
103
104
|
|
|
104
|
-
#
|
|
105
|
+
# 运行成交量异动策略
|
|
105
106
|
deeptrade volume-anomaly screen # 异动筛选 → upsert va_watchlist
|
|
106
107
|
deeptrade volume-anomaly analyze # LLM 主升浪启动预测
|
|
107
|
-
deeptrade volume-anomaly
|
|
108
|
-
|
|
109
|
-
# 推送链路自检
|
|
110
|
-
deeptrade stdout-channel test
|
|
108
|
+
deeptrade volume-anomaly evaluate # T+N 自动回测闭环
|
|
109
|
+
deeptrade volume-anomaly stats # 收益统计聚合
|
|
111
110
|
```
|
|
112
111
|
|
|
113
|
-
>
|
|
112
|
+
> **第三方 / 本地开发插件**:`deeptrade plugin install <SOURCE>` 三种来源统一处理,判定顺序为 *本地目录存在 → git URL → 注册表短名*:
|
|
113
|
+
>
|
|
114
|
+
> - `deeptrade plugin install ./path/to/my-plugin` — 本地目录
|
|
115
|
+
> - `deeptrade plugin install https://github.com/owner/repo` — 完整 git 仓库(仓库根需含 `deeptrade_plugin.yaml`)
|
|
116
|
+
> - `deeptrade plugin install my-plugin --ref v1.2.0` — 指定 tag/branch/sha
|
|
114
117
|
|
|
115
118
|
报告产出在 `~/.deeptrade/reports/<run_id>/`。
|
|
116
119
|
|
|
@@ -123,26 +126,27 @@ deeptrade stdout-channel test
|
|
|
123
126
|
| `deeptrade --version` / `-V` | 显示版本 |
|
|
124
127
|
| `deeptrade --help` / `-h` | 框架命令清单(**不**枚举插件子命令) |
|
|
125
128
|
| `deeptrade init [--no-prompts]` | 建库 + 应用 core migrations |
|
|
129
|
+
| `deeptrade db init` / `db upgrade` | 显式建库 / 应用待执行迁移 |
|
|
126
130
|
| `deeptrade config {show, set, set-tushare, set-llm, list-llm, test-llm}` | 全局配置 |
|
|
127
|
-
| `deeptrade plugin
|
|
128
|
-
| `deeptrade plugin
|
|
129
|
-
| `deeptrade plugin
|
|
131
|
+
| `deeptrade plugin search [keyword] [--no-cache]` | 浏览官方注册表 |
|
|
132
|
+
| `deeptrade plugin install <SOURCE> [--ref <REF>] [-y]` | 注册表短名 / GitHub URL / 本地路径 |
|
|
133
|
+
| `deeptrade plugin list` / `info <id>` | 列表 / 详情(未安装时回退注册表条目) |
|
|
134
|
+
| `deeptrade plugin enable <id>` / `disable <id>` | 启 / 停 |
|
|
130
135
|
| `deeptrade plugin uninstall <id> [--purge]` | 卸载(`--purge` 才 DROP 表) |
|
|
131
|
-
| `deeptrade plugin upgrade <
|
|
132
|
-
| `deeptrade data sync ...` |
|
|
136
|
+
| `deeptrade plugin upgrade <SOURCE> [--ref <REF>]` | 升级(SemVer 比较,禁止降级;增量 migrations) |
|
|
137
|
+
| `deeptrade data sync ...` | (暂停用,下版本恢复;改用插件自带的 sync 子命令) |
|
|
133
138
|
|
|
134
|
-
保留字(不可作为 plugin_id):`init / config / plugin / data`。
|
|
139
|
+
保留字(不可作为 plugin_id):`init / config / plugin / data / db`。
|
|
135
140
|
|
|
136
141
|
### 插件命令(按 plugin_id 透传,插件自管)
|
|
137
142
|
|
|
138
|
-
| 命令 |
|
|
143
|
+
| 命令 | 来源(注册表短名) |
|
|
139
144
|
|---|---|
|
|
140
|
-
| `deeptrade limit-up-board {run, sync, history, report}` |
|
|
141
|
-
| `deeptrade volume-anomaly {screen, analyze, prune, history, report}` |
|
|
142
|
-
| `deeptrade stdout-channel {test, log}` | 内建 stdout 通知插件 |
|
|
145
|
+
| `deeptrade limit-up-board {run, sync, history, report, settings}` | `limit-up-board`(strategy) |
|
|
146
|
+
| `deeptrade volume-anomaly {screen, analyze, evaluate, stats, prune, history, report}` | `volume-anomaly`(strategy) |
|
|
143
147
|
| `deeptrade <你的-plugin-id> ...` | 你自己写的任何插件 |
|
|
144
148
|
|
|
145
|
-
任意插件子命令的 `--help`
|
|
149
|
+
任意插件子命令的 `--help` 都由插件自身渲染——框架不感知动词语义。各插件的最新子命令、参数与运行手册见 [DeepTradePluginOfficial](https://github.com/ty19880929/DeepTradePluginOfficial)。
|
|
146
150
|
|
|
147
151
|
## 🧱 架构
|
|
148
152
|
|
|
@@ -150,33 +154,30 @@ deeptrade stdout-channel test
|
|
|
150
154
|
┌──────────────────────── deeptrade CLI (custom click.Group) ────────────────────────┐
|
|
151
155
|
│ │
|
|
152
156
|
│ framework commands (closed): │
|
|
153
|
-
│ init │ config │ plugin │ data
|
|
157
|
+
│ init │ config │ plugin │ data │ db │
|
|
154
158
|
│ │
|
|
155
159
|
│ plugin pass-through (open): │
|
|
156
160
|
│ <plugin_id> ──argv──→ Plugin.dispatch(argv) → int (plugin owns the rest) │
|
|
157
161
|
└──────────────────────────────────┬─────────────────────────────────────────────────┘
|
|
158
162
|
│
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
163
|
+
│
|
|
164
|
+
┌────────────────┴────────────────┐
|
|
165
|
+
▼ ▼
|
|
166
|
+
┌──────────────────┐ ┌────────────────────┐
|
|
167
|
+
│ Core services │ │ Plugins (strategy)│
|
|
168
|
+
│ DuckDB · Config │ │ • metadata │
|
|
169
|
+
│ Tushare · LLM │ │ • validate_static │
|
|
170
|
+
└──────────────────┘ │ • dispatch(argv) │
|
|
171
|
+
└────────────────────┘
|
|
168
172
|
```
|
|
169
173
|
|
|
170
|
-
|
|
174
|
+
每个插件通过自己的 migrations 声明并拥有 `<prefix>_*` 业务表;`tushare_sync_state` / `tushare_calls` / `llm_calls` 按 `plugin_id` 维度隔离,`__framework__` 为框架自身保留 sentinel。
|
|
171
175
|
|
|
172
|
-
## 📖
|
|
176
|
+
## 📖 参考
|
|
173
177
|
|
|
174
|
-
- [
|
|
175
|
-
- [
|
|
176
|
-
-
|
|
177
|
-
- [docs/plugin-development.md](docs/plugin-development.md) — 写一个新插件
|
|
178
|
-
- [docs/limit-up-board.md](docs/limit-up-board.md) — 打板策略说明
|
|
179
|
-
- [CHANGELOG.md](CHANGELOG.md) — 版本变更
|
|
178
|
+
- [CHANGELOG.md](CHANGELOG.md) — 版本变更与历次 breaking change 记录
|
|
179
|
+
- [DeepTradePluginOfficial](https://github.com/ty19880929/DeepTradePluginOfficial) — 官方插件源码、注册表、各插件运行手册
|
|
180
|
+
- 历史快照 `archive/with-builtin-plugins-v0.1.0-preview` — 含 builtin 子树的最后一版状态(v0.2.0 之前)
|
|
180
181
|
|
|
181
182
|
## ⚖️ 免责声明
|
|
182
183
|
|
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
# DeepTrade
|
|
2
2
|
|
|
3
|
-
> 本地运行的 A 股(沪深主板)选股 CLI
|
|
3
|
+
> 本地运行的 A 股(沪深主板)选股 CLI 框架:tushare 行情 + OpenAI 兼容 LLM(DeepSeek / Qwen / Kimi …)+ DuckDB 单机仓库 + 纯透传式插件 CLI。框架不携带任何业务策略,所有策略按需从官方注册表安装。
|
|
4
4
|
|
|
5
|
-
[
|
|
5
|
+
> 📖 **在线文档**:[deeptrade.tiey.ai](https://deeptrade.tiey.ai) — 用户手册 + 开发者手册 + 官方插件目录
|
|
6
|
+
|
|
7
|
+
[](#) [](#) [](LICENSE) [](CHANGELOG.md)
|
|
6
8
|
|
|
7
9
|
## ✨ 主要特性
|
|
8
10
|
|
|
9
11
|
- **轻量本地化**:单文件 DuckDB + uv,一条命令跑完,无需服务进程或容器。
|
|
10
|
-
-
|
|
12
|
+
- **框架与插件物理解耦**:`deeptrade-quant` wheel 只含框架(`init / config / plugin / data`),所有策略走 `deeptrade plugin install <短名>` 从注册表安装。
|
|
13
|
+
- **纯透传式插件 CLI**:未知首词一律按 `deeptrade <plugin_id> <argv...>` 透传给插件,插件自管 `--help`、子命令、参数、持久化。
|
|
11
14
|
- **数据隔离(Plan A)**:每个插件在自己的 migrations 里声明并拥有自己的表(含 tushare 派生数据),框架不持有任何业务表。`tushare_sync_state` / `tushare_calls` / `llm_calls` 都按 `plugin_id` 维度隔离。
|
|
12
|
-
- **顶层通知 API**:`from deeptrade import notify, notification_session` 一行发推送;框架根据已安装的 channel 插件自动路由,无 channel 时自动 noop。
|
|
13
15
|
- **多 LLM Provider 共存**:`llm.providers` 字典化配置,多个 OpenAI 兼容服务并存;插件通过 `LLMManager.get_client(name=...)` 按名取用,单次 run 内可调多家。
|
|
14
16
|
- **LLM 强约束**:JSON 模式 + Pydantic 双层校验;**永远**不传 tools / function calls。
|
|
15
|
-
- **盘中数据隔离**:`--allow-intraday` 模式下同步的不完整数据写入 `data_completeness='intraday'`,日终模式严格拒绝命中。
|
|
16
17
|
|
|
17
18
|
## 🚀 5 分钟上手
|
|
18
19
|
|
|
19
|
-
###
|
|
20
|
+
### 安装框架
|
|
20
21
|
|
|
21
22
|
```bash
|
|
22
23
|
# 推荐:pipx 隔离环境(命令名仍是 deeptrade)
|
|
@@ -39,7 +40,7 @@ pip install -e ".[dev]"
|
|
|
39
40
|
### 初始化与配置
|
|
40
41
|
|
|
41
42
|
```bash
|
|
42
|
-
deeptrade init # 建库 + 应用 core migrations
|
|
43
|
+
deeptrade init # 建库 + 应用 core migrations(交互式可选配 tushare / LLM)
|
|
43
44
|
deeptrade config set-tushare # 交互式输入 tushare token
|
|
44
45
|
deeptrade config set-llm # 交互式增/改/删 LLM provider(deepseek / qwen / kimi …)
|
|
45
46
|
deeptrade config list-llm # 列出已配置且可用的 provider
|
|
@@ -49,16 +50,16 @@ deeptrade config show # 表格展示当前配置(密钥脱
|
|
|
49
50
|
|
|
50
51
|
### 安装官方插件并运行
|
|
51
52
|
|
|
52
|
-
官方插件维护在 [DeepTradePluginOfficial](https://github.com/ty19880929/DeepTradePluginOfficial)
|
|
53
|
+
官方插件维护在 [DeepTradePluginOfficial](https://github.com/ty19880929/DeepTradePluginOfficial),框架按短名查注册表 → 拉 GitHub release tarball 自动安装。
|
|
53
54
|
|
|
54
55
|
```bash
|
|
55
56
|
# 浏览注册表
|
|
56
|
-
deeptrade plugin search
|
|
57
|
+
deeptrade plugin search # 全量列出
|
|
58
|
+
deeptrade plugin search anomaly # 关键词过滤
|
|
57
59
|
|
|
58
|
-
# 按短名安装(注册表 →
|
|
60
|
+
# 按短名安装(注册表 → 该插件最新 release tag)
|
|
59
61
|
deeptrade plugin install limit-up-board
|
|
60
62
|
deeptrade plugin install volume-anomaly
|
|
61
|
-
deeptrade plugin install stdout-channel
|
|
62
63
|
|
|
63
64
|
deeptrade plugin list # 查看已安装
|
|
64
65
|
|
|
@@ -67,16 +68,18 @@ deeptrade limit-up-board --help
|
|
|
67
68
|
deeptrade limit-up-board run # 默认日终模式
|
|
68
69
|
deeptrade limit-up-board run --allow-intraday --force-sync
|
|
69
70
|
|
|
70
|
-
#
|
|
71
|
+
# 运行成交量异动策略
|
|
71
72
|
deeptrade volume-anomaly screen # 异动筛选 → upsert va_watchlist
|
|
72
73
|
deeptrade volume-anomaly analyze # LLM 主升浪启动预测
|
|
73
|
-
deeptrade volume-anomaly
|
|
74
|
-
|
|
75
|
-
# 推送链路自检
|
|
76
|
-
deeptrade stdout-channel test
|
|
74
|
+
deeptrade volume-anomaly evaluate # T+N 自动回测闭环
|
|
75
|
+
deeptrade volume-anomaly stats # 收益统计聚合
|
|
77
76
|
```
|
|
78
77
|
|
|
79
|
-
>
|
|
78
|
+
> **第三方 / 本地开发插件**:`deeptrade plugin install <SOURCE>` 三种来源统一处理,判定顺序为 *本地目录存在 → git URL → 注册表短名*:
|
|
79
|
+
>
|
|
80
|
+
> - `deeptrade plugin install ./path/to/my-plugin` — 本地目录
|
|
81
|
+
> - `deeptrade plugin install https://github.com/owner/repo` — 完整 git 仓库(仓库根需含 `deeptrade_plugin.yaml`)
|
|
82
|
+
> - `deeptrade plugin install my-plugin --ref v1.2.0` — 指定 tag/branch/sha
|
|
80
83
|
|
|
81
84
|
报告产出在 `~/.deeptrade/reports/<run_id>/`。
|
|
82
85
|
|
|
@@ -89,26 +92,27 @@ deeptrade stdout-channel test
|
|
|
89
92
|
| `deeptrade --version` / `-V` | 显示版本 |
|
|
90
93
|
| `deeptrade --help` / `-h` | 框架命令清单(**不**枚举插件子命令) |
|
|
91
94
|
| `deeptrade init [--no-prompts]` | 建库 + 应用 core migrations |
|
|
95
|
+
| `deeptrade db init` / `db upgrade` | 显式建库 / 应用待执行迁移 |
|
|
92
96
|
| `deeptrade config {show, set, set-tushare, set-llm, list-llm, test-llm}` | 全局配置 |
|
|
93
|
-
| `deeptrade plugin
|
|
94
|
-
| `deeptrade plugin
|
|
95
|
-
| `deeptrade plugin
|
|
97
|
+
| `deeptrade plugin search [keyword] [--no-cache]` | 浏览官方注册表 |
|
|
98
|
+
| `deeptrade plugin install <SOURCE> [--ref <REF>] [-y]` | 注册表短名 / GitHub URL / 本地路径 |
|
|
99
|
+
| `deeptrade plugin list` / `info <id>` | 列表 / 详情(未安装时回退注册表条目) |
|
|
100
|
+
| `deeptrade plugin enable <id>` / `disable <id>` | 启 / 停 |
|
|
96
101
|
| `deeptrade plugin uninstall <id> [--purge]` | 卸载(`--purge` 才 DROP 表) |
|
|
97
|
-
| `deeptrade plugin upgrade <
|
|
98
|
-
| `deeptrade data sync ...` |
|
|
102
|
+
| `deeptrade plugin upgrade <SOURCE> [--ref <REF>]` | 升级(SemVer 比较,禁止降级;增量 migrations) |
|
|
103
|
+
| `deeptrade data sync ...` | (暂停用,下版本恢复;改用插件自带的 sync 子命令) |
|
|
99
104
|
|
|
100
|
-
保留字(不可作为 plugin_id):`init / config / plugin / data`。
|
|
105
|
+
保留字(不可作为 plugin_id):`init / config / plugin / data / db`。
|
|
101
106
|
|
|
102
107
|
### 插件命令(按 plugin_id 透传,插件自管)
|
|
103
108
|
|
|
104
|
-
| 命令 |
|
|
109
|
+
| 命令 | 来源(注册表短名) |
|
|
105
110
|
|---|---|
|
|
106
|
-
| `deeptrade limit-up-board {run, sync, history, report}` |
|
|
107
|
-
| `deeptrade volume-anomaly {screen, analyze, prune, history, report}` |
|
|
108
|
-
| `deeptrade stdout-channel {test, log}` | 内建 stdout 通知插件 |
|
|
111
|
+
| `deeptrade limit-up-board {run, sync, history, report, settings}` | `limit-up-board`(strategy) |
|
|
112
|
+
| `deeptrade volume-anomaly {screen, analyze, evaluate, stats, prune, history, report}` | `volume-anomaly`(strategy) |
|
|
109
113
|
| `deeptrade <你的-plugin-id> ...` | 你自己写的任何插件 |
|
|
110
114
|
|
|
111
|
-
任意插件子命令的 `--help`
|
|
115
|
+
任意插件子命令的 `--help` 都由插件自身渲染——框架不感知动词语义。各插件的最新子命令、参数与运行手册见 [DeepTradePluginOfficial](https://github.com/ty19880929/DeepTradePluginOfficial)。
|
|
112
116
|
|
|
113
117
|
## 🧱 架构
|
|
114
118
|
|
|
@@ -116,33 +120,30 @@ deeptrade stdout-channel test
|
|
|
116
120
|
┌──────────────────────── deeptrade CLI (custom click.Group) ────────────────────────┐
|
|
117
121
|
│ │
|
|
118
122
|
│ framework commands (closed): │
|
|
119
|
-
│ init │ config │ plugin │ data
|
|
123
|
+
│ init │ config │ plugin │ data │ db │
|
|
120
124
|
│ │
|
|
121
125
|
│ plugin pass-through (open): │
|
|
122
126
|
│ <plugin_id> ──argv──→ Plugin.dispatch(argv) → int (plugin owns the rest) │
|
|
123
127
|
└──────────────────────────────────┬─────────────────────────────────────────────────┘
|
|
124
128
|
│
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
129
|
+
│
|
|
130
|
+
┌────────────────┴────────────────┐
|
|
131
|
+
▼ ▼
|
|
132
|
+
┌──────────────────┐ ┌────────────────────┐
|
|
133
|
+
│ Core services │ │ Plugins (strategy)│
|
|
134
|
+
│ DuckDB · Config │ │ • metadata │
|
|
135
|
+
│ Tushare · LLM │ │ • validate_static │
|
|
136
|
+
└──────────────────┘ │ • dispatch(argv) │
|
|
137
|
+
└────────────────────┘
|
|
134
138
|
```
|
|
135
139
|
|
|
136
|
-
|
|
140
|
+
每个插件通过自己的 migrations 声明并拥有 `<prefix>_*` 业务表;`tushare_sync_state` / `tushare_calls` / `llm_calls` 按 `plugin_id` 维度隔离,`__framework__` 为框架自身保留 sentinel。
|
|
137
141
|
|
|
138
|
-
## 📖
|
|
142
|
+
## 📖 参考
|
|
139
143
|
|
|
140
|
-
- [
|
|
141
|
-
- [
|
|
142
|
-
-
|
|
143
|
-
- [docs/plugin-development.md](docs/plugin-development.md) — 写一个新插件
|
|
144
|
-
- [docs/limit-up-board.md](docs/limit-up-board.md) — 打板策略说明
|
|
145
|
-
- [CHANGELOG.md](CHANGELOG.md) — 版本变更
|
|
144
|
+
- [CHANGELOG.md](CHANGELOG.md) — 版本变更与历次 breaking change 记录
|
|
145
|
+
- [DeepTradePluginOfficial](https://github.com/ty19880929/DeepTradePluginOfficial) — 官方插件源码、注册表、各插件运行手册
|
|
146
|
+
- 历史快照 `archive/with-builtin-plugins-v0.1.0-preview` — 含 builtin 子树的最后一版状态(v0.2.0 之前)
|
|
146
147
|
|
|
147
148
|
## ⚖️ 免责声明
|
|
148
149
|
|
|
@@ -103,8 +103,7 @@ def _build_plugin_command(plugin_id: str) -> click.Command | None:
|
|
|
103
103
|
)
|
|
104
104
|
def _disabled() -> None:
|
|
105
105
|
typer.echo(
|
|
106
|
-
f"✘ plugin {plugin_id!r} is disabled; "
|
|
107
|
-
f"run `deeptrade plugin enable {plugin_id}`"
|
|
106
|
+
f"✘ plugin {plugin_id!r} is disabled; run `deeptrade plugin enable {plugin_id}`"
|
|
108
107
|
)
|
|
109
108
|
raise typer.Exit(2)
|
|
110
109
|
|
|
@@ -204,15 +203,16 @@ def init(
|
|
|
204
203
|
cmd_set_llm()
|
|
205
204
|
|
|
206
205
|
|
|
207
|
-
|
|
208
206
|
@app.command(name="db", context_settings={"ignore_unknown_options": True, "allow_extra_args": True})
|
|
209
207
|
def db_cmd(ctx: click.Context) -> None:
|
|
210
208
|
"""Database migration and management commands (legacy stub; use `deeptrade db init` via group if added)."""
|
|
211
209
|
pass
|
|
212
210
|
|
|
211
|
+
|
|
213
212
|
db_app = typer.Typer(name="db", help="Database migration and management commands.")
|
|
214
213
|
app.add_typer(db_app, name="db")
|
|
215
214
|
|
|
215
|
+
|
|
216
216
|
@db_app.command("init")
|
|
217
217
|
def db_init() -> None:
|
|
218
218
|
"""Initialize the core database tables and apply migrations."""
|
|
@@ -232,10 +232,12 @@ def db_init() -> None:
|
|
|
232
232
|
finally:
|
|
233
233
|
db.close()
|
|
234
234
|
|
|
235
|
+
|
|
235
236
|
@db_app.command("upgrade")
|
|
236
237
|
def db_upgrade() -> None:
|
|
237
238
|
"""Apply any pending core migrations."""
|
|
238
239
|
db_init()
|
|
239
240
|
|
|
241
|
+
|
|
240
242
|
if __name__ == "__main__":
|
|
241
243
|
app()
|
|
@@ -156,10 +156,12 @@ def cmd_set_llm() -> None:
|
|
|
156
156
|
existing = sorted(cfg.llm_providers.keys())
|
|
157
157
|
|
|
158
158
|
if existing:
|
|
159
|
-
choices =
|
|
160
|
-
|
|
161
|
-
"
|
|
162
|
-
|
|
159
|
+
choices = (
|
|
160
|
+
["[+] Add new provider"]
|
|
161
|
+
+ [f"[~] {n}" for n in existing]
|
|
162
|
+
+ ["[x] Delete a provider"]
|
|
163
|
+
)
|
|
164
|
+
picked = questionary.select("Pick action:", choices=choices).ask()
|
|
163
165
|
if picked is None:
|
|
164
166
|
raise typer.Exit(1)
|
|
165
167
|
if picked.startswith("[+]"):
|
|
@@ -177,9 +179,7 @@ def cmd_set_llm() -> None:
|
|
|
177
179
|
|
|
178
180
|
|
|
179
181
|
def _set_llm_new(svc: ConfigService) -> None:
|
|
180
|
-
name = questionary.text(
|
|
181
|
-
"Provider name (e.g. deepseek, qwen-plus, kimi):"
|
|
182
|
-
).ask()
|
|
182
|
+
name = questionary.text("Provider name (e.g. deepseek, qwen-plus, kimi):").ask()
|
|
183
183
|
if not name:
|
|
184
184
|
raise typer.Exit(1)
|
|
185
185
|
name = name.strip()
|
|
@@ -259,9 +259,7 @@ def _prompt_and_save_provider(
|
|
|
259
259
|
raise typer.Exit(2) from e
|
|
260
260
|
|
|
261
261
|
api_key_prompt = (
|
|
262
|
-
"API key (leave empty to keep existing):"
|
|
263
|
-
if defaults is not None
|
|
264
|
-
else "API key:"
|
|
262
|
+
"API key (leave empty to keep existing):" if defaults is not None else "API key:"
|
|
265
263
|
)
|
|
266
264
|
api_key = questionary.password(api_key_prompt).ask()
|
|
267
265
|
if api_key is None:
|
|
@@ -58,9 +58,7 @@ def _format_origin(resolved: ResolvedSource) -> str:
|
|
|
58
58
|
if resolved.origin == "local":
|
|
59
59
|
return f"本地路径 ({d.get('local_path', resolved.path)})"
|
|
60
60
|
if resolved.origin == "github_registry":
|
|
61
|
-
return (
|
|
62
|
-
f"GitHub 注册表 ({d['repo']}@{d['ref']}, subdir={d['subdir']})"
|
|
63
|
-
)
|
|
61
|
+
return f"GitHub 注册表 ({d['repo']}@{d['ref']}, subdir={d['subdir']})"
|
|
64
62
|
if resolved.origin == "github_url":
|
|
65
63
|
return f"GitHub URL ({d['repo']}@{d['ref']})"
|
|
66
64
|
return resolved.origin
|
|
@@ -68,9 +66,7 @@ def _format_origin(resolved: ResolvedSource) -> str:
|
|
|
68
66
|
|
|
69
67
|
@app.command("install")
|
|
70
68
|
def cmd_install(
|
|
71
|
-
source: str = typer.Argument(
|
|
72
|
-
..., help="短名(注册表)/ 本地路径 / GitHub URL"
|
|
73
|
-
),
|
|
69
|
+
source: str = typer.Argument(..., help="短名(注册表)/ 本地路径 / GitHub URL"),
|
|
74
70
|
ref: str | None = typer.Option(
|
|
75
71
|
None, "--ref", help="Tag / branch / sha (默认 = 该插件最新 release)"
|
|
76
72
|
),
|
|
@@ -150,9 +146,7 @@ def cmd_info(plugin_id: str = typer.Argument(...)) -> None:
|
|
|
150
146
|
try:
|
|
151
147
|
try:
|
|
152
148
|
rec = mgr.info(plugin_id)
|
|
153
|
-
typer.echo(
|
|
154
|
-
yaml.safe_dump(rec.metadata.model_dump(mode="json"), allow_unicode=True)
|
|
155
|
-
)
|
|
149
|
+
typer.echo(yaml.safe_dump(rec.metadata.model_dump(mode="json"), allow_unicode=True))
|
|
156
150
|
return
|
|
157
151
|
except PluginNotFoundError:
|
|
158
152
|
pass # fall through to registry lookup
|
|
@@ -237,9 +231,7 @@ def cmd_uninstall(
|
|
|
237
231
|
|
|
238
232
|
@app.command("upgrade")
|
|
239
233
|
def cmd_upgrade(
|
|
240
|
-
source: str = typer.Argument(
|
|
241
|
-
..., help="短名(注册表)/ 本地路径 / GitHub URL"
|
|
242
|
-
),
|
|
234
|
+
source: str = typer.Argument(..., help="短名(注册表)/ 本地路径 / GitHub URL"),
|
|
243
235
|
ref: str | None = typer.Option(
|
|
244
236
|
None, "--ref", help="Tag / branch / sha (默认 = 该插件最新 release)"
|
|
245
237
|
),
|
|
@@ -269,9 +261,7 @@ def cmd_upgrade(
|
|
|
269
261
|
pid = meta.plugin_id
|
|
270
262
|
except PluginInstallError:
|
|
271
263
|
pid = source
|
|
272
|
-
typer.echo(
|
|
273
|
-
f'✘ 插件 "{pid}" 未安装,请先执行 deeptrade plugin install'
|
|
274
|
-
)
|
|
264
|
+
typer.echo(f'✘ 插件 "{pid}" 未安装,请先执行 deeptrade plugin install')
|
|
275
265
|
raise typer.Exit(2) from e
|
|
276
266
|
except PluginInstallError as e:
|
|
277
267
|
typer.echo(f"✘ Upgrade failed: {e}")
|
|
@@ -293,9 +283,7 @@ def cmd_search(
|
|
|
293
283
|
keyword: str | None = typer.Argument(
|
|
294
284
|
None, help="可选过滤关键词(匹配 plugin_id / name / description)"
|
|
295
285
|
),
|
|
296
|
-
no_cache: bool = typer.Option(
|
|
297
|
-
False, "--no-cache", help="强制刷新注册表(旁路 ETag 缓存)"
|
|
298
|
-
),
|
|
286
|
+
no_cache: bool = typer.Option(False, "--no-cache", help="强制刷新注册表(旁路 ETag 缓存)"),
|
|
299
287
|
) -> None:
|
|
300
288
|
"""List plugins available in the official registry."""
|
|
301
289
|
try:
|
|
@@ -87,6 +87,11 @@ class AppConfig(BaseModel):
|
|
|
87
87
|
# tushare.* (token lives in secret_store)
|
|
88
88
|
tushare_rps: float = Field(default=6.0, gt=0)
|
|
89
89
|
tushare_timeout: int = Field(default=30, ge=1)
|
|
90
|
+
# Tenacity stop_after_attempt for transient errors (rate limit / server /
|
|
91
|
+
# transport). Default 7 keeps worst-case wait around one minute of
|
|
92
|
+
# jittered exponential backoff. Each attempt re-enters the token bucket,
|
|
93
|
+
# so retries never bypass rate limiting.
|
|
94
|
+
tushare_max_retries: int = Field(default=7, ge=1, le=20)
|
|
90
95
|
|
|
91
96
|
# Global preset name. v0.7 — renamed from ``deepseek.profile``; semantics
|
|
92
97
|
# are vendor-agnostic. Per-stage tuning is resolved by each plugin's
|
|
@@ -134,6 +139,7 @@ _DOT_TO_FIELD: dict[str, str] = {
|
|
|
134
139
|
"app.close_after": "app_close_after",
|
|
135
140
|
"tushare.rps": "tushare_rps",
|
|
136
141
|
"tushare.timeout": "tushare_timeout",
|
|
142
|
+
"tushare.max_retries": "tushare_max_retries",
|
|
137
143
|
"app.profile": "app_profile",
|
|
138
144
|
"llm.providers": "llm_providers",
|
|
139
145
|
"llm.audit_full_payload": "llm_audit_full_payload",
|
|
@@ -365,8 +371,7 @@ class ConfigService:
|
|
|
365
371
|
# already default; otherwise we'd leave the dict with no
|
|
366
372
|
# default at all. Preserve prior_default in that case.
|
|
367
373
|
other_has_default = any(
|
|
368
|
-
k != name and bool((v or {}).get("is_default"))
|
|
369
|
-
for k, v in current.items()
|
|
374
|
+
k != name and bool((v or {}).get("is_default")) for k, v in current.items()
|
|
370
375
|
)
|
|
371
376
|
new_default = prior_default if not other_has_default else False
|
|
372
377
|
|
|
@@ -374,7 +379,11 @@ class ConfigService:
|
|
|
374
379
|
# the invariant "at most one default" holds.
|
|
375
380
|
if new_default:
|
|
376
381
|
for other_name, other_cfg in current.items():
|
|
377
|
-
if
|
|
382
|
+
if (
|
|
383
|
+
other_name != name
|
|
384
|
+
and isinstance(other_cfg, dict)
|
|
385
|
+
and other_cfg.get("is_default")
|
|
386
|
+
):
|
|
378
387
|
current[other_name] = {**other_cfg, "is_default": False}
|
|
379
388
|
|
|
380
389
|
current[name] = {
|