deeptrade-quant 0.1.0__tar.gz → 0.2.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.
Files changed (115) hide show
  1. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/PKG-INFO +23 -7
  2. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/README.md +22 -6
  3. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/deeptrade/__init__.py +1 -1
  4. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/deeptrade/core/notifier.py +3 -2
  5. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/pyproject.toml +1 -1
  6. deeptrade_quant-0.1.0/deeptrade/channels_builtin/stdout/deeptrade_plugin.yaml +0 -25
  7. deeptrade_quant-0.1.0/deeptrade/channels_builtin/stdout/migrations/20260509_001_init.sql +0 -13
  8. deeptrade_quant-0.1.0/deeptrade/channels_builtin/stdout/stdout_channel/channel.py +0 -180
  9. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/limit_up_board/__init__.py +0 -0
  10. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/limit_up_board/deeptrade_plugin.yaml +0 -83
  11. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/limit_up_board/limit_up_board/__init__.py +0 -0
  12. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/limit_up_board/limit_up_board/calendar.py +0 -65
  13. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/limit_up_board/limit_up_board/cli.py +0 -269
  14. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/limit_up_board/limit_up_board/config.py +0 -76
  15. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/limit_up_board/limit_up_board/data.py +0 -1191
  16. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/limit_up_board/limit_up_board/pipeline.py +0 -869
  17. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/limit_up_board/limit_up_board/plugin.py +0 -30
  18. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/limit_up_board/limit_up_board/profiles.py +0 -85
  19. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/limit_up_board/limit_up_board/prompts.py +0 -485
  20. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/limit_up_board/limit_up_board/render.py +0 -890
  21. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/limit_up_board/limit_up_board/runner.py +0 -1087
  22. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/limit_up_board/limit_up_board/runtime.py +0 -164
  23. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/limit_up_board/limit_up_board/schemas.py +0 -178
  24. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/limit_up_board/migrations/20260509_001_init.sql +0 -188
  25. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/volume_anomaly/__init__.py +0 -0
  26. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/volume_anomaly/deeptrade_plugin.yaml +0 -53
  27. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/volume_anomaly/migrations/20260509_001_init.sql +0 -111
  28. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/__init__.py +0 -0
  29. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/calendar.py +0 -52
  30. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/cli.py +0 -246
  31. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/data.py +0 -2157
  32. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/pipeline.py +0 -327
  33. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/plugin.py +0 -22
  34. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/profiles.py +0 -49
  35. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/prompts.py +0 -187
  36. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/prompts_examples.py +0 -84
  37. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/render.py +0 -906
  38. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/runner.py +0 -772
  39. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/runtime.py +0 -84
  40. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/schemas.py +0 -97
  41. deeptrade_quant-0.1.0/deeptrade/strategies_builtin/volume_anomaly/volume_anomaly/stats.py +0 -174
  42. deeptrade_quant-0.1.0/tests/__init__.py +0 -0
  43. deeptrade_quant-0.1.0/tests/cli/__init__.py +0 -0
  44. deeptrade_quant-0.1.0/tests/core/__init__.py +0 -0
  45. deeptrade_quant-0.1.0/tests/plugins_api/__init__.py +0 -0
  46. deeptrade_quant-0.1.0/tests/strategies_builtin/__init__.py +0 -0
  47. deeptrade_quant-0.1.0/tests/strategies_builtin/limit_up_board/__init__.py +0 -0
  48. deeptrade_quant-0.1.0/tests/strategies_builtin/limit_up_board/test_phase_a_factors.py +0 -250
  49. deeptrade_quant-0.1.0/tests/strategies_builtin/limit_up_board/test_phase_b_factors.py +0 -164
  50. deeptrade_quant-0.1.0/tests/strategies_builtin/limit_up_board/test_v04_settings.py +0 -150
  51. deeptrade_quant-0.1.0/tests/strategies_builtin/volume_anomaly/__init__.py +0 -0
  52. deeptrade_quant-0.1.0/tests/strategies_builtin/volume_anomaly/test_alpha_features.py +0 -201
  53. deeptrade_quant-0.1.0/tests/strategies_builtin/volume_anomaly/test_candidate_features.py +0 -343
  54. deeptrade_quant-0.1.0/tests/strategies_builtin/volume_anomaly/test_dimension_scores.py +0 -128
  55. deeptrade_quant-0.1.0/tests/strategies_builtin/volume_anomaly/test_prompt_consistency.py +0 -185
  56. deeptrade_quant-0.1.0/tests/strategies_builtin/volume_anomaly/test_realized_returns.py +0 -165
  57. deeptrade_quant-0.1.0/tests/strategies_builtin/volume_anomaly/test_screen_rules.py +0 -224
  58. deeptrade_quant-0.1.0/tests/strategies_builtin/volume_anomaly/test_stats_query.py +0 -166
  59. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/.gitignore +0 -0
  60. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/LICENSE +0 -0
  61. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/deeptrade/cli.py +0 -0
  62. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/deeptrade/cli_config.py +0 -0
  63. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/deeptrade/cli_data.py +0 -0
  64. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/deeptrade/cli_plugin.py +0 -0
  65. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/deeptrade/core/__init__.py +0 -0
  66. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/deeptrade/core/config.py +0 -0
  67. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/deeptrade/core/config_migrations.py +0 -0
  68. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/deeptrade/core/db.py +0 -0
  69. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/deeptrade/core/github_fetch.py +0 -0
  70. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/deeptrade/core/llm_client.py +0 -0
  71. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/deeptrade/core/llm_manager.py +0 -0
  72. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/deeptrade/core/logging_config.py +0 -0
  73. {deeptrade_quant-0.1.0/deeptrade/channels_builtin → deeptrade_quant-0.2.0/deeptrade/core/migrations}/__init__.py +0 -0
  74. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/deeptrade/core/migrations/core/20260509_001_init.sql +0 -0
  75. {deeptrade_quant-0.1.0/deeptrade/channels_builtin/stdout → deeptrade_quant-0.2.0/deeptrade/core/migrations/core}/__init__.py +0 -0
  76. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/deeptrade/core/paths.py +0 -0
  77. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/deeptrade/core/plugin_manager.py +0 -0
  78. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/deeptrade/core/plugin_source.py +0 -0
  79. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/deeptrade/core/registry.py +0 -0
  80. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/deeptrade/core/run_status.py +0 -0
  81. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/deeptrade/core/secrets.py +0 -0
  82. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/deeptrade/core/tushare_client.py +0 -0
  83. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/deeptrade/plugins_api/__init__.py +0 -0
  84. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/deeptrade/plugins_api/base.py +0 -0
  85. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/deeptrade/plugins_api/channel.py +0 -0
  86. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/deeptrade/plugins_api/events.py +0 -0
  87. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/deeptrade/plugins_api/llm.py +0 -0
  88. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/deeptrade/plugins_api/metadata.py +0 -0
  89. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/deeptrade/plugins_api/notify.py +0 -0
  90. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/deeptrade/theme.py +0 -0
  91. {deeptrade_quant-0.1.0/deeptrade/channels_builtin/stdout/stdout_channel → deeptrade_quant-0.2.0/tests}/__init__.py +0 -0
  92. {deeptrade_quant-0.1.0/deeptrade/core/migrations → deeptrade_quant-0.2.0/tests/cli}/__init__.py +0 -0
  93. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/tests/cli/test_config_cmd.py +0 -0
  94. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/tests/cli/test_plugin_cmd.py +0 -0
  95. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/tests/cli/test_routing.py +0 -0
  96. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/tests/conftest.py +0 -0
  97. {deeptrade_quant-0.1.0/deeptrade/core/migrations → deeptrade_quant-0.2.0/tests}/core/__init__.py +0 -0
  98. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/tests/core/test_config.py +0 -0
  99. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/tests/core/test_config_migrations.py +0 -0
  100. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/tests/core/test_db.py +0 -0
  101. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/tests/core/test_github_fetch.py +0 -0
  102. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/tests/core/test_llm_client.py +0 -0
  103. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/tests/core/test_llm_manager.py +0 -0
  104. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/tests/core/test_notifier.py +0 -0
  105. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/tests/core/test_paths.py +0 -0
  106. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/tests/core/test_plugin_install.py +0 -0
  107. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/tests/core/test_plugin_source.py +0 -0
  108. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/tests/core/test_plugin_upgrade.py +0 -0
  109. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/tests/core/test_registry.py +0 -0
  110. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/tests/core/test_secrets.py +0 -0
  111. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/tests/core/test_tushare_client.py +0 -0
  112. {deeptrade_quant-0.1.0/deeptrade/strategies_builtin → deeptrade_quant-0.2.0/tests/plugins_api}/__init__.py +0 -0
  113. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/tests/plugins_api/test_notify.py +0 -0
  114. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/tests/plugins_api/test_protocol.py +0 -0
  115. {deeptrade_quant-0.1.0 → deeptrade_quant-0.2.0}/tests/test_smoke.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: deeptrade-quant
