stock-analysis-plugin 0.2.2__tar.gz → 0.2.4__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 (179) hide show
  1. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/.github/workflows/autofix.yml +2 -1
  2. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/.github/workflows/ci.yml +87 -32
  3. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/.github/workflows/publish.yml +19 -6
  4. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/AGENTS.md +6 -6
  5. stock_analysis_plugin-0.2.4/LICENSE +21 -0
  6. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/PKG-INFO +38 -13
  7. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/README.md +33 -11
  8. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/docs/hermes-integration.en.md +3 -3
  9. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/docs/hermes-integration.md +4 -4
  10. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/docs/openclaw-integration.md +4 -4
  11. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/docs/pi-integration.en.md +3 -3
  12. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/docs/pi-integration.md +3 -3
  13. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/dsh/README.md +2 -2
  14. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/dsh/index.ts +72 -13
  15. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/dsh/package.json +3 -3
  16. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/hermes/plugin.yaml +10 -0
  17. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/hermes/schemas.py +53 -3
  18. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/hermes/tools.py +30 -3
  19. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/openclaw/README.md +2 -2
  20. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/openclaw/index.ts +92 -23
  21. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/openclaw/openclaw.plugin.json +3 -0
  22. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/openclaw/package.json +1 -1
  23. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/package-lock.json +261 -143
  24. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/package.json +5 -5
  25. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/pi/index.ts +86 -8
  26. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/pyproject.toml +4 -2
  27. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/requirements-dev.txt +1 -1
  28. stock_analysis_plugin-0.2.4/ruff.toml +8 -0
  29. stock_analysis_plugin-0.2.4/scripts/ci-resolve-llm-host.mjs +29 -0
  30. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/scripts/setup-python.mjs +7 -9
  31. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/hot-theme/SKILL.md +3 -2
  32. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/stock-screener/SKILL.md +1 -1
  33. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/strategy-backtest/SKILL.md +9 -5
  34. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/strategies/examples/bottom_volume.yaml +5 -0
  35. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/strategies/examples/box_oscillation.yaml +5 -0
  36. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/strategies/examples/bull_trend.yaml +11 -3
  37. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/strategies/examples/dragon_head.yaml +4 -2
  38. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/strategies/examples/emotion_cycle.yaml +5 -0
  39. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/strategies/examples/ma_crossover.yaml +10 -3
  40. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/strategies/examples/rsi_oversold.yaml +5 -0
  41. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/strategies/examples/shrink_pullback.yaml +7 -1
  42. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/strategies/examples/volume_breakout.yaml +7 -1
  43. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/conftest.py +15 -0
  44. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/e2e/host_smoke.mjs +52 -55
  45. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/e2e/test_hermes_llm.py +12 -13
  46. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/e2e/test_openclaw_e2e.ts +5 -2
  47. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/e2e/test_pi_llm.ts +8 -9
  48. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/e2e/test_provider_network.py +12 -0
  49. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_alert_rules.py +43 -0
  50. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_anomaly_detect.py +25 -0
  51. stock_analysis_plugin-0.2.4/tests/test_backtest.py +727 -0
  52. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_backtest_advanced.py +15 -0
  53. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_capabilities.py +1 -1
  54. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_diagnostics.py +25 -0
  55. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_dsh_integration.ts +50 -5
  56. stock_analysis_plugin-0.2.4/tests/test_dsh_sdk_compat.ts +22 -0
  57. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_gather.py +75 -1
  58. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_hermes_integration.py +18 -0
  59. stock_analysis_plugin-0.2.4/tests/test_market_regime.py +148 -0
  60. stock_analysis_plugin-0.2.4/tests/test_market_review.py +229 -0
  61. stock_analysis_plugin-0.2.4/tests/test_name_resolver.py +135 -0
  62. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_openclaw_integration.ts +74 -14
  63. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_pi_integration.ts +3 -0
  64. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_report_renderer.py +66 -0
  65. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_risk_screening.py +32 -0
  66. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_screener.py +66 -0
  67. stock_analysis_plugin-0.2.4/tests/test_setup_python.mjs +21 -0
  68. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_stock_data.py +53 -1
  69. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_stock_data_failover.py +461 -0
  70. stock_analysis_plugin-0.2.4/tests/test_stock_data_margin.py +361 -0
  71. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_stock_data_short_term.py +14 -30
  72. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_technical.py +166 -0
  73. stock_analysis_plugin-0.2.4/tests/test_trading_calendar.py +300 -0
  74. stock_analysis_plugin-0.2.4/tests/test_volume_analysis.py +147 -0
  75. stock_analysis_plugin-0.2.4/tools/_subproc.py +95 -0
  76. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/alert_rules.py +19 -9
  77. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/anomaly_detect.py +24 -35
  78. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/backtest.py +180 -100
  79. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/capabilities.py +4 -5
  80. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/diagnostics.py +6 -6
  81. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/gather.py +13 -9
  82. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/import_parser.py +2 -5
  83. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/market_regime.py +27 -35
  84. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/market_review.py +56 -9
  85. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/name_resolver.py +2 -5
  86. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/pattern.py +2 -5
  87. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/position_context.py +2 -5
  88. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/report_renderer.py +10 -6
  89. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/requirements.txt +2 -1
  90. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/risk_screening.py +29 -23
  91. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/screener.py +26 -16
  92. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/search_intel.py +5 -13
  93. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/signal_tracker.py +2 -6
  94. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/stock_data.py +301 -92
  95. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/technical.py +136 -40
  96. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/trading_calendar.py +78 -18
  97. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/volume_analysis.py +2 -5
  98. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/watchlist.py +2 -5
  99. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/watchlist_context.py +2 -5
  100. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tsconfig.json +8 -1
  101. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/typings/openclaw/index.d.ts +1 -0
  102. stock_analysis_plugin-0.2.2/ruff.toml +0 -6
  103. stock_analysis_plugin-0.2.2/tests/test_backtest.py +0 -211
  104. stock_analysis_plugin-0.2.2/tests/test_market_regime.py +0 -90
  105. stock_analysis_plugin-0.2.2/tests/test_market_review.py +0 -115
  106. stock_analysis_plugin-0.2.2/tests/test_trading_calendar.py +0 -161
  107. stock_analysis_plugin-0.2.2/tools/_subproc.py +0 -46
  108. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/.github/release.yml +0 -0
  109. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/.gitignore +0 -0
  110. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/.npmignore +0 -0
  111. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/CLAUDE.md +0 -0
  112. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/dsh/cordis.patch.yml +0 -0
  113. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/hermes/__init__.py +0 -0
  114. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/openclaw/.npmignore +0 -0
  115. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/schemas/market_review_schema.json +0 -0
  116. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/schemas/report_schema.json +0 -0
  117. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/scripts/sync-version.sh +0 -0
  118. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/scripts/venv-python.mjs +0 -0
  119. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/bottom-volume/SKILL.md +0 -0
  120. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/bottom-volume/scripts/gather.py +0 -0
  121. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/box-oscillation/SKILL.md +0 -0
  122. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/box-oscillation/scripts/gather.py +0 -0
  123. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/bull-trend/SKILL.md +0 -0
  124. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/bull-trend/scripts/gather.py +0 -0
  125. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/chan-theory/SKILL.md +0 -0
  126. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/chan-theory/scripts/gather.py +0 -0
  127. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/dragon-head/SKILL.md +0 -0
  128. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/dragon-head/scripts/gather.py +0 -0
  129. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/emotion-cycle/SKILL.md +0 -0
  130. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/emotion-cycle/scripts/gather.py +0 -0
  131. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/event-driven/SKILL.md +0 -0
  132. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/event-driven/scripts/gather.py +0 -0
  133. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/expectation-repricing/SKILL.md +0 -0
  134. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/expectation-repricing/scripts/gather.py +0 -0
  135. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/growth-quality/SKILL.md +0 -0
  136. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/growth-quality/scripts/gather.py +0 -0
  137. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/hot-theme/scripts/gather.py +0 -0
  138. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/ma-crossover/SKILL.md +0 -0
  139. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/ma-crossover/scripts/gather.py +0 -0
  140. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/market-review/SKILL.md +0 -0
  141. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/market-review/scripts/gather.py +0 -0
  142. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/one-yang-three-yin/SKILL.md +0 -0
  143. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/one-yang-three-yin/scripts/gather.py +0 -0
  144. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/shrink-pullback/SKILL.md +0 -0
  145. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/shrink-pullback/scripts/gather.py +0 -0
  146. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/stock-analysis/SKILL.md +0 -0
  147. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/stock-analysis/references/short-term-trading.md +0 -0
  148. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/stock-analysis/scripts/gather.py +0 -0
  149. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/stock-screener/scripts/gather.py +0 -0
  150. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/strategy-backtest/scripts/gather.py +0 -0
  151. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/volume-breakout/SKILL.md +0 -0
  152. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/volume-breakout/scripts/gather.py +0 -0
  153. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/wave-theory/SKILL.md +0 -0
  154. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/wave-theory/scripts/gather.py +0 -0
  155. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/wisburg-research/SKILL.md +0 -0
  156. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/templates/_macros.j2 +0 -0
  157. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/templates/market_review/full.md.j2 +0 -0
  158. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/templates/stock_analysis/brief.md.j2 +0 -0
  159. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/templates/stock_analysis/full.md.j2 +0 -0
  160. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/__init__.py +0 -0
  161. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/_stubs/dsh-tools.ts +0 -0
  162. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/_stubs/openclaw-sdk.ts +0 -0
  163. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/_stubs/typebox.ts +0 -0
  164. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/e2e/dsh_tool_spy.mjs +0 -0
  165. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/e2e/test_dsh_e2e.ts +0 -0
  166. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/e2e/test_host_to_python.py +0 -0
  167. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/e2e/test_pi_e2e.ts +0 -0
  168. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_import_parser.py +0 -0
  169. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_pattern.py +0 -0
  170. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_position_context.py +0 -0
  171. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_search_intel.py +0 -0
  172. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_sentiment.py +0 -0
  173. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_signal_tracker.py +0 -0
  174. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_skill_workflows.py +0 -0
  175. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_subproc.py +0 -0
  176. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_watchlist.py +0 -0
  177. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_watchlist_context.py +0 -0
  178. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/__init__.py +0 -0
  179. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/typings/pi-agent/index.d.ts +0 -0
