MFX Hub
SDK reference

Execution

Generated from mfx-sdk-python 0.9.11·rebuilt on every release

Order entry. Every method returns an ExecutionResult and none raises: a timeout, a transport fault and a broker rejection are all results with a reason.

Types

AliasValues
SideLiteral['buy', 'sell']
OrderTypeLiteral['market', 'limit', 'stop', 'stop_limit']
AmountDecimal | str | int

Execution

Order entry for one tenant. Every method returns a result; none raises.

async place_order( terminal_id: Id, *, symbol: str, side: Side, volume: Amount, idempotency_key: str, order_type: OrderType = 'market', price: Amount | None = None, stop_limit_price: Amount | None = None, sl: Amount | None = None, tp: Amount | None = None, deviation_points: int | None = None, expires_at: dt.datetime | None = None, magic: int | None = None, comment: str | None = None, ) -> ExecutionResult

Place a market or pending order.

ParameterTypeDefaultDescription
terminal_idIdrequired

The terminal to act on. Another customer's id answers 404, never 403.

symbol keywordstrrequired

The broker's own symbol name, exactly as the catalogue returns it. MFX Hub never renames an instrument.

side keywordSiderequired

"buy" or "sell".

volume keywordAmountrequired

Lots, as a Decimal, a string or an int. A float is refused.

idempotency_key keywordstrrequired

Required on every write and never defaulted. Retrying with the same key returns the original answer; a fresh key asks for a new action.

order_type keywordOrderType'market'

"market" (the default), "limit" or "stop".

price keywordAmount | NoneNone

Entry price of a pending order, as a Decimal, a string or an int.

stop_limit_price keywordAmount | NoneNone

A stop_limit order has two prices: price is the stop price, where the order wakes up, and stop_limit_price is the limit order placed when it does.

sl keywordAmount | NoneNone

Stop loss price, as a Decimal, a string or an int.

tp keywordAmount | NoneNone

Take profit price, as a Decimal, a string or an int.

deviation_points keywordint | NoneNone

Largest slippage you accept on a market order, in points.

expires_at keyworddt.datetime | NoneNone

When a pending order expires. Timezone-aware.

magic keywordint | NoneNone

Your own integer tag on the order, returned on every deal it makes.

comment keywordstr | NoneNone

Up to 31 characters. Longer is refused rather than truncated.

Returns ExecutionResult

symbol is the broker's own name (EURUSD.sd): MFX never renames an instrument on a tenant's behalf. comment longer than 31 characters is refused rather than truncated, because the terminal cuts it without saying so.

A stop_limit order has two prices: price is the stop price, where the order wakes up, and stop_limit_price is the limit order placed when it does. stop_limit_price is required with stop_limit and refused with any other type; the platform says so, and the refusal comes back as the result.

volume, price, stop_limit_price, sl and tp take a Decimal, a string or an int, and refuse a float.

async cancel_order(terminal_id: Id, ticket: int, *, idempotency_key: str) -> ExecutionResult

Cancel a pending order. First class, not a modify with a special case.

ParameterTypeDefaultDescription
terminal_idIdrequired

The terminal to act on. Another customer's id answers 404, never 403.

ticketintrequired

The order's ticket number on the broker.

idempotency_key keywordstrrequired

Required on every write and never defaulted. Retrying with the same key returns the original answer; a fresh key asks for a new action.

Returns ExecutionResult

async modify_position( terminal_id: Id, ticket: int, *, idempotency_key: str, sl: Amount | None = None, tp: Amount | None = None, ) -> ExecutionResult

Move the stop loss, the take profit, or both. At least one is required.

ParameterTypeDefaultDescription
terminal_idIdrequired

The terminal to act on. Another customer's id answers 404, never 403.

ticketintrequired

The order's ticket number on the broker.

idempotency_key keywordstrrequired

Required on every write and never defaulted. Retrying with the same key returns the original answer; a fresh key asks for a new action.

sl keywordAmount | NoneNone

Stop loss price, as a Decimal, a string or an int.

tp keywordAmount | NoneNone

Take profit price, as a Decimal, a string or an int.

Returns ExecutionResult

async modify_order( terminal_id: Id, ticket: int, *, idempotency_key: str, price: Amount | None = None, stop_limit_price: Amount | None = None, sl: Amount | None = None, tp: Amount | None = None, expires_at: dt.datetime | None | _Keep = _KEEP, ) -> ExecutionResult

Amend a pending order's price, stops or expiry. At least one must change.

ParameterTypeDefaultDescription
terminal_idIdrequired

The terminal to act on. Another customer's id answers 404, never 403.

ticketintrequired

The order's ticket number on the broker.

idempotency_key keywordstrrequired

Required on every write and never defaulted. Retrying with the same key returns the original answer; a fresh key asks for a new action.

price keywordAmount | NoneNone

