Skip to main content

Safety

Guards designed to keep an off-script command from doing damage. All of these are state that lives in the CLI, not the exchange.

GuardScopePersistence
SimulationAll write-ops on every accountPersistent (per CLI install)
FatfingerSingle-order size cap, per symbolPersistent
BudgetCumulative notional cap on new exposureCap persistent; spend per-session
WhitelistSymbols that survive close longs/shorts/allPersistent

Simulation

Aliases: sim, dry-run.

simulation # show status
simulation on # enable
simulation off # disable
simulation status # same as bare form
sim on
dry-run off

When ON, every write-op (place / cancel / close / move / bump) short-circuits at simulationGate(ctx) before any exchange call. Reads (positions, orders, margin, etc.) are unaffected.

Persisted to ~/.tealstreet/simulation.json. Source: SimulationCommand.ts.

Use simulation when porting a new alias or recipe. Confirm the chain prints the right intent before you flip simulation off.


Fatfinger

A per-symbol cap on individual order size, in contracts. Checked just before placeOrder on:

  • buy, sell
  • scale, swarm
  • chase
  • twap

Reduce-only orders are skipped — closing a position cannot blow it up.

FormEffect
fatfingerList all configured limits
fatfinger <contracts>Set on focused symbol
fatfinger 0.5 BTCUSDTSet on named symbol
unfatfinger <symbol>Remove for one symbol
unfatfinger allRemove every limit

Persisted to ~/.tealstreet/fatfingers.json. Source: FatfingerCommand.ts, TradingBaseCommand.ts:enforceFatfinger.


Budget

An opt-in, off-by-default cumulative cap (in USD notional) on exposure-increasing orders placed this session. Where fatfinger caps a single order, budget caps the running total — useful for a hard ceiling on how much you can open in a sitting.

budget # show the cap and how much is spent
budget $5000 # set a $5000 cap (also: budget 5000)
budget off # disable (also: budget 0)
budget reset # zero the spent accumulator, keep the cap
FormEffect
budgetShow cap + session spend
budget $5000Set the cap (USD)
budget offDisable
budget resetReset the spent accumulator

The cap persists across sessions (~/.tealstreet/budget.json); the spent total is per-session and resets on restart, on budget reset, and whenever you change the cap. Each exposure-increasing order (buy/sell/scale/swarm) charges its USD notional against the total and is blocked once spent + order > cap. Reduce-only / close / cancel never count — the budget gates new exposure, not exits. Known limitation: twap / chase task-spawners are not yet budget-counted (their slices fire in a worker outside the command's state).

Persisted to ~/.tealstreet/budget.json. Source: BudgetCommand.ts, TradingBaseCommand.ts:enforceBudget.


Whitelist

Symbols you don't want a global "close all" to touch. Applies to:

  • close longs
  • close shorts
  • close allpos / close all

Per-symbol close calls (close BTCUSDT, close long) ignore the whitelist — the guard is only for the global variants.

FormEffect
whitelistList
whitelist BTCUSDTAdd (uppercased before store)
unwhitelist BTCUSDTRemove
unwhitelist allRemove every entry

Persisted to ~/.tealstreet/whitelist.json. Source: WhitelistCommand.ts.


Combining guards

These layer. Simulation short-circuits before fatfinger checks; fatfinger fires before the exchange call.

simulation on
buy 99999 BTCUSDT # blocked by simulation — no fatfinger needed

simulation off
fatfinger 0.5 BTCUSDT
buy $5000000 BTCUSDT # blocked by fatfinger

whitelist BTCUSDT
close longs # touches every long except BTCUSDT

Symbol resolution fails closed

buy / sell reject an explicit symbol token that doesn't resolve to a market on the connected exchange instead of silently routing the order to the focused symbol:

buy $100 XBTUSD # error: Unknown symbol "XBTUSD" (on an exchange with no XBTUSD)
buy $100 # OK — no symbol given, uses the focused symbol
buy $100 BTCUSDT # OK — explicit, resolvable symbol

This catches typos like trading the wrong contract on a multi-variant exchange (e.g. XBTUSD vs XBTUSDT). Omitting the symbol entirely still falls back to the focused symbol by design. Source: BaseBuySellCommand.ts.


Venue rules the CLI refuses to break

Beyond the guards you configure, some orders are refused because the venue cannot accept them. These fire before anything reaches the exchange, so you get a named error rather than a venue rejection:

buy 0.0004 BTCUSDT # error: order size 0.0004 rounds to 0 for 'BTCUSDT' — below the venue lot step
stop 58000 # on Paradex: 'paradex' does not support Full (Infinity) TP/SL orders

A bare stop <price> with no size means "cover the whole position", which is sent as a zero-size stop. Most venues read that as a Full stop; twelve do not — Weex, Backpack, Crypto.com, Bitrue, GRVT, Apex Omni, Coinbase, Kraken, Kraken Spot, Paradex, Polymarket and Lighter. Give the stop an explicit size there.

An order for a symbol whose market has not loaded yet is also refused rather than sent unrounded. On a global close, that refusal is per position — one symbol that is not ready does not stop the rest of the sweep.

See Sizing and prices for the rounding itself.


Degraded-connection lock

When an account's private data stream goes stale (the connection was up and has lost its heartbeat), commands that open or increase exposure are blocked — your position/order snapshot can't be trusted, so firing new orders blindly is unsafe:

buy $100 # error: connection degraded — refusing to open exposure
scale buy $1000 into 10 # blocked
twap buy $500 into 5 over 30 # blocked (won't start the task)

buy $100 reduce # OK — reduce-only reduces risk
close BTCUSDT # OK
cancel # OK
nuke # OK

Risk-reducing actions (close, cancel, nuke, and any reduce-only order) stay allowed so a degraded connection can never trap you in a position you can't exit. The lock fails open — if the private stream was never up or the exchange doesn't report health, it doesn't block. Run health to see connection status. Source: BaseCommand.healthGate.