@@ -18,7 +18,8 @@ jobs:
18
18
  cache: pip
19
19
 
20
20
  - name: Install ruff
21
- run: pip install "ruff>=0.4.0"
21
+ # Pinned — must match ci.yml and requirements-dev.txt.
22
+ run: pip install "ruff==0.15.20"
22
23
 
23
24
  - name: Ruff auto-fix (lint)
24
25
  run: ruff check --fix tools/ skills/ tests/ hermes/
@@ -7,9 +7,15 @@ on:
7
7
  branches: [main]
8
8
  workflow_call:
9
9
 
10
+ # One active run per branch/PR — new pushes cancel stale runs.
11
+ concurrency:
12
+ group: ${{ github.workflow }}-${{ github.ref }}
13
+ cancel-in-progress: true
14
+
10
15
  jobs:
11
16
  lint:
12
17
  runs-on: ubuntu-latest
18
+ timeout-minutes: 10
13
19
  steps:
14
20
  - uses: actions/checkout@v4
15
21
 
@@ -18,7 +24,8 @@ jobs:
18
24
  python-version: "3.11"
19
25
 
20
26
  - name: Install Python lint tools
21
- run: pip install ruff>=0.4.0
27
+ # Pinned — must match requirements-dev.txt and autofix.yml.
28
+ run: pip install ruff==0.15.20
22
29
 
