ALLOW, CUT and BLOCK
Every order gets one of three answers, in the same request. What each one means, and what your code does with it.
The three answers
| Answer | What it means | What the SDK does | What your code does |
|---|---|---|---|
| ALLOW | The order fits every rule. | Places it as sent, once. | Keep the decision id with your order record. |
| CUT | It fits only at a smaller quantity. | Places the smaller quantity reTrade approved. | Treat quantity as what was placed. Don’t send the rest another way. |
| BLOCK | It breaks a rule, or no room is left. | Places nothing. | Don’t send it another way. Resize to fits when it’s set, re-plan or ask your user. |
Nothing waits for a person. There are no holds and no approval step. An order that once would have waited for someone comes straight back to your agent as a BLOCK, with a reason code, and the agent decides what to do next.
The rule that decided
A CUT or BLOCK names the rule that decided it in deciding, exactly as reTrade sent it: {"code": "order_size_cap"}, for example, or {"code": "approval_line", "reason": "per_order"} for a dollar line. An ALLOW has none. Reason codes lists every code and what the agent can do.
Resizing to fits
Over a dollar line or in an agent conflict, a BLOCK also carries fits: the largest quantity that would pass, or 0 when none would. Your agent can send the order again at fits. That’s a new decision, checked in full, and it counts toward the agent’s orders-per-minute limit (runaway_throttle), as the BLOCK before it did. Resend once; don’t loop.
from dataclasses import replace
from retrade import Outcome, Placement
if (result.outcome is Outcome.BLOCK and result.fits
and result.placement is Placement.NOT_PLACED):
result = rt.place(replace(order, quantity=result.fits),
account="A1", agent="agt_momentum", via=broker)const resizable = result.outcome === "BLOCK" && result.placement === "not_placed"
&& result.fits !== null && result.fits !== "0";
if (resizable) {
result = await rt.place({ ...order, quantity: Number(result.fits) }, {
account: "A1", agent: "agt_momentum", via: broker,
});
}Check placement first, as here: in shadow mode the original order was already placed.
When the SDK decides itself
Sometimes the SDK has no answer it can trust: reTrade didn’t answer within 2.5 seconds (unreachable), or the answer failed a check (unverified). Then the SDK decides on its own: local is true, reason says why, and deciding is empty. In enforce and test mode that’s a BLOCK, and nothing is placed. A local result is never evidence for an insurer.
The SDK also says why in reason when it doesn’t place an approved order, such as expired or broker-rejected. Reason codes lists them all.
How long an answer lasts
An ALLOW or CUT lives 30 seconds by default (an admin can set 5 to 60), counted from when the SDK sent the request. The SDK places it only while time is left and no known stop covers the account and agent, and it places each decision at most once. Otherwise the result’s reason is expired or stopped, and nothing is placed. A BLOCK has no lifetime.
Modes
| Mode | What happens | Evidence for an insurer |
|---|---|---|
enforce | reTrade’s answer decides what reaches the broker. | Yes, for placed orders. |
shadow | Your agent’s orders are placed unchanged, whatever the answer. reTrade only records what it would have done. | No. |
test | Like enforce, for testing. | No. |
The mode is part of your bot key id, such as exk_test_…. A result’s claimable is true only for an enforce decision whose order was placed. It marks evidence and promises no payment.