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.
modify amends a resting order in place rather than cancelling and re-submitting it. Like every
write tool it is annotated destructiveHint: true, previews unless a call carries both
confirm: true and the preview_token its own preview returned, and needs
vike-cli mcp --node <host:port> plus VIKE_TRADEHUB_CONTROL_KEY.
Arguments
| Parameter | Type | Required | Notes |
|---|---|---|---|
client_order_id | string | yes | The order to amend |
new_qty | number | no | New quantity — but see below for what that means |
new_price | number | no | New price |
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 |
At least one of new_qty / new_price is required. verbs::verb_from_tool_args refuses a modify
that changes nothing, mirroring the REPL's rule — a modify that changes nothing is an authoring
mistake, not a command — and modify_with_nothing_to_change_is_a_tool_error pins that the error
text names new_qty so the agent can act on it.
The preview
modify_without_confirm_only_previews_the_shared_wire_command is the pin for the whole path: a
call with client_order_id: "c-1" and new_qty: 2.0 succeeds with no node configured, returns
will_execute: false, and shows a wire_command whose Modify carries c-1, new_qty 2.0 and
new_price null. Its guardrail reports within_limits: true — this verb has no order size for
the client-side check to look at.
That is exactly the same WireCommand::Modify the human REPL's modify c-1 --qty 2 builds. Both
surfaces resolve through verbs' one construction site, Verb::to_wire_command — the tool path
reaching it via wire_command_for — which is why an agent and an operator issue the same command.
The preview also hands back a preview_token, and a call that actually amends the order must
carry both confirm: true and that token. Either one alone returns another preview rather
than an error, so will_execute is what tells you which call you just made. The token fires once,
expires after 60 seconds, and is bound to this modify — confirming a differently-sized amend with
it is refused, and consumes it.
Live node is the full rule set.
A re-priced amend needs a re-preview
The binding compares the whole wire command, so changing your mind about new_price between the
preview and the confirm invalidates the token you were holding — deliberately. Preview the amend
you actually intend to send, then confirm with that token.
Under a notional ceiling, the node refuses a quantity raise with no price
Name a price whenever you change quantity
ControlLimits::notional_reason has a dedicated arm for a modify naming new_qty and no
new_price: on a node whose policy.toml sets max_notional_per_order, it is refused, with a
message naming that ceiling and telling you to re-send with an explicit price. A node with no
ceiling set never reaches the arm — the check returns early with nothing to enforce. The reason is
stated where the code performs it — this edge holds no order registry and no book, so it cannot
resolve the resting price needed to size the projected order, and "I cannot evaluate this ceiling"
must never render as "the ceiling passed". The shape used to fall through as "no price to size,
therefore fine", which let a small in-cap order be placed and then modified straight past the
node's one order-size ceiling.
A modify naming both a quantity and a price is size-checked, against
|new_qty| × |new_price| — magnitudes on both factors — and refused above the node's ceiling. A
modify naming only a price projects no quantity and matches none of the sizing arms, so it is not
notional-checked at this edge; the core RiskGate resolves the resting order's terms and is the
enforcing gate regardless. Every modify, whatever it names, still spends a rate token in
ControlLimits::vet.
What the quantity means is a per-venue fact
vike_model::venue_amend exists to answer one question: what does an amend's quantity mean?
Three conventions exist, and they disagree about how much more the order can still execute.
| Convention | The order | How much more can execute |
|---|---|---|
InPlaceTotal | survives, executions stay attached | new_qty − filled_qty |
CancelReplace | dies; a fresh order rests | the whole new_qty, on top of what the dead order did |
InPlaceRemaining | survives; the number replaces its outstanding size | the whole new_qty |
Only InPlaceTotal changes any pre-trade verdict — already_in_position returns a non-zero value
for that variant and 0.0 for every other, including the two AmendSemantics variants that
declare no convention at all: Unsupported, where the venue has no native amend for a convention
to describe, and Unknown, the value an unrecognised venue string resolves to. The asymmetry is
the safety argument: the arithmetic errs conservative, so it can wrongly deny an amend and can
never wrongly admit one.
A paper mount is not a made-up venue string
It is tempting to assume a paper mount runs under sim or paper and falls into the conservative
fallback for free. It does not: vike_mount::make_engine builds the engine with the real venue
string even when the absent-credentials gate fell back to the paper client. The paper book
implements the third convention — its modify assigns the amend's quantity as the size that can
still fill — so it declares InPlaceRemaining through the client rather than through the venue
table.
Outcomes
lower_command maps WireCommand::Modify to the core's OrderIntent::Modify and echoes the
client_order_id, since this is an order-scoped verb. Server::execute then awaits that
command's own ticket for two seconds: accepted with the echoed id, an error result carrying the
node's refusal, outcome: "unknown" on a timeout, or an error result naming the outcome unknown
when the control connection dropped. Both ambiguous cases mean the same thing — call
node_snapshot before you retry, because a re-sent modify is not
idempotent the way a re-sent submit is.
If the amend is large enough to be a different order, consider
cancel_order plus a fresh
submit_order instead; the states involved are described in
Order lifecycle.
Move my resting bid to 59,800 and cut the size to 0.2 — name the price, it is a qty change.
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.
flatten
Close one venue-and-symbol net position with a reduce-only market order sized at apply time — previewed by default, sent only against a confirming call that carries the preview_token.