23
30
  - name: Ruff check
24
31
  run: ruff check tools/ skills/ tests/ hermes/
@@ -29,21 +36,30 @@ jobs:
29
36
  - uses: actions/setup-node@v4
30
37
  with:
31
38
  node-version: "20"
39
+ cache: "npm"
32
40
 
41
+ # --ignore-scripts: tsc doesn't need the postinstall-built Python venv.
33
42
  - name: Install Node dependencies
34
- run: npm install
43
+ run: npm ci --ignore-scripts
35
44
 
36
45
  - name: TypeScript type check
37
46
  run: npx tsc --noEmit
38
47
 
39
48
  test:
40
49
  runs-on: ubuntu-latest
50
+ timeout-minutes: 15
51
+ strategy:
52
+ fail-fast: false
53
+ matrix:
54
+ # 3.10 leg guards the declared floor — verified: full dep set installs
55
+ # and the suite passes on cpython 3.10.19.
56
+ python-version: ["3.11", "3.10"]
41
57
  steps:
42
58
  - uses: actions/checkout@v4
43
59
 
44
60
  - uses: actions/setup-python@v5
45
61
  with:
46
- python-version: "3.11"
62
+ python-version: ${{ matrix.python-version }}
47
63
  cache: pip
48
64
 
49
65
  - name: Install dependencies
@@ -57,7 +73,11 @@ jobs:
57
73
  network:
58
74
  # Real provider calls (akshare/yfinance) — flaky upstreams by nature, so
59
75
  # gated to same-repo PRs and pushes (forks skip it, like e2e-llm).
76
+ # continue-on-error: see publish.yml — a flaky upstream must not block the
77
+ # release path; failures still surface as annotations on the run.
78
+ continue-on-error: true
60
79
  runs-on: ubuntu-latest
80
+ timeout-minutes: 20
61
81
  if: ${{ github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository }}
62
82
  steps:
63
83
  - uses: actions/checkout@v4
@@ -82,6 +102,7 @@ jobs:
82
102
  # structurally cannot see. Deterministic by design: no LLM, no secrets, and
83
103
  # the 4 round-trip tools are the non-network set (see tests/e2e/*.ts).
84
104
  runs-on: ${{ matrix.os }}
105
+ timeout-minutes: 15
85
106
  strategy:
86
107
  fail-fast: false
87
108
  matrix:
@@ -96,16 +117,20 @@ jobs:
96
117
  - uses: actions/setup-node@v4
97
118
  with:
98
119
  node-version: "20"
120
+ cache: "npm"
121
+
122
+ - name: Python setup failure check
123
+ run: node tests/test_setup_python.mjs
99
124
 
100
125
  # tests/conftest.py imports numpy/pandas at module load, so any pytest run
101
- # needs the tools' runtime deps in system python. npm install's postinstall
126
+ # needs the tools' runtime deps in system python. npm ci's postinstall
102
127
  # separately builds .venv (full requirements) — that's the python the
103
128
  # host↔python round-trips spawn.
104
129
  - name: Install dependencies
105
130
  run: |
106
131
  pip install -r tools/requirements.txt
107
132
  pip install -r requirements-dev.txt
108
- npm install
133
+ npm ci
109
134
 
110
135
  - name: TypeScript type check
111
136
  run: npx tsc --noEmit
@@ -119,6 +144,9 @@ jobs:
119
144
  - name: dsh plugin registration
120
145
  run: npx tsx tests/test_dsh_integration.ts
121
146
 
147
+ - name: dsh current SDK compatibility
148
+ run: npx tsx tests/test_dsh_sdk_compat.ts
149
+
122
150
  - name: Hermes plugin registration
123
151
  run: pytest tests/test_hermes_integration.py -v
124
152
 
@@ -135,9 +163,13 @@ jobs:
135
163
  run: npx tsx tests/e2e/test_dsh_e2e.ts
136
164
 
137
165
  e2e-llm:
138
- # Real DeepSeek call. Only runs when DEEPSEEK_API_KEY secret is present
166
+ # Real OpenAI-compatible call. API key is a secret; URL/model can also be variables.
139
167
  # (skipped on forks to prevent secret exposure).
168
+ # continue-on-error: like `network` — non-deterministic output must not
169
+ # block the release path (see publish.yml).
170
+ continue-on-error: true
140
171
  runs-on: ubuntu-latest
172
+ timeout-minutes: 20
141
173
  if: ${{ github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository }}
142
174
  steps:
143
175
  - uses: actions/checkout@v4
@@ -150,33 +182,43 @@ jobs:
150
182
  - uses: actions/setup-node@v4
151
183
  with:
152
184
  node-version: "20"
185
+ cache: "npm"
186
+
187
+ - name: Resolve model endpoint on runner
188
+ env:
189
+ OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL || vars.OPENAI_BASE_URL }}
190
+ run: node scripts/ci-resolve-llm-host.mjs
153
191
 
154
192
  - name: Install Python dependencies
155
193
  run: |
156
194
  pip install -r tools/requirements.txt
157
195
  pip install -r requirements-dev.txt
158
196
 
197
+ # Full npm ci (postinstall builds .venv) — the Pi LLM flow spawns tools
198
+ # through it.
159
199
  - name: Install Node dependencies
160
- run: npm install
200
+ run: npm ci
161
201
 
162
202
  - name: E2E — Hermes LLM flow
163
203
  env:
164
- DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
165
- DEEPSEEK_MODEL: ${{ vars.DEEPSEEK_MODEL || 'deepseek-v4-flash' }}
204
+ OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL || vars.OPENAI_BASE_URL }}
205
+ OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
206
+ OPENAI_MODEL: ${{ secrets.OPENAI_MODEL || vars.OPENAI_MODEL }}
166
207
  run: |
