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.
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/.github/workflows/autofix.yml +2 -1
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/.github/workflows/ci.yml +87 -32
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/.github/workflows/publish.yml +19 -6
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/AGENTS.md +6 -6
- stock_analysis_plugin-0.2.4/LICENSE +21 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/PKG-INFO +38 -13
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/README.md +33 -11
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/docs/hermes-integration.en.md +3 -3
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/docs/hermes-integration.md +4 -4
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/docs/openclaw-integration.md +4 -4
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/docs/pi-integration.en.md +3 -3
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/docs/pi-integration.md +3 -3
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/dsh/README.md +2 -2
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/dsh/index.ts +72 -13
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/dsh/package.json +3 -3
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/hermes/plugin.yaml +10 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/hermes/schemas.py +53 -3
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/hermes/tools.py +30 -3
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/openclaw/README.md +2 -2
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/openclaw/index.ts +92 -23
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/openclaw/openclaw.plugin.json +3 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/openclaw/package.json +1 -1
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/package-lock.json +261 -143
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/package.json +5 -5
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/pi/index.ts +86 -8
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/pyproject.toml +4 -2
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/requirements-dev.txt +1 -1
- stock_analysis_plugin-0.2.4/ruff.toml +8 -0
- stock_analysis_plugin-0.2.4/scripts/ci-resolve-llm-host.mjs +29 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/scripts/setup-python.mjs +7 -9
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/hot-theme/SKILL.md +3 -2
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/stock-screener/SKILL.md +1 -1
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/strategy-backtest/SKILL.md +9 -5
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/strategies/examples/bottom_volume.yaml +5 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/strategies/examples/box_oscillation.yaml +5 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/strategies/examples/bull_trend.yaml +11 -3
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/strategies/examples/dragon_head.yaml +4 -2
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/strategies/examples/emotion_cycle.yaml +5 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/strategies/examples/ma_crossover.yaml +10 -3
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/strategies/examples/rsi_oversold.yaml +5 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/strategies/examples/shrink_pullback.yaml +7 -1
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/strategies/examples/volume_breakout.yaml +7 -1
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/conftest.py +15 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/e2e/host_smoke.mjs +52 -55
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/e2e/test_hermes_llm.py +12 -13
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/e2e/test_openclaw_e2e.ts +5 -2
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/e2e/test_pi_llm.ts +8 -9
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/e2e/test_provider_network.py +12 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_alert_rules.py +43 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_anomaly_detect.py +25 -0
- stock_analysis_plugin-0.2.4/tests/test_backtest.py +727 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_backtest_advanced.py +15 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_capabilities.py +1 -1
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_diagnostics.py +25 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_dsh_integration.ts +50 -5
- stock_analysis_plugin-0.2.4/tests/test_dsh_sdk_compat.ts +22 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_gather.py +75 -1
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_hermes_integration.py +18 -0
- stock_analysis_plugin-0.2.4/tests/test_market_regime.py +148 -0
- stock_analysis_plugin-0.2.4/tests/test_market_review.py +229 -0
- stock_analysis_plugin-0.2.4/tests/test_name_resolver.py +135 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_openclaw_integration.ts +74 -14
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_pi_integration.ts +3 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_report_renderer.py +66 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_risk_screening.py +32 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_screener.py +66 -0
- stock_analysis_plugin-0.2.4/tests/test_setup_python.mjs +21 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_stock_data.py +53 -1
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_stock_data_failover.py +461 -0
- stock_analysis_plugin-0.2.4/tests/test_stock_data_margin.py +361 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_stock_data_short_term.py +14 -30
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_technical.py +166 -0
- stock_analysis_plugin-0.2.4/tests/test_trading_calendar.py +300 -0
- stock_analysis_plugin-0.2.4/tests/test_volume_analysis.py +147 -0
- stock_analysis_plugin-0.2.4/tools/_subproc.py +95 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/alert_rules.py +19 -9
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/anomaly_detect.py +24 -35
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/backtest.py +180 -100
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/capabilities.py +4 -5
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/diagnostics.py +6 -6
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/gather.py +13 -9
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/import_parser.py +2 -5
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/market_regime.py +27 -35
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/market_review.py +56 -9
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/name_resolver.py +2 -5
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/pattern.py +2 -5
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/position_context.py +2 -5
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/report_renderer.py +10 -6
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/requirements.txt +2 -1
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/risk_screening.py +29 -23
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/screener.py +26 -16
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/search_intel.py +5 -13
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/signal_tracker.py +2 -6
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/stock_data.py +301 -92
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/technical.py +136 -40
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/trading_calendar.py +78 -18
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/volume_analysis.py +2 -5
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/watchlist.py +2 -5
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/watchlist_context.py +2 -5
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tsconfig.json +8 -1
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/typings/openclaw/index.d.ts +1 -0
- stock_analysis_plugin-0.2.2/ruff.toml +0 -6
- stock_analysis_plugin-0.2.2/tests/test_backtest.py +0 -211
- stock_analysis_plugin-0.2.2/tests/test_market_regime.py +0 -90
- stock_analysis_plugin-0.2.2/tests/test_market_review.py +0 -115
- stock_analysis_plugin-0.2.2/tests/test_trading_calendar.py +0 -161
- stock_analysis_plugin-0.2.2/tools/_subproc.py +0 -46
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/.github/release.yml +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/.gitignore +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/.npmignore +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/CLAUDE.md +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/dsh/cordis.patch.yml +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/hermes/__init__.py +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/openclaw/.npmignore +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/schemas/market_review_schema.json +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/schemas/report_schema.json +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/scripts/sync-version.sh +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/scripts/venv-python.mjs +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/bottom-volume/SKILL.md +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/bottom-volume/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/box-oscillation/SKILL.md +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/box-oscillation/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/bull-trend/SKILL.md +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/bull-trend/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/chan-theory/SKILL.md +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/chan-theory/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/dragon-head/SKILL.md +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/dragon-head/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/emotion-cycle/SKILL.md +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/emotion-cycle/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/event-driven/SKILL.md +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/event-driven/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/expectation-repricing/SKILL.md +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/expectation-repricing/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/growth-quality/SKILL.md +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/growth-quality/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/hot-theme/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/ma-crossover/SKILL.md +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/ma-crossover/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/market-review/SKILL.md +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/market-review/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/one-yang-three-yin/SKILL.md +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/one-yang-three-yin/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/shrink-pullback/SKILL.md +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/shrink-pullback/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/stock-analysis/SKILL.md +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/stock-analysis/references/short-term-trading.md +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/stock-analysis/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/stock-screener/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/strategy-backtest/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/volume-breakout/SKILL.md +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/volume-breakout/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/wave-theory/SKILL.md +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/wave-theory/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/skills/wisburg-research/SKILL.md +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/templates/_macros.j2 +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/templates/market_review/full.md.j2 +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/templates/stock_analysis/brief.md.j2 +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/templates/stock_analysis/full.md.j2 +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/__init__.py +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/_stubs/dsh-tools.ts +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/_stubs/openclaw-sdk.ts +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/_stubs/typebox.ts +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/e2e/dsh_tool_spy.mjs +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/e2e/test_dsh_e2e.ts +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/e2e/test_host_to_python.py +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/e2e/test_pi_e2e.ts +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_import_parser.py +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_pattern.py +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_position_context.py +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_search_intel.py +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_sentiment.py +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_signal_tracker.py +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_skill_workflows.py +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_subproc.py +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_watchlist.py +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tests/test_watchlist_context.py +0 -0
- {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.4}/tools/__init__.py +0 -0
- {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
|
-
|
|
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
|
-
|
|
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
|
|
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:
|
|
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
|
|
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
|
|
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
|
|
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
|
|
200
|
+
run: npm ci
|
|
161
201
|
|
|
162
202
|
- name: E2E — Hermes LLM flow
|
|
163
203
|
env:
|
|
164
|
-
|
|
165
|
-
|
|
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 "$
|
|
168
|
-
echo "
|
|
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
|
-
|
|
176
|
-
|
|
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 "$
|
|
179
|
-
echo "
|
|
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
|
-
#
|
|
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
|
|
257
|
+
run: npm ci
|
|
211
258
|
|
|
212
259
|
- name: Install host CLIs
|
|
213
|
-
#
|
|
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.
|
|
219
|
-
npm i -g openclaw@2026.6
|
|
220
|
-
npm i -g @deepseek-ai/dsh@0.
|
|
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
|
-
|
|
226
|
-
|
|
227
|
-
|
|
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 "$
|
|
230
|
-
echo "
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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` ×
|
|
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` ×
|
|
13
|
-
- `dsh/` — dsh bundle (`package.json` `dsh.bundle` + `cordis.patch.yml` + `index.ts` cordis `apply(ctx)` with `defineTool` ×
|
|
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*
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
- **
|
|
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 启动后自动加载并注册
|
|
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 组合,注册
|
|
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` |
|
|
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 # 注册
|
|
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 #
|
|
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 ×
|
|
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 ×
|
|
503
|
+
│ └── index.ts # cordis apply(ctx) + defineTool ×51
|
|
479
504
|
│
|
|
480
505
|
├── tools/ # 共享 Python CLI 工具(23 个脚本)
|
|
481
506
|
│ ├── stock_data.py # 行情 / 资金流 / 新闻 / 财务 / 短线情绪
|