cancel_order
Cancel one resting order by client order id on a running vike-tradehub node — previewed by default, sent only on a second call carrying both confirm and the preview_token.
cancel_order withdraws exactly one resting order, named by its client order id. It is a write
tool, so it is annotated destructiveHint: true and previews unless a call carries both
confirm: true and the preview_token its own preview returned, and it needs
vike-cli mcp --node <host:port> plus VIKE_TRADEHUB_CONTROL_KEY.
Arguments
| Parameter | Type | Required | Notes |
|---|---|---|---|
client_order_id | string | yes | The id to cancel |
reason | string | no | Rationale for the node's audit trail |
confirm | boolean | no | Must be the JSON boolean true and be accompanied by preview_token — either one missing returns a preview |
preview_token | string | no | The token this tool's preview returned. Fires once, expires after 60s, bound to the command it previewed |
Omitting the id is a tool error from verbs::verb_from_tool_args before any command is built.
The preview
Call it without confirm and you get preview_of(...): will_execute: false, the resolved
wire_command, the advisory guardrail, the node's own dry-run when there is a node to ask, the
echoed reason, the confirm note, and a preview_token. Nothing is sent. With no node
configured nothing is opened either.
To execute, call again with the same arguments plus both confirm: true and that token.
Either one on its own returns another preview — not an error — so read will_execute rather than
assuming the second call landed. The token fires once, expires after 60 seconds and is bound to
this exact cancel; Live node has the
four rules and the argument for why it is not a secret.
The guardrail on this verb is always Guardrail::NoSize — rendered as within_limits: true with a
note saying there was no order size to check. That is not a pass; it is the honest answer that a
cancel has nothing to size.
The rationale round-trip is pinned by
a_write_preview_echoes_the_reason_without_changing_the_command, which uses this tool: a reason
of " stale quote after the feed gap " comes back trimmed, a blank one comes back null, and
the wire_command is byte-identical with and without it. The reason rides beside the command on
the wire and can never alter it.
What the node does with it
lower_command maps WireCommand::Cancel straight to the core's OrderIntent::Cancel, and this
is one of the order-scoped verbs, so the acknowledgement echoes the client_order_id you named
rather than an empty string.
ControlLimits::vet consumes a rate token, as it does for every command, and then stops: its doc
is explicit that the notional cap applies only to order-increasing verbs carrying a price, and that
cancel, flatten, mass-cancel, market-exit and trading-state are risk-reducing and never
size-capped. Cancelling is never refused for being too large.
Accepted means the node took the command, not that an order went away
A cancel is fire-and-forget, and the code says so plainly:
verbs::coid_charset_warning's argument closes with "cancel stays fire-and-forget, which is
honest: the node cannot confirm that an order EXISTS either way." An id that never existed is
acknowledged exactly like one that did. Call node_snapshot to
see whether the order actually left the book.
A malformed id is sent anyway, and that is deliberate
The human trade REPL refuses a submit --coid outside ^[A-Za-z0-9]{1,32}$ and only warns
on a cancel naming one. This MCP surface does not warn at all — coid_charset_warning is wired
into the REPL alone.
The asymmetry is argued rather than accidental. A submit is minting an id, so insisting on a
charset every venue accepts costs one retype. A cancel names an id that already exists at the
node, and this client is not the only thing that puts orders there:
submit_order passes an agent-supplied client_order_id through
unvalidated, and lower_command requires only that an id be non-empty. So an order with a coid
outside that charset can exist — and refusing to cancel it would make a live order uncancellable
from the console, to enforce a client-side convention. That trade is unacceptable in a tool whose
reason to exist includes flattening something in a hurry.
Outcomes
Server::execute awaits this command's own ticket for ACK_WAIT, two seconds. accepted returns
sent: true with the echoed id; a refusal is an error result carrying the node's reason; a timeout
returns outcome: "unknown"; a dropped control connection is an error result saying the outcome is
unknown and it may have executed. Both ambiguous cases end the same way — check
node_snapshot before retrying.
To clear a whole book instead of one order, use
mass_cancel; to change an order rather than withdraw it, use
modify. The states an order passes through on its way out are
described in Order lifecycle.
Cancel order a1b2c3d47 — it is stale after the feed gap.
submit_order
Place one order on a running vike-tradehub node — preview first, execute only on a second call carrying both confirm true and the single-use preview_token that preview returned.
modify
Change one resting order's quantity, price, or both — previewed by default and executed only against the preview_token that preview returned, and refused at a node with a notional ceiling when a quantity increase names no price.