167
- if [ -z "$DEEPSEEK_API_KEY" ]; then
168
- echo "DEEPSEEK_API_KEY not configured — skipping LLM e2e"
208
+ if [ -z "$OPENAI_BASE_URL" ] || [ -z "$OPENAI_API_KEY" ] || [ -z "$OPENAI_MODEL" ]; then
209
+ echo "OPENAI_BASE_URL, OPENAI_API_KEY, and OPENAI_MODEL are required — skipping LLM e2e"
169
210
  exit 0
170
211
  fi
171
212
  pytest tests/e2e/test_hermes_llm.py -m integration_llm -v
172
213
 
173
214
  - name: E2E — Pi LLM flow
174
215
  env:
175
- DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
176
- DEEPSEEK_MODEL: ${{ vars.DEEPSEEK_MODEL || 'deepseek-v4-flash' }}
216
+ OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL || vars.OPENAI_BASE_URL }}
217
+ OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
218
+ OPENAI_MODEL: ${{ secrets.OPENAI_MODEL || vars.OPENAI_MODEL }}
177
219
  run: |
178
- if [ -z "$DEEPSEEK_API_KEY" ]; then
179
- echo "DEEPSEEK_API_KEY not configured — skipping LLM e2e"
220
+ if [ -z "$OPENAI_BASE_URL" ] || [ -z "$OPENAI_API_KEY" ] || [ -z "$OPENAI_MODEL" ]; then
221
+ echo "OPENAI_BASE_URL, OPENAI_API_KEY, and OPENAI_MODEL are required — skipping LLM e2e"
180
222
  exit 0
181
223
  fi
182
224
  npx tsx tests/e2e/test_pi_llm.ts
@@ -201,39 +243,42 @@ jobs:
201
243
  python-version: "3.11"
202
244
 
203
245
  - uses: actions/setup-node@v4
204
- # Node 24: openclaw requires >= 22.19, and pi 0.83's undici breaks on 20.x
205
- # (dsh also requires ^22.19 || >=24)
246
+ # OpenClaw 2026.9.6 requires Node >=24.16.
206
247
  with:
207
- node-version: "24"
248
+ node-version: "24.16.0"
249
+ cache: "npm"
250
+
251
+ - name: Resolve model endpoint on runner
252
+ env:
253
+ OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL || vars.OPENAI_BASE_URL }}
254
+ run: node scripts/ci-resolve-llm-host.mjs
208
255
 
209
256
  - name: Install Node dependencies (also builds repo .venv via postinstall)
210
- run: npm install
257
+ run: npm ci
211
258
 
212
259
  - name: Install host CLIs
213
- # Pinned: pi latest and openclaw latest (slim repack) drifted from the
214
- # validated CLIs — openclaw@latest installed no working bin, and pi's
215
- # `list` flags changed between releases. dsh is a developer preview
216
- # (rc line), so pin it too. `dsh plugin` forwards to pnpm.
260
+ # Pin the current host releases so failures are reproducible.
217
261
  run: |
218
- npm i -g @earendil-works/pi-coding-agent@0.83.0
219
- npm i -g openclaw@2026.6.33
220
- npm i -g @deepseek-ai/dsh@0.1.0-rc.7
262
+ npm i -g @earendil-works/pi-coding-agent@0.99.0
263
+ npm i -g openclaw@2026.9.6
264
+ npm i -g @deepseek-ai/dsh@0.2.0-rc.2
221
265
  npm i -g pnpm@10
222
266
 
223
267
  - name: Real-host smoke QA (${{ matrix.host }})
224
268
  env:
225
- SMOKE_LLM_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
226
- SMOKE_LLM_BASE_URL: https://api.deepseek.com
227
- SMOKE_LLM_MODEL: ${{ vars.DEEPSEEK_MODEL || 'deepseek-v4-flash' }}
269
+ OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL || vars.OPENAI_BASE_URL }}
270
+ OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
271
+ OPENAI_MODEL: ${{ secrets.OPENAI_MODEL || vars.OPENAI_MODEL }}
228
272
  run: |
229
- if [ -z "$SMOKE_LLM_API_KEY" ]; then
230
- echo "SMOKE_LLM_API_KEY not configured — failing (this check is blocking by design)"
273
+ if [ -z "$OPENAI_BASE_URL" ] || [ -z "$OPENAI_API_KEY" ] || [ -z "$OPENAI_MODEL" ]; then
274
+ echo "OPENAI_BASE_URL, OPENAI_API_KEY, and OPENAI_MODEL are required (blocking check)"
231
275
  exit 1
232
276
  fi
233
277
  node tests/e2e/host_smoke.mjs ${{ matrix.host }}
234
278
 
235
279
  build:
236
280
  runs-on: ubuntu-latest
281
+ timeout-minutes: 10
237
282
  needs: [lint, test, compat]
238
283
  steps:
239
284
  - uses: actions/checkout@v4
@@ -241,9 +286,19 @@ jobs:
241
286
  - uses: actions/setup-node@v4
242
287
  with:
243
288
  node-version: "20"
289
+ cache: "npm"
244
290
 
291
+ # --ignore-scripts: packing/bundling doesn't need the Python venv
292
+ # (esbuild's binary arrives via optionalDependencies, not postinstall).
245
293
  - name: Install Node dependencies
246
- run: npm install
294
+ run: npm ci --ignore-scripts
295
+
296
+ # Bundle both compiled hosts here so esbuild breakage surfaces in CI
297
+ # instead of at tag-publish time.
298
+ - name: Build host bundles
299
+ run: |
300
+ npm run build:openclaw
301
+ npm run build:dsh
247
302
 
248
303
  - name: Verify pack contents
249
304
  run: npm pack --dry-run
@@ -6,6 +6,9 @@ on:
6
6
  - "v*"
7
7
 
8
8
  jobs:
9
+ # ci is a whole-workflow reusable call — a caller cannot `needs` individual
10
+ # jobs inside it, so the flaky jobs (network, e2e-llm) carry job-level
11
+ # `continue-on-error: true` in ci.yml to keep them off the release path.
9
12
  ci:
