Fail-closed behaviour
If reTrade can’t answer, or its answer can’t be trusted, the order isn’t placed.
The 2.5-second rule
The SDK gives each decision 2.5 seconds in total. A timeout, a dropped connection, a 429 or any 5xx status, or an unreadable answer counts as no answer. Within that time it retries once, at once, with the same bytes and the same idempotency key, signed again, so reTrade can never decide one order twice. If there’s still no answer, the SDK blocks the order itself:
result.outcome # Outcome.BLOCK
result.placement # Placement.NOT_PLACED
result.reason # "unreachable"
result.deciding # None: no answer from reTrade decided this
result.local # True
result.claimable # Falseresult.outcome // "BLOCK"
result.placement // "not_placed"
result.reason // "unreachable"
result.deciding // null: no answer from reTrade decided this
result.local // true
result.claimable // falseIn enforce and test mode nothing is placed. In shadow mode the original order is placed, with reason shadow-unreachable. A local BLOCK is never evidence for an insurer.
Answers that fail a check
An answer with a bad signature, an unknown key, other request bytes, or order fields or a quantity that differ from your request is treated the same way, with reason unverified: nothing is placed and nothing is reported. See what the SDK checks.
At start-up
The client fetches the key list and the signed status when it starts, which also opens the connection early. If reTrade can’t be reached then, the client still starts and logs a warning, and every order fails closed until reTrade answers. Any other start-up failure is an error: a root key that didn’t sign the key list raises VerificationFailed, and a request reTrade refuses raises RequestRefused.
Errors are for your code
place raises only for your code to fix (InvalidInput, ConfigError, RequestRefused) or when your adapter fails to read the account. Each of these comes before your adapter’s submit is called, so nothing was placed. A RequestRefused is a 4xx other than 429: a request reTrade couldn’t accept, to fix rather than retry.
Exits-only
The one exception to fail-closed is exits-only, an account setting an admin turns on. It’s a loosening, so it takes effect 24 hours later, or at once during first setup, and the SDK reads it only from the signed status. While reTrade can’t be reached, it lets the SDK place a limit sell of shares the broker holds now, less sells already working and recent sells the broker may not show yet; no more than 10% below the last price; of no company on the won’t-sell list; within the per-order line of the last rules the SDK decided under (5,000 when those rules have none); with no stop known for the account or the agent.
Everything else is still blocked. Such a sell is a local ALLOW with reason exit; a refused one gives a reason starting exits-only:, such as exits-only:over-held. Exits-only never applies to an unverified answer, and a sell it places isn’t evidence for an insurer either.
Fail closed in your own code
- Route every order through
place. Keep no second path to the broker that skips it, such as a retry, a fallback or an error handler that calls the broker directly. - If the client can’t start, don’t start trading. Don’t catch the error and carry on without reTrade.
- Never send an order again when its
placementisunknown: the broker may have it. The decision keeps counting at reTrade until the account data shows the order or its absence. - Keep your clock in time (NTP). An answer more than 60 seconds from your clock is refused as
unverified. - Test it: point the SDK at an address where nothing listens and check that orders come back BLOCK
unreachablewith nothing placed. SKILL.md has the test, in both languages.
# Nothing listens on port 9, so every order must come back BLOCK "unreachable".
RETRADE_BASE_URL=http://127.0.0.1:9 python first_check.py