Commit Graph
1110 Commits
Author SHA1 Message Date
Haozhe Wu 71933ecf31 feat(frontend): guided-minimalism WebUI overhaul — 12-way audit + fix fleet
Land the pre-talk WebUI campaign: first-frame stability (pre-paint theme
boot via CSP-safe public/theme-boot.js, self-hosted fonts + OFL license),
streaming performance (rAF token batching, throttled flush, streaming
markdown with deferred highlight, 160-row windowing, swarm state in its
own store slice with per-run coalescing), correctness (FIFO tool matching,
retry preserves request semantics, display/request separation, cache-hit
session refresh, multi-tab message.received), guided-minimalism welcome
(time-aware greeting + brand lockup + 4 quick actions + collapsible
library, fill-first affordance), SwarmDashboard rebuild with honest
indeterminate progress, five-locale copy de-jargoning with lazy locale
chunks, accessibility Level-A fixes (color-blind metric glyphs, aria-live
streaming, skip link, focus-visible affordances), robustness (markdown
link/table/KaTeX overflow, safe localStorage, portal modal), and '/' now
opens the product with marketing moved to /about.
2026-07-29 23:07:35 +08:00
Haozhe Wu c8741e34bf docs(readme): add 2026-07-29 news 2026-07-29 16:04:30 +08:00
Yufeng HeandHaozhe Wu 59fa3181b0 feat(backtest): emit risk x-ray artifacts in portfolio runs (Portfolio Studio slice) (#900)
* feat(backtest): emit risk x-ray artifacts in portfolio runs (Portfolio Studio slice)

Signed-off-by: Yufeng He <40085740+he-yufeng@users.noreply.github.com>

* fix(backtest): refuse the average-basket x-ray for long-short books

compute_risk_xray is long-only by contract, but average_invested_weights
filtered negative mean weights out before the check could fire — a
long-short run would emit an x-ray describing only its long half while
presenting it as the whole strategy. Net short average exposure now
raises, taking the same no-artifact path as flat and short-history runs.

---------

Signed-off-by: Yufeng He <40085740+he-yufeng@users.noreply.github.com>
Co-authored-by: Haozhe Wu <haozhe_wu@connect.hku.hk>
2026-07-29 15:51:56 +08:00
Hongi Nagaputra 7f8f52d8bf feat(backtest): model isolated and cross margin liquidation risk (#889)
* feat(backtest): calculate perpetual maintenance risk

Signed-off-by: zygora <122336305+honginp@users.noreply.github.com>

* feat(backtest): model isolated and cross liquidation

Signed-off-by: zygora <122336305+honginp@users.noreply.github.com>

* fix(backtest): enforce strict cross liquidation threshold

Signed-off-by: zygora <122336305+honginp@users.noreply.github.com>

* test(backtest): trim liquidation risk test budget

Signed-off-by: zygora <122336305+honginp@users.noreply.github.com>

* fix(backtest): value risk margin at mark

Signed-off-by: zygora <122336305+honginp@users.noreply.github.com>

---------

Signed-off-by: zygora <122336305+honginp@users.noreply.github.com>
2026-07-29 15:42:44 +08:00
89b15ac806 fix(backtest): keep bar_returns bit-identical for gapped positive series (#895)
* fix(backtest): keep bar_returns bit-identical for gapped positive series

#872 replaced close.pct_change().fillna(0.0) with bar_returns and stated that
results for strictly positive series are bit-identical, so ordinary equity and
crypto runs are unchanged. That was verified only on gapless series.

On the pinned pandas (>=2.0,<3.0) pct_change defaults to fill_method='pad' and
forward-fills the divisor. bar_returns divided by the raw shifted series, so any
positive series with an interior NaN diverged. _align deliberately limits its
ffill to 5 bars (base.py:166-179) to keep long suspensions visible, so a halt
longer than that reaches bar_returns as a NaN prior and the real move across it
is reported as 0.0 -- silently, because the undefined-bar counter excludes NaN
priors by construction. On a real _align run an 8-bar halt turned a +17.1429%
resumed-trading bar into +0.0000%.

Injecting a zero where a large move occurred shrinks dispersion. Return deltas
cancel by sign; that damage does not. On a 20-symbol universe with two halted
symbols and news-shaped gaps, annualised vol fell 4.9619% -> 4.4673% and Sharpe
rose 3.0502 -> 3.3817.

Carry the prior price forward explicitly. This restores the pre-#872 answer and,
unlike the deprecated default it replaces, gives the same result on every
supported pandas -- the old behaviour flips silently under pandas 3.0, where
fill_method is None. The #872 contract is untouched: a non-positive prior is
still undefined, still 0.0, still logged.

Second, smaller item: inf > 0 is True, so where(prev > 0) kept an infinite prior
and the bar after it read as a clean -1.0 with no warning. buy_and_hold_return
had the same asymmetry -- it checked isfinite(last) but only first > 0, so an
infinite entry price returned -100% instead of None. Both now assert finiteness.

Signed-off-by: Ali Emadi <ali@gatekeeperai.com>

* test(backtest): lock the _align boundary and align the undefined-bar warning

- add an engine-boundary regression: a halt longer than _align's ffill
  limit must still credit the across-gap move to the resumed bar
- the undefined-bar warning now also fires for non-finite prior prices,
  so say so in the message (and in the assertions that pin it)

---------

Signed-off-by: Ali Emadi <ali@gatekeeperai.com>
Co-authored-by: Ali Emadi <ali@gatekeeperai.com>
Co-authored-by: Haozhe Wu <haozhe_wu@connect.hku.hk>
2026-07-29 15:34:17 +08:00
Xiaotian Jin 6479fb6428 fix(cli): load ~/.vibe-trading/.env on the connector command path (#902)
`main()` routes the `connector` subcommand group straight to
`_dispatch_connector`, which — unlike the interactive TUI — never runs
preflight, so nothing populated `os.environ` from `~/.vibe-trading/.env`.
`EnvConfig` reads only `os.environ`, so every connector resolving
credentials through `get_env_config()` reported them as missing despite a
valid file on disk: Longbridge's app key / secret / access token (the only
broker credential set sourced from env vars rather than a JSON config
file), and Futu's `FUTU_TRADE_PWD_MD5` live-unlock hash.

Call the existing `_ensure_cli_env()` helper at the dispatcher entry.
`_ensure_dotenv()` is idempotent and loads with `override=False`, so a real
environment variable still outranks the file, and connectors that read JSON
config are unaffected.

Distinct from #477 / #541, which were the stale-`EnvConfig`-singleton
variant: there `_ensure_dotenv()` ran but no `reset_env_config()` followed.
Here it never ran at all, so that fix could not reach this path.

Closes #901

Signed-off-by: Xiaotian Jin <jin.xiaotian.kim@gmail.com>
2026-07-29 15:28:27 +08:00
卫斯李 348a25b8f8 fix(metrics): add missing annualisation entries for 15 data sources (#891)
* fix(metrics): add missing annualisation entries for 15 data sources

13 of 24 VALID_SOURCES entries had no trading_days or bars_per_day
lookup, causing calc_bars_per_year to silently return 252 for every
interval — intraday bars for these sources were never annualised
correctly (e.g. Longbridge 1m returned 252 instead of 252×390).

Add all 15 missing sources to _TRADING_DAYS and _BARS_PER_DAY:
- crypto: binance (365 days)
- A-share: baostock, tencent, eastmoney, sina (252 days, 240-min)
- US/international: yahoo, finnhub, alphavantage, tiingo, fmp,
  stooq, longbridge (252 days, 390-min)
- Indian: india_broker (252 days, 375-min)
- daily-only: qveris, local (252 days, 1 bar/day for all intervals)

24 new test assertions across 16 tests, including a cross-VALID_SOURCES
sweep that verifies every source returns >0 for both daily and intraday.

Closes #884

Signed-off-by: Robin1987China <41602358+Robin1987China@users.noreply.github.com>

* fix(metrics): restore _SOURCE_ALIASES, _normalize_interval, and related tests

These were accidentally dropped during stash conflict resolution;
restore the alias/interval-normalisation layer that loaders depend on
and re-add the 3 corresponding tests (lowercase hour/day matching,
yahoo→yfinance alias).

Signed-off-by: Robin1987China <41602358+Robin1987China@users.noreply.github.com>

* fix(metrics): address review — reclassify local/qveris, harden drift guard

Three changes from review (#891):
1. Reclassify local and qveris from daily-only to US equity session
   (252d/390-min) — both loaders support all intervals via resampling.
   Updated all 7 interval layers of _BARS_PER_DAY.
2. Already fixed in d6770bd: source_key lower normalisation via
   str(source).strip().lower() + _SOURCE_ALIASES guard — no change needed.
3. Strengthen test_no_intraday_source_falls_to_default with a
   set-coverage assertion that fails the moment a loader is registered
   without a _TRADING_DAYS + _BARS_PER_DAY entry.

Signed-off-by: Robin1987China <41602358+Robin1987China@users.noreply.github.com>

---------

Signed-off-by: Robin1987China <41602358+Robin1987China@users.noreply.github.com>
2026-07-29 15:21:22 +08:00
Santh a9e50e9bc1 fix(channels): preserve leading indent when splitting messages (#867)
* fix(channels): preserve leading indent when splitting messages

After a newline cut, lstrip() removed indentation on the next chunk, so
code blocks and nested markdown lost spaces across Discord/Slack/Telegram
splits. Drop only the separator character.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>

* fix(channels): keep Signal style offsets aligned after indent-preserving splits

split_message no longer blanket-lstrips; mirror that in _partition_styles so
indented chunks keep UTF-16 style ranges.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>

* fix(channels): advance style cursor on space separator preceding indented chunk

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>

---------

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-29 15:20:08 +08:00
Santh 72f6985825 fix(skills): parse frontmatter when closing fence is at EOF (#861)
* fix(skills): parse frontmatter when closing fence is at EOF

SKILL.md / memory files that end at the closing --- without a trailing
newline (common from editors and LLM skill saves) were treated as plain
text, so name/description were dropped. Empty ---/--- blocks had the
same miss. Accept EOF or empty meta between fences.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>

* fix(skills): require newline before closing frontmatter fence

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>

---------

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-29 15:19:35 +08:00
Haozhe Wu 749c37b09f chore(frontend): declare the Node 22 requirement
React Router 8 requires Node >=22.22.0, so `npm install` now fails for anyone
still on Node 20 with an error that does not name the cause. Declare it in
package.json engines, and say it on the Quick Start line that tells people to
run it, in all five READMEs.
2026-07-28 15:59:33 +08:00
Haozhe Wu bd9a9b70b8 docs(readme): add 2026-07-28 news 2026-07-28 15:58:42 +08:00
Haozhe Wu 1e5b79dac6 chore(frontend): move to Node 22 and React Router 8
React Router 7.12.0 through 8.2.x carry a high-severity RSC-mode CSRF bypass
(GHSA-qwww-vcr4-c8h2). We were on 7.18.1, inside that range. The advisory is not
reachable here — the app is a client-side SPA on createBrowserRouter with no
@react-router/server and no RSC entry point, and the frontend ships as static
Vite output — but 7.18.1 is the final 7.x release, no backport exists, and 8.3.0
is the only patched version, so staying put means staying on an EOL line with a
permanent open alert.

react-router-dom has no 8.x at all; the DOM exports moved into react-router
itself. So the dependency is swapped and every import rewritten. All ten APIs in
use here are unchanged in 8.3.0, and none of the data-layer surface that changed
most between majors is used.

react-router 8 requires Node >=22.22.0, which is the same wall that had jsdom 30
and @testing-library/jest-dom 7 sitting in the Dependabot ignore list. Node 20
reached EOL on 2026-04-30, so the toolchain moves to Node 22 across CI, the wiki
workflow, the Dockerfile and docker-compose. That unblocks all three at once:
jsdom and jest-dom are taken here too, and their ignores are removed rather than
left carrying a rationale that no longer holds.

Verified on the frontend suite: tsc -b and vite build clean, 310 tests across 35
files pass before and after the jsdom/jest-dom bumps.
2026-07-28 14:39:59 +08:00
dependabot[bot] cd04c93851 build(deps): bump the pip-minor-patch group across 1 directory with 6 updates (#893)
Bumps the pip-minor-patch group with 6 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [akshare](https://github.com/akfamily/akshare) | `1.18.79` | `1.18.80` |
| [fastapi](https://github.com/fastapi/fastapi) | `0.140.0` | `0.140.7` |
| [fastmcp](https://github.com/PrefectHQ/fastmcp) | `3.4.4` | `3.4.5` |
| [fastmcp-slim](https://github.com/PrefectHQ/fastmcp) | `3.4.4` | `3.4.5` |
| [openai](https://github.com/openai/openai-python) | `2.48.0` | `2.49.0` |
| [tqdm](https://github.com/tqdm/tqdm) | `4.69.1` | `4.70.0` |



Updates `akshare` from 1.18.79 to 1.18.80
- [Release notes](https://github.com/akfamily/akshare/releases)
- [Changelog](https://github.com/akfamily/akshare/blob/main/docs/changelog.md)
- [Commits](https://github.com/akfamily/akshare/compare/release-v1.18.79...release-v1.18.80)

Updates `fastapi` from 0.140.0 to 0.140.7
- [Release notes](https://github.com/fastapi/fastapi/releases)
- [Commits](https://github.com/fastapi/fastapi/compare/0.140.0...0.140.7)

Updates `fastmcp` from 3.4.4 to 3.4.5
- [Release notes](https://github.com/PrefectHQ/fastmcp/releases)
- [Changelog](https://github.com/PrefectHQ/fastmcp/blob/main/docs/changelog.mdx)
- [Commits](https://github.com/PrefectHQ/fastmcp/compare/v3.4.4...v3.4.5)

Updates `fastmcp-slim` from 3.4.4 to 3.4.5
- [Release notes](https://github.com/PrefectHQ/fastmcp/releases)
- [Changelog](https://github.com/PrefectHQ/fastmcp/blob/main/docs/changelog.mdx)
- [Commits](https://github.com/PrefectHQ/fastmcp/compare/v3.4.4...v3.4.5)

Updates `openai` from 2.48.0 to 2.49.0
- [Release notes](https://github.com/openai/openai-python/releases)
- [Changelog](https://github.com/openai/openai-python/blob/main/CHANGELOG.md)
- [Commits](https://github.com/openai/openai-python/compare/v2.48.0...v2.49.0)

Updates `tqdm` from 4.69.1 to 4.70.0
- [Release notes](https://github.com/tqdm/tqdm/releases)
- [Commits](https://github.com/tqdm/tqdm/compare/v4.69.1...v4.70.0)

---
updated-dependencies:
- dependency-name: akshare
  dependency-version: 1.18.80
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pip-minor-patch
- dependency-name: fastapi
  dependency-version: 0.140.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pip-minor-patch
- dependency-name: fastmcp
  dependency-version: 3.4.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pip-minor-patch
- dependency-name: fastmcp-slim
  dependency-version: 3.4.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pip-minor-patch
- dependency-name: openai
  dependency-version: 2.49.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: pip-minor-patch
- dependency-name: tqdm
  dependency-version: 4.70.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: pip-minor-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-28 14:30:09 +08:00
yagnikpipaliya d2f12a3e72 fix(anthropic): self-heal models that deprecate the temperature field (#890)
Problem
-------
Next-gen Claude models (e.g. claude-opus-5, claude-opus-4-8, claude-sonnet-5)
reject the "temperature" request field with HTTP 400 "temperature is deprecated
for this model." for ANY value, while older models (claude-opus-4-5,
claude-sonnet-4-5, ...) still accept it. _build_anthropic unconditionally
forwarded the global default temperature=0.0, so every run on a next-gen model
failed before producing output. Model names are not predictable (opus-4-5
accepts it, opus-4-8 does not) and the rejection is value-independent, so
neither a fixed model allowlist nor an "omit when 0.0" shortcut is a correct
fix.

Solution
--------
Add a temperature-safe ChatAnthropic subclass (_make_temperature_safe_anthropic)
that wraps all four generation entry points (_generate, _agenerate, _stream,
_astream). When the API reports temperature as unsupported it drops the field
and retries once, then records the model in a process-wide set so subsequent
requests omit it up front (no repeated failed request). Models that accept
temperature keep their configured deterministic value unchanged. The subclass
is built from the lazily-imported class and cached per base class, preserving
the optional langchain-anthropic dependency boundary and existing test doubles.

Correct for any temperature value, current and future model names, and the
streaming path the Web UI relies on.

Tests
-----
Add regression tests in agent/tests/test_llm.py: self-heal retry drops
temperature and remembers the model, temperature is preserved for supporting
models, and the error matcher only triggers on temperature-unsupported errors.
Full test_llm.py suite: 58 passed.
2026-07-28 13:38:11 +08:00
Haozhe Wu c63713c587 chore(deps): ignore the transitive versions ccxt exact-pins
ccxt does not use ranges — it exact-pins its entire transitive closure. All 23
of those packages that appear in our lock sit at precisely ccxt's pin, with no
mismatches, so none can move until ccxt itself releases, and ccxt 4.5.68 is
already the latest. Any Dependabot PR touching one is unmergeable by
construction: the pip group PR proposed five of them and died with
ResolutionImpossible on certifi against the ccxt line in the lock.

Re-running the resolver confirms this is the ceiling rather than a stale lock —
pip-compile --upgrade under python:3.11-slim, matching CI, reproduces every one
of those versions, so there is no lock change to make. pydantic-core is in the
same position via pydantic's own == pin, and was the sixth package in that PR.

Ignore the set. ccxt itself is deliberately not ignored: it is the package whose
bump legitimately carries all of them. This suppresses only the automated PRs —
Dependabot alerts come from the dependency graph and are unaffected by this
file, so a CVE in cryptography, urllib3, requests or certifi still surfaces in
the Security tab, where the remedy is a ccxt bump.
2026-07-28 12:57:46 +08:00
Haozhe Wu 452653c81c fix(backtest): make the buy-and-hold return path sign-safe
close.pct_change() silently assumes price[t-1] > 0. That holds for equities but
not for instruments that can print zero or negative prices, such as European
day-ahead power. As the divisor approaches zero an ordinary absolute move reads
as an enormous percentage move, so the compounded benchmark explodes — a
reported +39,560% where the honest figure was -42.7%. At exactly zero the next
bar is inf, which fillna(0.0) does not neutralise because it fills NaN, and
(1 + r).prod() then collapses to nan.

Adopt an explicit contract. A return is defined only when the previous price is
finite and strictly positive; otherwise it is 0.0, never inf or nan. Buy-and-
hold total return becomes the price relative P_end / P_start - 1 rather than the
compounded product, and is omitted entirely when the entry price is not
positive, because no honest percentage exists. Undefined bars are logged rather
than silently swallowed: a wrong return is a wrong reported number, not a crash.

bar_returns keeps the exact `close / prev - 1` expression pct_change uses, so
results for strictly positive series are bit-identical and ordinary equity and
crypto runs are unchanged.

The loader still rejects an exact-zero close, but the reason has narrowed to the
one that survives: sizing is target_notional / abs(price), undefined at zero.

Closes #872
2026-07-28 12:57:37 +08:00
Haozhe Wu 6a859902e9 fix(cli): inject a host session id into non-interactive runs
The research-goal tools are registered unconditionally and resolve their
session from the host runtime, so an entry point that calls _run_agent without
an id makes every goal call fail validation with "session_id is required" while
the run still reports SUCCESS. Reported for `vibe-trading run`; six of the seven
_run_agent call sites had the same omission, including cmd_session_chat, which
already received the session id as a parameter and simply never forwarded it.

Add _ensure_session_id, which builds a Session (whose id is populated at
construction) and persists it best effort, so a store or index failure still
yields a usable id rather than the empty string that caused the bug.
cmd_continue reuses one session across continuations so goals accumulate: a
session-backed run_id already is a session id, since sessions and their traces
share SESSIONS_DIR, so it is used directly; a plain run gets a derived id.
Re-registering an existing id is idempotent. The interactive REPL had the same
latent hole whenever _new_session returned None, and now falls back to an
unpersisted id.

Also align the MCP contract. All four MCP goal tools declared session_id
required while the in-process registry injects it and leaves it optional — the
opposite contract, which asked the model to invent an internal identifier it
has no way to know. session_id is now optional there too, defaulting to one
stable id per server process.

Closes #885
2026-07-28 12:57:28 +08:00
Haozhe Wu d528066646 docs(readme): fix Windows install steps in all five READMEs (#888)
CMD has no `cp`, so `cp agent/.env.example agent/.env` fails there; add the
`copy` form and note that PowerShell's `cp` alias already works. Also add the
CMD activation line and the execution-policy hint that blocks Activate.ps1.

Reported by @brady-cec in discussion #29.
2026-07-28 01:54:41 +08:00
Haozhe Wu e8c3bf6ee5 Merge pull request #881 from HKUDS/chore/unblock-dep-lock
chore(deps): unblock the ccxt/setuptools lock deadlock and cut dependabot churn
2026-07-27 18:11:00 +08:00
Haozhe Wu db3ed92cef chore(deps): ignore jsdom majors until the Node 22 migration
jsdom 30.x requires Node ^22.22.2 || ^24.15.0 || >=26 while CI and Docker are
on Node 20. On Node 20 the incompatibility surfaces indirectly as vitest
failing to start its pool workers rather than as a clean engine error, so #877
reads like a flaky frontend failure. Same wall as @testing-library/jest-dom 7.
2026-07-27 18:03:57 +08:00
Haozhe Wu 58363fc01f chore(deps): unblock the ccxt/setuptools lock deadlock and cut dependabot churn
Dependabot could not land either half of a mutually-blocking pair: the
minor/patch group wanted ccxt 4.5.68 (which pins setuptools==83.0.0) while
keeping setuptools at 82.0.1, and the separate setuptools 83.0.0 PR conflicted
with the ccxt 4.5.67 already in the lock. Neither can go green alone because
setuptools is a major bump and is excluded from the minor/patch group by
design, so it cannot ride along.

Regenerate the lock so both move together. Verified with pip-compile under
Python 3.11 on Linux (matching CI) and checked with CI's own gate,
pip install --dry-run --require-hashes. Note the lock is platform-sensitive:
regenerating on macOS drops jeepney/secretstorage and swaps py-mini-racer for
mini-racer, so it must be produced on Linux.

Also ignore websockets, capped at <16 by langgraph-sdk 0.4.2, and move all
three ecosystems to monthly with 2 concurrent PRs. Security updates are a
separate channel and are unaffected.
2026-07-27 18:03:14 +08:00
Haozhe Wu 2d0192a98b Merge pull request #876 from HKUDS/dependabot/npm_and_yarn/frontend/npm-minor-patch-8de1194a4f
build(deps): bump lucide-react from 1.26.0 to 1.27.0 in /frontend in the npm-minor-patch group
2026-07-27 17:51:22 +08:00
dependabot[bot] 2dc45d7ecf build(deps): bump lucide-react in /frontend in the npm-minor-patch group
Bumps the npm-minor-patch group in /frontend with 1 update: [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react).


Updates `lucide-react` from 1.26.0 to 1.27.0
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/1.27.0/packages/lucide-react)

---
updated-dependencies:
- dependency-name: lucide-react
  dependency-version: 1.27.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm-minor-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-27 09:33:03 +00:00
Haozhe Wu 218d453859 build(deps): ignore bumps blocked by upstream or infra constraints
caio: aiofile 3.11.1 (latest) requires caio~=0.9.0, so bumping caio to 0.10.x
makes pip unresolvable and the grouped PR fails CI. Ignore only caio, not the
whole minor/patch group.

@vitejs/plugin-react 6.x peers vite@^8 (we are on 6.x) and
@testing-library/jest-dom 7.x requires Node >=22 (CI/Docker use 20). Both are
migrations, not dependency bumps.
2026-07-27 17:31:41 +08:00
Haozhe Wu 612004243c fix(loaders): keep a stubbed config from writing cache into the working tree
loader_cache_enabled() returned the raw config value, so a MagicMock config
read truthy and switched the opt-in cache on. loader_cache_root() then passed
that MagicMock to Path(), which resolves via __fspath__ to a *relative* path
and put real market-data parquet under agent/MagicMock/ inside the repo.

Validate both at the boundary: require a genuine True to enable the cache, and
honor the root override only when it is a real non-blank str.
2026-07-27 17:31:41 +08:00
Haozhe Wu a69c55944b docs(readme): add 2026-07-27 news 2026-07-27 17:15:06 +08:00
Haozhe Wu 5222f418cf Merge pull request #866 from santhreal/fix/journal-to-float-strip-currency
fix(journal): strip currency symbols before float coerce
2026-07-27 15:49:02 +08:00
Haozhe Wu 5c690c7211 Merge branch 'main' into fix/journal-to-float-strip-currency
Resolves the import-list conflict in agent/tests/test_trade_journal.py
introduced when #862 landed on main: keep both _to_float (this branch)
and load_dataframe (#862).
2026-07-27 15:41:42 +08:00
Haozhe Wu 5904e615a1 Merge pull request #862 from santhreal/fix/journal-load-utf16-csv
fix(journal): accept UTF-16 BOM CSV exports in load_dataframe
2026-07-27 15:40:12 +08:00
Haozhe Wu 8c0369727d Merge pull request #868 from santhreal/fix/journal-infer-crypto-suffix-quotes
fix(journal): treat BTCUSDT-style symbols as crypto markets
2026-07-27 15:40:07 +08:00
Haozhe Wu fde1179bb1 Merge pull request #873 from ddy4633/fix-correlation-forward-fill
fix(backtest): stop forward-filling missing closes in the correlation matrix
2026-07-27 15:40:02 +08:00
Haozhe Wu c8fa7a263c Merge pull request #869 from y85998607/fix/vnpy-export-import-path
fix(vnpy-export): update CtaTemplate/BacktestingEngine imports to vn.py 4.0 layout
2026-07-27 15:39:56 +08:00
Haozhe Wu 7b2eda9636 Merge pull request #863 from santhreal/fix/skill-sanitize-keep-cjk-slug
fix(skills): keep CJK characters in skill directory slugs
2026-07-27 15:39:51 +08:00
Haozhe Wu 7fe894df86 Merge pull request #864 from santhreal/fix/metrics-bars-per-year-lowercase-interval
fix(metrics): annualize lowercase 1h/1d and yahoo like loaders
2026-07-27 15:39:47 +08:00
Haozhe Wu ded3e52ebc Merge pull request #865 from santhreal/fix/doc-reader-utf16-before-latin1
fix(tools): decode UTF-16 BOM text before latin-1 fallback
2026-07-27 15:39:42 +08:00
ddy4633 b913ef67eb fix(backtest): stop forward-filling missing closes in the correlation matrix
Under the project's pandas>=2,<3 pin, pct_change defaults to
fill_method='pad'. A halted session (NaN close) is forward-filled into a
fabricated 0% return, which survives the inner join and gets paired against
the peer's real move for that day.

regime.py:113 performs the identical computation with fill_method=None, and
its docstring states it "Mirrors the alignment in
_rolling_correlation_matrix" — the sibling was written from this function and
fixed there while the original was left behind. risk_xray.py:144 also passes
fill_method=None. The intended behaviour is already established in-tree.

Passing it explicitly also silences the FutureWarning; the default flips
again under pandas 3.
2026-07-27 03:15:41 +08:00
Haozhe Wu 5140803980 Merge pull request #871 from HKUDS/codex/fix-windows-background-self-kill
fix(background): prevent Windows host self-termination
2026-07-27 02:32:27 +08:00
Haozhe Wu f56a3d398f fix(background): prevent Windows host self-termination
Add task-scoped cancellation, reject broad Python process-name kills, expose timeout context, and cover the lifecycle on Windows 11 and Windows x64 with Python 3.14.

Signed-off-by: Haozhe Wu <haozhe_wu@connect.hku.hk>
2026-07-27 02:20:50 +08:00
Haozhe Wu d5ea0ec519 docs(readme): add 2026-07-26 news and ignore workbuddy 2026-07-26 19:13:36 +08:00
y85998607 9a7f60aca5 fix(vnpy-export): update CtaTemplate/BacktestingEngine imports to vn.py 4.0 layout
vn.py 4.0 split every app (CTA strategy, CTA backtester, ...) into its own
pip-installable package. The vnpy-export skill's generated strategy template
and SKILL.md docs still used the pre-4.0 import path
(`vnpy.app.cta_strategy`), which no longer exists — a strategy file exported
by this skill would fail to import in any current vn.py install.

Verified against a real vn.py 4.0 + vnpy_ctastrategy install: the old import
raises ModuleNotFoundError; the corrected import resolves and the exported
MaCrossStrategy class loads successfully.

Signed-off-by: y85998607 <y85998607@gmail.com>
2026-07-26 14:40:59 +08:00
Haozhe Wu 3470c0cb21 Merge pull request #859 from HKUDS/codex/fix-845-universe-metadata
fix(alpha): disclose benchmark universe degradation
2026-07-26 13:23:24 +08:00
Haozhe Wu 96e43b6e1d Merge pull request #858 from HKUDS/codex/fix-847-hash-lock
fix(deps): repair cold hash-locked installs
2026-07-26 13:23:01 +08:00
Haozhe Wu 0a690913c2 Merge pull request #852 from HKUDS/dependabot/npm_and_yarn/frontend/npm-minor-patch-3c68efc824
build(deps): bump the npm-minor-patch group in /frontend with 5 updates
2026-07-26 13:13:31 +08:00
Haozhe Wu 10d1b69aaf Merge pull request #851 from HKUDS/dependabot/github_actions/actions/setup-python-7.0.0
build(deps): bump actions/setup-python from 6.3.0 to 7.0.0
2026-07-26 13:13:08 +08:00
Haozhe Wu 453951ee1a Merge pull request #850 from HKUDS/dependabot/github_actions/actions-minor-patch-7a5a078ad4
build(deps): bump actions/checkout from 7.0.0 to 7.0.1 in the actions-minor-patch group
2026-07-26 13:12:37 +08:00
Haozhe Wu 2c1ccd7678 fix(alpha): disclose benchmark universe degradation 2026-07-26 13:03:57 +08:00
santhreal 5ed1eb5472 fix(journal): treat BTCUSDT-style symbols as crypto markets
Concatenated pairs like BTCUSDT are alphabetic, so isalpha() labeled them
as US equities. Recognize USDT/USDC/BUSD suffixes before that branch.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-25 21:55:00 -07:00
Haozhe Wu 8aa7a13bfe fix(deps): repair cold hash-locked installs 2026-07-26 12:53:22 +08:00
santhreal 0a59f57f9e fix(journal): strip currency symbols before float coerce
Broker CSV cells like $1,234.56 or ¥1000 failed float() after only commas
were stripped, so price/fee silently became 0.0. Strip common currency
tokens and unicode minus too.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-25 21:52:41 -07:00
santhreal 8a4f6260bb fix(tools): decode UTF-16 BOM text before latin-1 fallback
Notepad/Excel Unicode text exports start with a UTF-16 BOM; latin-1 never
raises so those bytes were accepted as mojibake. Detect BOM and decode as
utf-16 first.

Signed-off-by: santhreal <64453045+santhreal@users.noreply.github.com>
2026-07-25 21:50:16 -07:00