10
13
  uses: ./.github/workflows/ci.yml
11
14
  secrets: inherit
@@ -29,8 +32,9 @@ jobs:
29
32
  - name: Sync version from tag
30
33
  run: bash scripts/sync-version.sh
31
34
 
35
+ # --ignore-scripts: publishing only packs and uploads — no Python venv.
32
36
  - name: Install dependencies
33
- run: npm install
37
+ run: npm ci --ignore-scripts
34
38
 
35
39
  - name: Build and verify
36
40
  run: npm pack --dry-run
@@ -95,8 +99,9 @@ jobs:
95
99
  - name: Sync version from tag
96
100
  run: bash scripts/sync-version.sh
97
101
 
102
+ # --ignore-scripts: publishing only packs and uploads — no Python venv.
98
103
  - name: Install dependencies
99
- run: npm install
104
+ run: npm ci --ignore-scripts
100
105
 
101
106
  - name: Build compiled plugin entry (dist/index.js)
102
107
  run: npm run build:openclaw
@@ -111,6 +116,7 @@ jobs:
111
116
  fi
112
117
  done
113
118
  rm -f openclaw/scripts/sync-version.sh
119
+ cp LICENSE openclaw/LICENSE
114
120
 
115
121
  # Guard against regression of the issue behind
116
122
  # https://github.com/Weaxs/stock-analysis-plugin/issues/3 — a TS entry
@@ -124,11 +130,14 @@ jobs:
124
130
  npm pack --dry-run 2>&1 | tee pack-dry-run.txt
125
131
  grep -q "dist/index.js" pack-dry-run.txt \
126
132
  || { echo "::error::dist/index.js missing from openclaw npm tarball — build ran but files whitelist excludes dist/"; exit 1; }
133
+ grep -q "LICENSE" pack-dry-run.txt \
134
+ || { echo "::error::LICENSE missing from openclaw npm tarball"; exit 1; }
127
135
  test -f dist/index.js \
128
136
  || { echo "::error::openclaw/dist/index.js missing on disk — clawhub publish would ship no compiled entry"; exit 1; }
129
137
 
130
138
  - name: Install clawhub CLI
131
- run: npm i -g clawhub
139
+ # Pinned — an unpinned clawhub@latest broke a release before; bump deliberately.
140
+ run: npm i -g clawhub@0.23.3
132
141
 
133
142
  - name: npm publish
134
143
  working-directory: openclaw
@@ -142,10 +151,10 @@ jobs:
142
151
  CLAWHUB_TOKEN: ${{ secrets.CLAWHUB_TOKEN }}
143
152
 
144
153
  - name: Publish to ClawHub (dry-run)
145
- run: clawhub package publish ./openclaw --dry-run
154
+ run: clawhub package publish ./openclaw --family bundle-plugin --dry-run
146
155
 
147
156
  - name: Publish to ClawHub
148
- run: clawhub package publish ./openclaw
157
+ run: clawhub package publish ./openclaw --family bundle-plugin
149
158
 
150
159
  - name: Publish unscoped variant to npm
151
160
  # Same payload under the unscoped name. Runs after ClawHub so the
@@ -174,8 +183,9 @@ jobs:
174
183
  - name: Sync version from tag
175
184
  run: bash scripts/sync-version.sh
176
185
 
186
+ # --ignore-scripts: publishing only packs and uploads — no Python venv.
177
187
  - name: Install dependencies
178
- run: npm install
188
+ run: npm ci --ignore-scripts
179
189
 
180
190
  - name: Build compiled plugin entry (dist/index.js)
181
191
  run: npm run build:dsh
@@ -190,6 +200,7 @@ jobs:
190
200
  fi
191
201
  done
192
202
  rm -f dsh/scripts/sync-version.sh
203
+ cp LICENSE dsh/LICENSE
193
204
 
194
205
  # Same regression guard as the OpenClaw job: the dsh profile loader
195
206
  # imports built JS, so dist must survive the `files` whitelist, and the
@@ -202,6 +213,8 @@ jobs:
202
213
  || { echo "::error::dist/index.js missing from dsh npm tarball — build ran but files whitelist excludes dist/"; exit 1; }
203
214
  grep -q "cordis.patch.yml" pack-dry-run.txt \
204
215
  || { echo "::error::cordis.patch.yml missing from dsh npm tarball — dsh bundle manifest would dangle"; exit 1; }
216
+ grep -q "LICENSE" pack-dry-run.txt \
217
+ || { echo "::error::LICENSE missing from dsh npm tarball"; exit 1; }
205
218
 
206
219
  - name: npm publish
207
220
  working-directory: dsh
@@ -7,13 +7,13 @@ A multi-host agent plugin for stock analysis, screening, and strategy backtestin
7
7
  The architecture is **one Python core, four thin host adapters**:
8
8
 
9
9
  - `tools/*.py` — the shared CLI tools. **This is the single source of truth** for all behavior. Every tool prints JSON to stdout.
10
- - `pi/index.ts` — Pi extension. `pi.registerTool` ×48, each spawns a `tools/*.py` CLI.
10
+ - `pi/index.ts` — Pi extension. `pi.registerTool` ×51, each spawns a `tools/*.py` CLI.
11
11
  - `hermes/` — Hermes plugin (`plugin.yaml` + `register(ctx)` in `__init__.py`; `tools.py` handlers → subprocess to the same CLIs). Discovered via the `hermes_agent.plugins` entry point.
