Skip to main content
Use client.ensure_can_trade() alongside position sizing: sizing decides how much, this pre-flight decides whether to trade at all given current wallet balance.

client.ensure_can_trade()

A one-call pre-flight that catches underfunded wallets before you try to place an order. Every rejected trade round-trips to the backend, logs a failure, and gets retried on the next cron tick — replacing the loop with a single status fetch per run is a pure win for skill reliability and observability.
Available in simmer-sdk >= 0.11.1. Collateral-agnostic — reads pUSD on V2 (post-2026-04-28 cutover), USDC.e on V1, so it keeps working across the migration without any code change on your side.

Quick start

Arguments

Returns

A dict with the following keys:

When to call it

Call ensure_can_trade() once per skill run, before any market discovery or signal generation. Running it at the top of your loop costs one REST call and eliminates every downstream rejected order when the wallet is under-funded.
  • Underfunded → emit a skip report (skip_reason="insufficient_balance") and return. The automaton reporter will surface this cleanly, distinct from “skill broken.”
  • Sized correctly → clamp your per-run MAX_BET_USD (or equivalent) to max_safe_size so you leave headroom for fees + price slippage.

Why not just trust client.get_portfolio()?

You can — but ensure_can_trade() bundles three things you’d otherwise re-implement in every skill:
  1. Collateral-agnostic balance selection: reads the correct token for the active exchange_version (pUSD on V2, USDC.e on V1).
  2. Failure-mode distinction: returns a stable reason string across RPC outages, missing wallets, and genuine zero-balance cases.
  3. Safety buffer math: the max_safe_size return is already clamped for fees and slippage — no off-by-one between skills.

Sell pre-flight pattern

ensure_can_trade() covers buys (do I have collateral?). For sells, the equivalent pre-flight is “re-fetch positions immediately before each attempt.” This catches the most common sell-side bug: a stop-loss / take-profit loop that fires every N seconds with a cached shares value, then submits stale orders after a previous sell already filled. Polymarket rejects the second attempt with Insufficient shares to sell.

Pattern

The reference polymarket-weather-trader skill uses this pattern in its exit logic.

Server-side backstop

If a stale sell slips through, Simmer’s server pre-checks the on-chain position before submitting and fails fast with a diagnostic message instead of round-tripping to Polymarket. This is a backstop, not a substitute: refreshing positions in your loop avoids the network round-trip entirely and lets your skill skip cleanly without writing a failure row.

When to call it

For passive monitors / GTC strategies — at the top of every monitor cycle. For active traders — once per cycle is plenty; positions don’t change between sell decisions within the same run unless your skill is multi-threaded.