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.
ControlVerdictEvidenceNote
Size and exposure
Maximum order sizePresentraw.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 checkUnit 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 capPresentagent/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 gateA 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 leveragePresentagent/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 HardCapsExposure math is fail-closed on any unparseable position row.
Brakes and stops
Global circuit breakerPartialagent/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:0The 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-lossNot verifiedagent/src/live/mandate/model.py has no stop-loss field of any kind in HardCaps/MandateThe 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 shutdownPartialagent/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 observedThis 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 reconnectionNot verifiedagent/src/market_data.py implements a multi-source REST fallback chain with bounded retries (max_fallback_attempts=5) for market dataNo dedicated websocket module with explicit HTTP 429 backoff handling was located within budget; architecture may be pull/REST-based rather than streaming.
Duplicate-process lockPartialagent/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 contendedPrevents 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 alertsNot verifiedagent/src/live/audit.py fans out a 'live.action' SSE event on every order decision; agent/src/channels/ has Telegram/Discord/DingTalk messaging channelsNo explicit heartbeat/health-check endpoint or 'bot is down' alert was confirmed within budget.
Accounting and reconciliation
Position reconciliation with the exchangeNot verifiedagent/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 accountingNot verifiedagent/src/live/enforcement.py exposure math uses raw market_value from broker position rows; agent/backtest/factor_costs.py models fees but is backtest-onlyNot confirmed whether the live gate deducts fees/funding when sizing/valuing exposure.
Order rejection handlingPresentagent/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 logPresentagent/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 writeAlso fans out to per-run trace and SSE bus.
Security
API key permissionsPartialagent/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 callLeast-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 handlingPresentagent/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 valuesCredentials are declared to be stored via the OS keyring, not in code or plain config files.
Authenticated remote controlNot verifiedagent/src/channels/telegram.py (69.7KB) — only the markdown/HTML rendering header section was readDid 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 brakesPresentagent/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 validationPresentagent/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 forwardedStructural validation happens before any broker call.
Learns from its mistakesNot verifiedDirectories agent/src/hypotheses/, agent/src/strategy_discovery/, agent/src/strategy_store/ existNames 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 poisoningNot verifiedagent/src/scheduled_research/ and agent/src/agent/grounding/ directories existNot reviewed within budget.
Behavior without model quota or responseNot verifiedNot located within budgetNo 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

risk controls audit: 8/21 present

<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

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.