12
- - `openclaw/` — OpenClaw plugin (`openclaw.plugin.json` manifest + `index.ts` `definePluginEntry` + `registerTool` ×48). Bundled with esbuild.
13
- - `dsh/` — dsh bundle (`package.json` `dsh.bundle` + `cordis.patch.yml` + `index.ts` cordis `apply(ctx)` with `defineTool` ×48 via `@deepseek-ai/dsh-tools`; skills via `ctx.skills.register`). Bundled with esbuild, `@deepseek-ai/*` external (peer deps).
12
+ - `openclaw/` — OpenClaw plugin (`openclaw.plugin.json` manifest + `index.ts` `definePluginEntry` + `registerTool` ×51). Bundled with esbuild.
13
+ - `dsh/` — dsh bundle (`package.json` `dsh.bundle` + `cordis.patch.yml` + `index.ts` cordis `apply(ctx)` with `defineTool` ×51 via `@deepseek-ai/dsh-tools`; skills via `ctx.skills.register`). Bundled with esbuild, `@deepseek-ai/*` external (peer deps).
14
14
  - `skills/*/SKILL.md` — 20 workflow / strategy-methodology skills shared by all four hosts.
15
15
 
16
- > **The invariant that matters most:** the four adapters expose the *same* 48 tools over the *same* Python CLIs. A change to a tool's name, parameters, or JSON output shape must be applied to **all four adapters and the relevant SKILL.md together** — never just one.
16
+ > **The invariant that matters most:** the four adapters expose the *same* 51 tools over the *same* Python CLIs. A change to a tool's name, parameters, or JSON output shape must be applied to **all four adapters and the relevant SKILL.md together** — never just one.
17
17
 
18
18
  ---
19
19
 
@@ -132,7 +132,7 @@ This is the #1 regression surface (issues #2 / #7; the `compat` CI job exists sp
132
132
  - **Output is JSON on stdout, always.** Host adapters parse `result.stdout`. Human-readable prose goes to stderr, never stdout.
133
133
  - **Errors are data**: print a JSON object with an `error` key (and exit non-zero) rather than an uncaught traceback, so adapters can surface a clean message.
134
134
  - **argparse CLI per script**, subcommands per capability (`stock_data.py kline|quote|news|...`). See the README "独立 CLI 使用" section for the established shape.
135
- - **Keep `tools/` py3.9-compatible** (`ruff.toml` targets `py39`; OpenClaw hosts only guarantee Python ≥ 3.9) even though the Hermes wheel declares `requires-python >= 3.10`. No 3.10+-only syntax in `tools/`.
135
+ - **Keep `tools/` py3.10-compatible** (`ruff.toml` targets `py310`; the Python floor is 3.10 everywhere — Hermes wheel `requires-python >= 3.10`, OpenClaw hosts). PEP 604 annotations (`X | None`) and other 3.10 syntax are allowed; nothing 3.11+-only.
136
136
  - **Line length 120**, ruff rules `E,F,W,I,UP,B,SIM` (E501 ignored).
137
137
  - Adding a runtime dependency means adding it to `tools/requirements.txt` (the postinstall-built `.venv`) **and** considering the Hermes wheel's `dependencies` in `pyproject.toml`. Follow ponytail rung 5 — don't add a dependency for a one-call problem.
138
138
 
@@ -222,7 +222,7 @@ Versions live in **five** manifests that must stay in lockstep: `pyproject.toml`
222
222
 
223
223
  ## Adding a New Tool
224
224
 
225
- 1. Implement the CLI in the appropriate `tools/*.py` (argparse subcommand, JSON stdout, py3.9-compatible).
225
+ 1. Implement the CLI in the appropriate `tools/*.py` (argparse subcommand, JSON stdout, py3.10-compatible).
226
226
  2. Add a failing pytest first (`tests/test_<module>.py`), then make it pass (see `tdd`).
227
227
  3. Register it in all four adapters: `pi/index.ts`, `openclaw/index.ts`, `dsh/index.ts`, `hermes/tools.py` + `hermes/schemas.py` — same name, same params.
228
228
  4. Wire it into the relevant `skills/*/SKILL.md` workflow if an agent should call it.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Weaxs
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.
@@ -1,11 +1,12 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: stock-analysis-plugin
3
- Version: 0.2.2
3
+ Version: 0.2.4
4
4
  Summary: Hermes plugin for stock analysis, screening, and strategy backtesting across A/HK/US/JP/KR/TW markets
5
5
  Project-URL: Homepage, https://github.com/Weaxs/stock-analysis-plugin
6
6
  Project-URL: Repository, https://github.com/Weaxs/stock-analysis-plugin
7
7
  Project-URL: Issues, https://github.com/Weaxs/stock-analysis-plugin/issues
8
8
  License-Expression: MIT
9
+ License-File: LICENSE
9
10
  Keywords: a-shares,ai-agent,akshare,algorithmic-trading,backtest,backtesting,factor-investing,hermes-agent,hermes-plugin,hk-stocks,quantitative-finance,quantitative-trading,stock,stock-analysis,stock-market,stock-screener,technical-analysis,tushare,us-stocks,yfinance
10
11
  Classifier: Development Status :: 4 - Beta
11
12
  Classifier: Intended Audience :: Developers
@@ -20,11 +21,13 @@ Classifier: Topic :: Office/Business :: Financial :: Investment
20
21
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
21
22
  Classifier: Topic :: Scientific/Engineering :: Information Analysis
22
23
  Requires-Python: >=3.10
23
- Requires-Dist: akshare>=1.12.0
24
+ Requires-Dist: akshare>=1.14.0; python_version < '3.11'
25
+ Requires-Dist: akshare>=1.18.97; python_version >= '3.11'
24
26
  Requires-Dist: exchange-calendars>=4.5.0
25
27
  Requires-Dist: jinja2>=3.1.0
26
28
  Requires-Dist: numpy>=1.24.0
27
29
  Requires-Dist: pandas>=2.0.0
30
+ Requires-Dist: pyyaml>=6.0
28
31
  Requires-Dist: requests>=2.28.0
29
32
  Description-Content-Type: text/markdown
30
33
 