3
- Version: 0.1.0
3
+ Version: 0.2.0
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
@@ -53,10 +53,18 @@ Description-Content-Type: text/markdown
53
53
  ### 安装
54
54
 
55
55
  ```bash
56
- # 推荐
56
+ # 推荐:pipx 隔离环境(命令名仍是 deeptrade)
57
+ pipx install deeptrade-quant
58
+ # 或
59
+ uv tool install deeptrade-quant
60
+ ```
61
+
62
+ > **注**:PyPI 项目名是 `deeptrade-quant`,CLI 命令是 `deeptrade`,Python 包名是 `deeptrade`(`import deeptrade`)。三者不同是 Python 生态常态(同 `pip install scikit-learn` → `import sklearn`)。
63
+
64
+ ```bash
65
+ # 开发模式(克隆本仓库,editable install)
57
66
  uv sync --all-extras
58
67
  uv run pre-commit install
59
-
60
68
  # 兜底(无 uv)
61
69
  python -m venv .venv && source .venv/bin/activate # Windows: .\.venv\Scripts\activate
62
70
  pip install -e ".[dev]"
@@ -73,12 +81,18 @@ deeptrade config test-llm # 对所有 provider 做连通性自
73
81
  deeptrade config show # 表格展示当前配置(密钥脱敏)
74
82
  ```
