← Open Source
HKUDS

Vibe-Trading

"Vibe-Trading: Your Personal Trading Agent"

ApplicationsPersonalSpecialistsPython
Open on GitHub
Momentum
+193stars in 24 hours+0.6%
34.7k
Stars
5.64k
Forks
+549
This week
100
Contributors
Created 2026-04-01 · Updated 2026-10-05 · #74 today
Top developers
README

English | 中文 | 日本語 | 한국어 | العربية | Español | Bahasa Indonesia

Vibe-Trading Logo

Vibe-Trading: Your Personal Trading Agent

One Command to Empower Your Agent with Comprehensive Trading Capabilities

HKUDS%2FVibe-Trading | Trendshift

Python FastAPI React PyPI License

Feishu WeChat Discord

Website  ·  Docs  ·  News  ·  Features  ·  Shadow Account  ·  Demo  ·  Quick Start  ·  Examples  ·  API / MCP  ·  Roadmap  ·  Contributing

pip install vibe-trading-ai


📰 News

⚠️ Security warning: The X account VibeTrading_HKU, Virtuals project 101845, and token contract 0x640BDBF77b6447E8b7DB7894cED84BD1c40571f4 are not official Vibe-Trading assets. We have never launched or endorsed any token or memecoin. Do not buy, connect a wallet, or sign anything. Details.

  • 2026-10-06 🛠️ Live controls and report corrections: Stopping a live runner cancels its current analysis and waits for scheduler cleanup, including startup cancellation and API shutdown; status timestamps use the correct units (#1704). Emergency cancel/flatten scans skip malformed records without abandoning the remaining book (#1703); broker schedules are stored separately and writes handle concurrency and partial writes. US equity half-days respect the early closing bell (#1706). Report corrections preserve figures that passed validation, and bounded feedback no longer implies that unlisted figures passed (#1702).

  • 2026-10-05 🛠️ Research prompts and calculation fixes: Chat accepts longer research prompts and gives a localized recovery message when input is too large (#1701). Backtests use full-sample Sortino downside deviation; grouped validation purges overlapping labels, covariance weights remain finite, shadow RSI uses Wilder seeds, and memory removal accepts filename stems. Invalid call aliases now receive exact source references for correction (#1638); numeric validation stays unchanged.

  • 2026-10-04 🛠️ Scheduled reports and research workflows: Edit scheduled runs and choose a configured destination; Email reports support HTML or PDF attachments (#1649, #1680). Backtests expose structured summaries and paged artifact reads (#1646, #1647). Fixes cover memory-search snippets, export-path guidance, macro truncation, monthly risk, turnover on reversals and cash reentry, IV accuracy, VaR gaps, VCS updates and Robinhood option-order blocking.

Earlier news

  • 2026-10-03 🛠️ Research, reports and data reliability: CJK session search, channel setup, broker exposure pricing and file writes now handle cases that blocked everyday use. PDF delivery embeds CJK fonts, Swarm validates preset inputs and separates task artifacts, and replayed tool results survive context compaction (#1683, #1455, #1635). Backtests keep one adjustment basis, local caches distinguish sources, single-asset caps and weekly/monthly risk use the declared settings, audits retain loss signs, grounding checks the current engine output and exact list references, and Stooq retries after a denial cooldown (#1684, #1650, #1685, #1640).

  • 2026-10-02 🛠️ Backtests and report checks: strategy-file writes retain model provenance without crashing (#1673), and Monte Carlo drawdown and Sharpe include starting capital (#1664). Report audits preserve accounting negatives and units (#1663); grounding artifacts record fired declared checks (#1661); public loader-health reports include sanitized failure reasons (#1643). Indonesian tool documentation matches the registry (#1671).

  • 2026-10-01 ✅ Data correctness and reproducible backtests: A-share adjustment conversion now refuses ambiguous one-bar edge cases (#1551); Southbound Eastmoney amounts are scaled from million HKD and rejected responses no longer look empty (#1486); Northbound fallback data distinguishes post-2024-08-19 turnover from net flow (#1484); Binance-only unpriced positions are marked incomplete without penalising other brokers (#1505); and backtest run cards record model provenance and warn when the training cutoff is unknown or outside the test window (#1618, closes #1613).

  • 2026-09-30 🛠️ Feishu in the Web UI, a momentum factor that read today's price, and a profit factor for runs that never lost: Feishu joins the guided channel setup, with a standalone connection test and a hot reload that closes the old WebSocket (#1572). academic_carhart_mom subtracted the 1-month return from the 12-month one, so it moved with today's close; it is now the return from 12 months ago to 1 month ago (#1578). A run with no losing trade reports its profit factor as undefined instead of 0.0, which ranked it last (#1602). Stooq's anti-bot page now stops every later request in the process, not just the log line (#1637); MCP tool results reach the agent once instead of up to four times (#1634); and the first piece of loop.py moves into its own module (#1636).

  • 2026-09-29 🚀 v0.1.16 released (Release notes, pip install -U vibe-trading-ai): 492 commits and 116 merged pull requests since 0.1.15, from 16 contributors. The theme of this cycle is a number that can show where it came from. The grounding gate no longer guesses what a number is from the words around it: the model declares each figure's role (observed, derived, proposed, cited or count), the gate checks it against the session's tool evidence, and a figure that fails is cut instead of the whole answer being refused. A backtest's own output — Sortino, turnover, weights and Monte Carlo p-values, not only Sharpe — now grounds the report written about it, and run cards cite a metric only where the saved CSV agrees. Long research runs keep what they fetched: compaction follows each model's real context window instead of a fixed 40K estimate. The missing-data sweep reached 59 more alphas. Fixed in this release, from a user's report: failed runs keep their steps and the stop message names the call that produced nothing; read_file says where it may read instead of letting the model guess paths until the no-progress stop; on Codex, mid-run instructions no longer replace the system prompt, reasoning carries between turns and the default model is gpt-6-sol; and get_market_data asks for AAPL.US rather than returning empty data for a bare US ticker. New: Argentina (BYMA), weekly and monthly bars, Bahasa Indonesia, Gildata, OpenCode, Email and WebSocket channels, IM channel setup in the Web UI, and KIS, Upbit, Toss Securities and Scalable Capital connectors, 18 brokers in all. Thanks @Shizoqua, @zeus229, @cgycorey, @shadowinlife, @lorenzozanee, @he-yufeng, @chiww, @as950118, @woshi77777stars, @Yoruxyv, @sambazhu, @0xouzm, @tingkk, @tonydo, @alanwilhelm and @modelpath-dev!

  • 2026-09-28 🛠️ Source health and connector transparency: scheduled public-source canaries report outages and data drift with bounded, credential-free probes (#1627); BaoStock socket requests now have deadlines and serialize concurrent sessions (#1615). Copilot credential lookups refresh after a short cache TTL (#1619). A generated broker matrix preserves each profile’s paper/live permissions and labels declared capabilities separately from runtime verification (#1629). Grounding and MT5 follow-up: explicit evidence symbols and exact field references are preserved; localized grouped figures retain the existing numeric tolerance (#1584, #1586, #1588). Text-only correction attempts are bounded (#1600). MT5 search uses the selected terminal and refuses ambiguous broker aliases; backtest sandboxes receive only validated attachment settings (#1597, #1598).

  • 2026-09-27 🛠️ Verifiable run cards and safer research: Run cards now show hashed backtest execution records and verified metric-to-CSV references in JSON, Markdown and Run Detail (#1612). GTJA high/low recency factors use the correct day count and consistent tie handling (#1604); India short covers check the buy-side circuit band (#1608). Token usage remains readable without exempting arbitrary credential strings (#1606), malformed MCP schemas retain their object properties (#1607), and immediate-order goal checks preserve research questions (#1605). Setup documentation now correctly identifies OpenRouter as the shipped default (#1609).

  • 2026-09-26 🛠️ More reliable indicators and trading limits: Technical indicators retain their observation date and can reuse results lost during conversation compaction (#1590, #1601). All five Qlib158 WVMA windows now use absolute returns in the numerator (#1594); Benford checks preserve the correct leading digit at numeric boundaries (#1591). An explicitly zero exposure limit stays zero (#1593), and Dhan paper orders reject fractional or invalid quantities without rounding away input precision (#1595). Invalid optional numeric environment variables fall back to defaults while explicit configuration constraints remain enforced (#1592). Runtime triggers keep the correct field defaults and subclass factory behavior (#1599).

  • 2026-09-25 🛠️ More reliable research sessions and channel diagnostics: A text column in a backtest CSV no longer discards the numeric metrics (#1579), and conversation compaction now counts reasoning content in its retained-message budget (#1582). Failed channel loads now log the actual exception (#1580); the Telegram guide clarifies that CLI and Web controls share the same API runtime (#1583). Robinhood portfolio reads reject malformed buying-power objects while keeping omitted or null values unknown (#1526). Leaving a chat also cancels pending history-scroll timers. Thanks @Shizoqua and @lorenzozanee!

  • 2026-09-24 💱 A dollar line priced as pesos, Email and WebSocket in the Web UI, and a CI break from an SDK update: BYMA and the TSX list US-dollar lines beside their home-currency ones (GGALD.BA, DLR-U.TO), and an Argentine or Canadian backtest priced them in its single peso or Canadian-dollar pool. The loaders now admit a line only in its market's currency, as LSE lines already were, and every other declared quote currency travels with the data, so an answer names the right one (#1576). Hong Kong's RMB and USD counters (80700.HK, 9834.HK), which HKEX numbers in their own code ranges, are refused in a Hong Kong backtest for the same reason and quoted in their own currency. Stock profiles carry the listing's own venue and currency beside the issuer's fundamentals (#1577), grounding and symbol search know every market the data layer routes (#1575), and technical_indicators reports volume with the unit its source declares — board lots or shares, 100× apart (#1571). Email and WebSocket join the guided channel setup, with mail-server certificates now verified and settings writes closed to cross-site pages, and a plain IMAP login is upgraded with STARTTLS before the password goes out (#1544). Fixed: an explicit provider header lost to an ambient twin under openai 3.19.2, which had turned every PR's CI red (#1568); a backtest from a microsecond-resolution source was dated 1970 (#1560); a research goal that is plainly an order is refused again (#1562); a strict-bench OOS split could leave one side empty (#1559); HRP label alignment, cross-validation label order and non-finite quant inputs (#1555, #1556, #1557, #1558); the shadow-account overtrading window (#1563); and asset growth was read day over day (#1564). Thanks @Shizoqua, @zeus229 and @shadowinlife!

  • 2026-09-23 🇦🇷 Argentine listings, a short book sized upside down, and the last half of the tail-risk gate: .BA symbols — BYMA equities and CEDEARs — route to Yahoo as their own ARS market, and the Web UI groups and labels them like any other; an Argentine backtest still fails closed until BYMA execution rules are modelled (#1543). The mean-variance and turnover-aware optimizers scored every position as if it were held long, so the strongest shorts got the least capital. Both now size on position returns, where a long and a short of two correlated names hedge each other instead of reading as correlated — on a +0.92 correlated pair the old objective put the whole book on the long, the new one splits it 0.51 / -0.49 (#1548). And a tail-risk figure now has to name its own field once a session holds more than one measure or confidence level, so an ES 95% can no longer quote the VaR 95% value under a call id (#1425). Fixed: Monte-Carlo validation annualises at the venue's bars per year instead of a hardcoded 252, so its Sharpe agrees with the rest of the same report (#1546); a futures order on a negative-price bar is no longer rejected outright (#1547); a factor's IC ratio is left unset for a negative baseline instead of reading real decay as healthy improvement (#1549); and two memories sharing a title under different types keep their own index rows and link targets (#1545). Thanks @zeus229, @Shizoqua and @he-yufeng!

  • 2026-09-22 📅 Weekly and monthly bars, and a compaction replay that could lose evidence: get_market_data and backtests take 1W and 1M (rejected since 09-20 so 1M would not fetch minute bars). Every source still serves daily bars and the period bar is built from them, dated on the last trading day of its week or month, so a 21-month review is one call of 21 bars (#1479). A price index is stamped unadjusted instead of by what its source does to a stock (#1541). A read-only tool result that context compaction removed is restored from the run's own memory instead of fetched again, capped per run, and a write empties that memory so a regenerated file is read afresh (#1488). A tail-risk figure declared with a field ref is checked against that field, so a VaR 99% quoting the 95% value is caught (#1444). QVeris refuses stock and ETF bars, whose adjustment its search-ranked pick cannot state, and quotes priced per result (#1494). Thanks @sambazhu, @zeus229, @he-yufeng, @jw232 and @cgycorey!

  • 2026-09-22 💸 A backtest that died when funding pushed cash below zero, and three more tools that read a rejected query as no data: a crypto funding debit can leave free cash below zero, and the next position the strategy wanted then found no size that fit, not even zero, so the run aborted with "planned order … exceeds available capital" (or "insufficient capital for position rebalance"). That open is now skipped and reported once as insufficient_capital, the bar's reductions still run, and a close whose loss exceeds its margin still aborts the bar as before (#1542). Block trades, margin trading and financial statements now tell Eastmoney rejecting a stale query apart from a genuinely empty answer, through the same check shareholder count, dragon-tiger and lockup expiry use. Answers in Spanish, German and other decimal-comma locales now ground 17,93 % or 1.410,00 CNY against the tool results, while two unspaced numbers like 1400,1777 stay two numbers, and a figure has to match its evidence to the precision it is written at (#1517). Thanks @turtle696966969696 for a trace reconciled to the cent, and @zeus229!

  • 2026-09-21 🔌 IM channels configured from the Web UI, and 24 alphas that emitted a value computed from a missing bar: Settings now edits each IM channel with masked secrets, a connection test on the unsaved form, and a per-channel hot apply with no restart; DingTalk and QQ get guided setups (#1520, #1529), and every adapter logs through stdlib again, so diagnostics that a {} placeholder used to swallow reach the log (#1533). In the Alpha Zoo, a comparison whose operand is NaN because its window holds a missing bar reads False and emits a constant; the #1463 sweep, which nudged the bar by a tick, could not see it. A gap-versus-gap-free check found 24 more alphas, which now mask on their inputs' reach while a correlation undefined on complete data keeps its old verdict (#1523, #1534, #1463). Data: a lockup's free_shares is the unlocking quantity, not the float it was read from (#1513); dragon-tiger seats are ranked within each listing reason (#1512); shareholder-count history returns real periods (#1518); Tencent, Eastmoney and AKShare A-share prices are labelled dividend-additive (#1497); Gildata joins the A-share chain as a token-gated source (#1474); portfolios value any ISO-4217 currency and fail one source, not the snapshot, on a missing rate (#1510); connector account shows Binance, Futu and Trading 212 balances (#1539). New: Bahasa Indonesia UI and README (#1482). Removed: the Requesty provider — point openrouter at its base URL instead. Thanks @shadowinlife, @he-yufeng, @Shizoqua, @lorenzozanee, @cgycorey, @zeus229, @sambazhu, @Yoruxyv and @jastincheis!

  • 2026-09-20 🛠️ Clearer data requests and everyday fixes: monthly 1M requests are now explicitly rejected instead of silently fetching one-minute bars (#1487); weekly/monthly support remains tracked in #1479. Welcome quick actions highlight the selected chip (#1500), DingTalk sanitizes downloaded filenames (#1506), Signal preserves text around mentions after emoji (#1478), and credit-spread tables merge equivalent 5 / 5.0 tenor columns (#1507).

  • 2026-09-19 🛠️ Data errors that looked like missing disclosures or the wrong provider: A-share shareholder counts work again after an upstream column rename; rejected queries now report the provider's error instead of claiming the stock has no disclosure (#1490). Market-data provenance now names the loader that actually served each symbol, with the matching fallback flag and adjustment label, even when the requested SDK is unavailable (#1491). QVeris no longer overwrites indicators with an end date (#1496); adjustment selection, adjusted-response parsing and billing remain tracked in #1494. Thanks @cgycorey and @lorenzozanee!

  • 2026-09-18 ✂️ A redacted answer that lost its row numbers, and one starved order counted as twenty-six: when the grounding gate released an answer with its unverified figures cut, a ranked table came back with (omitted※) where 1, 2, 3, the 12m in its headers and "3 names" in the prose had been. Every integer in a table cell counted as a measurement, and each cut figure's digits were then swept off the rest of the page. A column that numbers its rows is now structure, a plain integer beside words in a cell is read as it would be in a sentence, and the sweep never keys on a single digit; invented returns and multiples are still cut (#1471). In hold mode, the search that scales a basket down to the available cash booked a zero_size rejection on every step, so one contract the cash could not hold read as 26 lot-rounding failures; it is now one insufficient_capital (#1470). Fixed: a local: code in a backtest is served from your own dataset or refused, never filled from a network source (#1467); the event-study CAR standard error now includes the covariance between daily forecasts that share estimated parameters — with a 30-day estimation window the standardised CAR's variance on null events was 1.41–1.46 and is now 1.07–1.08 (#1466); a real historical_var / parametric_var result grounds the VaR it returned (#1464); and twenty alphas no longer fill a missing bar with a constant, while recursive smoothers skip the gap and continue under a rule that is now written down and tested (#1463). Later the same day: a plain LANGCHAIN_PROVIDER=openai setup with gpt-5.6-terra failed on its first tool call, because Chat Completions refuses function tools for the gpt-5.6 models unless the reasoning effort is none. The adapter now retries such a request once on /v1/responses, where the reasoning is kept, and remembers that route for the model (#1473). New: OpenCode Go / Zen as a built-in opencode provider that sends the x-opencode-session id the relay requires, in the compaction thread too (#1416, closes #1415). Merged: an entry memory GC archived is no longer handed to compression as well (#1450); the Patell z uses each normal-return model's own degrees of freedom (#1449); the microstructure estimators reject NaN and infinite inputs instead of returning a zero spread (#1451); a source that must never fall back to the network keeps that promise per symbol too (#1441); and a backtest checks the declared interval against the served bar spacing before annualising, so a daily file declared 1H is no longer annualised at the hourly rate and a weekly file annualises at 52 (#1432). Thanks @5gaLbt and @turtle696966969696 for the reports, and @tonydo, @Shizoqua and @chiww for the fixes!

  • 2026-09-17 🔐 A Robinhood login that reaches several accounts, and a live gate that refused every real order while its tests passed: Robinhood can now be a read-only portfolio source that reads exactly one account, picked from Robinhood's own list with nothing preselected (#1428), and live trading binds each mandate to one account the same way (#1442). The runner and the pre-trade gate had been calling Robinhood with no account and reading its replies one level too shallow, so every reconciliation aborted and every order was refused, while the tests stayed green because their fixtures used a reply shape Robinhood never sends. Positions show unpriced until the quote reply is mapped. Fixed: a swarm worker saves its message log on every exit path that writes a summary (#1439); qlib158's up- and down-day counts no longer count a missing close as a flat day (#1459); a strategy's decay check no longer reads an infinite Sharpe as healthy (#1447); and a custom alpha-zoo root no longer replaces a bundled alpha of the same name process-wide (#1468). Thanks @balu1866 for the reply shapes, and @cgycorey and @0xouzm!

  • 2026-09-16 🧪 Four numerical slips that each returned a plausible number: "low" sat in the sentiment lexicon as both a bullish and a bearish word, cancelling itself out (#1448); head-and-shoulders detection divided by a signed shoulder average, so lopsided shoulders on a negative-valued series passed the symmetry check (#1456); the options engine annualised over one bar fewer than the shared metrics, exaggerating short runs (#1458); and copula pseudo-observations ranked a missing value as the largest and gave ties arbitrary distinct ranks (#1453). Thanks @Shizoqua.

  • 2026-09-15 🧮 A grounding gate that decided what a number was from the words around it: the check every market answer passes before release used to infer whether a figure was a price, a target or a metric from a catalogue of phrasings — 65 regular expressions that grew a fix commit per wording and could give a sentence and its translation different verdicts. The model now declares what each figure is in a figures block the reader never sees (observed, derived, proposed, cited, count); the gate reads only a number's shape and checks every declaration against the session's tool results. A rejected answer gets one correction that names each failing figure with the nearest observed prints, and if it still fails it is released with only those figures cut ((略※) / (omitted※)) instead of being replaced wholesale by a canned refusal, which remains only for an identity problem or a run that observed no price. While it waits, the chat shows "Checking the figures in this answer" in all eight languages. Before release it went through three rounds of adversarial review and real model runs, which added decimal commas, year-shaped prices, untagged code fences, integer prices of instruments quoted in the thousands, prices declared as counts and unchecked numbers reaching the stream. Metadata counts and metric-name tokens no longer ground a metric, and a sentence with several metrics is no longer rejected (#1418, #1420, #1421, #1426, #1433). Thanks @zeus229, @he-yufeng and @5gaLbt!

  • 2026-09-14 🇰🇷 A-shares backtested as perpetual futures, and a swarm argument the model could set but never change: every branchless data source that serves A-shares — local, tencent, eastmoney, baostock, mootdx, sina — routed a pure A-share basket to the crypto engine, which applies none of the A-share rules (stamp tax, T+1, price limits, 100-share lots) and does charge an 8-hourly perpetual funding fee against the position. The run succeeded and its metrics were internally consistent, which is what made it dangerous; a pure A-share basket now reaches ChinaAEngine from every source (#1431). Separately, the swarm worker overwrote every tool call's run_dir with the agent workspace, so for the tools that declare it — backtest above all — the model could pass any directory and read none of it, while the error named no path. A declared run_dir is now honoured inside the workspace and refused outside it with the boundary named, and the backtest tool says which directory it checked (#1430, #1429). New: four connectors land together and the count reaches 18 — KIS (한국투자증권; a genuine 모의투자 paper sandbox on its own host, plus read-only live), Upbit (KRW crypto; paper + read-only live, capped because the exchange exposes no paper/live discriminator), Toss Securities (read-only live; the closed-order history is paged to completion and refused rather than truncated past the cap; read paths validated against a real account) and Scalable Capital's Agentic MCP as a fully read-only profile with an explicit tool allowlist and no order capability (#1407, #1408, #1409, #1417). Fixed: the shared SDK diagnostics told every broker's user to check Longbridge; they now name the affected broker's SDK or gateway in all eight languages (#1436). Thanks @chiww, @cgycorey, @as950118, @dudco and @tingkk!

  • 2026-09-13 🗂️ A broker reply in the wrong shape that counted as an empty account, and run-card diagnostics that never reached the card: the portfolio layer read positions with an empty list as the default, so a reply that never carried a positions list — an MCP response with no mapping yet, or IBKR's official MCP answering without structured positions — became a source holding nothing, and the snapshot was stored as complete. That is exactly the quietly smaller portfolio the aggregation exists to rule out, so a read without a positions list is now refused: the source shows as an error and the snapshot is marked incomplete, while a genuinely empty account ("positions": []) still reads as empty. It surfaced while reviewing a new MCP connector whose holdings are not mapped yet. Separately, the run card kept only scalar metrics, so every dict- or list-shaped diagnostic the engine writes for card readers was dropped — a reader could see how many plans were rejected, but not for which symbol or why. Those metrics now travel in a structured_metrics block, capped at 4 KiB of UTF-8 JSON per metric with anything larger named under _omitted, and render in the Run Card tab in all eight languages (#1424). Thanks @cgycorey!

  • 2026-09-12 📥 A dividend row that looks like a holding, and a number format where one misplaced separator is a thousandfold error: extraETF's CSV exports can now be read into the portfolio layer's position shape — read-only, standard library only, and failing closed on anything it cannot read without guessing (#1406, toward #1170). The Investments export becomes positions and the Transaktionen export becomes typed movements, so a Dividende row, which carries a quantity and a price of its own, is never read as a position, and a transactions file cannot pose as an empty portfolio. Numbers follow the export's German grammar exactly: 1.386,608 is 1386.608, a US-ordered 1,234.56 is refused rather than read a thousandfold off, and a value the eight-decimal wire format cannot hold is refused rather than rounded — 0,000000004 shares would otherwise have become zero. An unknown header (the error names both known column sets), an unknown transaction label, a movement with no instrument, and one instrument listed twice under a single portfolio ID are all refused, while the same ISIN under two portfolio IDs — the export's normal multi-portfolio case — stays two positions. The export carries no snapshot date, so the file's modification time is reported as source_mtime and no position claims an observation time. Nothing calls the reader yet; wiring it into the portfolio container is next. Thanks @cgycorey and @KaiLuettmann!

  • 2026-09-11 📉 Eight years of Tencent history that came back as the last two, and an evidence gate that turned away every backtest the agent ran itself: Tencent's fqkline endpoint serves the last 500 bars of a window, not the first — a CSI 300 request for 2018-01-01..2026-06-30 returns 2024-06-06..2026-06-30 — while the loader paginated forward, stepped past the window after one page and returned a tail-only series with exit code 0 and no warning. It now walks backward from the end date, re-requests an empty page once before believing it, treats an error-shaped reply as a failure, and bumps the loader cache version so series cached by the old walk are never served again (#1411, closes #1410). refresh_strategy_evidence rejected every run produced by the backtest tool, because only the agent runtime wrote the state.json its ingestion gate reads; the tool now records success, failure and timeout itself, and the gate stays fail-closed for runs nobody vouches for (#1413, closes #1412). Concurrent cold-start data requests could come back _unresolved for symbols that were perfectly available: the loader registry marked itself initialised before its imports ran, so simultaneous first callers saw it empty — seven of eight in the reporter's run (#1405, closes #1403). A swarm worker's skills: list, documented as its allowlist, is now enforced by load_skill instead of only by the prompt (#1414), and the correlation skill's Engle-Granger example, which crashed on an unnamed series, now calls the tested quantlib functions instead of its own OLS fit (#1404). One more was ours: thirteen broker config files that hold API keys — alpaca.json, zerodha.json and the rest — were missing from .gitignore though its comment claimed them, so anyone whose VIBE_TRADING_HOME is the checkout was one git add -A away from committing credentials; a test now derives the list from the code. So was a paper cancel that answered for orders it never placed: the Zerodha, Dhan and Shoonya paper connectors simulate orders locally but read the real account, and acknowledged a cancel for any order id — a live one included, which would have kept working; they now accept only the ids their simulator issued. Thanks @shadowinlife, @alanwilhelm and @Shizoqua!

  • 2026-09-10 🧾 A remediation message that named a variable nothing reads, and an adapted strategy that wore its parent's sign-off: when stooq answers with its anti-bot challenge page, the loader tells the operator how to route around it — and both halves of that advice were unreachable as printed. VIBE_TRADING_MARKET_DATA_ORDER_* is read nowhere: the registry builds MARKET_DATA_ORDER_ and the config layer passes it to a bare os.getenv, so exporting the name as printed was a silent no-op and stooq stayed at position 2 of the US-equity chain. The other half, "drop stooq from it", is rejected outright — an override must be a permutation of the default chain, so a source can be reordered but not removed. The message now names the variable the registry actually reads and states the constraint, pinned to the registry rather than to a literal so it cannot drift again (#1402). Separately, the first half of description-driven strategy adaptation landed: an adapted strategy is a new artifact pointing at its parent through derived_from, the description may change universe, name and position sizing while the signal is copied verbatim, and the child starts with empty evidence so its numbers come from its own backtest instead of inheriting the parent's (#1391, refs #1149). Two gaps were closed on the way in, both one field over from the rule that PR was written to enforce. dataclasses.replace copies every field the call does not name, so the child came out UNVALIDATED while still carrying the parent's validator and approver — an independent sign-off worn by something that never earned it — along with an artifact_version and a model_version for code no model had generated yet. And the parent-evidence gate was reachable only from tests: register_adaptation never consulted it, so a stale or insufficient parent was written anyway, against what the substrate advertised. Its inputs are keyword-only and required now, so the check cannot be skipped by forgetting it. Thanks @chiww and @modelpath-dev!

  • 2026-09-09 🚀 v0.1.15 released (Release notes, pip install -U vibe-trading-ai): 551 commits and 162 merged pull requests since 0.1.14, from 35 contributors. The theme of this cycle is data that says what it is — and three of the biggest fixes turned out to be the same bug wearing different clothes: a default that quietly substitutes a plausible value for a missing one, which is indistinguishable downstream from a real observation. The Alpha Zoo's NaN contract moved out of the individual alphas and into the registry: an alpha that branches on an np.where comparison never sees a NaN — the comparison is False — so blanking every declared input on one bar left 84 of 462 alphas returning a number anyway, each consumed as a real signal because dropna() is what keeps a gap out of an IC. The registry now masks output wherever a declared dependency is missing on that bar, and the same sweep afterwards finds none (#1377, closes #1376). The warmup half stays open and stated rather than quietly carried: 52 alphas still emit a value inside their own declared min_warmup_bars, and a registry-level warmup mask would also blank rows for alphas that merely over-declare, so that half needs a direction call rather than 52 PRs. Same class, second instance: pandas still defaults pct_change() to forward-filling, so a missing close becomes a 0.0% return that never happened; four PRs fixed one call site each, and an exhaustive sweep found 24 sites across 10 files — two of them inside the very files those PRs were editing. Third instance: the futures loader chain named tushare and akshare, and neither implemented a futures endpoint at all, so every contract fell through to the A-share equity endpoint. AKShare now serves Chinese contracts off the keyless Sina daily endpoints — dated and main-continuous, verified live across SHFE, CFFEX, GFEX and ZCE — while a global contract returns empty and reaches local instead of being priced as an equity (#1395). Prices themselves now carry the adjustment caliber they were served under, and a source whose caliber was never measured against a live payload reports unknown rather than guessing one (#1317). Live trading fails closed in five more places: a broker position read returning an API error, error envelopes arriving mid halt-sweep, the flatten latch across runner restarts, unresolved Alpaca submissions recovered by exact client ID across a restart, and buy-limit orders sized at the worse of quote and limit on both transports. In the backtest: options signals fill on the next bar rather than the date they were computed from, short option legs hold margin and gate opens on buying power, perpetual funding settles by bar span on 8h+ intervals, an over-committed rebalance basket scales instead of aborting, and a halted position marks at the last traded close instead of entry cost. In the agent loop: a session that had already fetched fundamentals, fund flow, margin and research data had those results cleared to free context, and the de-duplication ledger went on refusing to re-fetch them — 44 blocked retries in one run, ending in "fundamental data not retrieved" for data the model had already received; results reconcile by exact call identity now, and the no-progress budget counts observations rather than activity. The final batch to land before the tag is those same three themes in miniature. CL2412.NYMEX matched no symbol pattern — the bare dated form (CL2412) matched and the venue form (ES.CME) matched, but the way a contract is actually written matched neither — so a US crude contract ran under T+1, with no shorting, settled in CNY; Tushare's own exchange spellings had the mirror-image problem on the China side, and both halves classify now (#1396, closes #1394). The pct_change() call sites were being fixed one at a time (#1397, #1398) before the exhaustive sweep found the rest, and the same default sat behind TopN selection ranking assets that had no factor observations (#1399) and sentiment orthogonalization regressing on zeros it had filled in itself (#1400). China-futures runs now state which products were priced on a generic default instead of a table entry — rb's real margin rate is 0.10, the same number as the default, and "looked up" must not read like "assumed" (closes #1393). And the ML walk-forward example purges future labels (#1392). New this cycle: UK equities (LSE .L/.IL, with SDRT modelled as a purchase-side-only duty, because charging both sides overstated every round trip by half), Zerodha Kite Connect as the fourteenth broker (capped at paper plus read-only, since Kite exposes no runtime live discriminator), a read-only multi-broker portfolio across Web, REST, CLI and agent tool where a source that fails to refresh is an error excluded from the totals rather than a stale cache, fifteen Quant Library additions (Heston, Hierarchical Risk Parity, copulas, VPIN/Roll/Amihud/Kyle microstructure, barrier options with finite-difference Greeks, ISDA CDS, Key Rate Duration, Vasicek, factor IC, Ornstein-Uhlenbeck, Ulcer/Pain, event-study tests, group-purged CV), Brazilian Portuguese as the eighth locale, read-only Nobitex and Wallex, calendar-triggered partial rebalancing, swarm replay and retry, and an offline evals harness that emits NOT_EVALUABLE rather than passing when the instrumentation it needs is absent. Thanks to all 35 contributors of this cycle!

  • 2026-09-08 🧪 An alpha that printed a number for a bar whose inputs were blank, and a spot-gold search that answered with a Swedish Bitcoin ETP: the Alpha Zoo contract preserves NaN through warmup and missing data, but an alpha that branches on an np.where comparison never sees a NaN — the comparison is False, so the ternary falls through to its constant. Blanking every declared input on one bar of a 462-alpha sweep, 84 alphas returned a number anyway, and since dropna() is what keeps a gap out of an IC, each of those constants was consumed as a real signal. The guard now sits in the registry rather than in each alpha — the output is masked to NaN wherever a declared dependency is missing on that bar — and the same sweep afterwards finds none (#1377, closes #1376). Eleven alphas were fixed for the other half of the contract, the warmup window (#1379, #1380, #1381, #1382, #1383) — and measuring that half the same way leaves 52 alphas still emitting a value inside their own declared min_warmup_bars. A registry-level warmup mask would also blank rows for alphas whose declaration is merely conservative, so that half stays open and stated rather than quietly carried. Separately, search_symbol("XAUUSD") returned exactly one candidate — VALOUR-BTC-0-SEK.ST, a Swedish Bitcoin ETP — which then locked the run's instrument identity; a metal or FX pair query is an exact instrument assertion now, keeping only candidates that name the same two legs in any spelling (#1282). Fixed: an announcement date carries no time of day, so on an intraday frame a filing became visible from the first bar of its own announcement day — a full session of lookahead. Sub-daily frames are refused now, with fundamental_subdaily="next_day" as the explicit opt-in (closes #1387). A metric claim formatted as a generic | Metric | Value | table escaped the analysis gate that rejects the same claim in prose (#1375), while the mirror-image error rejected a price word used as a formula variable — close/SMA50 > 1 was read as an asserted price (#1378, closes #1354). A pasted broker code (HK.00700, US.AAPL, SH.600519) scanned as no symbol at all, so every market tool answered identity_required (#1384). The three Archimedean copula CDFs returned wrong extreme values under strong dependence — Clayton 0.0, Gumbel 1.0, Frank inf — and are computed in log space now, verified against a 2500-digit reference across θ ∈ [-5000, 5000] (#1386, closes #1385). An MT5 order above the symbol's volume cap was silently clamped and sent, an eToro limit order with no limit price rested untriggered while reading as accepted, futu K-lines inherited an undeclared adjustment caliber, and BTCUSDT was routed through A-share rules — T+1 and no shorting, on a perpetual (#1388). Thanks @cgycorey, @Shizoqua, @he-yufeng, @Robin1987China, @laiyierjiangsu, @aminak58, and @nandofmike!

  • 2026-09-07 🪙 A 50-ounce gold order rounded down to nothing, and a currency future priced at 1/2500th of its contract size: in a cross-market backtest the composite engine dispatches every symbol through one shared sub-engine per market, but only apply_slippage refreshed that sub-engine's own active symbol — so round_size and calc_commission used whichever symbol had synced it last. A 50 oz gold position sized against FX's 1,000-unit micro lot rounded to 0, gold futures were charged the index future's rate-based fee (6.90) instead of their own flat one (20.00), and swap used the 100,000-unit standard lot rather than the 100 oz metal lot (#1370). Separately, _extract_product could not read a symbol whose product code contains a digit or ends in a letter that doubles as a month code: 6EZ4, 6JH25, M2K, MYM2503 and FESX2503 all fell through to the default multiplier of 50 — for 6E the true figure is 125,000 (#1369). Symbols now resolve against the multiplier table itself, longest match first, which also covers the dated forms (M2KZ4) and prefix collisions (SILZ4 vs SI). Fixed: four Alpha Zoo factors printed a hard ±1 or 0 through a trading halt and inside their own declared warmup, because a NaN comparison is False rather than NaN and the ternary fell through to its constant. min_warmup_bars is metadata that nothing trims, and what keeps a gap out of an IC is dropna() — so those constants were consumed as real signals (#1371, #1372, #1373, #1374). Measuring the whole zoo the same way puts 82 more alphas in the same shape; rather than one PR per alpha, that is now tracked as a registry-level guard in #1376. Strategy-discovery evidence also resolved position size once for the whole run instead of per regime, and a single unparseable benchmark cell could erase every evidence row that run produced (#1368). New: a run that keeps issuing tool calls without gaining information now stops after eight iterations with a visible recovery request, instead of spending its whole budget on path discovery — the reported case burned ~35 iterations re-guessing the same rejected paths. An identical call is refused from its second failure rather than its first, so one honest retry after a rate limit or a timeout still runs (#1363, closes #1353). Thanks @Shizoqua, @be-student, and @nandofmike!

  • 2026-09-06 🛡️ A buy limit sized at a price it would never fill at, and an audit that returned PASS having verified nothing: the MCP order gate priced a quantity order from the live quote alone, so a limit at twice the market cleared a cap sized for the quote and could fill at twice the authorized notional. It is sized at the worse of quote and limit now — the rule the direct-SDK path already used — and an unparseable limit price is denied rather than waved through (#1361). The report auditor skipped every point with no fetched value and then reported PASS because nothing had failed, certifying a report backed by no evidence at all; that fails closed now (#1362). Fixed: metrics survived a failed analysis tool, and the new exemption for attributed figures — right for a paper's Sharpe, wrong for a price this run is meant to observe — would have passed Analysts say TSLA.US last traded at 412.35 USD. with no tool call behind it (#1338, closes #1336); a cash-dividend row killed the whole trade-journal parse (#1356); compaction re-opened the de-duplication ledger by tool name, so clearing one argument variant left the rest gated (#1358); the compliance ledger refused its first append on Windows (#1261). New: Zerodha Kite Connect makes 14 brokers — read and paper only, since Kite exposes no runtime paper/live discriminator (#1193); Nobitex and Wallex add Iranian Toman pairs for 27 data sources, neither able to silently degrade into a USD-quoted venue (#1263); native Anthropic calls cache the static tools-and-system prefix instead of resending it at full price every turn (#1366). Thanks @cgycorey, @ashutoshsinghpr7, @saju01, @he-yufeng, @Emad211, @averatec0773, @birdxs, and @AirHua-byte!

  • 2026-09-05 🔓 A price the model invented passed the check in English but was caught in Chinese, and an agent that could not re-read data it had already fetched: the grounding gate matched close but not closed, so The stock closed at 412.35. with no tool call behind it went straight through, while the identical fabricated claim in Chinese (该股收盘 412.35。) was rejected. last traded at and quoted at had no rule at all, and Chinese had the mirror-image hole — 成交价 / 最新价 / 股价 / 收报 all missed. Both vocabularies are complete now, the English forms require a following "at" so volume and deal phrasings stay out, and a new suite asserts the two languages reach the same verdict per case instead of checking each in isolation. Separately, a session that had successfully fetched fundamentals, fund flow, margin and research data then had those results cleared to free context — and the de-duplication ledger went on refusing to re-fetch them, 44 blocked retries in one run, ending in "fundamental data not retrieved" for data the model had already received. Clearing a result now re-opens that tool, the ledger keys on arguments rather than the tool name, and the token budget counts tool-call arguments instead of scoring a 100 KB payload as ten tokens (#1349, #1341, #1352, closes #1343). Fixed: every backtest launched from the Web UI segfaulted on aarch64 — sandbox rlimits ran Python in the forked child of a multi-threaded server, undefined behaviour per POSIX; they are applied after exec now (closes #1355). GC=F and XAUUSD were classified as China A-shares (#1280); BRK.B.US and other dotted class shares fetched an empty chart (#1351); a fully invested rebalance basket aborted on a commission overdraft instead of scaling to fit (#1344, closes #1274); percentage-point deltas — 3.6pp, 3.6 个百分点, 250 基点 — were read as quoted prices (#1346); joined crypto pairs like BTCUSDT went unrecognised while spot platinum resolved to a crypto pair that does not exist (#1265); strategy-store history came back oldest-first when timestamps tied (#1347); the Codex adapter discarded the model the provider reports (#1348). New: market context stated earlier in a conversation can narrow symbol resolution, behind VIBE_CONTEXTUAL_IDENTITY_CONSTRAINTS (#1269); the investment-committee workers get the fundamental data panel their prompts already assumed (#1345); deterministic USD-M tolerance calibration from recorded comparisons (#1248). Thanks @nandofmike, @atomfive, @thisisjun786, @cgycorey, @saju01, @he-yufeng, @aminak58, @AirHua-byte, @lorenzozanee, @ethanstoner, @Shizoqua!

  • 2026-09-04 🩺 Every Claude 5 run failed on the first request, and a halted position was marked back to what you paid for it: langchain-anthropic moves temperature into extra_body for the current Anthropic SDK, and our self-heal only popped the top-level key — so the retry re-sent exactly the field the API had just rejected, and every run on claude-sonnet-5 / claude-opus-5 died at the first call (#1330, closes #1329). In backtests, a position held past the forward-fill limit was re-marked at its entry price: equity printed a drawdown with no market event behind it, and rebalance sizing ran against that phantom mark. A halt of any length now marks at the last traded close, while order fills still refuse a stale price (#1332, closes #1318). Fixed: three ways a commit-time adjustment could widen the mandate you approved — a stringified number skipped the numeric check, True passed as a number, and an instrument whitelist had no comparison at all; cash-only stays the floor of the leverage axis rather than an invalid type, so the safest mandate is still committable (#1285). The elapsed clock survives switching pages, reloading, and reopening a session from history (#1340, closes #1339), and the seven open npm advisories in the frontend and desktop lock files are patched. Thanks @averatec0773, @he-yufeng, and @Jackzigen!

  • 2026-09-03 📡 A data source that never answers, and dated figures that could not be proved: stooq serves non-browser clients a JavaScript proof-of-work page — HTTP 200 with an HTML body — which the loader read as "no data", so position 2 of the US-equity chain was dead weight on every fetch with nothing in the run log to show for it. It is now recognised as unavailable, with a one-time warning naming how to reorder or drop the source (#1342, closes #1315). Separately, a generic tool result carrying both a price and its date lost the date on the way into the grounding ledger, so a dated claim had no evidence that could match it and a correct answer was refused; timestamps are carried now, and a row's own date overrides one inherited from the payload (#1333). Fixed: the MCP wrappers for goal evidence and status demanded a goal id that the registered tools document as optional, so a client meaning "the current goal" got a validation error (#1331); the Codex adapter discarded the token counts the provider reports, leaving usage accounting on a character-count estimate (#1334). New: the swarm's MCP stdio path gets real subprocess coverage in place of a note saying it was untested (#1335). Thanks @he-yufeng and @Shizoqua!

  • 2026-09-02 💵 The last two loaders that booked dividends as losses, and an explicit source that answered as someone else: FMP and Tiingo still served raw OHLC while the rest of the chain served adjusted prices — the same ex-dividend gap read as a real drop, closed for Yahoo on 08-31 and now closed for both (#1320, closes #1296). Their rows in the price-caliber table were corrected in the same change: a frame that is adjusted must not be stamped raw, or the mixed-caliber warning added in #1317 is checking a label instead of the data. FMP also moved to the Stable endpoint, and an explicit source="fmp" now fails loudly instead of returning another source's numbers under FMP's name (#1276, closes #1270). Fixed: a ticker inside full-width parentheses — 公司名(代码)价格 — was split from its own figure, so the unsourced-symbol gate never saw the two together (#1326, closes #1260); every references/ link in the bundled skills now resolves both for the agent and for a human who clicks it on GitHub (#1328). New: Brazilian Portuguese joins the interface as the eighth language (#1327). Thanks @lorenzozanee, @thisisjun786, @cgycorey, @jw232, @ethanstoner, and @nandofmike!

  • 2026-09-01 🎯 Options backtests filled at the price the signal was computed from, and a naked short could sell premium it could never cover: a signal dated T priced off T's own close and IV — phantom edge in every options backtest, not just adversarial ones. Signals now fill on the next bar, and short legs post CBOE-style margin checked against buying power (#1299, #1306). Fixed: perpetual funding settled once a day against the engine's own 3x/day model (#1307); a 1x short was exempt from liquidation entirely (#1298); composite runs dropped India T+1 and failed open on every price-limit band (#1309). New: every served frame states its price caliber — adjusted, raw, or honestly unknown — and a mixed-caliber run says so (#1317, closes #1301). Thanks @he-yufeng, @cgycorey, @lorenzozanee, and @guestccc!

  • 2026-08-31 🧮 Yahoo booked every dividend as a loss, and the rebalance count you were shown had nothing to do with the fills: both Yahoo paths served dividend-unadjusted OHLC while the rest of the chain served adjusted prices, so every ex-dividend gap read as a real drop in any US-equity backtest Yahoo won. OHLC now scales to Yahoo's adjclose and the yfinance path requests the adjusted series; volume stays raw on both (#1287). Measuring the chain to verify that turned up something worth stating plainly: sina and longbridge still serve fully unadjusted prices, so which source you land on still changes the price caliber — that gap is now tracked in #1301. Separately, rebalance_count counted target-weight changes, not executions: a constant-target SPY/BND strategy reported one rebalance against 1,269 trades. Requested and executed are now separate metrics, the executed ones derived from immutable fill records (#1281, closes #1275). New: rebalance_mask runs partial rebalancing on a calendar or on explicit dates instead of every bar (#1277, closes #1273); the HTML alpha-bench report now carries the survivorship-bias disclosure the JSON already had, naming the constituent source and its as-of date (#1289). Fixed: one unresolved symbol no longer strands the rest of its batch — the chain retries only the missing ones and provenance names the source each symbol actually came from (#1288); a halt sweep could latch an episode it never swept, and two concurrent completions could lose each other's record (#1254); a working Futu OpenD connection rendered as unavailable because its health report omitted connection_state; the desktop updater read a permission-denied process probe as "backend exited" (#1284); and a session backgrounded mid-turn kept its sidebar spinner for the life of the tab (#1257, closes #1256). Thanks @he-yufeng, @cgycorey, @thisisjun786, @bonyohana, @lorenzozanee, and @iagop03!

  • 2026-08-30 🇬🇧 LSE equities arrive without turning pence into pounds, and closed markets stop firing live triggers: .L symbols now work end to end through Yahoo → yfinance → local market-data fallback, stock profiles and financial statements, trade-journal and Shadow consumers, and GBP-settled backtests. The loader treats .L only as a venue marker: declared GBp/p prices are divided by 100, GBP passes unchanged, and USD, other, or unknown currencies are rejected before the statically GBP accounting layer. Per-symbol conversion provenance survives cache round trips, and the cache version was bumped so older unsafe entries cannot return; UK execution also uses whole shares and slippage_uk (#1206, closes #1205). Fixed: market-triggered live ticks stop before broker reads while all attached markets are closed, while interval-only and event-driven channels remain ungated (#1253); Run Detail scrolls and clamps long prompts, then collapses them again when switching runs (#1258); non-backtest runs route to Studio instead of a blank dashboard, and an empty trade-artifact array no longer hides a populated trade_log (#1259). Thanks @cgycorey, @he-yufeng, and @iagop03!

  • 2026-08-29 🛑 A kill switch that skipped its own action, and a crypto pair that resolved to a different coin: when a halted channel's broker reads failed — the adapter returns an error envelope instead of raising, and the sweep iterated it as a list of orders — the sweep marked itself fired anyway. The cancel-and-flatten the kill switch exists to perform was silently skipped for that episode, and nothing retried it. It now latches only once a broker write has been attempted, claims each halt episode exclusively so two runners cannot duplicate a close, and no longer reads a broker rejection wrapped in a transport-level success as accepted (#1244). Separately, asking for ETH-USDT returned AETHUSDT-USD — Aave Ethereum USDT, a different asset — because symbol search never covered exchange pairs and Yahoo's nearest string won. Exact pairs now resolve against the venue catalogs, which are public and need no broker account (#1242, closes #1234). New: built-in connectors publish a machine-readable onboarding contract, so vibe-trading connector setup and the Portfolio connection center drive one generic flow, secrets kept per connection in the OS keyring (#1250). Fixed: stream retries escalate and honour Retry-After (#1208); a sleeve whose target rounds below one lot is reported instead of silently trading zero times (#1235); and an explicit benchmark is measured over the evaluated window, not the fetched one, so yesterday's warm-up boundary no longer compares two periods. Thanks @cgycorey, @pengpengyi92, @lorenzozanee, @goatyyc, @ethanstoner, @QG8000, and @turtle696966969696!

  • 2026-08-28 📏 Backtests that crashed, and backtests that quietly graded a year you never asked for: every cross-market backtest died on v0.1.14 — the runner deliberately passes bars_per_year=None for a basket spanning markets, and the new risk x-ray called math.sqrt on it. Two more consumers had the same gap; all four now resolve None through one shared span-derived factor (#1239, closes #1237). The quieter one: a long-lookback strategy needs bars from before the period you asked about, so the agent moved start_date back a year to feed MA200 — and then graded that year. A run billed as ten years reported eleven, with the extra year's trades, CAGR and benchmark folded in, nothing raised, and the metrics internally consistent. warmup_bars (or evaluation_start_date) now separates the data window from the evaluation window: warm-up bars prime the indicators and reach nothing else (#1240). New: quantlib gains Heston (1993) stochastic-volatility pricing, Hierarchical Risk Parity, Gaussian and Archimedean copulas, microstructure estimators (VPIN, Roll, Amihud, Kyle) and finite-difference barrier Greeks — 306 tested functions across 23 modules (#1195–#1198, #1203). Fixed: eight skill reference links pointed at paths read_file cannot open, so those documents silently failed to load. Thanks @cgycorey, @santhreal, @turtle696966969696, and @wanderkiller!

  • 2026-08-27 🛑 The kill-switch sweep now survives restarts and stops trusting a flaky broker: during a halt, the cancel-and-flatten sweep counted any broker response as success — but the MCP adapter turns a failed call into a {"status": "error"} envelope, so a dropped connection produced a compliant-looking audit trail while the resting order stayed live; error envelopes now fail closed in both passes (#1232). The sweep's fired-once latch also lived only in memory: a restart with flatten orders still working replayed the whole sweep — a fresh market order per position, enough to flip a long book net short; the latch is now persisted next to the HALT sentinel and bound to its halt episode, so clearing and re-tripping still re-arms it (#1233). New: every market's data-source fallback order is visible and reorderable in Settings → Data Source Priority — hot-applied, persisted per market (MARKET_DATA_ORDER_*), and strictly a reordering: adding or dropping sources is refused, and without an override the defaults are untouched (#1231); Binance USD-M reconciliation results now land as tamper-evident drift evidence artifacts — strict JSON, fail-closed on incomplete or unsupported snapshots, no order surface (#1230, toward #1030). Thanks @he-yufeng, @sambazhu, and @honginp!

  • 2026-08-26 ♻️ A live Alpaca order that loses its broker response stops being a mystery, and gold backtests stop being frictionless: the order gate now durably owns every Alpaca submission before the broker write, recovers the outcome by exact client_order_id only, attributes fills against the signed position delta, and HALTs on any contradiction — recovery never resubmits (#1213, #1221, #1222). Fixed: metals used FX pip/lot conventions, making gold's spread ~1,460× too cheap and rounding positions under 1,000 oz to zero (#1226); Futu HKD holdings were valued as USD, overstated by roughly the USD/HKD rate (#1228); Shadow Account read PnL keys the runner never emits, so every successful backtest reported PnL = 0.00 (#1217); streamed LLM calls never requested usage, under-reporting swarm output tokens ~18–36× (#1225). New: opt-in read-only Binance USD-M account snapshots — two allowlisted signed reads, no order surface (#1229, toward #1030); portfolio OAuth reconnects run in a bounded subprocess that cannot strand the web process or the callback port (#1211). Thanks @Elfsa-Miranda, @P1Piyush, @JaxonHu1024, @he-yufeng, @honginp, and @goatyyc!

  • 2026-08-25 🛡️ Two live-gate fail-opens closed, and purged CV stops wiping the training set between test blocks: Alpaca shorts booked as positive exposure (qty is a magnitude, direction lives in side), so selling more loosened max_total_exposure_usd instead of tightening it — quantity is now signed on both the TAP JSON and direct-SDK paths (#1209); OKX/Futu reads flattened a rejected API call into "empty book, status: ok", letting the mandate gate evaluate limits against nothing — they now return the error envelope the gate fails closed on (#1212). Both are Phase 0 of the audit roadmap in #1207. Fixed: combinatorial purged CV treated non-contiguous test blocks as one span, purging every training observation between them; segments now purge individually and an emptied fold raises (#1204); the credit-risk functions refuse NaN/inf inputs instead of returning NaN scores or a "grey" verdict (#1215, closes #1214). New: swarm workers retry with capped equal-jitter backoff (#1210, toward #1208), and vibe-trading --swarm-retry / /swarm retry reruns a failed run, keeping completed tasks with --resume (#1194). Thanks @he-yufeng, @santhreal, @Robin1987China, @pengpengyi92, and @SiMinus!

  • 2026-08-24 🔗 IBKR's official MCP goes from "lists tools" to a working read-only portfolio source, and scheduling gets an agent tool that cannot act alone: #1178 fixed the URL, but IBKR's gateway still rejected FastMCP's stock OAuth client registration before login. An IBKR-scoped OAuth provider — browser-profile headers, token_endpoint_auth_method: none, a stable callback port, and stale-registration recovery, applied only when the MCP host is api.ibkr.com — completes authorization (#1186), and the live-account-verified get_account_summary / get_account_positions tools now back the generic account/position reads, making ibkr-live-official-mcp-readonly an eligible /portfolio source (#1190, closes #1126). New: the agent sees exactly one scheduling tool, scheduled_research — its propose_create/propose_cancel never touch the job store until you confirm on the surface you are on (Web card, CLI y/N, or an exact confirm/确认 reply in IM), delivery targets are opaque operator-configured refs that never expose a raw chat/user id, and a job past its end_at expires instead of firing again (#1187). Fixed: the comps and three-statement engines now refuse non-finite inputs everywhere they enter the arithmetic — a NaN peer metric had been included in the multiple distribution and dragged the median to NaN, and abs(nan) > tolerance is False, so a NaN balance sheet sailed through the hard balance check (#1184, closes #1183); get_market_data validates codes, dates, source and interval before burning the loader fallback chain on a malformed call, and its source enum stopped silently rejecting six registered loaders (#1185); Feishu QR login now persists the app credentials it receives exactly once — atomically, owner-only — instead of reporting a success that did not survive the process (#1188); the risk-analysis skill doc's historical-VaR order statistic now matches the code (#1189). Thanks @sykuang, @goatyyc, @AirHua-byte, @Robin1987China, @cgycorey, and @youngjincho02-arch!

  • 2026-08-23 🔌 The IBKR MCP seed named the wrong URL, and closing one LLM adapter closed them all: The seeded official IBKR read-only MCP profile, the README and SKILL.md all pointed at https://api.ibkr.com/v1/api/mcp; IBKR's own AI-integration page publishes https://api.ibkr.com/v1/api/mcp-public, and the seed, all six READMEs and SKILL.md now name it — re-run vibe-trading connector configure ibkr-live-official-mcp-readonly --yes if your agent.json still carries the old URL. The OAuth client-registration step that IBKR's gateway rejects is still open in #1126 (#1178). Fixed: ChatLLM.close() closed LangChain's process-wide cached HTTPX clients, so one finished title-generation or image-vision call left every later request failing with "client has been closed" until a restart — only transports Vibe-Trading created itself are closed now (#1182); a service restart mid-reply dropped the streamed text and left the attempt running forever — partial replies are now checkpointed and reconciled as an explicit interrupted transcript entry on the next start (#1180). New: Web chat attaches up to five files per turn through the picker, drag-and-drop, or clipboard paste (#1179). Thanks @c020627 and @AirHua-byte!

  • 2026-08-22 💼 A Portfolio page — your holdings across brokers, read-only: Pick any read-only connector profiles (connection instances over account.read + positions.read; the IBKR official-MCP profile is not yet eligible) and the new /portfolio page aggregates them into immutable snapshots with per-source provenance, USD/CNY valuation, CSV export and a history chart. A source that fails to refresh is reported as an error and excluded from the totals — never carried forward — and the snapshot is marked incomplete. The portfolio_summary agent tool returns risk_xray_args that feed the existing portfolio_risk_xray, and vibe-trading portfolio show|refresh|sources prints the same snapshot in the terminal. Read-only connector plugins you write yourself live under ~/.vibe-trading/connectors/ (a manifest declaring any write capability is rejected; secrets go to the OS keyring via the [keyring] extra), and nothing on this path can place an order (#1072, toward #1171). Fixed: thirteen Alpha Zoo factors forward-filled a missing close before computing returns, turning a data gap into a finite "0% return" — the gap now stays NaN (#1172); independent MCP clients on one http/sse server shared a single fallback research-goal session (#1173); memory GC and compression left stale FTS rows and orphaned relation sidecars (#1174); cancel_run() never reached a swarm worker already streaming — the stop now interrupts the stream, skips that turn's tool calls and lands as a cancelled task (#1175); MCP get_research_reports dropped beginTime/endTime (#1176); get_options_chain answered a wrong-cycle expiration with ok: true and another date's contracts (#1177). Thanks @goatyyc, @Shizoqua and @cgycorey!

  • 2026-08-21 ⏱️ Runs that hung forever: A bash timeout killed the shell but not the grandchildren holding its pipe handles, so a run sat "running" for 20+ minutes. Commands now spawn in their own process group, a timeout kills the whole tree, a stall watchdog ends a run making no forward progress, and compaction stopped discarding the model's own verification records (#1169). Fixed: multi-year Tencent history silently truncated at 500 bars (#1154). New: swarm runs replay only their failed subgraph (#1158, closes #1157); Market Watch shows each monitor's latest verdict inline (#1156, closes #943); quantlib reaches 286 tested functions (#1159–#1168). Thanks @wiliao, @cgycorey, @he-yufeng, @BigFishEmily, @santhreal, @SiMinus, and @alinv0!

  • 2026-08-20 🚀 v0.1.14 released (Release notes, pip install -U vibe-trading-ai): 272 commits and 74 merged pull requests since 0.1.13. The headline is that a finished backtest is now something you can read rather than a folder of CSVs. Run Detail grows four tabs — Factor Research (IC series with its mean line, IC statistics, quantile-group equity, and a pairwise IC correlation matrix that existed nowhere before), Positions (weight pie/treemap on a date slider, sector net-exposure bars, weight-evolution area — the pie is gross composition and the bars are net, so a long/short pair in one sector nets to zero on the bars while both legs stay visible on the pie), Tearsheet (monthly-returns heatmap, annual bars, top-5 drawdowns annotated onto the equity curve), and an interactive research dashboard with KPIs, benchmark-relative equity, rolling Sharpe and the full trade ledger. All four read artifacts a run already writes — no new pipeline. A new Options Lab page adds an expiry payoff diagram, a spot×IV scenario matrix, portfolio Greeks and a live options chain, computed through the same test-pinned engine the MCP tools use. Install: Intel Macs can pip install vibe-trading-ai again — smartmoneyconcepts pulled in llvmlite, which ships no macOS x86_64 wheel from 0.46 on, so every Intel install became a CMake source build; it is now the opt-in [smc] extra and the stale <3.14 cap is gone (#1035). New: evidence-gated Strategy Discovery across the Alpha Zoo and the SDM store, with a population path, read-time freshness (fresh/aging/stale) and stale rows failing closed out of recommendations; scheduled research that delivers itself through a leased outbox and persists each monitor's verdict for the Market Watch list; seven read-only Futu endpoints; Vietnam (HOSE) as a backtest market; offline USD-M account reconciliation; Novita AI and GitHub Copilot providers; a hosted MetaTrader 5 data source; Spanish and German locales; and MCP grows to 74 tools. Correctness: the test suite stopped escaping into your real config root, where a full run had been appending synthetic order_rejected records to the live hash-chained audit ledger; build_registry() no longer returns a short tool list in silence; xirr survives long-horizon discount underflow and DCF refuses non-finite inputs instead of returning a negative share price; .VN symbols stopped executing under China A-share rules; the backtest archive stopped mixing two runs' artifacts; and a broad grounding pass ended a class of false refusals on dates, ordered lists, identity constants in rate formulas, and order lines read as quotes. Thanks @Shizoqua, @shadowinlife, @pengpengyi92, @cgycorey, @ofeksh-tr, @lorenzozanee, @AndyLongest, @zzz607, @wiliao, @jay79-boop, @Robin1987China, @Echoandelementwebsites, @zhiwuyazhe-fjr, @x-lambda, @sykuang, @straun-repo, @nstavros, @ngoanpv, @miguelangelo78, @lukiod, @jax-novita, @honginp, @he-yufeng, @fixXxerTech, @er-s-an, @daviddaco1, @birdxs, @QCYTSN, @549236606-oss and @1psconstructor.

  • 2026-08-19 🔌 Stalled runs, a per-task connection leak, and Intel Macs that could not install: A silent provider used to freeze a run — VIBE_TRADING_LLM_TIMEOUT_SECONDS (default 300s) now bounds the call, and tool-call markup is never released as a final answer (#1105). Every swarm task leaked a pooled HTTP connection (#1145, closes #1141). Also fixed: vibe-trading show crashing (#1147, closes #1146), overwritten in-flight deliveries (#1140), dropped backtest validation evidence (#1139), MCP paging (#1137, #1138), and non-finite prediction-market fields (#1136). New: seven read-only Futu endpoints (#1135) and an explicit Inferred chip on guessed strategy titles (#1134). Install: smartmoneyconcepts is now the [smc] extra — the llvmlite it pulled in ships no macOS x86_64 wheel, turning every Intel Mac install into a cmake source build (#1035); the <3.14 cap goes with it. Thanks @wiliao, @cgycorey, @Shizoqua, @Echoandelementwebsites, @549236606-oss, and @fixXxerTech!

  • 2026-08-18 🈶 Correct reports stopped being refused, and backtests stopped trading noise: \b is Unicode-aware, so 最 counts as a word character and (2026-07-14最低) had no boundary after the day — the date survived the mask and 2026, 7 and 14 reached the OHLC check as prices no observed range can contain (#1132, closes #1122). Four refusals of the same family went with it: a dash-form trading day (08-10(一)), a level stated as a range leaving -20 behind, a GTC line (100 @ $3.50) read as two observed quotes, and a report-style date cell that matched no evidence row at all. Backtests: position_adjustment="hold" dropped a requested resize in silence, and "rebalance" had no drift band — measured, a 0.01% daily move re-pinned a position on 19 of 30 bars, so a strategy with its own rebalance_freq traded every bar regardless. Dropped requests are now reported, and rebalance_tolerance is the band practitioners mean by "rebalance when weights move more than X", defaulting to 0.0 so no existing run changes. Nineteen industry-neutralized alpha101 alphas had been skipped on every SP500 bench run for want of a sector tag that was already in the table the constituents come from. New: a Market Watch monitor can push its briefing to an IM channel once the run finishes, through a persisted outbox that a restart cannot lose and a concurrent sweep cannot double-send (#942); German is the seventh UI language (#1117); run_dcf refuses non-finite inputs instead of returning a plausible negative share price (#1121, closes #1120); the MCP get_market_data response carries the _provenance its own docstring promised (#1131); a tool module that fails to import is named rather than quietly shrinking the registry (#1129, closes #1124); and offline USD-M account reconciliation compares local risk state with an exchange observation without opening a connection (#1106). Also: importing backtest.runner no longer loads a .env into the process, which had made a local full-suite run untrustworthy on any machine that has one (#1123). Thanks @Robin1987China, @newgo, @er-s-an, @Shizoqua, @1psconstructor, @honginp, @cgycorey, @alinv0, and @jelech!

  • 2026-08-17 🔒 The test suite stopped writing into your real config root — including the live audit ledger: Running the project's own suite appended fabricated order_rejected records to ~/.vibe-trading/live/audit.jsonl, an append-only, hash-chained ledger whose entire value is that its entries cannot be manufactured, and on Windows left a corrupted chain file behind. conftest.py had no config-root sandbox at all, so every module that baked Path.home() / ".vibe-trading" at import time resolved against the real home on any platform — Windows was worse only because Path.home() reads %USERPROFILE% there and ignores $HOME, leaving the isolation idiom the suite had been using inert. Home is now redirected before collection, the sandbox owns a single knob so per-test isolation still wins, and session end asserts the real ledgers are byte-identical instead of merely checking that the redirect was installed (#1118, closes #1116). Also: xirr and money_weighted_return raised ZeroDivisionError on horizons past ~51 years, where the discount factor underflows to zero — exactly the long, irregular streams XIRR exists for (#1119); and a backtest archived into an active run merged with the previous one's artifacts, so a single report could describe two different backtests while /runs/{id} listed the leftovers as its own (#1094). Thanks @lorenzozanee, @straun-repo, and @pengpengyi92!

  • 2026-08-16 🔧 Anthropic runs no longer die on recovery, and symbol search stops reporting empty results as healthy: Recovery paths appended mid-conversation system messages that the Anthropic API rejects, killing the run — recovery steering now travels as user messages with inline `` tags (#1112, closes #1109). search_symbol returned zero candidates with both sources reporting ok for ticker+name queries, so identity never locked and every data tool refused; the Yahoo path now reports such queries skipped instead of a misleading ok (#1114, closes #1108). Also: LANGCHAIN_REASONING_EFFORT is now honored on the Anthropic branch through a model allowlist (#1115); the Tencent loader recovers from CERTIFICATE_VERIFY_FAILED via the certifi CA bundle (#1113); the revenue - cogs gross-profit fallback is no longer dead code (#1111); and swarm workers use the shared truncation helper, so sub-agents always see the cut notice (#1110). Thanks @lorenzozanee, @straun-repo, @x-lambda, @cgycorey, and @Shizoqua!

  • 2026-08-15 🛡️ Safer desktop updates, reliable Windows packaging, and factor research in Run Detail: The dormant updater boundary now retains owned-process evidence for cleanup retries, probes TCP listeners instead of HTTP health, reserves recovery journals atomically, binds Authenticode and hashes to the same staged bytes, and rechecks immediately before launch (#1101). Windows packaging now owns bounded, checksum-verified Electron downloads and extracts the pinned GTK asset as data through 7-Zip instead of executing its flaky legacy installer; native Windows CI covers exit codes, timeouts, runtime assembly, NSIS, and packaged startup (#1104, closes #1093). Run Detail gains IC series and statistics, quantile equity, and IC correlation with bounded artifact traversal and finite JSON payloads (#1099, closes #1100); universal hash locks are verified natively on Linux, macOS ARM64, and Windows (#1102, closes #1089). Thanks @QCYTSN and @shadowinlife!

  • 2026-08-14 ⚙️ A reasoning setting that did nothing, and runs that stopped while they could still recover: LANGCHAIN_REASONING_EFFORT was silently a no-op for almost every provider — only direct OpenAI ever received it, so setting high on DeepSeek changed nothing and said so nowhere. Effort now reaches both transports through each adapter's own field: Chat Completions by default, the Responses API when LANGCHAIN_USE_RESPONSES_API=true. The providers given a top-level reasoning_effort are a verified allowlist rather than everything that speaks the OpenAI wire format — an endpoint that validates its request body strictly rejects an unknown key and fails the call, so the cost of guessing wrong is every request, not a missing setting (#1025). The grounding gate also stops handing back "confirm and continue" while a deterministic read-only recovery is still available: an unresolved instrument now drives search_symbol → get_market_data on its own bounded budget instead of spending the run's iterations and failing closed (#1092, closes #1081). New: an Options Lab page — multi-leg payoff diagram, spot × IV scenario matrix, portfolio Greeks and a live chain, computed by the existing payoff tool and quantlib rather than a second implementation of the math (#1096); a backtest tearsheet tab with a monthly-returns heatmap, annual returns and top-N drawdown episodes (#1091); tickerall as the 25th market-data source — hosted MetaTrader 5 forex/metals bars with no local terminal on any OS, explicit-only so a broker key is never a silent fallback target, and a truncated history window is an error rather than a quietly short series (#968, closes #897); and Novita AI plus GitHub Copilot as built-in providers (#1059, #990). eToro gains asset-class browsing by instrument type, and copy trading now refuses a demo account with a stated reason instead of failing obscurely (#1070). Thanks @cgycorey, @Shizoqua, @shadowinlife, @miguelangelo78, @jax-novita, @sykuang, and @ofeksh-tr.

  • 2026-08-13 🎯 Backtest reports show the book that actually filled: positions.csv held the optimiser's target weights, so a report could claim 80% exposure while lot rounding, fees, or a blocked order left the portfolio near 20% — and those targets also fed the invested-weight metrics and the risk x-ray. Fills now go to positions.csv, requests to target_positions.csv (#1082). Run Detail gains a research dashboard at ?view=dashboard (#1084), and Spanish is the sixth UI language (#1087). Also: get_research_reports was returning HTTP 400 for every A-share symbol (#1077); IBKR quotes separate the tier requested from the one applied (#1075); .env.partial is written atomically (#1086); the Docker workflow pins actions to commits and hash-locks channel SDKs (#1088); and the grounding gate stops reading support/resistance ladders and all-time highs as observed prices (#1060). Thanks @AndyLongest, @daviddaco1, @zzz607, @jay79-boop, @lukiod, @birdxs, and @wiliao.

  • 2026-08-12 📏 A-share volume no longer jumps 100× when the fallback source changes: Five sources in the A-share fallback chain reported board lots while BaoStock reported shares, and because the serving provenance carried no unit, a fallback could silently rescale every volume-based signal. Loaders now declare volume units per market, provenance exposes the unit of the source that actually served each symbol, BaoStock converts shares to board lots at the loader boundary, cache v4 prevents pre-fix entries from resurfacing, and a live-data cross-source regression requires settled-day values to agree within 1% (#1065, #1067, closes #1062). The ten-PR correctness pass also gives eToro complete runtime status and a five-locale SDK-connected UI (#1051); makes scheduled-run DELETE return a truly empty 204 (#1068); renders Alpaca's direct-SDK account payload in the CLI (#1073); normalizes Ollama roots to /v1 at the credential boundary used by the real model constructor (#1074); turns Docker Codex OAuth stdin EOF into actionable TTY guidance (#1054, closes #1050); stops Markdown ordered-list markers such as 1. from becoming unsupported numeric claims (#1063); makes two-character memory queries such as GE behave the same with or without FTS5 (#1071); and prices zero-volatility European options from discounted forward intrinsic value, restoring exercise-side logic and put-call parity (#1066). Thanks @shadowinlife, @ofeksh-tr, @zhiwuyazhe-fjr, @zzz607, @pengpengyi92, and @Shizoqua.

  • 2026-08-11 🧠 Compaction stops dropping conversation content, and a swarm retry can no longer delete its own run: Auto-compaction sliced the serialized history at a hard 80,000 characters before summarizing, so anything past that cut reached neither the summary call nor the preserved tail — it vanished with no error raised, against the function's own "zero info decay" guarantee, and the slice landed mid-object so the summarizer was handed invalid JSON. History is now packed on message boundaries and folded chunk by chunk through the existing iterative template; a single message too large for one chunk becomes labelled fragments instead of a truncation, and an empty model reply no longer wipes the summary accumulated so far (closes #1055). The new retry-time artifact cleanup ran shutil.rmtree on run_dir/artifacts/, where agent_id arrives unvalidated from a preset and user presets load from ~/.vibe-trading/swarm/presets/, so an id of .. resolved to the run directory itself — the path is now refused unless it is one safe segment resolving inside that run's artifacts directory. Plus technical_indicators RSI moving to the Wilder-EWM convention its own docstring already claimed, where a plain rolling mean can shift a reading across the 30/70 boundary (#1056); excess_return re-derived from the corrected benchmark total so the two fields stop contradicting each other inside one metrics dict (#1058); swarm deliverable validation rejecting ok/success-keyed raw tool envelopes passed off as analysis (#1052); a retried worker no longer inheriting the failed attempt's report.md (#1053); and worker prompts ordered so the agent-invariant blocks form one cache-eligible prefix (#1057). Thanks @Shizoqua and @Echoandelementwebsites.

  • 2026-08-10 🚀 v0.1.13 released (Release notes, pip install -U vibe-trading-ai): 408 commits and 162 merged pull requests since 0.1.12 — the largest release so far. The headline is a fix, not a feature: the identity gate stops refusing answers it already had the evidence for. A well-formed question would spend minutes on real tool calls and then return "cannot safely confirm instrument identity or price evidence". The causes: .SS and .SH were treated as different instruments, so every Shanghai ticker was permanently ambiguous; a failed side query could demote an already-locked identity; Yahoo's HTTP 400 on every CJK query was recorded as a source failure instead of "not listed here"; a hardcoded per-tool whitelist blocked 11 of the 17 documented argument spellings; Chinese answers were rejected for writing 雅虎 or 元 rather than the ASCII loader name; and a thousands separator split ¥1,309.22 so 1 was compared against the observed range. Conceptual questions and comparison reports no longer dead-end either. A quote outside recorded OHLC evidence is still refused. New: src/quantlib — 249 tested functions across 17 modules (options, bonds, credit, econometrics, VaR/CVaR/EVT, attribution, event studies, purged CV) reachable from the CLI, Web UI, REST API and MCP through the read-only quantlib_call, so skills import finance math instead of carrying formulas in markdown; a valuation engine (run_dcf / run_comps / three-statement) whose one rule is that a missing input makes a model NOT RUNNABLE rather than silently defaulted; an entity + irregular cash-flow spine (XIRR / MOIC / DPI / TVPI, TWR / Modified Dietz via cashflow_performance) kept deliberately parallel to the bar engines; governance in every run — a hash manifest over prompt, skills, tool registry and package versions, plus a hash-chained fsynced audit ledger where even a self-rehashed edit is caught one record later; four read-only data tools on free public sources (SEC 13F with quarter-over-quarter diffs, ETF look-through where a CSI-300 tracker resolves to 342 positions covering 98.66% of net assets instead of the quarterly top ten, prediction markets as labelled implied probability, and arXiv/OpenAlex with source-anchored claims); six institutional commands (/comps /dcf /attrib /memo /earnings /screen); investor lenses as a standalone skill; five scheduled-research playbooks; a desktop Electron shell with checksum-pinned Windows packaging and safeStorage; eToro as the 13th broker connector; Korea (KRX) as the 9th backtest engine; an OpenBB Workspace bridge; Canadian equities end to end; and sentiment, technical_indicators, options_payoff, orderbook_depth, ModelScope and vibe-trading update. Correctness: SEC periods are keyed on their (start, end) span — annual figures had been returning a single quarter, a 4.2× understatement; Tushare A-share prices are corporate-action adjusted, where a raw return across an ex-date was off by up to 47 percentage points; bar_returns no longer records a trading halt as a 0% move; annualisation covers all 24 data sources; a sandbox gap is closed where generated code could import the broker layer or reach socket/subprocess through a renamed binding; and mixed-currency composite backtests are refused instead of summed into one equity curve. Thanks @santhreal, @shadowinlife, @Robin1987China, @he-yufeng, @QCYTSN, @Shizoqua, @honginp, @cgycorey, @wiliao, @ngoanpv, @x-lambda, @ofeksh-tr, @00EVA, @zwrong, @yrk111222, @su322, @hhj123123, @dineeshd, @sambazhu, @ddy4633, @tyj147454413-cmd, @y85998607, @JungHoonGhae, @shugaoye, @TSENGCHIENFENG, @darkknight4563, @MuggleJinx, @klmtseng, @ebujinovch, @g0rdonL, @AmirF194, @Echoandelementwebsites, @yagnikpipaliya, @dvirarad and @1anter.

  • 2026-08-09 🪟 Secure Windows packaging, Canada markets, ModelScope, and Alpha Zoo over MCP: Windows desktop packaging now assembles a checksum-pinned embedded Python 3.12 runtime and x64 NSIS review/signing paths, plus Electron safeStorage for an allowlisted credential set. The renderer can set or clear secrets but never read them; plaintext configuration migrates once; decrypted values reach only the owned backend; and both unsigned review and signed builds fail closed on the wrong signature state. No installer artifac