vike
Tools

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.

flatten closes the net position in one (venue, symbol) book. It mints no size of its own: the quantity is the position, resolved when the intent is applied. Annotated destructiveHint: true like every write tool, it 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

ParameterTypeRequiredNotes
venuestringyesVenue id
symbolstringyesInstrument symbol
reasonstringnoRationale for the node's audit trail
confirmbooleannoMust be the JSON boolean true and be accompanied by preview_token — either one missing returns a preview
preview_tokenstringnoThe token this tool's preview returned. Fires once, expires after 60s, bound to the command it previewed

There is no quantity argument, and that is the design rather than an omission. OrderIntent::Flatten closes the (venue, symbol) net position with a reduce-only market order for |position|, resolved at apply time, and is a no-op when flat. If you want to take off part of a position, that is a reduce-only submit_order, not this tool.

The preview

Called without confirm, the write arm builds the command and returns 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, and with no node configured nothing is opened. The guardrail is Guardrail::NoSize (within_limits: true, "no order size to check for this verb"): the client cannot size a flatten either, because the position it will close lives on the node.

Closing the position takes a second call carrying both confirm: true and that token. Either one on its own returns a fresh preview instead — not an error — so will_execute is the field that tells you whether the flatten was actually issued. The token fires once, expires after 60 seconds and is bound to this (venue, symbol); Live node has the four rules.

The preview shows the intent, never the resulting order

Because the quantity is resolved at apply time on the node, the wire_command in the preview names only the venue and symbol. Nothing on this side can tell you how big the resulting market order will be. node_snapshot is what shows you the position before you confirm — and the fill afterwards.

What the node does with it

lower_command maps WireCommand::Flatten to the core's OrderIntent::Flatten with an empty coid. That is the account-wide-verb convention: the acknowledgement has no order id to echo, because the order does not exist yet. The accepted response says so in its own note — an empty client_order_id means an account-wide verb.

ControlLimits::vet consumes a rate token and stops there. Its doc lists flatten among the risk-reducing verbs — cancel, flatten, mass-cancel, market-exit, trading-state — that are never size-capped. A flatten cannot be refused for being too large, which is the right way round for the only verb whose whole job is getting smaller.

It works from a halted core

The reduce-only shape is what gets flatten past the kill switch when nothing else gets through. OrderIntent::MarketExit documents the rule for the compound verb built out of this one: the RiskGate kill switch admits a position-covered reduce under Halted (vike_model::is_covered_reduce), and that is exactly the shape a flatten mints — side opposite the position, quantity |position|. The same property makes it permitted under TradingState::Reducing. Admission at that arm is all it buys: the rest of RiskGate::check_inner still runs, so an armed max_notional_per_order or max_total_exposure denies an oversized flatten in any state, and under Halted the verdict is re-taken on the lot-rounded size — a |position| of 1.8 on a 1.0 lot rounds up to 2.0, which would flip the position, so that leg comes back denied with the reason halted.

That correction was made because the reverse had been true for the verb's whole life: the gate denied every order under Halted, reduce_only included, so the exits were disarmed in precisely the situations that reach Halted on their own. A kill switch must stop you opening risk, never trap you in it. Risk and arming sets out the order the gates are consulted in, and set_trading_state is the tool that moves the switch.

Outcomes

Server::execute awaits this command's own ticket for two seconds. accepted returns sent: true with an empty client_order_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. For both ambiguous cases, call node_snapshot before retrying — a repeated flatten against a book that is already flat is a no-op, but a repeat issued while the first is still in flight is not obviously one.

To empty one venue or the whole account rather than one book, use mass_cancel for the resting orders and market_exit for both at once.

Flatten the BTCUSDT position on binance.

On this page