75
83
 
76
- ### 安装内置插件并运行
84
+ ### 安装官方插件并运行
85
+
86
+ 官方插件维护在 [DeepTradePluginOfficial](https://github.com/ty19880929/DeepTradePluginOfficial),框架通过短名查注册表 → 拉 GitHub release tarball 自动安装。
77
87
 
78
88
  ```bash
79
- # 安装一个 strategy 插件 + 一个 channel 插件
80
- deeptrade plugin install ./deeptrade/strategies_builtin/limit_up_board -y
81
- deeptrade plugin install ./deeptrade/channels_builtin/stdout -y
89
+ # 浏览注册表
90
+ deeptrade plugin search
91
+
92
+ # 按短名安装(注册表 → 最新 release tag)
93
+ deeptrade plugin install limit-up-board
94
+ deeptrade plugin install volume-anomaly
95
+ deeptrade plugin install stdout-channel
82
96
 
83
97
  deeptrade plugin list # 查看已安装
84
98
 
@@ -96,6 +110,8 @@ deeptrade volume-anomaly prune --days 30 # 剔除追踪 ≥30 日的标的
96
110
  deeptrade stdout-channel test
97
111
  ```
98
112
 
113
+ > **第三方插件 / 本地开发**:`deeptrade plugin install ./path/to/my-plugin` 仍可装本地目录;`deeptrade plugin install https://github.com/owner/repo` 装完整 git 仓库(仓库根需含 `deeptrade_plugin.yaml`)。详见 [`docs/plugin-development.md`](docs/plugin-development.md)。
114
+
99
115
  报告产出在 `~/.deeptrade/reports/<run_id>/`。
100
116
 
101
117
  ## 📦 命令矩阵
@@ -19,10 +19,18 @@
19
19
  ### 安装
20
20
 
21
21
  ```bash
22
- # 推荐
22
+ # 推荐:pipx 隔离环境(命令名仍是 deeptrade)
23
+ pipx install deeptrade-quant
24
+ # 或
25
+ uv tool install deeptrade-quant
26
+ ```
27
+
28
+ > **注**:PyPI 项目名是 `deeptrade-quant`,CLI 命令是 `deeptrade`,Python 包名是 `deeptrade`(`import deeptrade`)。三者不同是 Python 生态常态(同 `pip install scikit-learn` → `import sklearn`)。
29
+
30
+ ```bash
31
+ # 开发模式(克隆本仓库,editable install)
23
32
  uv sync --all-extras
24
33
  uv run pre-commit install
25
-
26
34
  # 兜底(无 uv)
27
35
  python -m venv .venv && source .venv/bin/activate # Windows: .\.venv\Scripts\activate
28
36
  pip install -e ".[dev]"
@@ -39,12 +47,18 @@ deeptrade config test-llm # 对所有 provider 做连通性自
39
47
  deeptrade config show # 表格展示当前配置(密钥脱敏)
40
48
  ```
41
49
 
42
- ### 安装内置插件并运行
50
+ ### 安装官方插件并运行
51
+
52
+ 官方插件维护在 [DeepTradePluginOfficial](https://github.com/ty19880929/DeepTradePluginOfficial),框架通过短名查注册表 → 拉 GitHub release tarball 自动安装。
43
53
 
44
54
  ```bash
45
- # 安装一个 strategy 插件 + 一个 channel 插件
46
- deeptrade plugin install ./deeptrade/strategies_builtin/limit_up_board -y
47
- deeptrade plugin install ./deeptrade/channels_builtin/stdout -y
55
+ # 浏览注册表
56
+ deeptrade plugin search
57
+
58
+ # 按短名安装(注册表 → 最新 release tag)
59
+ deeptrade plugin install limit-up-board
60
+ deeptrade plugin install volume-anomaly
61
+ deeptrade plugin install stdout-channel
48
62
 
49
63
  deeptrade plugin list # 查看已安装
50
64
 
@@ -62,6 +76,8 @@ deeptrade volume-anomaly prune --days 30 # 剔除追踪 ≥30 日的标的
62
76
  deeptrade stdout-channel test
63
77
  ```
64
78
 
79
+ > **第三方插件 / 本地开发**:`deeptrade plugin install ./path/to/my-plugin` 仍可装本地目录;`deeptrade plugin install https://github.com/owner/repo` 装完整 git 仓库(仓库根需含 `deeptrade_plugin.yaml`)。详见 [`docs/plugin-development.md`](docs/plugin-development.md)。
80
+
65
81
  报告产出在 `~/.deeptrade/reports/<run_id>/`。
66
82
 
67
83
  ## 📦 命令矩阵
@@ -4,5 +4,5 @@ from __future__ import annotations
4
4
 
5
5
  from deeptrade.core.notifier import notification_session, notify
6
6
 
7
- __version__ = "0.1.0"
7
+ __version__ = "0.2.0"
8
8
  __all__ = ["__version__", "notification_session", "notify"]
@@ -7,8 +7,9 @@ Three layers compose top-down:
7
7
  └─ ChannelPlugin instances (loaded from type=channel plugins)
8
8
 
9
9
  The framework knows nothing about feishu / dingtalk / wechat-work. Channels
10
- are delivered as plugins (``channels_builtin/`` mirrors ``strategies_builtin/``);
11
- new channels = new plugin packages, zero framework change.
10
+ are delivered as ``type: channel`` plugins, installed at runtime through
11
+ ``deeptrade plugin install`` from the official registry or any local/git
12
+ source. New channels = new plugin packages, zero framework change.
12
13
 
13
14
  Top-level API (used by any plugin that needs to notify):
14
15
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "deeptrade-quant"
7
- version = "0.1.0"
7
+ version = "0.2.0"
8
8
  description = "LLM-driven A-share (Shanghai/Shenzhen main board) stock screening CLI"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -1,25 +0,0 @@
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: "20260509_001"
19
- file: migrations/20260509_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
@@ -1,13 +0,0 @@
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
- );
@@ -1,180 +0,0 @@
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
@@ -1,83 +0,0 @@
1
- plugin_id: limit-up-board
2
- name: 打板策略
3
- version: 0.4.0
4
- type: strategy
5
- api_version: "1"
6
- entrypoint: limit_up_board.plugin:LimitUpBoardPlugin
7
- description: A 股打板策略:双轮 LLM 漏斗(强势标的分析 → 连板预测)
8
- author: DeepTrade
9
-
10
- permissions:
11
- tushare_apis:
12
- required:
13
- - stock_basic
14
- - trade_cal
15
- - daily
16
- - daily_basic
17
- - stock_st
18
- - limit_list_d
19
- - limit_step
20
- - moneyflow
21
- - top_list
22
- - top_inst
23
- - cyq_perf
24
- optional:
25
- - limit_list_ths
26
- - limit_cpt_list
27
- - ths_hot
28
- - dc_hot
29
- - stk_auction_o
30
- - anns_d
31
- - suspend_d
32
- - stk_limit
33
- llm: true
34
- llm_tools: false
35
-
36
- migrations:
37
- - version: "20260509_001"
38
- file: migrations/20260509_001_init.sql
39
- checksum: "sha256:8f6bc721fedbd94f652fa356779eea7b4ef801483968dabfa6648cf2f639064f"
40
-
41
- tables:
42
- - name: lub_stock_basic
43
- description: stock_basic 落库(限本插件使用)
44
- purge_on_uninstall: true
45
- - name: lub_trade_cal
46
- description: trade_cal 落库
47
- purge_on_uninstall: true
48
- - name: lub_daily
49
- description: daily 行情落库
50
- purge_on_uninstall: true
51
- - name: lub_daily_basic
52
- description: daily_basic 行情指标落库
53
- purge_on_uninstall: true
54
- - name: lub_moneyflow
55
- description: moneyflow 资金流落库
56
- purge_on_uninstall: true
57
- - name: lub_limit_list_d
58
- description: 涨停明细缓存(limit_list_d)
59
- purge_on_uninstall: true
60
- - name: lub_limit_ths
61
- description: 同花顺涨停榜单缓存(limit_list_ths)
62
- purge_on_uninstall: true
63
- - name: lub_stage_results
64
- description: 策略各阶段(R1/R2/final_ranking)结构化结果
65
- purge_on_uninstall: true
66
- - name: lub_runs
67
- description: 本插件 run 历史(替代框架 strategy_runs)
68
- purge_on_uninstall: true
69
- - name: lub_events
70
- description: 本插件 run 事件流(替代框架 strategy_events)
71
- purge_on_uninstall: true
72
- - name: lub_top_list
73
- description: 龙虎榜个股明细(top_list)
74
- purge_on_uninstall: true
75
- - name: lub_top_inst
76
- description: 龙虎榜机构席位明细(top_inst)
77
- purge_on_uninstall: true
78
- - name: lub_cyq_perf
79
- description: 筹码每日指标(cyq_perf)
80
- purge_on_uninstall: true
81
- - name: lub_config
82
- description: 本插件用户可调设置(流通市值 / 股价上限)
83
- purge_on_uninstall: true
@@ -1,65 +0,0 @@
1
- """TradeCalendar — pure helper around tushare trade_cal frames."""
2
-
3
- from __future__ import annotations
4
-
5
- import pandas as pd
6
-
7
-
8
- class TradeCalendar:
9
- """Read-only view over the trade_cal DataFrame.
10
-
11
- Required columns: cal_date (str YYYYMMDD), is_open (0/1), pretrade_date (str).
12
- """
13
-
14
- def __init__(self, df: pd.DataFrame) -> None:
15
- if not {"cal_date", "is_open"}.issubset(df.columns):
16
- raise ValueError("trade_cal frame missing required columns")
17
-
18
- # ⚠ Bug fix: tushare trade_cal returns cal_date as int64 in some
19
- # environments; JSON cache round-trip can also widen "20260428" → 20260428.
20
- # Normalize to string up-front so all downstream comparisons are str↔str.
21
- df = df.copy()
22
- df["cal_date"] = df["cal_date"].astype(str)
23
- if "pretrade_date" in df.columns:
24
- # Some non-trading days have NaN pretrade_date; preserve NaN, stringify the rest
25
- df["pretrade_date"] = df["pretrade_date"].apply(
26
- lambda v: str(v) if pd.notna(v) else None
27
- )
28
- # is_open is sometimes "1"/"0" strings — coerce to int for ==1 comparison
29
- df["is_open"] = pd.to_numeric(df["is_open"], errors="coerce").fillna(0).astype(int)
30
-
31
- # Normalize: deduplicate on cal_date, keeping the SSE/last row
32
- sorted_df = df.sort_values("cal_date").drop_duplicates("cal_date", keep="last")
33
- self._df = sorted_df.reset_index(drop=True)
34
- self._idx: dict[str, int] = {
35
- str(row.cal_date): i for i, row in enumerate(self._df.itertuples(index=False))
36
- }
37
-
38
- def is_open(self, date: str) -> bool:
39
- idx = self._idx.get(date)
40
- if idx is None:
41
- return False
42
- return int(self._df.at[idx, "is_open"]) == 1
43
-
44
- def pretrade_date(self, date: str) -> str:
45
- """Return the most recent open day strictly BEFORE `date`."""
46
- # Walk backwards through cal_date sorted index
47
- candidates = self._df[self._df["cal_date"] < date]
48
- opens = candidates[candidates["is_open"] == 1]
49
- if opens.empty:
50
- raise ValueError(f"no prior open trading day before {date}")
51
- return str(opens.iloc[-1]["cal_date"])
52
-
53
- def next_open(self, date: str) -> str:
54
- """Return the first open day strictly AFTER `date`."""
55
- candidates = self._df[self._df["cal_date"] > date]
56
- opens = candidates[candidates["is_open"] == 1]
57
- if opens.empty:
58
- raise ValueError(f"no future open trading day after {date}")
59
- return str(opens.iloc[0]["cal_date"])
60
-
61
- def latest_closed_on_or_before(self, date: str) -> str:
62
- """Return the latest open day ≤ `date` (i.e. `date` itself if open, else preceding)."""
63
- if self.is_open(date):
64
- return date
65
- return self.pretrade_date(date)