Repository navigation
refactor(intelligence): merge the two causal-chain engines into one (P1.2) - #67
Merged
Merged
Conversation
Closes #48 (P1.2). There were two parallel engines: ImpactChainEngine (in-code templates, substring match) and CausalChainConstructor/EventImpactEngine (YAML templates, regex + LLM fallback). The latter is canonical (core trading pipeline). Make ImpactChainEngine a thin ADAPTER over CausalChainConstructor so there is one chain-construction engine, preserving its public API. - impact_chain.py: ImpactChainEngine now delegates to CausalChainConstructor. build_chain() bridges CausalChain→ImpactChain (bullish→positive, confidence→ magnitude, order→lag). CHAIN_TEMPLATES is retained ONLY to build a sector→stock map that re-binds affected_stocks (Engine B resolves sectors only) — so find_stock_impact keeps working. Engine B and its callers (aggregator/investment_director/trading_loop) are untouched. - config/impact_chain_templates.yaml: add usd_strengthen / usd_weaken templates so USD→gold transmission (the one capability the in-code engine had and the YAML lacked) is preserved — making the merge lossless. - tests: rewrite test_impact_chain.py to the new contract (incl. a test proving find_stock_impact returns stock-level impacts); restore test_usd_affects_gold. Verified: full unit suite 3811 passed; ruff clean. detect_event_type is now single-match (documented semantic shift; no caller depended on multi-match). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
daymade
added a commit
to daymade/ashare-ai-analyst
that referenced
this pull request
Sep 8, 2026
* feat: v2.0 — AI-first autonomous agent architecture (+ 智能选股, Basic Auth) (Jcstack#39) ## Summary Major **v2.0** upgrade: moves the platform from the linear data → analysis → prediction → strategy pipeline to an **AI-first autonomous agent** centered on an OODA decision loop, fed by a market-intelligence pipeline, quant signals, and a smart stock screener, over a Redis-Streams event bus. **Simulation-only toy project** — no live order routing (see the disclaimer in `README.md`). The functionality was imported from the upstream dev branch as **fresh, clean history** — no upstream commits, no private `.claude/` session state, no internal docs, no secrets. ## Commits (5) 1. `feat: port AI-first autonomous agent architecture` — `src/agent_loop/` (OODA loop, signal aggregation, Bayesian prescreen, bull/bear debate, risk gates, Kelly sizing, InvestmentDirector, thesis/outcome tracking, calibration), `src/intelligence(_hub)/` (5-layer sources, 7-dim scoring, causal chains, NetworkX knowledge graph), `src/quant/` (HMM regime, signal library), `src/event_bus/` (Redis Streams), `src/risk/` + `src/trading/` (circuit breaker, VaR, gates, A-share constraints), new frontend pages, LLM gateway. Removes the legacy rule-based recommendation flow. 2. `test: fix inherited stale assertions + add pytest-asyncio` — 32 stale assertions corrected to current behaviour (no behavioural change); adds the missing `pytest-asyncio` so async tests actually run. 3. `feat: restore recommendation (智能选股) subsystem, adapted to v2` — multi-style screener + LLM review + T+1 overnight risk + persistence + UI, **fed into the agent loop's signal aggregator** (reviving a previously-dead signal source). Drops `session_strategies` (superseded by the heartbeat mission router). 4. `docs: rewrite README / dev-guide / CLAUDE.md for v2.0 + CHANGELOG`. 5. `feat(web): optional HTTP Basic Auth for the dashboard/API` — gated by `WEB_USERNAME`/`WEB_PASSWORD` (off by default; `/health` public). Also fixes a latent upstream bug (non-latin-1 `WWW-Authenticate` realm → 500). ## Verification - ruff lint + format: clean - `pytest tests/unit`: **3801 passed / 0 failed** - frontend `tsc --noEmit` + `vite build`: pass - gitleaks (repo config): no leaks - smoke run: app boots (242 routes), `/health` ok, recommendation endpoints respond, the agent loop constructs with the recommendation feed wired live, Basic Auth verified (no creds → 401, correct → 200, `/health` public) 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Jcstack <Jcstack@users.noreply.github.com> * fix: triage & resolve CodeQL alerts (real bugs, FPs, CI hardening) (Jcstack#40) ## Summary Code-scan triage of the v2 import (follow-up to Jcstack#39). Fixes real issues, clears false positives **at the source**, hardens CI, and verifies no behaviour change. Remaining low-severity noise (log-injection / empty-except / cyclic-import etc.) is triaged and dismissed separately with rationale — none are exploitable in this app. ## What changed (45 fixes across 40 files) - **Real bugs** (7): dead/always-true branches and dead stores CodeQL surfaced in trend_hunter, event_correlator, decision_pipeline, review_agent, debate_memory, alternative_bars, realtime_analyzer. - **CI hardening**: least-privilege `permissions:` on workflows; gitleaks action pinned to a full commit SHA. - **Security**: path-containment guard in `config.py` (clears py/path-injection); generic error responses in 7 api_v1 routes (clears py/stack-trace-exposure). - **False positives cleared at source**: NaN idioms → `math.isnan`/`pd.notna`; implicit string-concat → explicit; `side-effect-in-assert` → extracted. ## Verification ruff clean · `pytest tests/unit`: **3801 passed / 0 failed** · frontend tsc + build green. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Jcstack <Jcstack@users.noreply.github.com> * docs: add tiered post-v2.0.0 roadmap (grounded in code audit) (Jcstack#41) ## What Adds `ROADMAP.md` — a tiered, evidence-grounded roadmap derived from a multi-agent audit of the v2 codebase, ordered to move the project from **"asserted"** to **"shown"**. - **P0 — correctness bugs** (each verified against code): preflight circuit-breaker gate is a no-op (`preflight.py:139` never reads persisted halt state); preflight advertises a T+1 check it never runs; `review_agent` score-cutoff mismatch. - **P1 — dedup / dead code / honest naming**: A-share constraints duplicated 4×; two causal-chain engines; two data-failover paths; dead modules (`alternative_bars.py`, `get_sector_win_rates`); overstated `Alpha158` / "causal chains" / `IC`; stub `_sector_calibration`. - **P2 — validation & design** (highest leverage): publish an out-of-sample A-share backtest of the v2 stack; fix the Bayesian likelihood derivation; close `OutcomeTracker` test gaps + trading-day horizons; validate the LLM-debate dependency. - **P3 — adoption**: one-command quickstart; technical write-up + demo. Every item cites `file:line` evidence. ## Why Captures the honest state of the project post-`v2.0.0` and the prioritized path forward, so the work is tracked rather than tribal. ## Notes Docs-only change. Simulation-only project; **not investment advice**. Co-authored-by: Jcstack <Jcstack@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(backtest): bridge the v2 quant stack into the backtest engine (P2.1 scaffold) (Jcstack#43) Implements the **P2.1** scaffold from `ROADMAP.md` — the highest-leverage item: make the **v2 signal stack backtestable**. ## Why The audit found the v2 signal layer (`SignalLibrary` + `RegimeDetector`) and the A-share backtest engine were **architecturally forked** — the OODA agent loop never touched `src/backtest/`. So the v2 stack had *never* been run out-of-sample, and its likelihood tables / thresholds were unvalidated. This builds the bridge. ## What - **`src/strategy/quant_v2.py`** — `QuantSignalV2Strategy`, a `BaseStrategy` adapter. For each bar it evaluates the v2 signals on the **expanding window `df[:i+1]` only** (no look-ahead) and fuses the signal consensus with an optional regime gate: buys are vetoed in a bear regime, and strength is modulated by regime confirmation. The HMM regime is recomputed every `regime_stride` bars and carried forward to keep the pass O(N) fits rather than O(N²). - **`scripts/backtest_v2.py`** — runnable CLI that drives the adapter through the existing engine (T+1, board price limits, 100-share lots, stamp tax) and prints metrics + an **honest buy-and-hold baseline**. Loads history from the configured data sources, or fully offline from a local OHLCV CSV. - **`tests/unit/test_quant_v2_strategy.py`** — contract tests + a **no-look-ahead** test: `generate_signals(df)[:k] == generate_signals(df[:k])`, which can only hold if every bar depends solely on past data. ## Verified `ruff` clean; 6 adapter tests pass; end-to-end smoke run on a 180-bar synthetic series produces a real equity curve (5 round-trips, Sharpe ≈ 0.49, +10pp excess vs buy-and-hold). ## Not in this PR Publishing out-of-sample results on **real** A-share data (a chosen universe/window) is the follow-up — that needs network/data and a maintainer decision on the test window. This PR delivers the runnable bridge + tests. Simulation/research only — **not investment advice**. --- Part of Jcstack#53 Co-authored-by: Jcstack <Jcstack@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(risk): enforce circuit-breaker halt + T+1 in preflight; name review_agent score cutoffs (Jcstack#42) Fixes the three **P0 correctness bugs** from the post-`v2.0.0` audit (tracked in `ROADMAP.md`). Each was verified against the code before fixing. ## P0.1 — preflight circuit-breaker gate was a no-op `PreflightRiskCheck._check_circuit_breaker` constructed a fresh `CircuitBreaker()` and read its in-memory `_state`, which always initializes to `NORMAL`. It never called `load_from_redis()`/`is_halted()`, so a **persisted halt was silently bypassed** — the gate always passed. **Fix:** call `breaker.is_halted()` (loads Redis state + honors active cooldown). ## P0.2 — preflight advertised a T+1 check it never ran The class docstring listed "T+1 sellability" but `check()` never called `can_sell_today`. **Fix:** add an optional `buy_date` to `check()` and a real `_check_t1_sellability()` that blocks selling a position opened today. Enforced when `buy_date` is supplied; passes (with honest docstring) when it isn't. Existing positional callers are unaffected (param defaults to `None`). ## P0.3 — review_agent score-cutoff inconsistency Two unexplained cutoffs (`0.65` in the LLM path, `0.55` in the fallback) and a test whose docstring said `0.65` while it exercised the `0.55` fallback — passing by luck. **Fix:** name both as intentional constants (`BUY_SCORE_THRESHOLD` / `WATCH_SCORE_THRESHOLD`), document why they differ, and rewrite the test to assert the exact boundary. ## Tests New regression tests: halted breaker blocks an order; same-day sell blocked by T+1 while an earlier buy passes; no-`buy_date` skips enforcement; fallback keeps `>= WATCH` and drops below it. `ruff` clean; affected suites green (`test_preflight`, `test_review_agent`, `test_circuit_breaker`, `test_execution_bridge`, `test_recommendation_service`). Simulation-only project; **not investment advice**. --- Closes Jcstack#44 Closes Jcstack#45 Closes Jcstack#46 --------- Co-authored-by: Jcstack <Jcstack@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(backtest): publish honest out-of-sample results for the v2 stack (P2.1) (Jcstack#59) Closes Jcstack#53 — the first real, out-of-sample evaluation of whether the **v2 signal/sizing stack** predicts anything. **It does not, in this configuration** — and publishing that honestly is the point. ## Result Over **2019–2024** (14 sector-diverse A-shares, equal-weight), the v2 strategy returned **+25.5%** vs buy-and-hold's **+351.7%**, and **beat buy-and-hold on 0 of 14** names.  | Window | Strategy | Buy & Hold | Excess | Sharpe | Beat B&H | |---|---|---|---|---|---| | Full 2019–2024 | +25.5% | +351.7% | −326.2% | 0.14 | 0/14 | | Bull 2019–2021 | +25.2% | +410.3% | −385.1% | 0.41 | 0/14 | | Bear 2022–2024 | +4.7% | +1.1% | +3.6% | −0.19 | 8/14 | ## What it actually is A **drawdown-limiter that caps trend upside**, not an alpha engine: - The engine's **15% take-profit** exits every winner early (300750/CATL ran **+1153%** buy-and-hold; the strategy captured **+58%**). This single rule, not signal quality, drives most of the gap. - **~40% per-trade win rate** — the entry signals aren't separating winners from losers. - It only "wins" in the isolated 2022–24 downturn (8/14), and even there mean Sharpe is negative — the edge is *avoided losses*, not skill. This confirms the project's own honest self-assessment ("machinery real, inputs unproven") — now **measured**, not asserted. ## Contents - `docs/backtest-v2-results.md` — full write-up (TL;DR, regime breakdown, per-name table, why it underperforms, next steps, methodology, reproduce, limitations). - `docs/assets/backtest-v2-equity.png` — equal-weight equity curve. - `scripts/backtest_v2_universe.py` — reproducible universe runner (table + chart; board inferred from code prefix; CSV cache for offline re-runs). `ruff` clean. - README + docs index links. ## Reproduce ```bash python -m scripts.backtest_v2_universe --start 20190101 --end 20241231 --chart docs/assets/backtest-v2-equity.png ``` ## Follow-ups this reframes Exit-rule study (remove/raise the 15% TP — highest signal/noise), Jcstack#54 (Bayesian likelihood), Jcstack#56 (LLM-debate validation), broaden the universe + walk-forward. Docs/script only — no `src/` runtime change. Simulation only; **not investment advice**. Co-authored-by: Jcstack <Jcstack@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(cleanup): remove dead code + no-op calibration dimension (P1.4, P1.6) (Jcstack#60) Closes Jcstack#50, closes Jcstack#52. ## Jcstack#50 — dead code (all verified 0 production callers before removal) - `src/quant/alternative_bars.py` (+ test) — orphaned module. - `RecStore.get_sector_win_rates` — unused **and** buggy (`GROUP BY style` while the docstring claimed per-sector). - `OvernightRiskProfile.to_context_str` (+ test) — built but never called. (The live `to_context_str` on `IntelChain`, used by `recommendation_service`, is untouched.) - Deprecated `PROFESSIONAL_ANALYSIS_FRAMEWORK` / `QUICK_ANALYSIS_FRAMEWORK` prompt constants — superseded by the v7.0 seven-dimension framework. ## Jcstack#52 — stubs behind advertised features - `ConfidenceCalibrator` advertised a per-sector calibration dimension that **always returned 0.0**. Removed the dead dimension + method; kept the (now-reserved) `sector` param and documented it honestly. **Behavior-preserving** (it contributed exactly 0.0). - Made `LiveBroker`'s simulation-only-by-design status explicit in its docstring + `NotImplementedError` messages. ## Verified `ruff check` + `ruff format --check` clean; import smoke + 366 related tests green (overnight-risk, recommendation, calibrator, broker, quant, prediction). No behavior change. Simulation-only project; not investment advice. Co-authored-by: Jcstack <Jcstack@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(agent_loop): Bayesian likelihoods + trading-day horizons + debate de-risk (P2.2–P2.4) (Jcstack#61) Closes Jcstack#54, closes Jcstack#55, closes Jcstack#56. ## Jcstack#54 — fix the Bayesian likelihood derivation `OutcomeTracker.get_calibration_data` set `P(signal|bull) = hit-rate` and `P(signal|bear) = 1 − hit-rate` — conflating a **posterior** (accuracy) with a **likelihood**, and asserting a complementarity that only holds for posteriors. Replaced with genuine **conditional frequencies**: the realized state is reconstructed per signal from `direction × correctness`, and `P(bullish reading | bull)` / `P(bullish reading | bear)` are estimated as Laplace-smoothed counts. They are real likelihoods (need not sum to 1); `log(p_bull/p_bear)` is now positive only for genuinely informative sources. ## Jcstack#55 — trading-day T+N horizons `t1/t3/t5 = created_at + timedelta(days=N)` used **calendar** days, so a T+1 lookup after a Friday landed on a non-trading Saturday. Now uses `TradingCalendar` (N sessions, with a calendar-day fallback) and gates each horizon on *target session ≤ today*. Adds the **first dedicated `OutcomeTracker` unit test** (the feedback heart was only covered indirectly). ## Jcstack#56 — de-risk the LLM-debate dependency The pipeline hard-refused buys when the debate engine was unavailable, so live decision quality rested entirely on an unvalidated oracle. Added opt-in `allow_degraded_buys` (**default OFF — behavior-preserving**): when enabled, the deterministic stack issues a *damped* buy off the Bayesian prescreen, so a missing/failed debate degrades gracefully instead of silently dropping signals. ## Verified `ruff` clean; **382** agent_loop / bayesian / decision / outcome / execution tests green, including **8 new** (3 likelihood-correctness, 2 trading-day, 3 degraded-buy). Simulation-only project; not investment advice. Co-authored-by: Jcstack <Jcstack@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(naming): stop overstating Alpha158 / causal chains / IC (P1.5) (Jcstack#62) Closes Jcstack#51. **Documentation/label honesty only — no behavior change.** - **Alpha158:** `README`, dev-guide, and the `qlib_alpha` docstring now say "Qlib custom alpha factors". It is a hand-written ~20-factor set in the Qlib DSL, **not** Qlib's 158-factor `Alpha158` dataset handler (which the code never instantiates). - **"Causal chains":** `impact_chain` is documented as hand-authored, keyword-matched transmission **templates** (a curated rule base with fixed confidences) — not statistically inferred causality. - **IC:** both `qlib_worker` call sites are annotated that the value is a serial **return autocorrelation proxy**, not a true cross-sectional Information Coefficient. The `"ic"` key is kept for config/back-compat. `ruff` clean; imports + 69 quant/intelligence tests green. Simulation-only; not investment advice. Co-authored-by: Jcstack <Jcstack@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: "How It Works" overview tying architecture to backtest results (P3.2) (Jcstack#63) Closes Jcstack#58. A short, newcomer-friendly technical write-up of the OODA decision loop (aggregate → Bayesian prescreen → bull/bear debate → risk gates → Kelly sizing) and the closed calibration loop, ending with the **honest out-of-sample backtest** (no demonstrated alpha — +25.5% vs +351.7% buy-and-hold, 0/14) and a reproduce command. Clearly separates what is **real** (the machinery) from what is **unproven** (the inputs). Linked from README + docs index. A screen-recorded demo GIF still needs a manual capture — noted as a follow-up rather than fabricated. Docs-only; simulation-only project, not investment advice. Co-authored-by: Jcstack <Jcstack@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(constants): single source of truth for A-share constants (P1.1) (Jcstack#64) Closes Jcstack#47. The lot size, commission/stamp rates, max-position cap, and board price limits were re-declared as literal defaults in **trading**, **strategy**, **backtest**, and **risk** modules. Introduces `src/utils/ashare_constants.py` as the canonical source; the sites now import the shared values instead of re-hardcoding them. - `strategy/base.py`: `PRICE_LIMITS` imported from canonical and re-exported (so `backtest/engine`'s `from src.strategy.base import PRICE_LIMITS` is unchanged); numeric defaults reference `LOT_SIZE`/`COMMISSION_RATE`/`STAMP_DUTY_RATE`. - `trading/constraints.py`: CHINEXT/STAR prefixes + numeric defaults from canonical. - `risk/position_sizer.py`: `LOT_SIZE` / `MAX_SINGLE_POSITION` from canonical. **Behavior-preserving** — all values identical. Verified: `PRICE_LIMITS` identity-equal across the re-export chain; 249 strategy/backtest/constraint/risk tests green; ruff clean. **Scope note:** each module's board-*detection* logic still lives locally (the implementations genuinely diverge — decimal vs percent limits, differing BSE handling). Unifying that logic is a deeper, behavior-sensitive follow-up; this PR removes the duplicated *constants*, which was the drift hazard. Simulation-only; not investment advice. Co-authored-by: Jcstack <Jcstack@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(demo): one-command offline quickstart via make demo (P3.1) (Jcstack#65) Closes Jcstack#57. Lowers onboarding friction with a **zero-setup demo** — no Docker, API keys, or network: ```bash pip install -r requirements.txt make demo ``` Runs the v2 backtest on a bundled sample dataset (`scripts/sample/demo_ohlcv.csv`, 160 synthetic bars) and prints a full performance report in one command. README gains a "30-second / no-setup" Quick Start step above the Docker path. Verified `make demo` runs end-to-end offline. The full Docker stack (`make up`) is unchanged. Simulation-only; not investment advice. Co-authored-by: Jcstack <Jcstack@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(data): unify source-health tracking on one shared router (P1.3) (Jcstack#66) Closes Jcstack#49. There were **two overlapping failover/health mechanisms** with no single source of truth: the daily fetcher's inline cascade recorded **no** health, while realtime/news each built their own `DataSourceRouter` and `/admin` created a **third, empty** one — so health was fragmented and the dashboard showed nothing real. ## Fix — unify on a shared router, **without touching the proven cascade** - `source_router.py`: `get_source_router()` process-wide singleton + `reset_source_router()`. - `fetcher.py`: record per-source **success (on fresh data)** / **failure (on exception)** at the 4 cascade points. *Stale data is data lag, not a source failure → not recorded.* Recording is wrapped defensively so it can **never break a fetch**. - `realtime.py` / `news_fetcher.py` / `admin.py`: default to the shared router, so all sources feed (and `/admin` reads) one health view. - `conftest.py`: autouse reset for test isolation (health is in-memory + shared). ## Behavior-preserving Cascade order / retry / freshness logic is **unchanged** — only additive health instrumentation on a hot path, wrapped to be failure-proof. `ruff` clean; **69** data/router/realtime/news tests green (incl. **5 new** proving the singleton is shared and the fetcher records into it). **Scope note:** making the cascade *consult* the router to skip DOWN sources (routing-aware failover) is a deliberate Phase-2 follow-up — higher risk on the hot path; this PR establishes the single health brain first. Simulation-only; not investment advice. Co-authored-by: Jcstack <Jcstack@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(intelligence): merge the two causal-chain engines into one (P1.2) (Jcstack#67) Closes Jcstack#48. Two parallel engines existed: `ImpactChainEngine` (in-code templates, substring match) and `CausalChainConstructor`/`EventImpactEngine` (YAML templates, regex + LLM fallback). The latter is canonical (it drives the core trading pipeline). This makes `ImpactChainEngine` a thin **adapter** over `CausalChainConstructor` — one engine — while preserving its public API. ## How - `impact_chain.py`: `ImpactChainEngine` delegates to `CausalChainConstructor`; `build_chain` bridges `CausalChain`→`ImpactChain` (bullish→positive, confidence→magnitude, order→lag). The old `CHAIN_TEMPLATES` is kept **only** to build a sector→stock map that re-binds `affected_stocks` — because Engine B resolves *sectors only* — so **`find_stock_impact` keeps working** (this was the silent-regression trap; it's defused + tested). Engine B + its callers (aggregator / investment_director / trading_loop) are **untouched**. - `config/impact_chain_templates.yaml`: added `usd_strengthen`/`usd_weaken` so USD→gold (the one capability the in-code engine had that the YAML lacked) is preserved — the merge is **lossless**. - tests: `test_impact_chain.py` rewritten to the new contract (incl. a test proving `find_stock_impact` returns stock-level impacts); `test_usd_affects_gold` restored. ## Verified Full unit suite **3811 passed**; `ruff` clean; intelligence sweep 234 green. `detect_event_type` is now single-match (documented semantic shift; no caller relied on multi-match). Simulation-only; not investment advice. Co-authored-by: Jcstack <Jcstack@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(changelog): add [2.0.1] — post-v2.0.0 hardening (Jcstack#68) Adds the `[2.0.1]` CHANGELOG entry summarizing the 12 commits since v2.0.0 (honest backtest, audit-driven fixes, de-duplication, quickstart). Docs-only; precedes the `v2.0.1` tag + release. Co-authored-by: Jcstack <Jcstack@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: retain local startup fixes on upstream v2.0.1 * build: pin Ruff to the validated lint baseline * fix: restore real data and reliable local workbench startup * fix: fetch market indices only on screens that use them * fix: keep the MCP server on its supported v1 SDK --------- Co-authored-by: JcStack <xinjiangzuiqiang@live.com> Co-authored-by: Jcstack <Jcstack@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #48. Two parallel engines existed:
ImpactChainEngine(in-code templates, substring match) andCausalChainConstructor/EventImpactEngine(YAML templates, regex + LLM fallback). The latter is canonical (it drives the core trading pipeline). This makesImpactChainEnginea thin adapter overCausalChainConstructor— one engine — while preserving its public API.How
impact_chain.py:ImpactChainEnginedelegates toCausalChainConstructor;build_chainbridgesCausalChain→ImpactChain(bullish→positive, confidence→magnitude, order→lag). The oldCHAIN_TEMPLATESis kept only to build a sector→stock map that re-bindsaffected_stocks— because Engine B resolves sectors only — sofind_stock_impactkeeps working (this was the silent-regression trap; it's defused + tested). Engine B + its callers (aggregator / investment_director / trading_loop) are untouched.config/impact_chain_templates.yaml: addedusd_strengthen/usd_weakenso USD→gold (the one capability the in-code engine had that the YAML lacked) is preserved — the merge is lossless.test_impact_chain.pyrewritten to the new contract (incl. a test provingfind_stock_impactreturns stock-level impacts);test_usd_affects_goldrestored.Verified
Full unit suite 3811 passed;
ruffclean; intelligence sweep 234 green.detect_event_typeis now single-match (documented semantic shift; no caller relied on multi-match). Simulation-only; not investment advice.