stock-analysis-plugin 0.2.6__tar.gz → 0.2.7__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.6 → stock_analysis_plugin-0.2.7}/.github/workflows/ci.yml +19 -6
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/.gitignore +3 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/AGENTS.md +4 -4
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/PKG-INFO +77 -15
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/README.md +76 -14
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/docs/hermes-integration.en.md +1 -116
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/docs/hermes-integration.md +2 -117
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/docs/openclaw-integration.md +1 -124
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/docs/pi-integration.en.md +8 -79
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/docs/pi-integration.md +8 -79
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/dsh/README.md +17 -1
- stock_analysis_plugin-0.2.7/dsh/discovery.ts +62 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/dsh/index.ts +658 -12
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/dsh/package.json +1 -1
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/hermes/plugin.yaml +7 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/hermes/schemas.py +389 -9
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/hermes/tools.py +43 -1
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/openclaw/README.md +1 -1
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/openclaw/index.ts +197 -11
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/openclaw/openclaw.plugin.json +8 -1
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/openclaw/package.json +1 -1
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/package-lock.json +2 -2
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/package.json +2 -1
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/pi/index.ts +817 -71
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/pyproject.toml +1 -1
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/schemas/market_review_schema.json +12 -5
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/schemas/report_schema.json +65 -1
- stock_analysis_plugin-0.2.7/scripts/cli-timeout.mjs +27 -0
- stock_analysis_plugin-0.2.7/scripts/json-input.mjs +26 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/event-driven/SKILL.md +4 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/growth-quality/SKILL.md +4 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/market-review/SKILL.md +2 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/stock-analysis/SKILL.md +17 -3
- stock_analysis_plugin-0.2.7/skills/stock-analysis/references/stateless-analysis.md +66 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/stock-screener/SKILL.md +5 -1
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/strategy-backtest/SKILL.md +9 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/templates/market_review/full.md.j2 +7 -0
- stock_analysis_plugin-0.2.7/templates/stock_analysis/_evidence.md.j2 +11 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/templates/stock_analysis/brief.md.j2 +2 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/templates/stock_analysis/full.md.j2 +2 -0
- stock_analysis_plugin-0.2.7/tests/analysis_quality.py +203 -0
- stock_analysis_plugin-0.2.7/tests/e2e/llm-host.ts +76 -0
- stock_analysis_plugin-0.2.7/tests/e2e/test_analysis_quality.py +83 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/e2e/test_dsh_e2e.ts +11 -0
- stock_analysis_plugin-0.2.6/tests/e2e/test_pi_llm.ts → stock_analysis_plugin-0.2.7/tests/e2e/test_host_llm.ts +10 -50
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/e2e/test_host_to_python.py +21 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/e2e/test_openclaw_e2e.ts +12 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/e2e/test_pi_e2e.ts +11 -0
- stock_analysis_plugin-0.2.7/tests/fixtures/analysis_quality.json +151 -0
- stock_analysis_plugin-0.2.7/tests/fixtures/stateless_analysis.json +630 -0
- stock_analysis_plugin-0.2.7/tests/test_analysis_quality.py +320 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_backtest.py +112 -3
- stock_analysis_plugin-0.2.7/tests/test_dsh_discovery.ts +95 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_dsh_integration.ts +29 -2
- stock_analysis_plugin-0.2.7/tests/test_dsh_sdk_compat.ts +35 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_gather.py +16 -5
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_hermes_integration.py +60 -0
- stock_analysis_plugin-0.2.7/tests/test_json_input.ts +27 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_kline_adjustment.py +6 -5
- stock_analysis_plugin-0.2.7/tests/test_llm_hosts.ts +32 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_market_review.py +41 -5
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_openclaw_integration.ts +28 -1
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_pi_integration.ts +99 -2
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_report_renderer.py +14 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_screener.py +112 -7
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_signal_tracker.py +165 -2
- stock_analysis_plugin-0.2.7/tests/test_stateless_analysis.py +576 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_stock_data.py +50 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_stock_data_failover.py +139 -11
- stock_analysis_plugin-0.2.7/tests/test_subproc.py +262 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_watchlist_context.py +39 -0
- stock_analysis_plugin-0.2.7/tools/_subproc.py +150 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tools/backtest.py +73 -14
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tools/capabilities.py +8 -0
- stock_analysis_plugin-0.2.7/tools/cli_budgets.json +26 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tools/gather.py +4 -6
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tools/market_review.py +30 -9
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tools/screener.py +57 -15
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tools/signal_tracker.py +77 -6
- stock_analysis_plugin-0.2.7/tools/stateless_analysis.py +630 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tools/stock_data.py +90 -15
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tools/watchlist_context.py +18 -7
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/typings/openclaw/index.d.ts +1 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/typings/pi-agent/index.d.ts +5 -0
- stock_analysis_plugin-0.2.6/docs/research/issue-44-coverage-sources.md +0 -122
- stock_analysis_plugin-0.2.6/docs/research/issue-51-reverse-holdings.md +0 -30
- stock_analysis_plugin-0.2.6/tests/test_dsh_sdk_compat.ts +0 -22
- stock_analysis_plugin-0.2.6/tests/test_subproc.py +0 -119
- stock_analysis_plugin-0.2.6/tools/_subproc.py +0 -95
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/.github/release.yml +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/.github/workflows/autofix.yml +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/.github/workflows/publish.yml +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/.npmignore +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/CLAUDE.md +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/LICENSE +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/dsh/cordis.patch.yml +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/hermes/__init__.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/openclaw/.npmignore +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/requirements-dev.txt +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/ruff.toml +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/scripts/ci-resolve-llm-host.mjs +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/scripts/setup-python.mjs +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/scripts/sync-version.sh +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/scripts/venv-python.mjs +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/bottom-volume/SKILL.md +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/bottom-volume/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/box-oscillation/SKILL.md +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/box-oscillation/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/bull-trend/SKILL.md +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/bull-trend/references/fat-tails.md +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/bull-trend/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/bull-trend/scripts/tail_analysis.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/chan-theory/SKILL.md +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/chan-theory/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/dragon-head/SKILL.md +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/dragon-head/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/emotion-cycle/SKILL.md +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/emotion-cycle/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/event-driven/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/expectation-repricing/SKILL.md +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/expectation-repricing/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/growth-quality/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/hot-theme/SKILL.md +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/hot-theme/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/ma-crossover/SKILL.md +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/ma-crossover/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/market-review/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/one-yang-three-yin/SKILL.md +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/one-yang-three-yin/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/shrink-pullback/SKILL.md +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/shrink-pullback/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/stock-analysis/references/short-term-trading.md +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/stock-analysis/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/stock-screener/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/strategy-backtest/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/volume-breakout/SKILL.md +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/volume-breakout/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/wave-theory/SKILL.md +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/wave-theory/scripts/gather.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/skills/wisburg-research/SKILL.md +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/strategies/examples/bottom_volume.yaml +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/strategies/examples/box_oscillation.yaml +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/strategies/examples/bull_trend.yaml +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/strategies/examples/dragon_head.yaml +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/strategies/examples/emotion_cycle.yaml +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/strategies/examples/ma_crossover.yaml +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/strategies/examples/rsi_oversold.yaml +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/strategies/examples/shrink_pullback.yaml +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/strategies/examples/volume_breakout.yaml +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/templates/_macros.j2 +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/__init__.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/_stubs/dsh-tools.ts +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/_stubs/openclaw-sdk.ts +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/_stubs/typebox.ts +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/conftest.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/e2e/dsh_tool_spy.mjs +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/e2e/host_smoke.mjs +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/e2e/test_hermes_llm.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/e2e/test_provider_network.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_alert_rules.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_anomaly_detect.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_backtest_advanced.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_capabilities.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_data_cache.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_diagnostics.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_disclosures.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_hk_lixinger.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_import_parser.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_market_regime.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_name_resolver.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_pattern.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_position_context.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_provider_network_helpers.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_risk_screening.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_search_intel.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_sec_edgar.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_sec_holders.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_sentiment.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_setup_python.mjs +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_skill_workflows.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_stock_data_margin.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_stock_data_short_term.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_tail_analysis_skill.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_technical.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_trading_calendar.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_value_data.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_volume_analysis.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tests/test_watchlist.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tools/__init__.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tools/_cache.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tools/alert_rules.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tools/anomaly_detect.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tools/diagnostics.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tools/import_parser.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tools/lixinger.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tools/market_regime.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tools/name_resolver.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tools/pattern.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tools/position_context.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tools/report_renderer.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tools/requirements.txt +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tools/risk_screening.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tools/search_intel.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tools/sec_edgar.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tools/sec_holders.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tools/technical.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tools/trading_calendar.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tools/value_data.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tools/volume_analysis.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tools/watchlist.py +0 -0
- {stock_analysis_plugin-0.2.6 → stock_analysis_plugin-0.2.7}/tsconfig.json +0 -0
|
@@ -147,6 +147,12 @@ jobs:
|
|
|
147
147
|
- name: dsh current SDK compatibility
|
|
148
148
|
run: npx tsx tests/test_dsh_sdk_compat.ts
|
|
149
149
|
|
|
150
|
+
- name: LLM host adapters (offline)
|
|
151
|
+
run: npx tsx tests/test_llm_hosts.ts
|
|
152
|
+
|
|
153
|
+
- name: Large JSON input transport and cleanup
|
|
154
|
+
run: npx tsx tests/test_json_input.ts
|
|
155
|
+
|
|
150
156
|
- name: Hermes plugin registration
|
|
151
157
|
run: pytest tests/test_hermes_integration.py -v
|
|
152
158
|
|
|
@@ -154,7 +160,7 @@ jobs:
|
|
|
154
160
|
run: pytest tests/e2e/test_host_to_python.py -v
|
|
155
161
|
|
|
156
162
|
- name: Signal store and analysis regressions
|
|
157
|
-
run: pytest tests/test_signal_tracker.py tests/test_gather.py tests/test_watchlist.py tests/test_watchlist_context.py -q
|
|
163
|
+
run: pytest tests/test_signal_tracker.py tests/test_gather.py tests/test_watchlist.py tests/test_watchlist_context.py tests/test_stateless_analysis.py -q
|
|
158
164
|
|
|
159
165
|
- name: Pi host real subprocess round-trip
|
|
160
166
|
run: npx tsx tests/e2e/test_pi_e2e.ts
|
|
@@ -172,6 +178,10 @@ jobs:
|
|
|
172
178
|
# block the release path (see publish.yml).
|
|
173
179
|
continue-on-error: true
|
|
174
180
|
runs-on: ubuntu-latest
|
|
181
|
+
strategy:
|
|
182
|
+
fail-fast: false
|
|
183
|
+
matrix:
|
|
184
|
+
host: [hermes, pi, openclaw, dsh]
|
|
175
185
|
timeout-minutes: 20
|
|
176
186
|
if: ${{ github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository }}
|
|
177
187
|
steps:
|
|
@@ -193,16 +203,18 @@ jobs:
|
|
|
193
203
|
run: node scripts/ci-resolve-llm-host.mjs
|
|
194
204
|
|
|
195
205
|
- name: Install Python dependencies
|
|
206
|
+
if: matrix.host == 'hermes'
|
|
196
207
|
run: |
|
|
197
208
|
pip install -r tools/requirements.txt
|
|
198
209
|
pip install -r requirements-dev.txt
|
|
199
210
|
|
|
200
|
-
# Full npm ci
|
|
201
|
-
# through it.
|
|
211
|
+
# Full npm ci builds .venv for the TypeScript host adapters.
|
|
202
212
|
- name: Install Node dependencies
|
|
213
|
+
if: matrix.host != 'hermes'
|
|
203
214
|
run: npm ci
|
|
204
215
|
|
|
205
216
|
- name: E2E — Hermes LLM flow
|
|
217
|
+
if: matrix.host == 'hermes'
|
|
206
218
|
env:
|
|
207
219
|
OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL || vars.OPENAI_BASE_URL }}
|
|
208
220
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
@@ -212,9 +224,10 @@ jobs:
|
|
|
212
224
|
echo "OPENAI_BASE_URL, OPENAI_API_KEY, and OPENAI_MODEL are required — skipping LLM e2e"
|
|
213
225
|
exit 0
|
|
214
226
|
fi
|
|
215
|
-
pytest tests/e2e/test_hermes_llm.py -m integration_llm -v
|
|
227
|
+
pytest tests/e2e/test_hermes_llm.py tests/e2e/test_analysis_quality.py -m integration_llm -v
|
|
216
228
|
|
|
217
|
-
- name: E2E —
|
|
229
|
+
- name: E2E — ${{ matrix.host }} LLM flow
|
|
230
|
+
if: matrix.host != 'hermes'
|
|
218
231
|
env:
|
|
219
232
|
OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL || vars.OPENAI_BASE_URL }}
|
|
220
233
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
@@ -224,7 +237,7 @@ jobs:
|
|
|
224
237
|
echo "OPENAI_BASE_URL, OPENAI_API_KEY, and OPENAI_MODEL are required — skipping LLM e2e"
|
|
225
238
|
exit 0
|
|
226
239
|
fi
|
|
227
|
-
npx tsx tests/e2e/
|
|
240
|
+
npx tsx tests/e2e/test_host_llm.ts ${{ matrix.host }}
|
|
228
241
|
|
|
229
242
|
e2e-host:
|
|
230
243
|
# Real-host smoke: install the plugin into the actual pi / openclaw /
|
|
@@ -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` ×67, 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` ×67). Bundled with esbuild.
|
|
13
|
+
- `dsh/` — dsh bundle (`package.json` `dsh.bundle` + `cordis.patch.yml` + `index.ts` cordis `apply(ctx)` with `defineTool` ×67 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* 67 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
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: stock-analysis-plugin
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.7
|
|
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
|
|
@@ -73,7 +73,7 @@ A 股 / 港股 / 美股 / 日股 / 韩股 / 台股综合分析、多因子选股
|
|
|
73
73
|
|
|
74
74
|
## 功能概览
|
|
75
75
|
|
|
76
|
-
- **
|
|
76
|
+
- **67 个工具** — 行情数据、技术分析、K 线形态、资金流向、估值历史、财报日历、股东/ETF/股息、新闻舆情、风险筛查、市场状态等
|
|
77
77
|
- **20 个 Skills** — 综合分析、全市场选股、策略回测 + 17 个策略方法论(缠论、波浪、龙头、情绪周期等)
|
|
78
78
|
- **策略回测引擎** — YAML DSL 定义策略,参数化条件组合,自动诊断,按需进行有限轮参数优化
|
|
79
79
|
- **多数据源 Failover** — 11 个数据源自动容灾切换(akshare / tushare / efinance / 腾讯行情 / 新浪行情 / pytdx / baostock / yfinance / finnhub / longbridge / alphavantage),A 股链路带粘性优选(最近成功的数据源下次优先尝试)
|
|
@@ -111,6 +111,8 @@ npm install @weaxs/stock-analysis-plugin
|
|
|
111
111
|
|
|
112
112
|
Pi 启动后自动加载,输入 `/skills` 确认。详见 [Pi Agent 接入指南](docs/pi-integration.md)([English](docs/pi-integration.en.md))。
|
|
113
113
|
|
|
114
|
+
新版 Pi(已核验 1.2.0)提供原生 `tool_search` 时,插件自动启用按需工具发现,67 项能力保留注册,仅命中工具加载完整定义。缺少原生发现接口的旧版 Pi 或 SDK 宿主保持全量暴露。检索使用英文关键词或工具名,例如 `get_quote`、`get_financials`。
|
|
115
|
+
|
|
114
116
|
### Hermes Agent Plugin
|
|
115
117
|
|
|
116
118
|
```bash
|
|
@@ -134,7 +136,7 @@ register(ctx)
|
|
|
134
136
|
openclaw plugins install clawhub:@weaxs/openclaw-stock-analysis
|
|
135
137
|
```
|
|
136
138
|
|
|
137
|
-
OpenClaw Gateway 启动后自动加载并注册
|
|
139
|
+
OpenClaw Gateway 启动后自动加载并注册 67 个 tool。安装时 postinstall 会自动建 `.venv` 并装好 Python 依赖(前提:本机有 `python3 >= 3.10`)。
|
|
138
140
|
|
|
139
141
|
详见 [OpenClaw 接入指南](docs/openclaw-integration.md),或 plugin 自身说明 [`openclaw/README.md`](openclaw/README.md)。
|
|
140
142
|
|
|
@@ -145,7 +147,9 @@ dsh plugin --profile <你的profile> add @weaxs/dsh-stock-analysis
|
|
|
145
147
|
dsh --profile <你的profile>
|
|
146
148
|
```
|
|
147
149
|
|
|
148
|
-
作为 dsh bundle 安装:`dsh plugin add` 会把 `cordis.patch.yml` 叠加进 profile 组合,注册
|
|
150
|
+
作为 dsh bundle 安装:`dsh plugin add` 会把 `cordis.patch.yml` 叠加进 profile 组合,注册 67 个 tool + 20 个 skill。postinstall 自动建 `.venv`(pnpm 需在 profile 的 `pnpm-workspace.yaml` 里给本包配 `allowBuilds`,否则回退系统 `python3`)。
|
|
151
|
+
|
|
152
|
+
新版 dsh 的原生函数调用模式默认通过 `stock_tool_search` 按 Agent 搜索、加载所需工具,支持中文关键词或工具名;旧接口、搜索入口不可用时保留全量暴露。可设置 `toolDiscovery: false` 关闭,配置与 PTC 模式边界见下方接入文档。
|
|
149
153
|
|
|
150
154
|
详见 [`dsh/README.md`](dsh/README.md)。
|
|
151
155
|
|
|
@@ -322,9 +326,9 @@ Agent 会自动调用行情 → 技术面 → 基本面 → 资金面 → 消息
|
|
|
322
326
|
|
|
323
327
|
| 工具 | 说明 |
|
|
324
328
|
|------|------|
|
|
325
|
-
| `screen_stocks` |
|
|
329
|
+
| `screen_stocks` | 全市场多因子筛选(可选 L2;factor_coverage 展示缺失因子、覆盖度、实际权重及 L2 effective_scores) |
|
|
326
330
|
| `screen_risk` | 风险因子筛查 |
|
|
327
|
-
| `run_backtest` | YAML
|
|
331
|
+
| `run_backtest` | YAML 策略回测,默认收盘信号于次日开盘成交,execution 返回模型与限制 |
|
|
328
332
|
| `detect_market_regime` | 市场状态检测(牛/熊/震荡) |
|
|
329
333
|
| `get_market_review` | 市场日度复盘数据 |
|
|
330
334
|
| `get_review_history` | 复盘归档历史(最近 N 条,最新在前,用于纵向对比) |
|
|
@@ -361,8 +365,8 @@ Agent 会自动调用行情 → 技术面 → 基本面 → 资金面 → 消息
|
|
|
361
365
|
| `check_alert_rules` | 无状态检查价格、涨跌幅、异动和风险规则 |
|
|
362
366
|
| `record_signal` | 记录 AI 分析建议信号(本地 JSONL 持久化) |
|
|
363
367
|
| `evaluate_signals` | 评估到期信号(target_hit/stop_hit/timeout 结算) |
|
|
364
|
-
| `get_signal_summary` |
|
|
365
|
-
| `render_stock_report` | 将结构化个股报告渲染为 Markdown |
|
|
368
|
+
| `get_signal_summary` | 信号胜率及分来源平均收益、有效收益样本数与小样本提示(按 source/symbol/status 过滤) |
|
|
369
|
+
| `render_stock_report` | 将结构化个股报告渲染为 Markdown,展示 evidence 与 data_quality 限制 |
|
|
366
370
|
| `render_market_report` | 将结构化市场复盘渲染为 Markdown(save=true 时归档到本地 JSONL) |
|
|
367
371
|
|
|
368
372
|
批量自选股分析和摘要的 `success` 表示至少获取了有效行情价格、K 线收盘价或技术评分;全部关键数据失败时计入 `failed`,部分结果仍保留。采集脚本复用返回的 K 线计算技术指标,并按股票所属市场查询大盘状态;日/韩/台市场状态暂不可用,非 A 股板块榜单也暂不可用,均会明确返回错误。
|
|
@@ -373,6 +377,43 @@ Agent 会自动调用行情 → 技术面 → 基本面 → 资金面 → 消息
|
|
|
373
377
|
|
|
374
378
|
选股的 `filters_applied` 只列实际执行的条件,显式条件缺少数据时报错。回测的 `period` 是实际数据期间,`requested_period` 保留请求期间,`warnings` 提示覆盖差异;买入预算包含佣金,年化收益和回撤按实际数据及初始资金计算。
|
|
375
379
|
|
|
380
|
+
### 无状态研究与风险计算
|
|
381
|
+
|
|
382
|
+
| 工具 | 说明 |
|
|
383
|
+
|------|------|
|
|
384
|
+
| `compare_stocks` | 比较显式输入的同行指标;检查单位、期间和口径,仅对可比数值排序 |
|
|
385
|
+
| `analyze_disclosure_changes` | 比较新旧公告正文与财务指标,返回来源、变更行号和增长率限制 |
|
|
386
|
+
| `analyze_portfolio_risk` | 一次性持仓的集中度、行业/币种敞口、价格盈亏、止损情景与可选相关性 |
|
|
387
|
+
| `calculate_position_size` | 按现金、风险预算、费用、滑点和交易单位计算本次可买数量 |
|
|
388
|
+
| `analyze_event_study` | 事件前一交易日收盘至各窗口的股票/基准收益差,标明缺失和重叠样本 |
|
|
389
|
+
| `validate_backtest` | 复用现有引擎,滚动训练选候选、样本外验证,比较参数及多个标的 |
|
|
390
|
+
| `compare_analysis_snapshots` | 比较调用方传入的快照,区分新增、删除、变化、数据失效和恢复 |
|
|
391
|
+
|
|
392
|
+
这些工具不保存自选股、账户或分析历史,也不提供调度/通知。现有数据工具采集行情和财务,宿主传入本次持仓、正文或快照;[完整输入约定与解读工作流](skills/stock-analysis/references/stateless-analysis.md)供四个宿主共用。
|
|
393
|
+
|
|
394
|
+
大输入经权限受限的临时 JSON 文件传给 Python,调用结束后清理,避免 Windows 命令行长度限制;CLI 也支持 stdin 和 `--input` 文件。公告正文由宿主读取:PDF/OCR 不包含在本次扩展中,只有标题或链接不能声称已读全文。
|
|
395
|
+
|
|
396
|
+
例如仓位预算(所有金额同币种,lot_size 由用户或交易规则确认):
|
|
397
|
+
|
|
398
|
+
```json
|
|
399
|
+
{
|
|
400
|
+
"equity": 100000, "cash": 20000,
|
|
401
|
+
"entry_price": 100, "stop_price": 95,
|
|
402
|
+
"risk_fraction": 0.01, "lot_size": 100,
|
|
403
|
+
"fee_rate": 0.001, "slippage_rate": 0.001
|
|
404
|
+
}
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
将上述 JSON 保存为 `input.json` 后运行:
|
|
408
|
+
|
|
409
|
+
```bash
|
|
410
|
+
python tools/stateless_analysis.py position_size --input input.json
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
对应宿主工具是 `calculate_position_size`。其余 CLI 子命令依次为 `peers/disclosure/portfolio/event_study/robustness/snapshot`。事件研究可直接传 `symbol/benchmark/start_date/end_date/event_dates`;回测验证可传 `symbols/start_date/end_date/strategies`,由 Python 复用行情接口,避免模型重新抄写历史 K 线。显式价格/datasets 模式仍支持离线计算,两种模式互斥。
|
|
414
|
+
|
|
415
|
+
跨币种组合必须提供显式汇率;价格盈亏不含历史汇兑损益。稳健性工具仅支持 next_open、每窗口重新从现金开始,样本内敏感性不等于样本外表现。
|
|
416
|
+
|
|
376
417
|
## 策略回测 DSL
|
|
377
418
|
|
|
378
419
|
策略以 YAML 格式定义,支持参数化和条件组合:
|
|
@@ -415,10 +456,13 @@ position:
|
|
|
415
456
|
max_positions: 1
|
|
416
457
|
```
|
|
417
458
|
|
|
459
|
+
行情 JSON 保留原有数组/字典形状,添加 `source`、UTC `fetched_at` 和 `data_as_of`。采集时间不是报价时间,提供方未给时间时为 null;仅提供交易日时保留 YYYY-MM-DD,不补造具体时刻;K 线 data_as_of 是该条的日期标签,周/月线标签不是实际末次成交时间;`as_of_basis=trading_calendar` 表示交易日历推断。A 股复权口径延续 qfq/none;其他市场按来源标为 total_return/qfq/unknown,不把 unknown 当已验证复权。
|
|
460
|
+
|
|
418
461
|
其他可用键:
|
|
419
462
|
|
|
420
463
|
- `exit.trailing_stop`:移动止损,价格自持仓期间最高收盘价回撤达到该比例即卖出(如 `0.08` = 峰值回撤 8% 触发);与 `stop_loss` 同时设置时先判固定止损。
|
|
421
464
|
- `benchmark`(顶层):基准对比标的代码(如 `"sh000300"` 沪深300;指数代码必须带 sh/sz 交易所前缀,裸 6 位数字会被当作个股),设置后回测结果附带 `benchmark` 块(基准买入持有收益与 `excess_return` 超额收益)。
|
|
465
|
+
- `simulation.execution`:默认 `next_open`,前日收盘信号、次日开盘加滑点成交;显式 `same_close` 复现旧收盘成交假设。交易同时返回 signal_date/date。零成交量阻止成交;一字板限制只在输入提供同口径历史 limit_up/limit_down 时执行。`execution` 列出阻止成交次数、未成交订单及限制;止损是收盘信号,未模拟盘口排队、部分成交、结算和市场冲击。
|
|
422
466
|
- `simulation`(顶层):交易成本。`slippage`(滑点,买卖双边,默认 0.001)、`commission`(佣金,买卖双边,默认 0.0015)、`stamp_tax`(印花税,仅卖出收取,默认 0;A股为 0.0005,各市场税率不同且会调整,按当下实际费率填写)。费率均须在 [0, 1) 区间,越界报错。回测结果附带 `costs` 块(实际生效费率与实付费用合计 `commission_paid`/`stamp_tax_paid`)。
|
|
423
467
|
|
|
424
468
|
### 可用指标
|
|
@@ -542,27 +586,27 @@ GitHub Actions 的 `e2e-host` 使用 Pi、Hermes、OpenClaw、dsh 的真实运
|
|
|
542
586
|
| `OPENAI_API_KEY` | Secret | 对应的 API key |
|
|
543
587
|
| `OPENAI_MODEL` | Variable 或 Secret | 支持 tool calling 的模型 ID |
|
|
544
588
|
|
|
545
|
-
`e2e-llm`
|
|
589
|
+
`e2e-llm` 也使用这三项配置,Hermes(含报告质量评测)、Pi、OpenClaw 和 dsh 通过四个 matrix 作业并行运行,互不因失败而取消;同仓库 PR 和主分支推送会运行,fork PR 不读取 API key。`e2e-host` 缺少任一项时会失败。URL 和 model 同时存在于 Variable 与 Secret 时,优先使用 Secret。
|
|
546
590
|
|
|
547
591
|
## 项目结构
|
|
548
592
|
|
|
549
593
|
```
|
|
550
594
|
stock-analysis/
|
|
551
595
|
├── pi/ # Pi Agent Extension
|
|
552
|
-
│ └── index.ts # 注册
|
|
596
|
+
│ └── index.ts # 注册 67 个工具 + 20 个 skill
|
|
553
597
|
├── hermes/ # Hermes Agent Plugin
|
|
554
598
|
│ ├── plugin.yaml # 插件清单
|
|
555
599
|
│ ├── __init__.py # register(ctx) 入口
|
|
556
600
|
│ ├── schemas.py # 工具 JSON Schema 定义
|
|
557
|
-
│ └── tools.py #
|
|
601
|
+
│ └── tools.py # 67 个 handler → subprocess 调 CLI
|
|
558
602
|
├── openclaw/ # OpenClaw Plugin
|
|
559
603
|
│ ├── openclaw.plugin.json # manifest(contracts.tools)
|
|
560
604
|
│ ├── package.json # 含 openclaw 块(pluginApi/SDK 版本)
|
|
561
|
-
│ └── index.ts # definePluginEntry + registerTool ×
|
|
605
|
+
│ └── index.ts # definePluginEntry + registerTool ×67
|
|
562
606
|
├── dsh/ # DeepSeek Harness (dsh) Plugin
|
|
563
607
|
│ ├── cordis.patch.yml # bundle patch(insert 插件入口)
|
|
564
608
|
│ ├── package.json # 含 dsh.bundle 块(bundle manifest)
|
|
565
|
-
│ └── index.ts # cordis apply(ctx) + defineTool ×
|
|
609
|
+
│ └── index.ts # cordis apply(ctx) + defineTool ×67
|
|
566
610
|
│
|
|
567
611
|
├── tools/ # 共享 Python CLI 工具
|
|
568
612
|
│ ├── stock_data.py # 行情 / 资金流 / 新闻 / 财务 / 短线情绪
|
|
@@ -696,6 +740,24 @@ python3 tools/sec_edgar.py holdings 0001067983 --mode manager
|
|
|
696
740
|
|
|
697
741
|
首次下载当前 SEC 包约 100 MB;ZIP 按周缓存,CUSIP 反查结果按天缓存,流式扫描不解压整个持仓表、不增加数据库依赖。返回 `report_date`(持仓日期)、`filing_window_end`(公开申报窗口截止)、`cusip_evidence`(原文映射依据),不把文件披露窗口当作持仓日期。`mapping_complete=false` 表示最近十份结构化 13D/G 可能未覆盖所有证券类别或 CUSIP 变更;缺映射直接报错,不做名称模糊匹配。`complete_for_mapped_cusips` 仅在该报告期没有未解决申报链时为 true,不代表实时全部股东。期权与本金持仓在 `positions` 保留,`shares` 合计只计无 PUT/CALL 的 SH 股票。不能将跨机构合计当作已去重的全市场持股。
|
|
698
742
|
|
|
699
|
-
|
|
743
|
+
13F CLI 预算为 300 秒,宿主另留 30 秒接收输出;其他命令按共享预算表执行。机构查询优先寻找最新已知报告期的原始 13F:较新修订对应的原始版未找到时明确报错,历史分片仍未完全检索时返回 `history_truncated` 与警告。发行人 CUSIP 查询会跳过不可访问/无效 XML,继续核对后续原文;没有任何可验证映射时才报缺失。
|
|
744
|
+
|
|
745
|
+
## 分析可靠性验证
|
|
746
|
+
|
|
747
|
+
命令预算集中于 `tools/cli_budgets.json`:通用采集默认 120 秒、市场快照 240 秒、选股 top 须为正整数,预算按候选数及 6 个 worker 的批次计算(默认 20 个候选为 1830 秒)、13F 300 秒;技术分析、市场状态、回测和风险筛查按实际嵌套调用另留预算;四个宿主额外留 30 秒接收 CLI 输出。综合采集保留安全 JSON 错误及 error_code(timeout/empty_output/invalid_json/process_failed/tool_error),不会把失败当成有效空数据。
|
|
748
|
+
|
|
749
|
+
最终报告的固定证据案例覆盖完整、缺失、过期、同口径冲突及样本不足:
|
|
750
|
+
|
|
751
|
+
```bash
|
|
752
|
+
.venv/bin/python -m pytest tests/test_analysis_quality.py -q
|
|
753
|
+
# 需要 OPENAI_BASE_URL / OPENAI_API_KEY / OPENAI_MODEL;只调用模型,数据源使用固定夹具
|
|
754
|
+
.venv/bin/python -m pytest tests/e2e/test_analysis_quality.py -m integration_llm -v
|
|
755
|
+
```
|
|
756
|
+
|
|
757
|
+
真实模型评测同时要求结构化证据检查与独立上下文的结论审稿通过:审稿检查正文事实、限制说明是否诚实,以及是否过度外推。未运行审稿、结果缺失或模糊都不能算通过;报告自行声明通过不被采信。另有人工核对的正确报告及两类反例用于验证审稿器(正确引用但正文捏造现价、3笔交易却保证长期胜率)。空回答也失败。离线渲染和规则检查不代表真实模型通过,也不证明策略未来有效。信号建议可沿用 source 标识策略版本,按来源复盘胜率、平均收益和样本量;未扣成本、未匹配基准的观察记录不能当作策略回测。
|
|
758
|
+
|
|
759
|
+
信号结算仅在价格口径可核实时进行:原始价格可直接比较;复权日线需记录日 adjustment_factor(复权价/原始价),当前日线 Tushare、Alpha Vantage 可提供。缺失系数或口径未知时返回 skipped_price_basis,保持未结算,不猜测除权比例。换算后的 exit_price 是记录时价格单位的等价值,实际市场价可不同,evaluation_price_basis 保留依据。evaluate_signals 的 CLI 预算为 300 秒,内部提前结束采集并保存已完成结果,complete/deferred/warnings 指示需要重试的记录;预算耗尽后调整未结算记录的处理顺序,下轮优先处理尚未尝试的记录,避免慢请求长期阻塞后续信号。
|
|
760
|
+
|
|
761
|
+
市场复盘数据不足时温度/姿态为 null,信号 unknown,data_quality.limitations 说明限制。自选股异动采集失败时 anomaly_status=unavailable、anomaly_count=null,保留警告并计入 summary.partial,不能当成无异常。
|
|
700
762
|
|
|
701
|
-
|
|
763
|
+
L1 与 L2 综合分均在排序前按可用因子重新归一化;缺失或非有限因子不作零分处理,因子组内部也仅平均有效输入。factor_coverage.ratio 保留原始权重覆盖率,effective_weights 是实际归一化后的权重,高分仍需结合覆盖率判断。
|
|
@@ -32,7 +32,7 @@ A 股 / 港股 / 美股 / 日股 / 韩股 / 台股综合分析、多因子选股
|
|
|
32
32
|
|
|
33
33
|
## 功能概览
|
|
34
34
|
|
|
35
|
-
- **
|
|
35
|
+
- **67 个工具** — 行情数据、技术分析、K 线形态、资金流向、估值历史、财报日历、股东/ETF/股息、新闻舆情、风险筛查、市场状态等
|
|
36
36
|
- **20 个 Skills** — 综合分析、全市场选股、策略回测 + 17 个策略方法论(缠论、波浪、龙头、情绪周期等)
|
|
37
37
|
- **策略回测引擎** — YAML DSL 定义策略,参数化条件组合,自动诊断,按需进行有限轮参数优化
|
|
38
38
|
- **多数据源 Failover** — 11 个数据源自动容灾切换(akshare / tushare / efinance / 腾讯行情 / 新浪行情 / pytdx / baostock / yfinance / finnhub / longbridge / alphavantage),A 股链路带粘性优选(最近成功的数据源下次优先尝试)
|
|
@@ -70,6 +70,8 @@ npm install @weaxs/stock-analysis-plugin
|
|
|
70
70
|
|
|
71
71
|
Pi 启动后自动加载,输入 `/skills` 确认。详见 [Pi Agent 接入指南](docs/pi-integration.md)([English](docs/pi-integration.en.md))。
|
|
72
72
|
|
|
73
|
+
新版 Pi(已核验 1.2.0)提供原生 `tool_search` 时,插件自动启用按需工具发现,67 项能力保留注册,仅命中工具加载完整定义。缺少原生发现接口的旧版 Pi 或 SDK 宿主保持全量暴露。检索使用英文关键词或工具名,例如 `get_quote`、`get_financials`。
|
|
74
|
+
|
|
73
75
|
### Hermes Agent Plugin
|
|
74
76
|
|
|
75
77
|
```bash
|
|
@@ -93,7 +95,7 @@ register(ctx)
|
|
|
93
95
|
openclaw plugins install clawhub:@weaxs/openclaw-stock-analysis
|
|
94
96
|
```
|
|
95
97
|
|
|
96
|
-
OpenClaw Gateway 启动后自动加载并注册
|
|
98
|
+
OpenClaw Gateway 启动后自动加载并注册 67 个 tool。安装时 postinstall 会自动建 `.venv` 并装好 Python 依赖(前提:本机有 `python3 >= 3.10`)。
|
|
97
99
|
|
|
98
100
|
详见 [OpenClaw 接入指南](docs/openclaw-integration.md),或 plugin 自身说明 [`openclaw/README.md`](openclaw/README.md)。
|
|
99
101
|
|
|
@@ -104,7 +106,9 @@ dsh plugin --profile <你的profile> add @weaxs/dsh-stock-analysis
|
|
|
104
106
|
dsh --profile <你的profile>
|
|
105
107
|
```
|
|
106
108
|
|
|
107
|
-
作为 dsh bundle 安装:`dsh plugin add` 会把 `cordis.patch.yml` 叠加进 profile 组合,注册
|
|
109
|
+
作为 dsh bundle 安装:`dsh plugin add` 会把 `cordis.patch.yml` 叠加进 profile 组合,注册 67 个 tool + 20 个 skill。postinstall 自动建 `.venv`(pnpm 需在 profile 的 `pnpm-workspace.yaml` 里给本包配 `allowBuilds`,否则回退系统 `python3`)。
|
|
110
|
+
|
|
111
|
+
新版 dsh 的原生函数调用模式默认通过 `stock_tool_search` 按 Agent 搜索、加载所需工具,支持中文关键词或工具名;旧接口、搜索入口不可用时保留全量暴露。可设置 `toolDiscovery: false` 关闭,配置与 PTC 模式边界见下方接入文档。
|
|
108
112
|
|
|
109
113
|
详见 [`dsh/README.md`](dsh/README.md)。
|
|
110
114
|
|
|
@@ -281,9 +285,9 @@ Agent 会自动调用行情 → 技术面 → 基本面 → 资金面 → 消息
|
|
|
281
285
|
|
|
282
286
|
| 工具 | 说明 |
|
|
283
287
|
|------|------|
|
|
284
|
-
| `screen_stocks` |
|
|
288
|
+
| `screen_stocks` | 全市场多因子筛选(可选 L2;factor_coverage 展示缺失因子、覆盖度、实际权重及 L2 effective_scores) |
|
|
285
289
|
| `screen_risk` | 风险因子筛查 |
|
|
286
|
-
| `run_backtest` | YAML
|
|
290
|
+
| `run_backtest` | YAML 策略回测,默认收盘信号于次日开盘成交,execution 返回模型与限制 |
|
|
287
291
|
| `detect_market_regime` | 市场状态检测(牛/熊/震荡) |
|
|
288
292
|
| `get_market_review` | 市场日度复盘数据 |
|
|
289
293
|
| `get_review_history` | 复盘归档历史(最近 N 条,最新在前,用于纵向对比) |
|
|
@@ -320,8 +324,8 @@ Agent 会自动调用行情 → 技术面 → 基本面 → 资金面 → 消息
|
|
|
320
324
|
| `check_alert_rules` | 无状态检查价格、涨跌幅、异动和风险规则 |
|
|
321
325
|
| `record_signal` | 记录 AI 分析建议信号(本地 JSONL 持久化) |
|
|
322
326
|
| `evaluate_signals` | 评估到期信号(target_hit/stop_hit/timeout 结算) |
|
|
323
|
-
| `get_signal_summary` |
|
|
324
|
-
| `render_stock_report` | 将结构化个股报告渲染为 Markdown |
|
|
327
|
+
| `get_signal_summary` | 信号胜率及分来源平均收益、有效收益样本数与小样本提示(按 source/symbol/status 过滤) |
|
|
328
|
+
| `render_stock_report` | 将结构化个股报告渲染为 Markdown,展示 evidence 与 data_quality 限制 |
|
|
325
329
|
| `render_market_report` | 将结构化市场复盘渲染为 Markdown(save=true 时归档到本地 JSONL) |
|
|
326
330
|
|
|
327
331
|
批量自选股分析和摘要的 `success` 表示至少获取了有效行情价格、K 线收盘价或技术评分;全部关键数据失败时计入 `failed`,部分结果仍保留。采集脚本复用返回的 K 线计算技术指标,并按股票所属市场查询大盘状态;日/韩/台市场状态暂不可用,非 A 股板块榜单也暂不可用,均会明确返回错误。
|
|
@@ -332,6 +336,43 @@ Agent 会自动调用行情 → 技术面 → 基本面 → 资金面 → 消息
|
|
|
332
336
|
|
|
333
337
|
选股的 `filters_applied` 只列实际执行的条件,显式条件缺少数据时报错。回测的 `period` 是实际数据期间,`requested_period` 保留请求期间,`warnings` 提示覆盖差异;买入预算包含佣金,年化收益和回撤按实际数据及初始资金计算。
|
|
334
338
|
|
|
339
|
+
### 无状态研究与风险计算
|
|
340
|
+
|
|
341
|
+
| 工具 | 说明 |
|
|
342
|
+
|------|------|
|
|
343
|
+
| `compare_stocks` | 比较显式输入的同行指标;检查单位、期间和口径,仅对可比数值排序 |
|
|
344
|
+
| `analyze_disclosure_changes` | 比较新旧公告正文与财务指标,返回来源、变更行号和增长率限制 |
|
|
345
|
+
| `analyze_portfolio_risk` | 一次性持仓的集中度、行业/币种敞口、价格盈亏、止损情景与可选相关性 |
|
|
346
|
+
| `calculate_position_size` | 按现金、风险预算、费用、滑点和交易单位计算本次可买数量 |
|
|
347
|
+
| `analyze_event_study` | 事件前一交易日收盘至各窗口的股票/基准收益差,标明缺失和重叠样本 |
|
|
348
|
+
| `validate_backtest` | 复用现有引擎,滚动训练选候选、样本外验证,比较参数及多个标的 |
|
|
349
|
+
| `compare_analysis_snapshots` | 比较调用方传入的快照,区分新增、删除、变化、数据失效和恢复 |
|
|
350
|
+
|
|
351
|
+
这些工具不保存自选股、账户或分析历史,也不提供调度/通知。现有数据工具采集行情和财务,宿主传入本次持仓、正文或快照;[完整输入约定与解读工作流](skills/stock-analysis/references/stateless-analysis.md)供四个宿主共用。
|
|
352
|
+
|
|
353
|
+
大输入经权限受限的临时 JSON 文件传给 Python,调用结束后清理,避免 Windows 命令行长度限制;CLI 也支持 stdin 和 `--input` 文件。公告正文由宿主读取:PDF/OCR 不包含在本次扩展中,只有标题或链接不能声称已读全文。
|
|
354
|
+
|
|
355
|
+
例如仓位预算(所有金额同币种,lot_size 由用户或交易规则确认):
|
|
356
|
+
|
|
357
|
+
```json
|
|
358
|
+
{
|
|
359
|
+
"equity": 100000, "cash": 20000,
|
|
360
|
+
"entry_price": 100, "stop_price": 95,
|
|
361
|
+
"risk_fraction": 0.01, "lot_size": 100,
|
|
362
|
+
"fee_rate": 0.001, "slippage_rate": 0.001
|
|
363
|
+
}
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
将上述 JSON 保存为 `input.json` 后运行:
|
|
367
|
+
|
|
368
|
+
```bash
|
|
369
|
+
python tools/stateless_analysis.py position_size --input input.json
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
对应宿主工具是 `calculate_position_size`。其余 CLI 子命令依次为 `peers/disclosure/portfolio/event_study/robustness/snapshot`。事件研究可直接传 `symbol/benchmark/start_date/end_date/event_dates`;回测验证可传 `symbols/start_date/end_date/strategies`,由 Python 复用行情接口,避免模型重新抄写历史 K 线。显式价格/datasets 模式仍支持离线计算,两种模式互斥。
|
|
373
|
+
|
|
374
|
+
跨币种组合必须提供显式汇率;价格盈亏不含历史汇兑损益。稳健性工具仅支持 next_open、每窗口重新从现金开始,样本内敏感性不等于样本外表现。
|
|
375
|
+
|
|
335
376
|
## 策略回测 DSL
|
|
336
377
|
|
|
337
378
|
策略以 YAML 格式定义,支持参数化和条件组合:
|
|
@@ -374,10 +415,13 @@ position:
|
|
|
374
415
|
max_positions: 1
|
|
375
416
|
```
|
|
376
417
|
|
|
418
|
+
行情 JSON 保留原有数组/字典形状,添加 `source`、UTC `fetched_at` 和 `data_as_of`。采集时间不是报价时间,提供方未给时间时为 null;仅提供交易日时保留 YYYY-MM-DD,不补造具体时刻;K 线 data_as_of 是该条的日期标签,周/月线标签不是实际末次成交时间;`as_of_basis=trading_calendar` 表示交易日历推断。A 股复权口径延续 qfq/none;其他市场按来源标为 total_return/qfq/unknown,不把 unknown 当已验证复权。
|
|
419
|
+
|
|
377
420
|
其他可用键:
|
|
378
421
|
|
|
379
422
|
- `exit.trailing_stop`:移动止损,价格自持仓期间最高收盘价回撤达到该比例即卖出(如 `0.08` = 峰值回撤 8% 触发);与 `stop_loss` 同时设置时先判固定止损。
|
|
380
423
|
- `benchmark`(顶层):基准对比标的代码(如 `"sh000300"` 沪深300;指数代码必须带 sh/sz 交易所前缀,裸 6 位数字会被当作个股),设置后回测结果附带 `benchmark` 块(基准买入持有收益与 `excess_return` 超额收益)。
|
|
424
|
+
- `simulation.execution`:默认 `next_open`,前日收盘信号、次日开盘加滑点成交;显式 `same_close` 复现旧收盘成交假设。交易同时返回 signal_date/date。零成交量阻止成交;一字板限制只在输入提供同口径历史 limit_up/limit_down 时执行。`execution` 列出阻止成交次数、未成交订单及限制;止损是收盘信号,未模拟盘口排队、部分成交、结算和市场冲击。
|
|
381
425
|
- `simulation`(顶层):交易成本。`slippage`(滑点,买卖双边,默认 0.001)、`commission`(佣金,买卖双边,默认 0.0015)、`stamp_tax`(印花税,仅卖出收取,默认 0;A股为 0.0005,各市场税率不同且会调整,按当下实际费率填写)。费率均须在 [0, 1) 区间,越界报错。回测结果附带 `costs` 块(实际生效费率与实付费用合计 `commission_paid`/`stamp_tax_paid`)。
|
|
382
426
|
|
|
383
427
|
### 可用指标
|
|
@@ -501,27 +545,27 @@ GitHub Actions 的 `e2e-host` 使用 Pi、Hermes、OpenClaw、dsh 的真实运
|
|
|
501
545
|
| `OPENAI_API_KEY` | Secret | 对应的 API key |
|
|
502
546
|
| `OPENAI_MODEL` | Variable 或 Secret | 支持 tool calling 的模型 ID |
|
|
503
547
|
|
|
504
|
-
`e2e-llm`
|
|
548
|
+
`e2e-llm` 也使用这三项配置,Hermes(含报告质量评测)、Pi、OpenClaw 和 dsh 通过四个 matrix 作业并行运行,互不因失败而取消;同仓库 PR 和主分支推送会运行,fork PR 不读取 API key。`e2e-host` 缺少任一项时会失败。URL 和 model 同时存在于 Variable 与 Secret 时,优先使用 Secret。
|
|
505
549
|
|
|
506
550
|
## 项目结构
|
|
507
551
|
|
|
508
552
|
```
|
|
509
553
|
stock-analysis/
|
|
510
554
|
├── pi/ # Pi Agent Extension
|
|
511
|
-
│ └── index.ts # 注册
|
|
555
|
+
│ └── index.ts # 注册 67 个工具 + 20 个 skill
|
|
512
556
|
├── hermes/ # Hermes Agent Plugin
|
|
513
557
|
│ ├── plugin.yaml # 插件清单
|
|
514
558
|
│ ├── __init__.py # register(ctx) 入口
|
|
515
559
|
│ ├── schemas.py # 工具 JSON Schema 定义
|
|
516
|
-
│ └── tools.py #
|
|
560
|
+
│ └── tools.py # 67 个 handler → subprocess 调 CLI
|
|
517
561
|
├── openclaw/ # OpenClaw Plugin
|
|
518
562
|
│ ├── openclaw.plugin.json # manifest(contracts.tools)
|
|
519
563
|
│ ├── package.json # 含 openclaw 块(pluginApi/SDK 版本)
|
|
520
|
-
│ └── index.ts # definePluginEntry + registerTool ×
|
|
564
|
+
│ └── index.ts # definePluginEntry + registerTool ×67
|
|
521
565
|
├── dsh/ # DeepSeek Harness (dsh) Plugin
|
|
522
566
|
│ ├── cordis.patch.yml # bundle patch(insert 插件入口)
|
|
523
567
|
│ ├── package.json # 含 dsh.bundle 块(bundle manifest)
|
|
524
|
-
│ └── index.ts # cordis apply(ctx) + defineTool ×
|
|
568
|
+
│ └── index.ts # cordis apply(ctx) + defineTool ×67
|
|
525
569
|
│
|
|
526
570
|
├── tools/ # 共享 Python CLI 工具
|
|
527
571
|
│ ├── stock_data.py # 行情 / 资金流 / 新闻 / 财务 / 短线情绪
|
|
@@ -655,6 +699,24 @@ python3 tools/sec_edgar.py holdings 0001067983 --mode manager
|
|
|
655
699
|
|
|
656
700
|
首次下载当前 SEC 包约 100 MB;ZIP 按周缓存,CUSIP 反查结果按天缓存,流式扫描不解压整个持仓表、不增加数据库依赖。返回 `report_date`(持仓日期)、`filing_window_end`(公开申报窗口截止)、`cusip_evidence`(原文映射依据),不把文件披露窗口当作持仓日期。`mapping_complete=false` 表示最近十份结构化 13D/G 可能未覆盖所有证券类别或 CUSIP 变更;缺映射直接报错,不做名称模糊匹配。`complete_for_mapped_cusips` 仅在该报告期没有未解决申报链时为 true,不代表实时全部股东。期权与本金持仓在 `positions` 保留,`shares` 合计只计无 PUT/CALL 的 SH 股票。不能将跨机构合计当作已去重的全市场持股。
|
|
657
701
|
|
|
658
|
-
|
|
702
|
+
13F CLI 预算为 300 秒,宿主另留 30 秒接收输出;其他命令按共享预算表执行。机构查询优先寻找最新已知报告期的原始 13F:较新修订对应的原始版未找到时明确报错,历史分片仍未完全检索时返回 `history_truncated` 与警告。发行人 CUSIP 查询会跳过不可访问/无效 XML,继续核对后续原文;没有任何可验证映射时才报缺失。
|
|
703
|
+
|
|
704
|
+
## 分析可靠性验证
|
|
705
|
+
|
|
706
|
+
命令预算集中于 `tools/cli_budgets.json`:通用采集默认 120 秒、市场快照 240 秒、选股 top 须为正整数,预算按候选数及 6 个 worker 的批次计算(默认 20 个候选为 1830 秒)、13F 300 秒;技术分析、市场状态、回测和风险筛查按实际嵌套调用另留预算;四个宿主额外留 30 秒接收 CLI 输出。综合采集保留安全 JSON 错误及 error_code(timeout/empty_output/invalid_json/process_failed/tool_error),不会把失败当成有效空数据。
|
|
707
|
+
|
|
708
|
+
最终报告的固定证据案例覆盖完整、缺失、过期、同口径冲突及样本不足:
|
|
709
|
+
|
|
710
|
+
```bash
|
|
711
|
+
.venv/bin/python -m pytest tests/test_analysis_quality.py -q
|
|
712
|
+
# 需要 OPENAI_BASE_URL / OPENAI_API_KEY / OPENAI_MODEL;只调用模型,数据源使用固定夹具
|
|
713
|
+
.venv/bin/python -m pytest tests/e2e/test_analysis_quality.py -m integration_llm -v
|
|
714
|
+
```
|
|
715
|
+
|
|
716
|
+
真实模型评测同时要求结构化证据检查与独立上下文的结论审稿通过:审稿检查正文事实、限制说明是否诚实,以及是否过度外推。未运行审稿、结果缺失或模糊都不能算通过;报告自行声明通过不被采信。另有人工核对的正确报告及两类反例用于验证审稿器(正确引用但正文捏造现价、3笔交易却保证长期胜率)。空回答也失败。离线渲染和规则检查不代表真实模型通过,也不证明策略未来有效。信号建议可沿用 source 标识策略版本,按来源复盘胜率、平均收益和样本量;未扣成本、未匹配基准的观察记录不能当作策略回测。
|
|
717
|
+
|
|
718
|
+
信号结算仅在价格口径可核实时进行:原始价格可直接比较;复权日线需记录日 adjustment_factor(复权价/原始价),当前日线 Tushare、Alpha Vantage 可提供。缺失系数或口径未知时返回 skipped_price_basis,保持未结算,不猜测除权比例。换算后的 exit_price 是记录时价格单位的等价值,实际市场价可不同,evaluation_price_basis 保留依据。evaluate_signals 的 CLI 预算为 300 秒,内部提前结束采集并保存已完成结果,complete/deferred/warnings 指示需要重试的记录;预算耗尽后调整未结算记录的处理顺序,下轮优先处理尚未尝试的记录,避免慢请求长期阻塞后续信号。
|
|
719
|
+
|
|
720
|
+
市场复盘数据不足时温度/姿态为 null,信号 unknown,data_quality.limitations 说明限制。自选股异动采集失败时 anomaly_status=unavailable、anomaly_count=null,保留警告并计入 summary.partial,不能当成无异常。
|
|
659
721
|
|
|
660
|
-
|
|
722
|
+
L1 与 L2 综合分均在排序前按可用因子重新归一化;缺失或非有限因子不作零分处理,因子组内部也仅平均有效输入。factor_coverage.ratio 保留原始权重覆盖率,effective_weights 是实际归一化后的权重,高分仍需结合覆盖率判断。
|
|
@@ -61,121 +61,6 @@ services.hermes-agent = {
|
|
|
61
61
|
|
|
62
62
|
After starting Hermes Agent, use `/plugins` to view loaded plugins — you should see `stock-analysis`.
|
|
63
63
|
|
|
64
|
-
You can also verify programmatically:
|
|
65
|
-
|
|
66
|
-
```python
|
|
67
|
-
from hermes import register
|
|
68
|
-
|
|
69
|
-
class MockCtx:
|
|
70
|
-
def __init__(self):
|
|
71
|
-
self.tools = []
|
|
72
|
-
self.skills = []
|
|
73
|
-
|
|
74
|
-
def register_tool(self, name, toolset, schema, handler):
|
|
75
|
-
self.tools.append(name)
|
|
76
|
-
|
|
77
|
-
def register_skill(self, name, path):
|
|
78
|
-
self.skills.append(name)
|
|
79
|
-
|
|
80
|
-
ctx = MockCtx()
|
|
81
|
-
register(ctx)
|
|
82
|
-
print(f"Tools: {len(ctx.tools)}") # Should print 48
|
|
83
|
-
print(f"Skills: {len(ctx.skills)}") # Should print 20
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
## How It Works
|
|
87
|
-
|
|
88
|
-
### Plugin Discovery
|
|
89
|
-
|
|
90
|
-
Hermes discovers this plugin through two mechanisms:
|
|
91
|
-
|
|
92
|
-
1. **pip entry point**: `pyproject.toml` declares the `hermes_agent.plugins` entry point:
|
|
93
|
-
|
|
94
|
-
```toml
|
|
95
|
-
[project.entry-points."hermes_agent.plugins"]
|
|
96
|
-
stock-analysis = "hermes"
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
> Note: the entry point must reference the **module** (`hermes`), not `hermes:register` — Hermes 0.19's loader calls `ep.load()` and then `getattr(module, "register")`. Pointing at the function makes `ep.load()` return the function itself, and the loader reports "no register() function" and silently skips tool registration.
|
|
100
|
-
|
|
101
|
-
2. **Directory discovery**: `hermes/plugin.yaml` serves as the plugin manifest for Hermes CLI installs.
|
|
102
|
-
|
|
103
|
-
### Tool Registration
|
|
104
|
-
|
|
105
|
-
`hermes/__init__.py` exports a `register(ctx)` function that receives the Hermes PluginContext:
|
|
106
|
-
|
|
107
|
-
```python
|
|
108
|
-
from pathlib import Path
|
|
109
|
-
from . import schemas, tools
|
|
110
|
-
|
|
111
|
-
PROJECT_ROOT = Path(__file__).resolve().parent.parent
|
|
112
|
-
SKILLS_DIR = PROJECT_ROOT / "skills"
|
|
113
|
-
|
|
114
|
-
def register(ctx):
|
|
115
|
-
for schema in schemas.TOOL_SCHEMAS:
|
|
116
|
-
name = schema["name"]
|
|
117
|
-
handler = _HANDLER_MAP[name]
|
|
118
|
-
ctx.register_tool(
|
|
119
|
-
name=name,
|
|
120
|
-
toolset="stock-analysis",
|
|
121
|
-
schema=schema,
|
|
122
|
-
handler=handler,
|
|
123
|
-
)
|
|
124
|
-
|
|
125
|
-
for child in sorted(SKILLS_DIR.iterdir()):
|
|
126
|
-
skill_md = child / "SKILL.md"
|
|
127
|
-
if child.is_dir() and skill_md.exists():
|
|
128
|
-
ctx.register_skill(child.name, str(skill_md))
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
### Tool Definitions (Schema)
|
|
132
|
-
|
|
133
|
-
`hermes/schemas.py` defines the JSON Schema for all 51 tools, each containing `name`, `description`, and `parameters`:
|
|
134
|
-
|
|
135
|
-
```python
|
|
136
|
-
TOOL_SCHEMAS = [
|
|
137
|
-
{
|
|
138
|
-
"name": "get_kline",
|
|
139
|
-
"description": "Fetch stock OHLCV candlestick data...",
|
|
140
|
-
"parameters": {
|
|
141
|
-
"type": "object",
|
|
142
|
-
"properties": {
|
|
143
|
-
"symbol": {"type": "string", "description": "Stock symbol"},
|
|
144
|
-
"period": {"type": "string", "enum": ["daily", "weekly", "monthly"]},
|
|
145
|
-
"count": {"type": "number", "description": "Number of data points"},
|
|
146
|
-
},
|
|
147
|
-
"required": ["symbol"],
|
|
148
|
-
},
|
|
149
|
-
},
|
|
150
|
-
# ... 30 more
|
|
151
|
-
]
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
### Tool Handlers
|
|
155
|
-
|
|
156
|
-
`hermes/tools.py` implements 48 handler functions, each calling the corresponding Python CLI script via `subprocess`:
|
|
157
|
-
|
|
158
|
-
```python
|
|
159
|
-
PROJECT_ROOT = Path(__file__).resolve().parent.parent
|
|
160
|
-
TOOLS_DIR = PROJECT_ROOT / "tools"
|
|
161
|
-
|
|
162
|
-
def _find_python():
|
|
163
|
-
venv_python = PROJECT_ROOT / ".venv" / "bin" / "python3"
|
|
164
|
-
if venv_python.exists():
|
|
165
|
-
return str(venv_python)
|
|
166
|
-
return "python3"
|
|
167
|
-
|
|
168
|
-
def _run(script, args):
|
|
169
|
-
python = _find_python()
|
|
170
|
-
cmd = f"{python} {TOOLS_DIR / script} {args}"
|
|
171
|
-
result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=120)
|
|
172
|
-
return result.stdout
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
### Path Resolution
|
|
176
|
-
|
|
177
|
-
The plugin locates the project root via `Path(__file__).resolve().parent.parent`. When installed via pip, both `hermes/` and `tools/` are installed as top-level packages in site-packages, maintaining the expected relative path structure.
|
|
178
|
-
|
|
179
64
|
## Environment Variables
|
|
180
65
|
|
|
181
66
|
Environment variables are grouped by function — configure as needed:
|
|
@@ -298,7 +183,7 @@ stock-analysis-plugin (wheel)
|
|
|
298
183
|
├── hermes/
|
|
299
184
|
│ ├── __init__.py # register(ctx) entry point
|
|
300
185
|
│ ├── plugin.yaml # Plugin manifest
|
|
301
|
-
│ ├── schemas.py # JSON Schema definitions for
|
|
186
|
+
│ ├── schemas.py # JSON Schema definitions for 67 tools
|
|
302
187
|
│ └── tools.py # 51 handlers calling CLI via subprocess
|
|
303
188
|
└── tools/ # Python CLI tools
|
|
304
189
|
```
|