deeptrade-quant 0.0.2__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.
Files changed (116) hide show
  1. deeptrade_quant-0.0.2/.gitignore +47 -0
  2. deeptrade_quant-0.0.2/LICENSE +21 -0
  3. deeptrade_quant-0.0.2/PKG-INFO +166 -0
  4. deeptrade_quant-0.0.2/README.md +133 -0
  5. deeptrade_quant-0.0.2/deeptrade/__init__.py +8 -0
  6. deeptrade_quant-0.0.2/deeptrade/channels_builtin/__init__.py +0 -0
  7. deeptrade_quant-0.0.2/deeptrade/channels_builtin/stdout/__init__.py +0 -0
  8. deeptrade_quant-0.0.2/deeptrade/channels_builtin/stdout/deeptrade_plugin.yaml +25 -0
  9. deeptrade_quant-0.0.2/deeptrade/channels_builtin/stdout/migrations/20260429_001_init.sql +13 -0
  10. deeptrade_quant-0.0.2/deeptrade/channels_builtin/stdout/stdout_channel/__init__.py +0 -0
  11. deeptrade_quant-0.0.2/deeptrade/channels_builtin/stdout/stdout_channel/channel.py +180 -0
  12. deeptrade_quant-0.0.2/deeptrade/cli.py +214 -0
  13. deeptrade_quant-0.0.2/deeptrade/cli_config.py +396 -0
  14. deeptrade_quant-0.0.2/deeptrade/cli_data.py +33 -0
  15. deeptrade_quant-0.0.2/deeptrade/cli_plugin.py +176 -0
  16. deeptrade_quant-0.0.2/deeptrade/core/__init__.py +8 -0
  17. deeptrade_quant-0.0.2/deeptrade/core/config.py +344 -0
  18. deeptrade_quant-0.0.2/deeptrade/core/config_migrations.py +138 -0
  19. deeptrade_quant-0.0.2/deeptrade/core/db.py +176 -0
  20. deeptrade_quant-0.0.2/deeptrade/core/llm_client.py +591 -0
  21. deeptrade_quant-0.0.2/deeptrade/core/llm_manager.py +174 -0
  22. deeptrade_quant-0.0.2/deeptrade/core/logging_config.py +61 -0
  23. deeptrade_quant-0.0.2/deeptrade/core/migrations/__init__.py +0 -0
  24. deeptrade_quant-0.0.2/deeptrade/core/migrations/core/20260427_001_init.sql +121 -0
  25. deeptrade_quant-0.0.2/deeptrade/core/migrations/core/20260501_002_drop_llm_calls_stage.sql +10 -0
  26. deeptrade_quant-0.0.2/deeptrade/core/migrations/core/__init__.py +0 -0
  27. deeptrade_quant-0.0.2/deeptrade/core/notifier.py +302 -0
  28. deeptrade_quant-0.0.2/deeptrade/core/paths.py +49 -0
  29. deeptrade_quant-0.0.2/deeptrade/core/plugin_manager.py +616 -0
  30. deeptrade_quant-0.0.2/deeptrade/core/run_status.py +29 -0
  31. deeptrade_quant-0.0.2/deeptrade/core/secrets.py +152 -0
  32. deeptrade_quant-0.0.2/deeptrade/core/tushare_client.py +824 -0
  33. deeptrade_quant-0.0.2/deeptrade/plugins_api/__init__.py +44 -0
  34. deeptrade_quant-0.0.2/deeptrade/plugins_api/base.py +66 -0
  35. deeptrade_quant-0.0.2/deeptrade/plugins_api/channel.py +42 -0
  36. deeptrade_quant-0.0.2/deeptrade/plugins_api/events.py +61 -0
  37. deeptrade_quant-0.0.2/deeptrade/plugins_api/llm.py +46 -0
  38. deeptrade_quant-0.0.2/deeptrade/plugins_api/metadata.py +84 -0
  39. deeptrade_quant-0.0.2/deeptrade/plugins_api/notify.py +67 -0
  40. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/__init__.py +0 -0
  41. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/limit_up_board/__init__.py +0 -0
  42. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/limit_up_board/deeptrade_plugin.yaml +101 -0
  43. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/limit_up_board/limit_up_board/__init__.py +0 -0
  44. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/limit_up_board/limit_up_board/calendar.py +65 -0
  45. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/limit_up_board/limit_up_board/cli.py +269 -0
  46. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/limit_up_board/limit_up_board/config.py +76 -0
  47. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/limit_up_board/limit_up_board/data.py +1191 -0
  48. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/limit_up_board/limit_up_board/pipeline.py +869 -0
  49. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/limit_up_board/limit_up_board/plugin.py +30 -0
  50. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/limit_up_board/limit_up_board/profiles.py +85 -0
  51. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/limit_up_board/limit_up_board/prompts.py +485 -0
  52. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/limit_up_board/limit_up_board/render.py +890 -0
  53. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/limit_up_board/limit_up_board/runner.py +1087 -0
  54. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/limit_up_board/limit_up_board/runtime.py +172 -0
  55. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/limit_up_board/limit_up_board/schemas.py +178 -0
  56. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/limit_up_board/migrations/20260430_001_init.sql +150 -0
  57. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/limit_up_board/migrations/20260501_002_lub_stage_results_llm_provider.sql +8 -0
  58. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/limit_up_board/migrations/20260508_001_lub_lhb_tables.sql +36 -0
  59. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/limit_up_board/migrations/20260508_002_lub_cyq_perf.sql +18 -0
  60. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/limit_up_board/migrations/20260508_003_lub_lhb_pk_fix.sql +46 -0
  61. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/limit_up_board/migrations/20260508_004_lub_lhb_drop_pk.sql +53 -0
  62. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/limit_up_board/migrations/20260508_005_lub_config.sql +17 -0
  63. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/volume_anomaly/__init__.py +0 -0
  64. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/volume_anomaly/deeptrade_plugin.yaml +59 -0
  65. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/volume_anomaly/migrations/20260430_001_init.sql +94 -0
  66. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/volume_anomaly/migrations/20260601_001_realized_returns.sql +44 -0
  67. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/volume_anomaly/migrations/20260601_002_dimension_scores.sql +13 -0
  68. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/__init__.py +0 -0
  69. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/calendar.py +52 -0
  70. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/cli.py +247 -0
  71. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/data.py +2154 -0
  72. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/pipeline.py +327 -0
  73. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/plugin.py +22 -0
  74. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/profiles.py +49 -0
  75. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/prompts.py +187 -0
  76. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/prompts_examples.py +84 -0
  77. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/render.py +906 -0
  78. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/runner.py +772 -0
  79. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/runtime.py +90 -0
  80. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/schemas.py +97 -0
  81. deeptrade_quant-0.0.2/deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/stats.py +174 -0
  82. deeptrade_quant-0.0.2/deeptrade/theme.py +48 -0
  83. deeptrade_quant-0.0.2/pyproject.toml +52 -0
  84. deeptrade_quant-0.0.2/tests/__init__.py +0 -0
  85. deeptrade_quant-0.0.2/tests/cli/__init__.py +0 -0
  86. deeptrade_quant-0.0.2/tests/cli/test_config_cmd.py +64 -0
  87. deeptrade_quant-0.0.2/tests/cli/test_routing.py +139 -0
  88. deeptrade_quant-0.0.2/tests/conftest.py +29 -0
  89. deeptrade_quant-0.0.2/tests/core/__init__.py +0 -0
  90. deeptrade_quant-0.0.2/tests/core/test_config.py +220 -0
  91. deeptrade_quant-0.0.2/tests/core/test_config_migrations.py +182 -0
  92. deeptrade_quant-0.0.2/tests/core/test_db.py +131 -0
  93. deeptrade_quant-0.0.2/tests/core/test_llm_client.py +427 -0
  94. deeptrade_quant-0.0.2/tests/core/test_llm_manager.py +175 -0
  95. deeptrade_quant-0.0.2/tests/core/test_notifier.py +189 -0
  96. deeptrade_quant-0.0.2/tests/core/test_paths.py +42 -0
  97. deeptrade_quant-0.0.2/tests/core/test_plugin_install.py +177 -0
  98. deeptrade_quant-0.0.2/tests/core/test_secrets.py +89 -0
  99. deeptrade_quant-0.0.2/tests/core/test_tushare_client.py +468 -0
  100. deeptrade_quant-0.0.2/tests/plugins_api/__init__.py +0 -0
  101. deeptrade_quant-0.0.2/tests/plugins_api/test_notify.py +94 -0
  102. deeptrade_quant-0.0.2/tests/plugins_api/test_protocol.py +55 -0
  103. deeptrade_quant-0.0.2/tests/strategies_builtin/__init__.py +0 -0
  104. deeptrade_quant-0.0.2/tests/strategies_builtin/limit_up_board/__init__.py +0 -0
  105. deeptrade_quant-0.0.2/tests/strategies_builtin/limit_up_board/test_phase_a_factors.py +250 -0
  106. deeptrade_quant-0.0.2/tests/strategies_builtin/limit_up_board/test_phase_b_factors.py +164 -0
  107. deeptrade_quant-0.0.2/tests/strategies_builtin/limit_up_board/test_v04_settings.py +150 -0
  108. deeptrade_quant-0.0.2/tests/strategies_builtin/volume_anomaly/__init__.py +0 -0
  109. deeptrade_quant-0.0.2/tests/strategies_builtin/volume_anomaly/test_alpha_features.py +201 -0
  110. deeptrade_quant-0.0.2/tests/strategies_builtin/volume_anomaly/test_candidate_features.py +344 -0
  111. deeptrade_quant-0.0.2/tests/strategies_builtin/volume_anomaly/test_dimension_scores.py +128 -0
  112. deeptrade_quant-0.0.2/tests/strategies_builtin/volume_anomaly/test_prompt_consistency.py +186 -0
  113. deeptrade_quant-0.0.2/tests/strategies_builtin/volume_anomaly/test_realized_returns.py +167 -0
  114. deeptrade_quant-0.0.2/tests/strategies_builtin/volume_anomaly/test_screen_rules.py +225 -0
  115. deeptrade_quant-0.0.2/tests/strategies_builtin/volume_anomaly/test_stats_query.py +167 -0
  116. deeptrade_quant-0.0.2/tests/test_smoke.py +34 -0
