1
About HKUDS/Vibe-Trading
HKUDS/Vibe-Trading is an open-source project on GitHub, mainly written in Python. "Vibe-Trading: Your Personal Trading Agent" It currently holds 33,523 stars and 0 forks with 0 open issues, and was last pushed on an unknown date (repository created unknown).
Project Overview
AI Homed tracks it on the AI Models & LLM Tools board.
GitHub Repository Details
README
English | 中文 | 日本語 | 한국어 | العربية | Español
Vibe-Trading: Your Personal Trading Agent
One Command to Empower Your Agent with Comprehensive Trading Capabilities
Website · Docs · News · Features · Shadow Account · Demo · Quick Start · Examples · API / MCP · Roadmap · Contributing
---
📰 News
⚠️ Security warning: The X accountVibeTrading_HKU, Virtuals project101845, and token contract0x640BDBF77b6447E8b7DB7894cED84BD1c40571f4are 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-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
figuresblock 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 reachesChinaAEnginefrom every source (#1431). Separately, the swarm worker overwrote every tool call'srun_dirwith the agent workspace, so for the tools that declare it —backtestabove all — the model could pass any directory and read none of it, while the error named no path. A declaredrun_diris 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 astructured_metricsblock, 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!
Earlier news
- 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
Dividenderow, 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,608is 1386.608, a US-ordered1,234.56is refused rather than read a thousandfold off, and a value the eight-decimal wire format cannot hold is refused rather than rounded —0,000000004shares 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 assource_mtimeand 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
fqklineendpoint serves the last 500 bars of a window, not the first — a CSI 300 request for2018-01-01..2026-06-30returns2024-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_evidencerejected every run produced by thebacktesttool, because only the agent runtime wrote thestate.jsonits 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_unresolvedfor 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'sskills:list, documented as its allowlist, is now enforced byload_skillinstead 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.jsonand the rest — were missing from.gitignorethough its comment claimed them, so anyone whoseVIBE_TRADING_HOMEis the checkout was onegit add -Aaway 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 buildsMARKET_DATA_ORDER_and the config layer passes it to a bareos.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 throughderived_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.replacecopies every field the call does not name, so the child came outUNVALIDATEDwhile still carrying the parent'svalidatorandapprover— an independent sign-off worn by something that never earned it — along with anartifact_versionand amodel_versionfor code no model had generated yet. And the parent-evidence gate was reachable only from tests:register_adaptationnever 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 annp.wherecomparison never sees a NaN — the comparison isFalse— so blanking every declared input on one bar left 84 of 462 alphas returning a number anyway, each consumed as a real signal becausedropna()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 declaredmin_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 defaultspct_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: thefuturesloader chain namedtushareandakshare, 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 reacheslocalinstead 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 reportsunknownrather 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.NYMEXmatched 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). Thepct_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 emitsNOT_EVALUABLErather 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.wherecomparison never sees a NaN — the comparison isFalse, 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 sincedropna()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 declaredmin_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, withfundamental_subdaily="next_day"as the explicit opt-in (closes #1387). A metric claim formatted as a generic| Metric | Value |table es
GitHub Stars & Activity
33,523Stars
0Forks
0Open issues
PythonLanguage
GitHub Popularity
GitHub stars33,523
Forks0
Open issues0
Primary languagePython
License-
Stars gained today0
Created-
Last pushed-
Trending History
Trending statusnot on today's boards
Related AI Projects
2
3
4
5
6
7
8