@@ -54,6 +57,7 @@ A 股 / 港股 / 美股 / 日股 / 韩股 / 台股综合分析、多因子选股
54
57
  - [策略回测 DSL](#策略回测-dsl)
55
58
  - [市场路由规则](#市场路由规则)
56
59
  - [独立 CLI 使用](#独立-cli-使用)
60
+ - [CI 真实宿主测试](#ci-真实宿主测试)
57
61
  - [项目结构](#项目结构)
58
62
  - [致谢](#致谢)
59
63
  - [常见问题](#常见问题)
@@ -61,7 +65,7 @@ A 股 / 港股 / 美股 / 日股 / 韩股 / 台股综合分析、多因子选股
61
65
 
62
66
  ## 功能概览
63
67
 
64
- - **48 个工具** — 行情数据、技术分析、K 线形态、资金流向、财务指标、新闻舆情、风险筛查、市场状态等
68
+ - **51 个工具** — 行情数据、技术分析、K 线形态、资金流向、财务指标、新闻舆情、风险筛查、市场状态等
65
69
  - **20 个 Skills** — 综合分析、全市场选股、策略回测 + 17 个策略方法论(缠论、波浪、龙头、情绪周期等)
66
70
  - **策略回测引擎** — YAML DSL 定义策略,参数化条件组合,自动诊断,按需进行有限轮参数优化
67
71
  - **多数据源 Failover** — 11 个数据源自动容灾切换(akshare / tushare / efinance / 腾讯行情 / 新浪行情 / pytdx / baostock / yfinance / finnhub / longbridge / alphavantage),A 股链路带粘性优选(最近成功的数据源下次优先尝试)
@@ -122,7 +126,7 @@ register(ctx)
122
126
  openclaw plugins install clawhub:@weaxs/openclaw-stock-analysis
123
127
  ```
124
128
 
125
- OpenClaw Gateway 启动后自动加载并注册 48 个 tool。安装时 postinstall 会自动建 `.venv` 并装好 Python 依赖(前提:本机有 `python3 >= 3.9`)。
129
+ OpenClaw Gateway 启动后自动加载并注册 51 个 tool。安装时 postinstall 会自动建 `.venv` 并装好 Python 依赖(前提:本机有 `python3 >= 3.10`)。
126
130
 
127
131
  详见 [OpenClaw 接入指南](docs/openclaw-integration.md),或 plugin 自身说明 [`openclaw/README.md`](openclaw/README.md)。
128
132
 
@@ -133,7 +137,7 @@ dsh plugin --profile <你的profile> add @weaxs/dsh-stock-analysis
133
137
  dsh --profile <你的profile>
134
138
  ```
135
139
 
136
- 作为 dsh bundle 安装:`dsh plugin add` 会把 `cordis.patch.yml` 叠加进 profile 组合,注册 48 个 tool + 20 个 skill。postinstall 自动建 `.venv`(pnpm 需在 profile 的 `pnpm-workspace.yaml` 里给本包配 `allowBuilds`,否则回退系统 `python3`)。
140
+ 作为 dsh bundle 安装:`dsh plugin add` 会把 `cordis.patch.yml` 叠加进 profile 组合,注册 51 个 tool + 20 个 skill。postinstall 自动建 `.venv`(pnpm 需在 profile 的 `pnpm-workspace.yaml` 里给本包配 `allowBuilds`,否则回退系统 `python3`)。
137
141
 
138
142
  详见 [`dsh/README.md`](dsh/README.md)。
139
143
 
@@ -266,7 +270,7 @@ Agent 会自动调用行情 → 技术面 → 基本面 → 资金面 → 消息
266
270
  | 工具 | 说明 |
267
271
  |------|------|
268
272
  | `get_kline` | K 线数据(OHLCV),支持日/周/月线 |
269
- | `get_quote` | 实时行情快照(非交易时段返回最近交易日收盘价并以 as_of/stale 标注) |
273
+ | `get_quote` | 实时行情快照(非交易时段返回最近交易日收盘价并以 as_of/stale 标注;ETF 的 premium_discount_rate 为正=溢价、负=折价) |
270
274
  | `get_capital_flow` | 资金流向(仅 A 股) |
271
275
  | `get_news` | 个股相关新闻 |
272
276
  | `get_financials` | 财务指标 |
@@ -279,14 +283,16 @@ Agent 会自动调用行情 → 技术面 → 基本面 → 资金面 → 消息
279
283
  | `get_market_stats` | 市场统计(涨跌家数、涨停等) |
280
284
  | `get_limit_up_pool` | 涨停池/涨停板复盘(连板数、封板资金、炸板次数等,仅 A 股;非交易日自动回退到最近交易日并以 requested_date/stale 标注) |
281
285
  | `get_dragon_tiger` | 龙虎榜(净买额/上榜原因/解读,仅 A 股;非交易日自动回退到最近交易日并以 requested_date/stale 标注) |
282
- | `get_hot_stocks` | 全市场人气热搜榜(东财→雪球→百度,仅 A 股) |
286
+ | `get_hot_stocks` | 全市场人气热搜榜(东财→百度,仅 A 股) |
287
+ | `get_margin_trading` | 个股融资融券明细(融资余额/融资买入额/融券余量等,沪深交易所官方数据,仅 A 股两融标的;金额单位为元,short_*_shares 单位为股) |
288
+ | `get_northbound_flow` | 北向资金市场级净买入序列(东财沪深港通历史数据;2024-08-16 起交易所停止披露日度净买额,仅 2024-08 之前历史数据可查,仅 A 股) |
283
289
  | `get_fundamental_context` | 基本面综合上下文 |
284
290
 
285
291
  ### 分析计算
286
292
 
287
293
  | 工具 | 说明 |
288
294
  |------|------|
289
- | `get_technical_analysis` | 全面技术指标分析(MA/MACD/RSI/BOLL/KDJ) |
295
+ | `get_technical_analysis` | 全面技术指标分析(MA/MACD/RSI/BOLL/KDJ;多周期共振时 resonance.direction ∈ aligned_bullish/aligned_bearish/divergent) |
290
296
  | `analyze_pattern` | K 线形态识别 |
291
297
  | `calculate_ma` | 多周期均线计算 |
292
298
  | `get_volume_analysis` | 量价分析 |
@@ -302,6 +308,7 @@ Agent 会自动调用行情 → 技术面 → 基本面 → 资金面 → 消息
302
308
  | `run_backtest` | YAML 策略回测 |
303
309
  | `detect_market_regime` | 市场状态检测(牛/熊/震荡) |
304
310
  | `get_market_review` | 市场日度复盘数据 |
311
+ | `get_review_history` | 复盘归档历史(最近 N 条,最新在前,用于纵向对比) |
305
312
  | `run_watchlist_analysis` | 批量自选股分析 |
306
313
 
307
314
  ### 搜索与舆情
@@ -337,7 +344,7 @@ Agent 会自动调用行情 → 技术面 → 基本面 → 资金面 → 消息
337
344
  | `evaluate_signals` | 评估到期信号(target_hit/stop_hit/timeout 结算) |
338
345
  | `get_signal_summary` | 信号胜率汇总(按 source/symbol/status 过滤) |
339
346
  | `render_stock_report` | 将结构化个股报告渲染为 Markdown |
340
- | `render_market_report` | 将结构化市场复盘渲染为 Markdown |
347
+ | `render_market_report` | 将结构化市场复盘渲染为 Markdown(save=true 时归档到本地 JSONL) |
341
348
 
342
349
  ## 策略回测 DSL
343
350
 
@@ -381,6 +388,12 @@ position:
381
388
  max_positions: 1
382
389
  ```
383
390
 
391
+ 其他可用键:
392
+
393
+ - `exit.trailing_stop`:移动止损,价格自持仓期间最高收盘价回撤达到该比例即卖出(如 `0.08` = 峰值回撤 8% 触发);与 `stop_loss` 同时设置时先判固定止损。
394
+ - `benchmark`(顶层):基准对比标的代码(如 `"sh000300"` 沪深300;指数代码必须带 sh/sz 交易所前缀,裸 6 位数字会被当作个股),设置后回测结果附带 `benchmark` 块(基准买入持有收益与 `excess_return` 超额收益)。
395
+ - `simulation`(顶层):交易成本。`slippage`(滑点,买卖双边,默认 0.001)、`commission`(佣金,买卖双边,默认 0.0015)、`stamp_tax`(印花税,仅卖出收取,默认 0;A股为 0.0005,各市场税率不同且会调整,按当下实际费率填写)。费率均须在 [0, 1) 区间,越界报错。回测结果附带 `costs` 块(实际生效费率与实付费用合计 `commission_paid`/`stamp_tax_paid`)。
396
+
384
397
  ### 可用指标
385
398
 
386
399
  | 指标 | 说明 | 需要 period |
@@ -457,25 +470,37 @@ python tools/risk_screening.py screen 600519
457
470
  python tools/market_regime.py detect A
458
471
  ```
459
472
 
473
+ ## CI 真实宿主测试
474
+
475
+ GitHub Actions 的 `e2e-host` 使用 Pi、Hermes、OpenClaw、dsh 的真实运行时执行工具调用。在仓库 **Settings → Secrets and variables → Actions** 中配置以下三项,所有 E2E 共用:
476
+
477
+ | 名称 | 存放位置 | 内容 |
478
+ |---|---|---|
479
+ | `OPENAI_BASE_URL` | Variable 或 Secret | OpenAI 兼容的 API base URL,包含服务商要求的路径(例如 `/v1`) |
480
+ | `OPENAI_API_KEY` | Secret | 对应的 API key |
481
+ | `OPENAI_MODEL` | Variable 或 Secret | 支持 tool calling 的模型 ID |
482
+
483
+ `e2e-llm` 也使用这三项配置;同仓库 PR 和主分支推送会运行,fork PR 不读取 API key。`e2e-host` 缺少任一项时会失败。URL 和 model 同时存在于 Variable 与 Secret 时,优先使用 Secret。
484
+
460
485
  ## 项目结构
461
486
 
462
487
  ```
463
488
  stock-analysis/
464
489
  ├── pi/ # Pi Agent Extension
465
- │ └── index.ts # 注册 48 个工具 + 20 个 skill
490
+ │ └── index.ts # 注册 51 个工具 + 20 个 skill
466
491
  ├── hermes/ # Hermes Agent Plugin
467
492
  │ ├── plugin.yaml # 插件清单
468
493
  │ ├── __init__.py # register(ctx) 入口
469
494
  │ ├── schemas.py # 工具 JSON Schema 定义
470
- │ └── tools.py # 48 个 handler → subprocess 调 CLI
495
+ │ └── tools.py # 51 个 handler → subprocess 调 CLI
471
496
  ├── openclaw/ # OpenClaw Plugin
472
497
  │ ├── openclaw.plugin.json # manifest(contracts.tools)
473
498
  │ ├── package.json # 含 openclaw 块(pluginApi/SDK 版本)
474
- │ └── index.ts # definePluginEntry + registerTool ×48
499
+ │ └── index.ts # definePluginEntry + registerTool ×51
475
500
  ├── dsh/ # DeepSeek Harness (dsh) Plugin
476
501
  │ ├── cordis.patch.yml # bundle patch(insert 插件入口)
477
502
  │ ├── package.json # 含 dsh.bundle 块(bundle manifest)
478
- │ └── index.ts # cordis apply(ctx) + defineTool ×48
503
+ │ └── index.ts # cordis apply(ctx) + defineTool ×51
479
504
  │
480
505
  ├── tools/ # 共享 Python CLI 工具(23 个脚本)
481
506
  │ ├── stock_data.py # 行情 / 资金流 / 新闻 / 财务 / 短线情绪