@@ -0,0 +1,47 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ *.egg
7
+ *.egg-info/
8
+ build/
9
+ dist/
10
+ .eggs/
11
+
12
+ # Virtual environments
13
+ .venv/
14
+ venv/
15
+ env/
16
+
17
+ # Tooling caches
18
+ .pytest_cache/
19
+ .ruff_cache/
20
+ .mypy_cache/
21
+ .coverage
22
+ htmlcov/
23
+ .tox/
24
+
25
+ # Editor
26
+ .idea/
27
+ .vscode/
28
+ *.swp
29
+ *.swo
30
+
31
+ # Environment
32
+ .env
33
+ .env.local
34
+
35
+ # DeepTrade local artifacts
36
+ .deeptrade/
37
+ dev.duckdb
38
+ dev.duckdb.wal
39
+ *.duckdb-wal
40
+
41
+ # Logs
42
+ *.log
43
+ logs/
44
+
45
+ # OS
46
+ .DS_Store
47
+ Thumbs.db
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 DeepTrade
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,166 @@
1
+ Metadata-Version: 2.4
2
+ Name: deeptrade-quant
3
+ Version: 0.0.2
4
+ Summary: LLM-driven A-share (Shanghai/Shenzhen main board) stock screening CLI
5
+ Project-URL: Homepage, https://github.com/ty19880929/deeptrade
6
+ Project-URL: Repository, https://github.com/ty19880929/deeptrade
7
+ Project-URL: Issues, https://github.com/ty19880929/deeptrade/issues
8
+ Author: DeepTrade
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: a-share,cli,deepseek,duckdb,llm,stock,tushare
12
+ Requires-Python: >=3.11
13
+ Requires-Dist: click>=8.1
14
+ Requires-Dist: duckdb>=1.0
15
+ Requires-Dist: keyring>=25.0
16
+ Requires-Dist: openai>=1.0
17
+ Requires-Dist: pandas>=2.2
18
+ Requires-Dist: pydantic>=2.7
19
+ Requires-Dist: pyyaml>=6.0
20
+ Requires-Dist: questionary>=2.0
21
+ Requires-Dist: rich>=13.7
22
+ Requires-Dist: tenacity>=8.0
23
+ Requires-Dist: tushare>=1.4
24
+ Requires-Dist: typer>=0.12
25
+ Provides-Extra: dev
26
+ Requires-Dist: mypy>=1.10; extra == 'dev'
27
+ Requires-Dist: pre-commit>=3.7; extra == 'dev'
28
+ Requires-Dist: pytest-mock>=3.12; extra == 'dev'
29
+ Requires-Dist: pytest>=8.0; extra == 'dev'
30
+ Requires-Dist: ruff>=0.5; extra == 'dev'
31
+ Requires-Dist: types-pyyaml>=6.0; extra == 'dev'
32
+ Description-Content-Type: text/markdown
33
+
34
+ # DeepTrade
35
+
36
+ > 本地运行的 A 股(沪深主板)选股 CLI 工具:tushare 行情 + OpenAI 兼容 LLM(DeepSeek / Qwen / Kimi …)+ DuckDB 单机仓库 + 插件式 CLI 框架。
37
+
38
+ [![tests](https://img.shields.io/badge/tests-passing-brightgreen)](#) [![python](https://img.shields.io/badge/python-3.11+-blue)](#) [![license](https://img.shields.io/badge/license-MIT-green)](LICENSE)
39
+
40
+ ## ✨ 主要特性
41
+
42
+ - **轻量本地化**:单文件 DuckDB + uv,一条命令跑完,无需服务进程或容器。
43
+ - **纯透传式插件 CLI**:框架命令面**封闭**——只管 `init / config / plugin / data`;其余命令一律按 `deeptrade <plugin_id> <argv...>` 透传给插件,插件自管 `--help`、子命令、参数、持久化。新增插件类型(皮肤、新数据源、回测、IM 渠道……)零框架改动。
44
+ - **数据隔离(Plan A)**:每个插件在自己的 migrations 里声明并拥有自己的表(含 tushare 派生数据),框架不持有任何业务表。`tushare_sync_state` / `tushare_calls` / `llm_calls` 都按 `plugin_id` 维度隔离。
45
+ - **顶层通知 API**:`from deeptrade import notify, notification_session` 一行发推送;框架根据已安装的 channel 插件自动路由,无 channel 时自动 noop。
46
+ - **多 LLM Provider 共存**:`llm.providers` 字典化配置,多个 OpenAI 兼容服务并存;插件通过 `LLMManager.get_client(name=...)` 按名取用,单次 run 内可调多家。
47
+ - **LLM 强约束**:JSON 模式 + Pydantic 双层校验;**永远**不传 tools / function calls。
48
+ - **盘中数据隔离**:`--allow-intraday` 模式下同步的不完整数据写入 `data_completeness='intraday'`,日终模式严格拒绝命中。
49
+
50
+ ## 🚀 5 分钟上手
51
+
52
+ ### 安装
53
+
54
+ ```bash
55
+ # 推荐
56
+ uv sync --all-extras
57
+ uv run pre-commit install
58
+
59
+ # 兜底(无 uv)
60
+ python -m venv .venv && source .venv/bin/activate # Windows: .\.venv\Scripts\activate
61
+ pip install -e ".[dev]"
62
+ ```
63
+
64
+ ### 初始化与配置
65
+
66
+ ```bash
67
+ deeptrade init # 建库 + 应用 core migrations
68
+ deeptrade config set-tushare # 交互式输入 tushare token
69
+ deeptrade config set-llm # 交互式增/改/删 LLM provider(deepseek / qwen / kimi …)
70
+ deeptrade config list-llm # 列出已配置且可用的 provider
71
+ deeptrade config test-llm # 对所有 provider 做连通性自检(也可加 <name> 单测)
72
+ deeptrade config show # 表格展示当前配置(密钥脱敏)
73
+ ```
74
+
75
+ ### 安装内置插件并运行
76
+
77
+ ```bash
78
+ # 安装一个 strategy 插件 + 一个 channel 插件
79
+ deeptrade plugin install ./deeptrade/strategies_builtin/limit_up_board -y
80
+ deeptrade plugin install ./deeptrade/channels_builtin/stdout -y
81
+
82
+ deeptrade plugin list # 查看已安装
83
+
84
+ # 运行打板策略(CLI 由插件自管,--help 由插件渲染)
85
+ deeptrade limit-up-board --help
86
+ deeptrade limit-up-board run # 默认日终模式
87
+ deeptrade limit-up-board run --allow-intraday --force-sync
88
+
89
+ # 运行成交量异动策略(三模式)
90
+ deeptrade volume-anomaly screen # 异动筛选 → upsert va_watchlist
91
+ deeptrade volume-anomaly analyze # LLM 主升浪启动预测
92
+ deeptrade volume-anomaly prune --days 30 # 剔除追踪 ≥30 日的标的
93
+
94
+ # 推送链路自检
95
+ deeptrade stdout-channel test
96
+ ```
97
+
98
+ 报告产出在 `~/.deeptrade/reports/<run_id>/`。
99
+
100
+ ## 📦 命令矩阵
101
+
102
+ ### 框架命令(封闭集合)
103
+
104
+ | 命令 | 用途 |
105
+ |---|---|
106
+ | `deeptrade --version` / `-V` | 显示版本 |
107
+ | `deeptrade --help` / `-h` | 框架命令清单(**不**枚举插件子命令) |
108
+ | `deeptrade init [--no-prompts]` | 建库 + 应用 core migrations |
109
+ | `deeptrade config {show, set, set-tushare, set-llm, list-llm, test-llm}` | 全局配置 |
110
+ | `deeptrade plugin install <path> [-y]` | 本地路径安装(绝不联网) |
111
+ | `deeptrade plugin list / info <id>` | 列表 / 详情 |
112
+ | `deeptrade plugin enable <id> / disable <id>` | 启 / 停 |
113
+ | `deeptrade plugin uninstall <id> [--purge]` | 卸载(`--purge` 才 DROP 表) |
114
+ | `deeptrade plugin upgrade <path>` | 升级(增量 migrations) |
115
+ | `deeptrade data sync ...` | (暂停用,下版本恢复) |
116
+
117
+ 保留字(不可作为 plugin_id):`init / config / plugin / data`。
118
+
119
+ ### 插件命令(按 plugin_id 透传,插件自管)
120
+
121
+ | 命令 | 来源 |
122
+ |---|---|
123
+ | `deeptrade limit-up-board {run, sync, history, report}` | 内建打板策略插件 |
124
+ | `deeptrade volume-anomaly {screen, analyze, prune, history, report}` | 内建成交量异动插件 |
125
+ | `deeptrade stdout-channel {test, log}` | 内建 stdout 通知插件 |
126
+ | `deeptrade <你的-plugin-id> ...` | 你自己写的任何插件 |
127
+
128
+ 任意插件子命令的 `--help` 都由插件自身渲染——框架不感知动词语义。
129
+
130
+ ## 🧱 架构
131
+
132
+ ```
133
+ ┌──────────────────────── deeptrade CLI (custom click.Group) ────────────────────────┐
134
+ │ │
135
+ │ framework commands (closed): │
136
+ │ init │ config │ plugin │ data │
137
+ │ │
138
+ │ plugin pass-through (open): │
139
+ │ <plugin_id> ──argv──→ Plugin.dispatch(argv) → int (plugin owns the rest) │
140
+ └──────────────────────────────────┬─────────────────────────────────────────────────┘
141
+
142
+ ┌──────────────────────┼──────────────────────────┐
143
+ ▼ ▼ ▼
144
+ ┌─────────────────┐ ┌──────────────────┐ ┌────────────────────┐
145
+ │ Core services │ │ deeptrade.notify │ │ Plugins (any type)│
146
+ │ DuckDB · Config │ │ → routes to all │ │ • metadata │
147
+ │ Tushare · LLM │ │ enabled │ │ • validate_static │
148
+ │ Notifier │ │ channel plugins│ │ • dispatch(argv) │
149
+ └─────────────────┘ └──────────────────┘ │ (channel: + push) │
150
+ └────────────────────┘
151
+ ```
152
+
153
+ 设计决策见 [docs/plugin_cli_dispatch_evaluation.md](docs/plugin_cli_dispatch_evaluation.md)。
154
+
155
+ ## 📖 文档
156
+
157
+ - [DESIGN.md](DESIGN.md) — 设计文档
158
+ - [docs/plugin_cli_dispatch_evaluation.md](docs/plugin_cli_dispatch_evaluation.md) — 当前架构的评估与决策记录(v0.3)
159
+ - [docs/quick-start.md](docs/quick-start.md) — 上手指南
160
+ - [docs/plugin-development.md](docs/plugin-development.md) — 写一个新插件
161
+ - [docs/limit-up-board.md](docs/limit-up-board.md) — 打板策略说明
162
+ - [CHANGELOG.md](CHANGELOG.md) — 版本变更
163
+
164
+ ## ⚖️ 免责声明
165
+
166
+ 本工具仅用于策略研究、数据整理与候选标的分析,**不构成投资建议**,**不进行自动交易**。所有 LLM 输出基于提交的结构化数据,不引用任何外部信息源;用户应自行核验候选标的的最新状态后再做决策。
@@ -0,0 +1,133 @@
1
+ # DeepTrade
2
+
3
+ > 本地运行的 A 股(沪深主板)选股 CLI 工具:tushare 行情 + OpenAI 兼容 LLM(DeepSeek / Qwen / Kimi …)+ DuckDB 单机仓库 + 插件式 CLI 框架。
4
+
5
+ [![tests](https://img.shields.io/badge/tests-passing-brightgreen)](#) [![python](https://img.shields.io/badge/python-3.11+-blue)](#) [![license](https://img.shields.io/badge/license-MIT-green)](LICENSE)
6
+
7
+ ## ✨ 主要特性
8
+
9
+ - **轻量本地化**:单文件 DuckDB + uv,一条命令跑完,无需服务进程或容器。
10
+ - **纯透传式插件 CLI**:框架命令面**封闭**——只管 `init / config / plugin / data`;其余命令一律按 `deeptrade <plugin_id> <argv...>` 透传给插件,插件自管 `--help`、子命令、参数、持久化。新增插件类型(皮肤、新数据源、回测、IM 渠道……)零框架改动。
11
+ - **数据隔离(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
+ - **多 LLM Provider 共存**:`llm.providers` 字典化配置,多个 OpenAI 兼容服务并存;插件通过 `LLMManager.get_client(name=...)` 按名取用,单次 run 内可调多家。
14
+ - **LLM 强约束**:JSON 模式 + Pydantic 双层校验;**永远**不传 tools / function calls。
15
+ - **盘中数据隔离**:`--allow-intraday` 模式下同步的不完整数据写入 `data_completeness='intraday'`,日终模式严格拒绝命中。
16
+
17
+ ## 🚀 5 分钟上手
18
+
19
+ ### 安装
20
+
21
+ ```bash
22
+ # 推荐
23
+ uv sync --all-extras
24
+ uv run pre-commit install
25
+
26
+ # 兜底(无 uv)
27
+ python -m venv .venv && source .venv/bin/activate # Windows: .\.venv\Scripts\activate
28
+ pip install -e ".[dev]"
29
+ ```
30
+
31
+ ### 初始化与配置
32
+
33
+ ```bash
34
+ deeptrade init # 建库 + 应用 core migrations
35
+ deeptrade config set-tushare # 交互式输入 tushare token
36
+ deeptrade config set-llm # 交互式增/改/删 LLM provider(deepseek / qwen / kimi …)
37
+ deeptrade config list-llm # 列出已配置且可用的 provider
38
+ deeptrade config test-llm # 对所有 provider 做连通性自检(也可加 <name> 单测)
39
+ deeptrade config show # 表格展示当前配置(密钥脱敏)
40
+ ```
41
+
42
+ ### 安装内置插件并运行
43
+
44
+ ```bash
45
+ # 安装一个 strategy 插件 + 一个 channel 插件
46
+ deeptrade plugin install ./deeptrade/strategies_builtin/limit_up_board -y
47
+ deeptrade plugin install ./deeptrade/channels_builtin/stdout -y
48
+
49
+ deeptrade plugin list # 查看已安装
50
+
51
+ # 运行打板策略(CLI 由插件自管,--help 由插件渲染)
52
+ deeptrade limit-up-board --help
53
+ deeptrade limit-up-board run # 默认日终模式
54
+ deeptrade limit-up-board run --allow-intraday --force-sync
55
+
56
+ # 运行成交量异动策略(三模式)
57
+ deeptrade volume-anomaly screen # 异动筛选 → upsert va_watchlist
58
+ deeptrade volume-anomaly analyze # LLM 主升浪启动预测
59
+ deeptrade volume-anomaly prune --days 30 # 剔除追踪 ≥30 日的标的
60
+
61
+ # 推送链路自检
62
+ deeptrade stdout-channel test
63
+ ```
64
+
65
+ 报告产出在 `~/.deeptrade/reports/<run_id>/`。
66
+
67
+ ## 📦 命令矩阵
68
+
69
+ ### 框架命令(封闭集合)
70
+
71
+ | 命令 | 用途 |
72
+ |---|---|
73
+ | `deeptrade --version` / `-V` | 显示版本 |
74
+ | `deeptrade --help` / `-h` | 框架命令清单(**不**枚举插件子命令) |
75
+ | `deeptrade init [--no-prompts]` | 建库 + 应用 core migrations |
76
+ | `deeptrade config {show, set, set-tushare, set-llm, list-llm, test-llm}` | 全局配置 |
77
+ | `deeptrade plugin install <path> [-y]` | 本地路径安装(绝不联网) |
78
+ | `deeptrade plugin list / info <id>` | 列表 / 详情 |
79
+ | `deeptrade plugin enable <id> / disable <id>` | 启 / 停 |
80
+ | `deeptrade plugin uninstall <id> [--purge]` | 卸载(`--purge` 才 DROP 表) |
81
+ | `deeptrade plugin upgrade <path>` | 升级(增量 migrations) |
82
+ | `deeptrade data sync ...` | (暂停用,下版本恢复) |
83
+
84
+ 保留字(不可作为 plugin_id):`init / config / plugin / data`。
85
+
86
+ ### 插件命令(按 plugin_id 透传,插件自管)
87
+
88
+ | 命令 | 来源 |
89
+ |---|---|
90
+ | `deeptrade limit-up-board {run, sync, history, report}` | 内建打板策略插件 |
91
+ | `deeptrade volume-anomaly {screen, analyze, prune, history, report}` | 内建成交量异动插件 |
92
+ | `deeptrade stdout-channel {test, log}` | 内建 stdout 通知插件 |
93
+ | `deeptrade <你的-plugin-id> ...` | 你自己写的任何插件 |
94
+
95
+ 任意插件子命令的 `--help` 都由插件自身渲染——框架不感知动词语义。
96
+
97
+ ## 🧱 架构
98
+
99
+ ```
100
+ ┌──────────────────────── deeptrade CLI (custom click.Group) ────────────────────────┐
101
+ │ │
102
+ │ framework commands (closed): │
103
+ │ init │ config │ plugin │ data │
104
+ │ │
105
+ │ plugin pass-through (open): │
106
+ │ <plugin_id> ──argv──→ Plugin.dispatch(argv) → int (plugin owns the rest) │
107
+ └──────────────────────────────────┬─────────────────────────────────────────────────┘
108
+
109
+ ┌──────────────────────┼──────────────────────────┐
110
+ ▼ ▼ ▼
111
+ ┌─────────────────┐ ┌──────────────────┐ ┌────────────────────┐
112
+ │ Core services │ │ deeptrade.notify │ │ Plugins (any type)│
113
+ │ DuckDB · Config │ │ → routes to all │ │ • metadata │
114
+ │ Tushare · LLM │ │ enabled │ │ • validate_static │
115
+ │ Notifier │ │ channel plugins│ │ • dispatch(argv) │
116
+ └─────────────────┘ └──────────────────┘ │ (channel: + push) │
117
+ └────────────────────┘
118
+ ```
119
+
120
+ 设计决策见 [docs/plugin_cli_dispatch_evaluation.md](docs/plugin_cli_dispatch_evaluation.md)。
121
+
122
+ ## 📖 文档
123
+
124
+ - [DESIGN.md](DESIGN.md) — 设计文档
125
+ - [docs/plugin_cli_dispatch_evaluation.md](docs/plugin_cli_dispatch_evaluation.md) — 当前架构的评估与决策记录(v0.3)
126
+ - [docs/quick-start.md](docs/quick-start.md) — 上手指南
127
+ - [docs/plugin-development.md](docs/plugin-development.md) — 写一个新插件
128
+ - [docs/limit-up-board.md](docs/limit-up-board.md) — 打板策略说明
129
+ - [CHANGELOG.md](CHANGELOG.md) — 版本变更
130
+
131
+ ## ⚖️ 免责声明
132
+
133
+ 本工具仅用于策略研究、数据整理与候选标的分析,**不构成投资建议**,**不进行自动交易**。所有 LLM 输出基于提交的结构化数据,不引用任何外部信息源;用户应自行核验候选标的的最新状态后再做决策。
@@ -0,0 +1,8 @@
1
+ """DeepTrade — LLM-driven A-share stock screening CLI."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from deeptrade.core.notifier import notification_session, notify
6
+
7
+ __version__ = "0.0.1"
8
+ __all__ = ["__version__", "notification_session", "notify"]
@@ -0,0 +1,25 @@
1
+ plugin_id: stdout-channel
2
+ name: Stdout Channel
3
+ version: 0.1.0
4
+ type: channel
5
+ api_version: "1"
6
+ entrypoint: stdout_channel.channel:StdoutChannel
7
+ description: Reference notification channel — fully consumes the payload but only prints "✔ push success" to stdout.
8
+ author: DeepTrade
9
+
10
+ permissions:
11
+ tushare_apis:
12
+ required: []
13
+ optional: []
14
+ llm: false
15
+ llm_tools: false
16
+
17
+ migrations:
18
+ - version: "20260429_001"
19
+ file: migrations/20260429_001_init.sql
20
+ checksum: "sha256:7317d23d4ac91b9a1259e2ba4d990863491de8fe1115e19052b02f83939399cc"
21
+
22
+ tables:
23
+ - name: stdout_channel_log
24
+ description: Audit log of payloads delivered through the stdout channel
25
+ purge_on_uninstall: true
@@ -0,0 +1,13 @@
1
+ -- stdout channel: delivery log so we can verify the payload was actually
2
+ -- consumed (not just acknowledged with a fake "✔ push success").
3
+ CREATE TABLE IF NOT EXISTS stdout_channel_log (
4
+ delivered_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
5
+ plugin_id VARCHAR NOT NULL,
6
+ run_id UUID NOT NULL,
7
+ status VARCHAR NOT NULL,
8
+ title VARCHAR NOT NULL,
9
+ section_count INTEGER NOT NULL,
10
+ item_count INTEGER NOT NULL,
11
+ metric_count INTEGER NOT NULL,
12
+ PRIMARY KEY (run_id, plugin_id, delivered_at)
13
+ );
@@ -0,0 +1,180 @@
1
+ """Stdout reference channel plugin.
2
+
3
+ Implements the framework's ``ChannelPlugin`` Protocol:
4
+ * ``validate_static`` — install-time self-check (no network)
5
+ * ``dispatch(argv)`` — CLI dispatch (subcommands: test, log)
6
+ * ``push(ctx, payload)`` — receive a NotificationPayload from the notifier
7
+
8
+ Behaviour on push:
9
+ * FULLY consume the NotificationPayload (walk every section/item/metric)
10
+ so any structural bug surfaces immediately.
11
+ * Persist a one-row audit record to ``stdout_channel_log``.
12
+ * Emit ONE concise line: "✔ push success (...)".
13
+
14
+ This channel is the zero-dependency target for unit tests of the notify
15
+ plumbing and is safe to ship enabled-by-default in dev installs.
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ import argparse
21
+ import sys
22
+ from typing import TYPE_CHECKING
23
+
24
+ if TYPE_CHECKING: # pragma: no cover
25
+ from deeptrade.plugins_api.base import PluginContext
26
+ from deeptrade.plugins_api.notify import NotificationPayload
27
+
28
+
29
+ class StdoutChannel:
30
+ """Stdout-only IM channel plugin."""
31
+
32
+ metadata = None # injected by framework after install
33
+
34
+ # ----- Plugin Protocol -------------------------------------------------
35
+
36
+ def validate_static(self, ctx: PluginContext) -> None: # noqa: ARG002
37
+ # Sanity: the audit table must exist (created by our own migration).
38
+ # If it's missing, the install pipeline already failed; this is just a
39
+ # belt-and-braces self-check that doesn't touch the network.
40
+ return
41
+
42
+ def dispatch(self, argv: list[str]) -> int:
43
+ """Channel-side CLI: ``test`` and ``log``.
44
+
45
+ ``test`` synthesizes a minimal payload and routes it back through this
46
+ channel's own ``push`` so the user can verify the channel is wired up
47
+ without running a real strategy. ``log`` dumps the most recent
48
+ ``stdout_channel_log`` rows.
49
+ """
50
+ parser = argparse.ArgumentParser(
51
+ prog="deeptrade stdout-channel",
52
+ description="Stdout notification channel — local self-test + audit log.",
53
+ )
54
+ sub = parser.add_subparsers(dest="cmd", required=False)
55
+
56
+ sub.add_parser("test", help="Push a synthetic payload through this channel.")
57
+ log_p = sub.add_parser("log", help="Print recent delivery audit rows.")
58
+ log_p.add_argument("--limit", type=int, default=20)
59
+
60
+ args = parser.parse_args(argv)
61
+ if args.cmd is None:
62
+ parser.print_help()
63
+ return 0
64
+ if args.cmd == "test":
65
+ return self._cmd_test()
66
+ if args.cmd == "log":
67
+ return self._cmd_log(args.limit)
68
+ return 2
69
+
70
+ # ----- ChannelPlugin Protocol ------------------------------------------
71
+
72
+ def push(self, ctx: PluginContext, payload: NotificationPayload) -> None:
73
+ # 1) Walk the payload — counts come from real iteration, never from
74
+ # dict.len(), so we cannot "succeed" without having actually read the
75
+ # plugin's data.
76
+ section_count = len(payload.sections)
77
+ item_count = sum(len(s.items) for s in payload.sections)
78
+ metric_count = len(payload.metrics)
79
+ for section in payload.sections:
80
+ for item in section.items:
81
+ _ = (item.code, item.name, item.rank, item.score, item.label, item.note)
82
+ for k, v in payload.metrics.items():
83
+ _ = (k, v)
84
+ _ = payload.title, payload.summary, payload.report_dir, payload.extras
85
+
86
+ # 2) Persist a delivery audit row.
87
+ ctx.db.execute(
88
+ "INSERT INTO stdout_channel_log(plugin_id, run_id, status, title, "
89
+ "section_count, item_count, metric_count) VALUES (?, ?, ?, ?, ?, ?, ?)",
90
+ (
91
+ payload.plugin_id,
92
+ payload.run_id,
93
+ payload.status.value,
94
+ payload.title,
95
+ section_count,
96
+ item_count,
97
+ metric_count,
98
+ ),
99
+ )
100
+
101
+ # 3) One concise line. Use sys.stdout (not rich console) so this stays
102
+ # out of any TUI / strategy console that the caller may have running.
103
+ sys.stdout.write(
104
+ f"✔ push success (channel=stdout-channel run_id={payload.run_id} "
105
+ f"status={payload.status.value})\n"
106
+ )
107
+ sys.stdout.flush()
108
+
109
+ # ----- private helpers -------------------------------------------------
110
+
111
+ def _cmd_test(self) -> int:
112
+ """Round-trip a synthetic payload through ``deeptrade.notify``.
113
+
114
+ Goes through the framework's notifier layer (not directly through
115
+ ``self.push``) so the test exercises the full path: install →
116
+ build_notifier → dispatch → push.
117
+ """
118
+ import uuid
119
+
120
+ from deeptrade import notify
121
+ from deeptrade.core import paths
122
+ from deeptrade.core.db import Database
123
+ from deeptrade.core.run_status import RunStatus
124
+ from deeptrade.plugins_api.notify import (
125
+ NotificationItem,
126
+ NotificationPayload,
127
+ NotificationSection,
128
+ )
129
+
130
+ payload = NotificationPayload(
131
+ plugin_id="stdout-channel",
132
+ run_id=str(uuid.uuid4()),
133
+ status=RunStatus.SUCCESS,
134
+ title="DeepTrade — stdout channel test",
135
+ summary="Synthetic payload from `deeptrade stdout-channel test`.",
136
+ sections=[
137
+ NotificationSection(
138
+ key="demo",
139
+ title="Demo items",
140
+ items=[
141
+ NotificationItem(
142
+ code="600519.SH", name="贵州茅台", rank=1, score=87.5,
143
+ label="top_candidate", note="演示条目,非真实推荐",
144
+ ),
145
+ ],
146
+ ),
147
+ ],
148
+ metrics={"selected": 1},
149
+ )
150
+ db = Database(paths.db_path())
151
+ try:
152
+ notify(db, payload)
153
+ finally:
154
+ db.close()
155
+ return 0
156
+
157
+ def _cmd_log(self, limit: int) -> int:
158
+ from deeptrade.core import paths
159
+ from deeptrade.core.db import Database
160
+
161
+ db = Database(paths.db_path())
162
+ try:
163
+ rows = db.fetchall(
164
+ "SELECT delivered_at, plugin_id, run_id, status, title, "
165
+ "section_count, item_count, metric_count "
166
+ "FROM stdout_channel_log ORDER BY delivered_at DESC LIMIT ?",
167
+ (limit,),
168
+ )
169
+ finally:
170
+ db.close()
171
+
172
+ if not rows:
173
+ sys.stdout.write("(no deliveries yet)\n")
174
+ return 0
175
+ for r in rows:
176
+ sys.stdout.write(
177
+ f"{r[0]} {r[1]:<20} {r[3]:<8} sec={r[5]} item={r[6]} "
178
+ f"metric={r[7]} {r[4]}\n"
179
+ )
180
+ return 0