Entry price of a pending order, as a Decimal, a string or an int.

stop_limit_price keywordAmount | NoneNone

stop_limit_price is a stop-limit order's second price (2.14); on any other order the host refuses it, and the refusal comes back as the result.

sl keywordAmount | NoneNone

Stop loss price, as a Decimal, a string or an int.

tp keywordAmount | NoneNone

Take profit price, as a Decimal, a string or an int.

expires_at keyworddt.datetime | None | _Keep_KEEP

When a pending order expires. Timezone-aware.

Returns ExecutionResult

What is not given keeps the order's present value, because MetaTrader's amend takes the whole order. A level of "0" clears a stop or a take-profit. For the expiry the three states are told apart: leaving expires_at out keeps the order's own, None makes it good-till-cancelled, and a time sets it. Volume, side, type and symbol cannot be amended — a tenant cancels and places again.

stop_limit_price is a stop-limit order's second price (2.14); on any other order the host refuses it, and the refusal comes back as the result.

price, stop_limit_price, sl and tp take a Decimal, a string or an int, and refuse a float.

async close_position( terminal_id: Id, ticket: int, *, idempotency_key: str, deviation_points: int | None = None, ) -> ExecutionResult

Close a position in full.

ParameterTypeDefaultDescription
terminal_idIdrequired

The terminal to act on. Another customer's id answers 404, never 403.

ticketintrequired

The order's ticket number on the broker.

idempotency_key keywordstrrequired

Required on every write and never defaulted. Retrying with the same key returns the original answer; a fresh key asks for a new action.

deviation_points keywordint | NoneNone

Largest slippage you accept on a market order, in points.

Returns ExecutionResult

No comment parameter: PositionClose has no such field and forbids extras, so one would be refused by the platform rather than ignored.

async close_position_by( terminal_id: Id, ticket: int, by_ticket: int, *, idempotency_key: str, ) -> ExecutionResult

Close a position against an opposite one in the same symbol (hedging accounts).

ParameterTypeDefaultDescription
terminal_idIdrequired

The terminal to act on. Another customer's id answers 404, never 403.

ticketintrequired

The order's ticket number on the broker.

by_ticketintrequired

ticket is the position being closed and by_ticket the opposite one.

idempotency_key keywordstrrequired

Required on every write and never defaulted. Retrying with the same key returns the original answer; a fresh key asks for a new action.

Returns ExecutionResult

ticket is the position being closed and by_ticket the opposite one. The smaller of the two disappears and the larger is reduced by its volume, and the spread is paid once and not twice. The result's exec_volume is the volume closed; it has no exec_price, because a close-by has no single price.

Two tickets that are not open positions of the account, in one symbol, on opposite sides are refused before the broker is asked - which is also what a netting account gets, since there the two cannot both exist. The refusal comes back as the result.

async close_position_partial( terminal_id: Id, ticket: int, *, volume: Amount, idempotency_key: str, deviation_points: int | None = None, ) -> ExecutionResult

Close part of a position — the volume to close, inside the symbol's step.

ParameterTypeDefaultDescription
terminal_idIdrequired

The terminal to act on. Another customer's id answers 404, never 403.

ticketintrequired

The order's ticket number on the broker.

volume keywordAmountrequired

Lots, as a Decimal, a string or an int. A float is refused.

idempotency_key keywordstrrequired

Required on every write and never defaulted. Retrying with the same key returns the original answer; a fresh key asks for a new action.

deviation_points keywordint | NoneNone

Largest slippage you accept on a market order, in points.

Returns ExecutionResult

Takes a Decimal, a string or an int and refuses a float.

async get_command(command_id: Id, *, idempotency_key: str = '') -> ExecutionResult

One command and its result. A command belonging to another tenant is a 404, never 403.

ParameterTypeDefaultDescription
command_idIdrequired

The command's id from an earlier result.

idempotency_key keywordstr''

Required on every write and never defaulted. Retrying with the same key returns the original answer; a fresh key asks for a new action.

Returns ExecutionResult

Reading is on the execution boundary too: a caller checking what happened to an order must not have to catch an exception to find out that it cannot tell.

async wait_for( command_id: Id, *, timeout_s: float = 30.0, idempotency_key: str = '', ) -> ExecutionResult

Poll until the command is final, or until timeout_s.

ParameterTypeDefaultDescription
command_idIdrequired

The command's id from an earlier result.

timeout_s keywordfloat30.0

Poll until the command is final, or until timeout_s.

idempotency_key keywordstr''

Required on every write and never defaulted. Retrying with the same key returns the original answer; a fresh key asks for a new action.

Returns ExecutionResult

Returns the last answer either way — a command that is still EXECUTING when the time runs out is reported as it is, not raised and not guessed at. A non-final result is never a licence to re-send: an UNKNOWN command may already be a position.

