Audits › Controls › Execution paths that skip the cap
Size and exposure · control 2 of 21
Execution paths that skip the cap: does your trading bot have it?
Do all order-sending paths go through the same risk check, or are there shortcuts such as rebalance, emergency close, batch or a newer strategy that bypass it?
Why it matters
A second execution path without the check is how CloddsBot issue #127 happened: the fix covered one path and the next feature added another.
How to check it in the code
- List every function that calls the exchange's create-order endpoint.
- For each one, trace back whether it passes through the same validator as the main path.
- Look at recent pull requests: new adapters and fallbacks are where the bypasses appear.
This is what the audit does for every bot in the list, on public code, without installing or running anything. Verdict values: present, partial, absent, not applicable, not verified. See the method.
Results across audited bots
Across 10 audited bots: 2 present, 4 partial, 3 absent, 0 not applicable, 1 not verified.
| Bot | Verdict | Evidence | Note |
|---|---|---|---|
| HKUDS/Vibe-Trading | 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). |
| hummingbot/hummingbot | Not verified | Would require checking every legacy strategy under hummingbot/strategy/, every V2 controller under hummingbot/strategy_v2/, and every script under scripts/ to confirm each one calls BudgetChecker/OrderCandidate before sending an order. | Not verifiable in this session: repo is 566MB / hundreds of files and GitHub code search is capped at 10 requests/minute, insufficient to cover that full surface with the session budget. |
| Drakkar-Software/OctoBot | Absent | No unified/deterministic order-size-cap module was found that all trading modes route through; each Trading/Mode tentacle (ai_trading_mode, index_trading_mode, grid_trading_mode, dca_trading_mode, etc.) computes and submits its own order sizes independently (packages/tentacles/Trading/Mode/ directory listing). | Since no tope_orden exists centrally, there is structurally no single choke point all routes pass through; a new trading mode/tentacle is free to size orders however it wants. |
| freqtrade/freqtrade | Partial | docs/configuration.md, key 'max_entry_position_adjustment' -- same URL as above | Normal entries always size from stake_amount, but the DCA/position-adjustment route (adjust_trade_position callback) is bounded by a separate parameter, not by the same stake cap, so it is a distinct control rather than a shared one. |
| jesse-ai/jesse | Partial | jesse/services/broker.py routes market/limit/stop/reduce orders all through self.api -> jesse/services/api.py -> the exchange driver, so in backtest every route hits the same on_order_submission check; jesse/exchanges/sandbox/Sandbox.py confirms the simulated driver has one entry point (order_service.create_order) | Single code path in backtest/paper is consistent, but since the check itself is disabled in live mode (see tope_orden), the question of 'which live routes skip it' cannot be answered from this repo. |
| chrisleekr/binance-trading-bot | Partial | apps/api/src/lib/order-feasibility.ts (dispatches via the shared AnyStrategy contract's checkOrderFeasibility); GET /search/code filename:feasibility.ts repo-wide returns only 2 files (the generic dispatcher + trailing-trade's implementation) | Trailing-trade's cap is confirmed. Did not verify within session budget whether the momentum and rebalance strategy packages implement the same checkOrderFeasibility contract member with an equivalent budget cap, or route through it at all. |
| alsk1992/CloddsBot | Partial | src/trading/orchestrator.ts explicitly wraps buyLimit/sellLimit/marketBuy/marketSell/makerBuy/makerSell/protectedBuy/protectedSell/placeOrdersBatch with preTradeCheck() (kill switch + safety.validateTrade + breaker). BUT issue #126 (OPEN) lists Drift, Pump.fun and Meteora agent handlers (src/agents/handlers/solana.ts#L1123,#L1188,#L352) and the bundled /bf skill (src/skills/bundled/binance-futures/index.ts#L194) as order paths that reach submission without the breaker or maxOrderSize. Issue #127 (OPEN) confirms a direct Opinion-exchange fallback in src/agents/index.ts (~L13225-13233) that consults only env DRY_RUN, with no breaker/size check. https://github.com/alsk1992/CloddsBot/issues/126 , https://github.com/alsk1992/CloddsBot/issues/127 | One central, well-documented gate exists (orchestrator.ts), but confirmed sibling entry points bypass it at the audited commit. |
| Lumiwealth/lumibot | Absent | Same ENV_VARS.md entry: the only cap found is scoped to 'market BUY dollar amount' on one broker; no single control point shared by all order-submission paths (agent tools orders.submit, strategy.submit_order, all broker adapters) was found in the docs reviewed. | |
| YizhiSong/FriesTrader | Present | README.md 'How it works' + PHASE_B_TASK.md Step 7: every buy (new entry or top-up) is routed through the same three scripts -- entry_gate.py -> rank_candidates.py -> position_sizing.py. Full repo tree (git/trees/main, 15 files) has no second order-sizing path. | Sells (stop_loss/take_profit/conviction_trim/exit_existing) are explicitly exempt from this gate by design, since selling never increases exposure -- consistent with the spec, not a gap. |
| c9s/bbgo | Absent | pkg/risk/riskcontrol/position.go; pkg/bbgo/trader.go (generic OrderExecutor path has no built-in cap) | There is no central order gate all strategies pass through; any strategy that does not wire in PositionRiskControl sends orders with no size cap at all. |
If your bot does not have it
The watchdog enforces daily loss, drawdown, position size and heartbeat limits from outside the bot, with a read-only key, whatever the bot's own code does.