Audits › HKUDS/Vibe-Trading
Open-source trading bot · audit
HKUDS/Vibe-Trading
"Vibe-Trading: Your Personal Trading Agent"
Repository facts
- Repository
- HKUDS/Vibe-Trading
- Stars
- 33,596
- Forks
- 5,481
- Open issues
- 25
- Language
- Python
- License
- MIT
- Created
- 2026-04-01
- Last push
- 2026-09-17
- README names exchanges
- binance, okx, robinhood, alpaca, ccxt
- README mentions an LLM
- yes
- Backtesting mentioned
- yes
- Paper trading / dry run mentioned
- yes
Source: GitHub API, 2026-09-17. Exchange and LLM mentions come from a keyword scan of the README, not from running the bot.
Risk-control audit
Audited 2026-09-17 · main @ tree
21 of 21 controls checked: 8 present, 4 partial, 0 absent, 0 not applicable, 9 not verified.
- Main risk
- There is no automatic circuit breaker: per-order and per-account caps are enforced on every trade, but nothing in the code found so far halts the bot automatically after a daily loss, a drawdown, or a string of failed/rejected orders — only a human-triggered kill switch exists.
- Summary
- Vibe-Trading is an AI agent that connects to 18 real brokers (Robinhood, IBKR, Binance, etc.) and can place live orders for the user. It has an unusually strong pre-trade gate: every order is checked against per-order size, total exposure, and leverage caps before it reaches the broker, the AI's own risk opinion can never override those hard limits, and every action is written to a tamper-evident, fsynced audit log. What could not be confirmed within this audit's time budget is any AUTOMATIC stop triggered by mounting losses (the only kill switch found is manual), live position reconciliation at startup, stop-loss persistence, and the authorization logic behind Telegram remote control.
| Control | Verdict | Evidence | Note |
|---|---|---|---|
| Size and exposure | |||
| Maximum order size | Present | raw.githubusercontent.com/HKUDS/Vibe-Trading/main/agent/src/live/enforcement.py check_mandate() step 4 'Single-order notional' compares against caps.max_order_notional_usd; agent/src/live/order_guard.py _normalize_intent_notional() enforces MAX(explicit notional, quantity*live_price) before the cap check | Unit is USD notional; a quantity-only order is priced via a live quote and fail-closed DENIED if no quote is obtainable. |
| Execution paths that skip the cap | Present | agent/src/live/registry.py wrap_live_broker_tools(): every WRITE or UNKNOWN tool across all 18 broker connectors is re-wrapped in LiveOrderGuardTool; unclassified ops default to UNKNOWN->WRITE (fail-closed); only READ tools bypass the gate | A parallel 'direct-SDK gate' (agent/src/live/sdk_order_gate.py, 43KB) exists for non-MCP connectors; referenced as sharing the same notional rule in order_guard.py comments, but its full content was not read line-by-line (budget). |
| Total exposure and leverage | Present | agent/src/live/enforcement.py check_mandate() steps 5-6 check max_total_exposure_usd (post-trade gross exposure) and max_leverage; fields defined in agent/src/live/mandate/model.py HardCaps | Exposure math is fail-closed on any unparseable position row. |
| Brakes and stops | |||
| Global circuit breaker | Partial | agent/src/live/halt.py: global/per-broker filesystem sentinel HALT, checked via halt_flag_set() before every order (fail-closed). GET /search/code?q=drawdown+repo:HKUDS/Vibe-Trading and q=max_daily_loss+repo:HKUDS/Vibe-Trading both returned total_count:0 | The kill switch is MANUAL only (tripped by CLI/frontend/file touch via trip_halt(by=...)). No automatic trigger on daily loss, drawdown, or consecutive failures was found. |
| Orphaned stop-loss | Not verified | agent/src/live/mandate/model.py has no stop-loss field of any kind in HardCaps/Mandate | The system is a limits gate (notional/exposure/leverage), not a stop-loss manager. Any stop order the LLM chooses to place would be forwarded to the real broker and live on the broker's own book (not in-process memory), but no dedicated tracking/management subsystem was found to confirm this with code evidence. |
| Orderly shutdown | Partial | agent/src/live/halt.py register_halt_action()/on_halt_action(): a registered callable (in production src.live.runtime.flatten.flatten_and_cancel) cancels resting orders and optionally flattens positions (mandate.flatten_on_halt) when a halt trip is observed | This fires only when the HALT sentinel is observed, not confirmed to also fire on a normal process stop (SIGINT/Ctrl-C/SIGTERM). No signal.signal handler wiring this cleanup was found. |
| Connection and operation | |||
| Websocket and data reconnection | Not verified | agent/src/market_data.py implements a multi-source REST fallback chain with bounded retries (max_fallback_attempts=5) for market data | No dedicated websocket module with explicit HTTP 429 backoff handling was located within budget; architecture may be pull/REST-based rather than streaming. |
| Duplicate-process lock | Partial | agent/src/live/daily_count.py daily_order_lock(): cross-process advisory lock (fcntl on POSIX / msvcrt on Windows) per broker, wrapping the order-submission critical section; raises DailyOrderLockUnavailable if contended | Prevents concurrent order submission for the same broker from two processes, but is scoped to the order critical section, not a whole-process single-instance lock. |
| Heartbeat and alerts | Not verified | agent/src/live/audit.py fans out a 'live.action' SSE event on every order decision; agent/src/channels/ has Telegram/Discord/DingTalk messaging channels | No explicit heartbeat/health-check endpoint or 'bot is down' alert was confirmed within budget. |
| Accounting and reconciliation | |||
| Position reconciliation with the exchange | Not verified | agent/backtest/binance_account_reconciliation.py exists but lives under agent/backtest/ (shadow-account/backtest verification), not under agent/src/live/ | Did not find a live position-vs-broker reconciliation routine run at startup within budget. |
| Fees and funding in the accounting | Not verified | agent/src/live/enforcement.py exposure math uses raw market_value from broker position rows; agent/backtest/factor_costs.py models fees but is backtest-only | Not confirmed whether the live gate deducts fees/funding when sizing/valuing exposure. |
| Order rejection handling | Present | agent/src/live/order_guard.py _allow(): inspects the broker response envelope; an error envelope is audited as kind='order_rejected'/outcome='error' and does NOT increment the daily counter; class attribute 'repeatable = False' documented as 'a live order must never be silently re-issued' | No automatic retry on rejection; explicit no-retry design avoids exposure multiplication. |
| Auditable log | Present | agent/src/live/audit.py: append-only audit.jsonl (fsynced every write) plus a hash-chained tamper-evident copy audit_chain.jsonl via src/governance/ledger.py; secrets redacted via src.tools.redaction.redact_payload before any write | Also fans out to per-run trace and SSE bus. |
| Security | |||
| API key permissions | Partial | agent/src/trading/onboarding.py: explicit setup_hint text for several connectors, e.g. Binance 'Create a read-only Spot API key; do not enable withdrawals', OKX 'do not grant Trade or Withdraw permissions', Upbit 'do not grant withdrawal permission'. GET /search/code?q=withdraw+repo:HKUDS/Vibe-Trading+language:Python returned 10 hits, none inspected as an actual withdrawal API call | Least-privilege credentials are documented policy for the connectors checked, but not exhaustively verified across all 18 connectors that the code itself never calls a withdraw/transfer endpoint. |
| Secrets handling | Present | agent/src/trading/onboarding.py to_dict(): "secret_storage": "os_keyring" if self.credential_fields else None; agent/.env.example is a checked-in template of variable names, not real secret values | Credentials are declared to be stored via the OS keyring, not in code or plain config files. |
| Authenticated remote control | Not verified | agent/src/channels/telegram.py (69.7KB) — only the markdown/HTML rendering header section was read | Did not reach the chat_id/user authorization section within budget. GET /search/code?q=allowed_user_ids+repo:HKUDS/Vibe-Trading returned 0 hits (may use a different variable name). |
| AI and learning | |||
| The model cannot override the brakes | Present | agent/src/live/advisory/__init__.py docstring: 'Advisory verdicts are purely observational: they never block, deny, or alter order execution. The mandate gate (check_mandate) remains the sole authority for order allow/deny decisions.' | Confirmed in order_guard.py: the advisory verdict is attached only as metadata after check_mandate has already allowed the order. |
| Model output validation | Present | agent/src/live/order_guard.py execute(): extractor() returning None denies with 'order intent could not be parsed'; _normalize_intent_notional rejects NaN/non-positive notional fail-closed; enforcement.py check_mandate validates symbol/side/instrument_type/asset_class against whitelists before any order is forwarded | Structural validation happens before any broker call. |
| Learns from its mistakes | Not verified | Directories agent/src/hypotheses/, agent/src/strategy_discovery/, agent/src/strategy_store/ exist | Names suggest a strategy hypothesis/self-correction subsystem but contents were not opened within budget; cannot confirm whether self-revisions pass through backtest/review before going live. |
| Model poisoning | Not verified | agent/src/scheduled_research/ and agent/src/agent/grounding/ directories exist | Not reviewed within budget. |
| Behavior without model quota or response | Not verified | Not located within budget | No file specifically examined for LLM quota/cost-cap handling. |
Audit A009: HKUDS/Vibe-Trading — risk controls (plain-language summary)
**What it is.** Vibe-Trading is an open-source AI trading agent (33.6k GitHub stars, MIT license, Python) that lets an LLM act on the user's behalf and place real orders through 18 broker connectors, including Robinhood, Interactive Brokers, Binance, OKX, Alpaca, MetaTrader5 and more.
**Audited:** `main` branch, tree `1b888f8c3fff8623ef227a66191e037aa31670b0`, last pushed 2026-09-17 13:49 UTC. Audit date: 2026-09-17.
**What is unusually strong.** Every order-placing tool call from the AI, across all 18 brokers, is forced through a single "mandate gate" before it ever reaches a broker: it checks a per-order dollar cap, a total-portfolio exposure cap, and a leverage cap, and it fails closed (denies) on any unparseable data. A quantity-only order is priced against a live quote before the cap check, closing an obvious loophole. The AI can also get a second, "advisory" opinion on a trade, but that opinion is explicitly documented as observational only — it can never override or bypass the hard caps. Every order attempt, accepted or rejected, is written to an append-only, cryptographically hash-chained audit log that is fsynced to disk immediately, so the record survives a crash and cannot be silently edited after the fact.
**What is missing or unverified.** The kill switch that halts all trading is manual only — a human (or an external script) has to trip it by touching a file or using the CLI/frontend. No automatic circuit breaker was found that halts the bot after a daily loss, a drawdown, or a run of failed orders; targeted code searches for "drawdown" and "max_daily_loss" both returned zero results in the whole repository. Given the size of this project (70,000+ files, dozens of broker-specific modules), several checklist points could not be confirmed within this audit's budget and are marked "not verified" rather than guessed: whether stop-loss orders persist safely if the bot restarts, whether positions are reconciled against the broker at startup, whether trading fees are deducted from exposure math, and the exact authorization logic behind the Telegram remote-control channel.
**Main risk.** The safety net is per-trade and per-account, not per-day: an AI agent that starts making one bad (but individually-compliant) trade after another has nothing automatic stopping it before a human notices and manually halts it.
Full point-by-point results with file/line evidence: see `auditoria.json` in this folder.
Badge for the README
<a href="https://saasfactoryagents.com/bots/hkuds-vibe-trading/"><img src="https://saasfactoryagents.com/bots/hkuds-vibe-trading/badge.svg" alt="risk controls audit: 8/21 present"></a>
Fixed a control? Request a free re-audit at the new commit.
Exchanges
- Does Vibe-Trading work with Binance.US?
- Does Vibe-Trading work with Coinbase?
- Does Vibe-Trading work with Kraken?
- Does Vibe-Trading work with Robinhood Crypto?
Also named in the README: binance, okx, alpaca, ccxt.
Running Vibe-Trading with real money?
The watchdog runs apart from the bot with a read-only key and alerts you when drawdown, position size or heartbeat cross your limits. Founding price 19 USD/month, early access open.