Reason (StrEnum)

Why a command ended as it did.

The platform's dictionary plus the four the SDK itself can conclude. A reason the platform adds later arrives as its own string rather than as one of these — see reason_text — because bucketing a reason the caller has never seen is how a granular vocabulary quietly becomes "failed".

MemberValueMeaning
SUCCESS'success'
REQUOTE'requote'
INSTRUMENT_DISABLED'instrument_disabled'
NO_LIQUIDITY'no_liquidity'
MARKET_CLOSED'market_closed'
INVALID_STOPS'invalid_stops'
INVALID_VOLUME'invalid_volume'
INSUFFICIENT_FUNDS'insufficient_funds'
TRADE_DISABLED'trade_disabled'
REJECTED_OTHER'rejected_other'
RATE_LIMITED'rate_limited'
EXPIRED'expired'
UNKNOWN'unknown'
MAINTENANCE'maintenance'

A planned maintenance window suspended order placement for this terminal: the API refused it with 403 maintenance, or a command queued before the window was refused by the platform before it ran. Nothing reached the broker, so it is retryable once the window ends - retry_at says when, where the platform said.

TRANSPORT_ERROR'transport_error'

Concluded by the SDK, never sent by the platform: the request never got an answer.

TIMEOUT'timeout'

Concluded by the SDK: no answer in time. Never retried — a timed-out order may have been placed, and deal-history reconciliation is the only safe recovery (design ).

REFUSED'refused'

The platform refused the request itself: a 4xx that is not a rate limit.

CommandState (StrEnum)

. Final: SUCCEEDED, FAILED, EXPIRED, REJECTED. UNKNOWN is visible and not final.

MemberValueMeaning
ACCEPTED'ACCEPTED'
ENQUEUED'ENQUEUED'
DELIVERED'DELIVERED'
EXECUTING'EXECUTING'
SUCCEEDED'SUCCEEDED'
FAILED'FAILED'
EXPIRED'EXPIRED'
REJECTED'REJECTED'
UNKNOWN'UNKNOWN'

Tickets

the terminal relates one order, one deal and one position per fill; null where the terminal has none yet.

FieldTypeDefaultMeaning
orderint | NoneNone
dealint | NoneNone
positionint | NoneNone
from_dict(raw: Any) -> Tickets
ParameterTypeDefaultDescription
rawAnyrequired

Returns Tickets

ExecutionResult

The whole answer to one execution call. Never raised — always returned.

FieldTypeDefaultMeaning
okbool
idempotency_keystr

The idempotency key this call was made with, so a retry can reuse it without bookkeeping.

client_rtt_msfloat

How long the SDK waited, end to end. Always known, even when nothing else is.

command_idstr | NoneNone
stateCommandState | NoneNone
finalboolFalse

True once the platform will not change this answer again.

retryableboolFalse

Whether sending the same order again under a NEW key can succeed. False while UNKNOWN.

duplicateboolFalse

The same key with the same body: this is the original command, not a second one.

reasonReason | NoneNone
reason_textstr | NoneNone

The reason exactly as it arrived, including one this SDK version does not know.

mt5_retcodeint | NoneNone
retcode_textstr | NoneNone
comment_rawstr | NoneNone

The broker's own comment, verbatim, for a human to read beside the reason.

terminal_statestr | NoneNone
ticketsTicketsdefault_factory=Tickets
exec_priceDecimal | NoneNone
exec_volumeDecimal | NoneNone
broker_latency_msint | NoneNone
agent_latency_msint | NoneNone
attemptsint0
rerouted_fromstr | NoneNone

The terminal a failover moved this command from, when one did.

detailstr | NoneNone

What the platform said when it refused the request outright.

retry_atdt.datetime | NoneNone

When sending it again can work: the maintenance window's end, for a maintenance refusal.

from_command(body: Any, *, idempotency_key: str, client_rtt_ms: float) -> Self

Build from a Command or a CommandAccepted body, whichever the call answered with.

ParameterTypeDefaultDescription
bodyAnyrequired
idempotency_key keywordstrrequired

Required on every write and never defaulted. Retrying with the same key returns the original answer; a fresh key asks for a new action.

client_rtt_ms keywordfloatrequired

Returns Self

refused( reason: Reason, *, idempotency_key: str, client_rtt_ms: float, detail: str, retry_at: dt.datetime | None = None, ) -> Self

An answer the SDK concluded itself: no transport, no time, or a refusal.

ParameterTypeDefaultDescription
reasonReasonrequired

Your own words, recorded with the action.

idempotency_key keywordstrrequired

Required on every write and never defaulted. Retrying with the same key returns the original answer; a fresh key asks for a new action.

client_rtt_ms keywordfloatrequired
detail keywordstrrequired
retry_at keyworddt.datetime | NoneNone

Returns Self