Appearance
trader.trades
3 methods on trader.trades. Each returns the answer's data and throws NoviqaError on a failed answer.
create
POST
/trader/v1/tradesSend a trade request
Opens, closes or changes a position or a pending order of the signed-in account. The request passes validation (symbol rules), routing (book, dealer or liquidity provider) and execution (money, positions); the call waits for the outcome. Login, group and leverage come from the session: a body carrying them (or any other unknown field) is refused. Body at most 4 KB. An investor (read-only) session is refused with trade.read_only.
More details
request_id (required). A new UUID per request. Sending the same id again never trades twice: it returns the answer the first copy got (the last 1000 answers per account are kept; a copy that arrives while the first is still with a dealer waits for the same answer). Reuse an id only to retry after a lost answer; any new request needs a new id.
action (required) and the fields each one reads:
open: market order.symbol_id,side(buy/sell) andvolumerequired;kindempty ormarket.priceis the price the trader saw (ask for a buy, bid for a sell): under instant execution, or a routing rule that confirms at the client's price, the fill stays withindeviation_ptspoints of it or the answer is a requote; 0/absent takes the market. Optionalstop_loss,take_profit,fill_policy,comment.place: pending order.symbol_id,side,kind(limit,stoporstop_limit),volumeandpricerequired. A buy limit waits below the ask, a buy stop above it, a sell limit above the bid, a sell stop below it, each at least the symbol's stops level away.stop_limitalso needstrigger_price(the stop price);priceis then the limit price, below the trigger for a buy and above it for a sell. Optional stops,expirationwithexpires_at,fill_policy(exchange execution only),comment.close:position_idrequired.volumecloses that part (up to the position's volume, on the symbol's step); 0 or absent closes all.price/deviation_ptsas for open.close_by:position_idandby_position_id: two different, opposite positions of one symbol on a hedging account. The smaller volume closes against the other. Each leg closes at the other leg's open price; theposition_idleg carries the pair's profit and theby_position_idleg books zero profit. Both legs realise their swap for the closed volume; any excess volume stays open.modify:position_idrequired.stop_lossandtake_profitREPLACE both levels: send the current value to keep one, 0 to remove it. Refused withtrade.frozenwhile a level is within the freeze level of the market.modify_pending:order_idrequired.price/trigger_pricechange when positive (0 keeps them);stop_loss/take_profitreplace both (0 removes);expirationchanges when sent (withexpires_at). Sendsideandkindtoo so validation can check the new price.cancel:order_idrequired. Send the order'sside,kindandprice(ortrigger_pricefor stop_limit) so the freeze level can be checked.
For close, close_by, modify, modify_pending and cancel, symbol_id may be omitted: execution resolves it from the account's owned position or order before validation. A supplied symbol that differs from the target is refused with invalid_input; another account's target is not found.
Numbers. volume (lots), price, trigger_price, stop_loss, take_profit are exact decimal strings (e.g. "0.10", "1.08500"), never floats, and never negative; prices must sit on the symbol's point grid (its digits). Volume must be within the symbol's volume_min..volume_max on steps of volume_step counted from volume_min (close: up to max, on the step). Ids and deviation_pts are whole numbers, not negative. comment at most 64 characters; fill_policy and expiration at most 32.
Stops. For a buy, stop loss below and take profit above the reference price (the reverse for a sell), at least the symbol's stops_level_pts away (exactly at the level is allowed; exchange execution has no level). The reference is the close price (bid for a buy) for open/modify, the order's own price for pending orders. 0 means no level.
fill_policy. fill_or_kill, immediate_or_cancel or book_or_cancel, among the symbol's allowed_fill_policies and what its execution type can do (instant/request: fill_or_kill; market: + immediate_or_cancel; exchange: all three; book_or_cancel only for limit and stop_limit). Empty takes the symbol's first usable policy.
Expiration (place/modify_pending). until_cancelled (default when empty), today, specified_time or specified_day, among the symbol's allowed_expirations; a group without order expiration allows only until_cancelled. specified_time and specified_day need expires_at (RFC3339 UTC) in the future.
Answer. Once the trading services decide, the answer is a success envelope whose data.status says what happened:
done: filled;order,deals,positionsandmoneyhold the result.placed: the pending order was accepted (order).partial: part of the volume filled.requote: prices moved;bid/askcarry the new prices andcodeistrade.requote. Under instant execution this ends the request: send a new request (newrequest_id) at the new price. When a dealer requoted, the request stays open until the symbol's request timeout: answer it with POST /trader/v1/trades/{request_id}/requote.rejected: refused;codeandmessagesay why (list below).
A request routed to a dealer is held while the dealer decides (at most 2 minutes); the call waits for that answer. If no dealer answers in time the answer is rejected with trade.timeout.
Refusal codes in data.code (status rejected): trade.symbol_unavailable (group does not trade the symbol), trade.disabled (symbol, account or group trading off), trade.close_only, trade.side_not_allowed (long-only or short-only symbol), trade.market_closed (outside the trade sessions or on a holiday), trade.no_prices (no price, or older than the symbol's quote timeout), trade.order_type_not_allowed (order, stop loss/take profit or close_by not allowed on the symbol, or close_by on a netting account), trade.invalid_volume, trade.invalid_price (off the point grid, wrong side of the market or inside the stops level), trade.invalid_stops, trade.frozen, trade.fill_policy_not_supported, trade.invalid_expiration, trade.no_money (free margin would go negative), trade.too_many_orders (group limit on pending orders, positions or symbols), trade.volume_limit (group or symbol volume cap), trade.hedging_not_allowed, trade.position_not_found, trade.order_not_found (also for another account's id), trade.requote (a declined requote), trade.rejected (by a dealer or a routing rule; no dealer online), trade.timeout, invalid_input (a request the trading services found malformed, e.g. a missing side), not_found (the account is not loaded in execution) and internal.
Error answers (HTTP errors, nothing was traded): invalid_input for a malformed body (see the shape rules above: unknown field, missing request_id, unknown action/side/kind, negative number, long comment, body over 4 KB); trade.read_only; auth.too_many_attempts from the rate limit; trade.timeout when the trading services did not answer in time (the outcome is unknown: retry with the same request_id to learn it); not_found when the account is gone.
Rate limit. 20 trade requests per account per second. The 20th inside one second blocks the account's trade requests for 5 minutes; each further block within a day doubles, up to an hour. Requote answers are not counted.
Side effects. Every decided request writes a journal line (trade.<action>) visible in GET /trader/v1/journal. A fill, close or order change also reaches the account's live socket as a trade, order or position event (see /docs/ws), so other open terminals update.
Parameters
X-HST-Accountstring · headerIntended signed-in login captured by the browser tab before dispatch and retained across retries. A mismatch returns auth.account_changed (409) before mutation or refresh rotation. This never selects or authorizes an account; omission preserves existing API client compatibility.
Request body
actionTradeActionTradeAction is what a trade request asks for. -
open: market order - close: close all or part of a position - close_by: close a position by an opposite one (hedging) - modify: change a position's stop loss / take profit - place: place a pending order - modify_pending: change a pending order - cancel: cancel a pending order - activate: Requests the engine makes itself when a price reaches a level. Routing sees each as its own kind, so a rule can send it to a liquidity provider; the side is the position's (stop loss, take profit, stop out) or the order's. a pending order reached its price - activate_stop_limit: the stop price of a stop-limit order was reached: it becomes a limit order - stop_loss: a position's stop loss was reached - take_profit: a position's take profit was reached - stop_out: a stop out closes a position - stop_out_order: a stop out removes the pending order holding the most marginopen close close_by modify place modify_pending cancel activate activate_stop_limit stop_loss take_profit stop_out stop_out_orderby_position_idanyTrade target identity, 0 through 9223372036854775807. Browsers must send exact decimal strings; never convert IDs to JavaScript numbers. Legacy integers remain accepted. Null preserves an existing value; fresh null or omitted optional IDs mean zero; the action still validates its required target.
commentstringdeviation_ptsintegerexpirationstringexpires_atstringUTC time, RFC 3339.
fill_policystringkindOrderKindOrderKind is how an order waits for its price. -
market: fill now - limit: fill at this price or better - stop: becomes market when the price reaches it - stop_limit: becomes a limit order when the price reaches itmarket limit stop stop_limitorder_idanyTrade target identity, 0 through 9223372036854775807. Browsers must send exact decimal strings; never convert IDs to JavaScript numbers. Legacy integers remain accepted. Null preserves an existing value; fresh null or omitted optional IDs mean zero; the action still validates its required target.
originanyposition_idanyTrade target identity, 0 through 9223372036854775807. Browsers must send exact decimal strings; never convert IDs to JavaScript numbers. Legacy integers remain accepted. Null preserves an existing value; fresh null or omitted optional IDs mean zero; the action still validates its required target.
pricestringExact decimal as a string. Never parse it into a binary float for money or prices.
request_idstringnew UUID per request; the same id twice runs once
sideSideSide is the direction of an order, position or deal.
buy sellstop_lossstringExact decimal as a string. Never parse it into a binary float for money or prices.
symbol_idanyTrade target identity, 0 through 9223372036854775807. Browsers must send exact decimal strings; never convert IDs to JavaScript numbers. Legacy integers remain accepted. Null preserves an existing value; fresh null or omitted optional IDs mean zero; the action still validates its required target.
take_profitstringExact decimal as a string. Never parse it into a binary float for money or prices.
trigger_pricestringExact decimal as a string. Never parse it into a binary float for money or prices.
volumestringExact decimal as a string. Never parse it into a binary float for money or prices.
Returns
Promise<TradeResult>The answer's
data.Errors
400
invalid_input: invalid input401
auth.session_expired: session expired, sign in again403
auth.csrf_invalid: request refused: reload the page and try again403
auth.invalid_terminal: this terminal cannot be used here403
auth.otp_enrol_required: your group requires one-time codes: set them up to continue403
auth.password_change_required: you must change your password first403
trade.read_only: read-only access cannot trade404
not_found: not found409
auth.account_changed: the signed-in account changed; sign in again before continuing429
auth.too_many_attempts: too many attempts, try again later500
internal: something went wrong504
trade.timeout: request timed outts
import { trader } from "@/lib/noviqa"
const data = await trader.trades.create({
action: "open",
comment: "breakout",
deviation_pts: 20,
fill_policy: "fill_or_kill",
price: "1.08500",
request_id: "3f2a9c1e-8b7d-4e6f-a5c4-1b2d3e4f5a6b",
side: "buy",
stop_loss: "1.08000",
symbol_id: 12,
take_profit: "1.09500",
volume: "0.10"
})bash
curl -X POST "$NOVIQA_API_URL/trader/v1/trades" \
-H "Authorization: Bearer $NOVIQA_TOKEN" \
-H "Content-Type: application/json" \
--data-raw '{
"action": "open",
"comment": "breakout",
"deviation_pts": 20,
"fill_policy": "fill_or_kill",
"price": "1.08500",
"request_id": "3f2a9c1e-8b7d-4e6f-a5c4-1b2d3e4f5a6b",
"side": "buy",
"stop_loss": "1.08000",
"symbol_id": 12,
"take_profit": "1.09500",
"volume": "0.10"
}'json
{
"success": true,
"code": "ok",
"message": "done",
"data": {
"ask": "1.08460",
"bid": "1.08452",
"code": "ok",
"deals": [
{
"action": "buy",
"calc_type": "forex",
"comment": "Deposit via bank",
"commission": "1.08452",
"contract_size": "1.08452",
"dealer": 1,
"digits": 5,
"entry": "in",
"external_id": "string",
"fee": "1.08452",
"gateway_id": 1,
"id": 1
}
],
"deleted": [
1
],
"margin_check": {
"additional_margin": "1.08452",
"before": {
"agent_commission": "1.08452",
"balance": "1000.00",
"balance_prev_day": "1.08452",
"balance_prev_month": "1.08452",
"blocked_commission": "1.08452",
"blocked_profit": "1.08452",
"credit": "0.00",
"currency": "USD",
"currency_digits": 1,
"day": "2026-09-25T10:15:00Z",
"effective_leverage": "1.08452",
"equity": "1012.40"
},
"group": "real\\standard",
"projected": {
"agent_commission": "1.08452",
"balance": "1000.00",
"balance_prev_day": "1.08452",
"balance_prev_month": "1.08452",
"blocked_commission": "1.08452",
"blocked_profit": "1.08452",
"credit": "0.00",
"currency": "USD",
"currency_digits": 1,
"day": "2026-09-25T10:15:00Z",
"effective_leverage": "1.08452",
"equity": "1012.40"
},
"shortfall": "1.08452",
"symbol": "EURUSD",
"virtual_credit": "1.08452"
},
"message": "string",
"money": {
"agent_commission": "1.08452",
"balance": "1000.00",
"balance_prev_day": "1.08452",
"balance_prev_month": "1.08452",
"blocked_commission": "1.08452",
"blocked_profit": "1.08452",
"credit": "0.00",
"currency": "USD",
"currency_digits": 1,
"day": "2026-09-25T10:15:00Z",
"effective_leverage": "1.08452",
"equity": "1012.40"
},
"order": {
"activated_at": "2026-09-25T10:15:00Z",
"by_position_id": 1,
"comment": "Deposit via bank",
"contract_size": "1.08452",
"created_at": "2026-09-25T10:15:00Z",
"dealer": 1,
"deviation_pts": 1,
"digits": 5,
"done_at": "2026-09-25T10:15:00Z",
"expiration": "string",
"expires_at": "2026-09-25T10:15:00Z",
"external_id": "string"
},
"positions": [
{
"comment": "Deposit via bank",
"contract_size": "1.08452",
"dealer": 1,
"digits": 5,
"external_id": "string",
"id": 1,
"login": 1001,
"margin": "108.45",
"opened_at": "2026-09-25T10:15:00Z",
"origin": {},
"price_current": "1.08452",
"price_open": "1.08452"
}
],
"request_id": "3f2a9c1e-8b7d-4e6f-a5c4-1b2d3e4f5a6b",
"status": "done"
},
"request_id": "5b7f2c1e"
}ts
trader.trades.create(body: account.Trade, options?: RequestOptions): Promise<models.TradeResult>outcome
GET
/trader/v1/trades/{request_id}/outcomeRead a trade request outcome
Only the signed-in account is ever read: the login comes from the session, never from the request. Read-only reconciliation from execution and durable ledger outcomes. Returns complete, pending, or unknown. Unknown never authorizes resubmission. Available when EA permission is disabled; does not execute anything.
Parameters
X-HST-Accountstring · headerIntended signed-in login captured by the browser tab before dispatch and retained across retries. A mismatch returns auth.account_changed (409) before mutation or refresh rotation. This never selects or authorizes an account; omission preserves existing API client compatibility.
request_idstring · pathrequiredThe original trade request UUID.
Returns
Promise<TradeOutcome>The answer's
data.Errors
400
invalid_input: invalid input401
auth.session_expired: session expired, sign in again403
auth.invalid_terminal: this terminal cannot be used here403
auth.otp_enrol_required: your group requires one-time codes: set them up to continue403
auth.password_change_required: you must change your password first409
auth.account_changed: the signed-in account changed; sign in again before continuing500
internal: something went wrongts
import { trader } from "@/lib/noviqa"
const data = await trader.trades.outcome("3f2a9c1e-8b7d-4e6f-a5c4-1b2d3e4f5a6b")bash
curl -X GET "$NOVIQA_API_URL/trader/v1/trades/3f2a9c1e-8b7d-4e6f-a5c4-1b2d3e4f5a6b/outcome" \
-H "Authorization: Bearer $NOVIQA_TOKEN"json
{
"success": true,
"code": "ok",
"message": "done",
"data": {
"result": {
"ask": "1.08460",
"bid": "1.08452",
"code": "ok",
"deals": [
{}
],
"deleted": [
1
],
"margin_check": {
"additional_margin": "1.08452",
"before": {},
"group": "real\\standard",
"projected": {},
"shortfall": "1.08452",
"symbol": "EURUSD",
"virtual_credit": "1.08452"
},
"message": "string",
"money": {
"agent_commission": "1.08452",
"balance": "1000.00",
"balance_prev_day": "1.08452",
"balance_prev_month": "1.08452",
"blocked_commission": "1.08452",
"blocked_profit": "1.08452",
"credit": "0.00",
"currency": "USD",
"currency_digits": 1,
"day": "2026-09-25T10:15:00Z",
"effective_leverage": "1.08452",
"equity": "1012.40"
},
"order": {
"activated_at": "2026-09-25T10:15:00Z",
"by_position_id": 1,
"comment": "Deposit via bank",
"contract_size": "1.08452",
"created_at": "2026-09-25T10:15:00Z",
"dealer": 1,
"deviation_pts": 1,
"digits": 5,
"done_at": "2026-09-25T10:15:00Z",
"expiration": "string",
"expires_at": "2026-09-25T10:15:00Z",
"external_id": "string"
},
"positions": [
{}
],
"request_id": "3f2a9c1e-8b7d-4e6f-a5c4-1b2d3e4f5a6b",
"status": "done"
},
"state": "string"
},
"request_id": "5b7f2c1e"
}ts
trader.trades.outcome(requestId: string, options?: RequestOptions): Promise<models.TradeOutcome>requote
POST
/trader/v1/trades/{request_id}/requoteAnswer a dealer's requote
When a dealer requoted a request of the signed-in account, the POST /trader/v1/trades call answered status requote with the offered bid/ask. Send {"accept": true} to fill at the offered price (ask for a buy, bid for a sell) or {"accept": false} to decline, before the symbol's request timeout (at most 2 minutes) runs out. accept is required.
More details
The answer is the trade result: done (filled, with deals and positions), rejected with trade.requote after a decline, rejected with another trade code when the fill is refused (e.g. trade.no_money), or queued when the symbol needs the dealer to confirm an accepted requote: the final outcome then arrives on the live socket as a trade event. Only a dealer requote can be answered: an instant-execution requote is final (send a new request). not_found when there is no open requote for this id on this account (never requoted, already answered, expired, or another account's). An investor (read-only) session is refused with trade.read_only.
Parameters
X-HST-Accountstring · headerIntended signed-in login captured by the browser tab before dispatch and retained across retries. A mismatch returns auth.account_changed (409) before mutation or refresh rotation. This never selects or authorizes an account; omission preserves existing API client compatibility.
request_idstring · pathrequiredThe
request_id of the requoted trade request.Request body
acceptbooleantrue fills at the offered prices while the requote is still open; false declines it.
Returns
Promise<TradeResult>The answer's
data.Errors
400
invalid_input: invalid input401
auth.session_expired: session expired, sign in again403
auth.csrf_invalid: request refused: reload the page and try again403
auth.invalid_terminal: this terminal cannot be used here403
auth.otp_enrol_required: your group requires one-time codes: set them up to continue403
auth.password_change_required: you must change your password first403
trade.read_only: read-only access cannot trade404
not_found: not found409
auth.account_changed: the signed-in account changed; sign in again before continuing500
internal: something went wrong504
trade.timeout: request timed outts
import { trader } from "@/lib/noviqa"
const data = await trader.trades.requote("3f2a9c1e-8b7d-4e6f-a5c4-1b2d3e4f5a6b", {
accept: true
})bash
curl -X POST "$NOVIQA_API_URL/trader/v1/trades/3f2a9c1e-8b7d-4e6f-a5c4-1b2d3e4f5a6b/requote" \
-H "Authorization: Bearer $NOVIQA_TOKEN" \
-H "Content-Type: application/json" \
--data-raw '{
"accept": true
}'json
{
"success": true,
"code": "ok",
"message": "done",
"data": {
"ask": "1.08460",
"bid": "1.08452",
"code": "ok",
"deals": [
{
"action": "buy",
"calc_type": "forex",
"comment": "Deposit via bank",
"commission": "1.08452",
"contract_size": "1.08452",
"dealer": 1,
"digits": 5,
"entry": "in",
"external_id": "string",
"fee": "1.08452",
"gateway_id": 1,
"id": 1
}
],
"deleted": [
1
],
"margin_check": {
"additional_margin": "1.08452",
"before": {
"agent_commission": "1.08452",
"balance": "1000.00",
"balance_prev_day": "1.08452",
"balance_prev_month": "1.08452",
"blocked_commission": "1.08452",
"blocked_profit": "1.08452",
"credit": "0.00",
"currency": "USD",
"currency_digits": 1,
"day": "2026-09-25T10:15:00Z",
"effective_leverage": "1.08452",
"equity": "1012.40"
},
"group": "real\\standard",
"projected": {
"agent_commission": "1.08452",
"balance": "1000.00",
"balance_prev_day": "1.08452",
"balance_prev_month": "1.08452",
"blocked_commission": "1.08452",
"blocked_profit": "1.08452",
"credit": "0.00",
"currency": "USD",
"currency_digits": 1,
"day": "2026-09-25T10:15:00Z",
"effective_leverage": "1.08452",
"equity": "1012.40"
},
"shortfall": "1.08452",
"symbol": "EURUSD",
"virtual_credit": "1.08452"
},
"message": "string",
"money": {
"agent_commission": "1.08452",
"balance": "1000.00",
"balance_prev_day": "1.08452",
"balance_prev_month": "1.08452",
"blocked_commission": "1.08452",
"blocked_profit": "1.08452",
"credit": "0.00",
"currency": "USD",
"currency_digits": 1,
"day": "2026-09-25T10:15:00Z",
"effective_leverage": "1.08452",
"equity": "1012.40"
},
"order": {
"activated_at": "2026-09-25T10:15:00Z",
"by_position_id": 1,
"comment": "Deposit via bank",
"contract_size": "1.08452",
"created_at": "2026-09-25T10:15:00Z",
"dealer": 1,
"deviation_pts": 1,
"digits": 5,
"done_at": "2026-09-25T10:15:00Z",
"expiration": "string",
"expires_at": "2026-09-25T10:15:00Z",
"external_id": "string"
},
"positions": [
{
"comment": "Deposit via bank",
"contract_size": "1.08452",
"dealer": 1,
"digits": 5,
"external_id": "string",
"id": 1,
"login": 1001,
"margin": "108.45",
"opened_at": "2026-09-25T10:15:00Z",
"origin": {},
"price_current": "1.08452",
"price_open": "1.08452"
}
],
"request_id": "3f2a9c1e-8b7d-4e6f-a5c4-1b2d3e4f5a6b",
"status": "done"
},
"request_id": "5b7f2c1e"
}ts
trader.trades.requote(requestId: string, body: http.docTraderRequote, options?: RequestOptions): Promise<models.TradeResult>