Skip to main content
Any unattended strategy should sit inside a heartbeat. If the process dies, the heartbeat expires and the server closes every open order on the account.

The shape

Choosing the timeout

The valid range is 10 to 300 seconds.
  • Short (10 to 30 s). Tight protection. A slow tick risks a self-inflicted closure. Refresh at T/3.
  • Long (120 to 300 s). Tolerant of hiccups. Leaves exposure open longer after a genuine crash.
Refresh on a timer independent of your trading loop. If refreshing is coupled to a loop that can block on a slow REST call, a stall expires the heartbeat and closes your book.

The code

On exit, close_all/ with a sport closes every open order on that sport in one call, with no paging. It also closes orders on that sport that other programs on the account placed. If several strategies share a sport, list the open orders page by page and close your own with close_many/. See Bulk close. Close betslips you stop quoting with DELETE /v2/betslips/{betslip_id}/; an account can hold only a limited number open.

Idempotency under retry

Always send a request_uuid. Under retry, a reused UUID returns the error code order_already_created with the existing order_id. Without one, a timeout followed by a retry can double-place. Persist the UUID before you send, so a crash between send and response is recoverable through GET /v2/orders/tracked/{uuid}/.

Rate limits

Order placement has its own budget of 5 requests per second. Betslip creation has its own budget of 10 requests per second and 2,000 betslips per rolling 24 hours. Every create counts, including a rejected one. A refresh does not count. The budget refills continuously, with no fixed reset. Both are per account, across all keys. A quoting loop that re-quotes every selection every tick will hit them. Re-quote only what moved. See Errors and rate limits.

Test first

Run the loop with a small stake before you leave it unattended. The Claude skill repository has a runnable single-order version with heartbeat protection, 03-market-making.py. It is dry-run by default.