跳转至

FIX 报文

来源状态

正文摘录自 postman/Polaris-FIX-Document.postman_collection.json

(Pepperstone Crypto FIX API 机构接入指南)。 本地 ptrader-fix-server 检出目前仅有 README(无 src/)。 字段表在源码核验前视为已发布的客户端契约 — 见 待确认清单。

中英对照

下列协议术语、Tag 表与报文示例保留英文原文(FIX 线路契约)。导航与说明使用中文。

Market data — MarketDataRequest (35=V)

Three modes are supported, selected by SubscriptionRequestType (263). If 263 is omitted, the gateway defaults to snapshot mode.

263 Mode Server response
0 Snapshot only One 35=W per requested symbol; the subscription is not retained.
1 Snapshot + updates One 35=W per symbol, then a stream of 35=X.
2 Unsubscribe No payload; matching MDReqID is removed.

Required fields

Tag Field Req? Notes
262 MDReqID Y Must be unique while the subscription is active.
263 SubscriptionRequestType Cond. One of 0 / 1 / 2. Defaults to 0.
264 MarketDepth N 0 = full book; 1 = top of book; N = top-N levels.
267 NoMDEntryTypes N Repeating group of 269. Defaults to {0 BID, 1 OFFER}.
146 NoRelatedSym Y Repeating group of 55. At least one entry required.
55 Symbol Y Format BASE_QUOTE, e.g. BTC_USDT. Case-insensitive (normalised to upper).

Snapshot example

Inbound · MarketDataRequest (snapshot)

8=FIXT.1.1|9=...|35=V|34=40|49=CLIENT|56=PtradeFIXServer-AU|
262=md-001|263=0|264=10|267=2|269=0|269=1|146=1|55=BTC_USDT|10=...

Outbound · MarketDataSnapshotFullRefresh (35=W)

8=FIXT.1.1|9=...|35=W|34=41|49=PtradeFIXServer-AU|56=CLIENT|
262=md-001|55=BTC_USDT|1187=Y|268=4|
269=0|270=62000.10|271=0.85|290=1|
269=0|270=61999.90|271=2.10|290=2|
269=1|270=62000.80|271=0.50|290=1|
269=1|270=62001.20|271=1.20|290=2|10=...

Snapshot + updates

The gateway re-publishes the entire top-N book on every tick, rather than emitting per-level diffs. This costs a small amount of bandwidth for guaranteed correctness under packet loss.

Outbound · MarketDataIncrementalRefresh (35=X)

8=FIXT.1.1|9=...|35=X|34=52|49=PtradeFIXServer-AU|56=CLIENT|
262=md-sub-001|268=2|
279=0|269=0|55=BTC_USDT|278=md-sub-001-BTC_USDT-0-1|270=62001.20|271=0.40|290=1|
279=0|269=1|55=BTC_USDT|278=md-sub-001-BTC_USDT-1-1|270=62001.80|271=0.30|290=1|10=...

Rejects

The gateway pre-validates requested symbols against the live catalog. The first symbol not in the catalog causes the entire request to be rejected — no subscription state is registered. Reject codes on MDReqRejReason (281):

281 Meaning Trigger
0 UNKNOWN_SYMBOL Symbol missing, empty group, or not in the active catalog.
1 DUPLICATE_MDREQID An active subscription already exists with the same MDReqID.
4 UNSUPPORTED_SUBSCRIPTIONREQUESTTYPE Missing MDReqID, or 263 value not in {0,1,2}.
6 UNSUPPORTED_MDUPDATETYPE MDUpdateType (265) present but not 0 or 1.
8 UNSUPPORTED_MDENTRYTYPE No requested entry types can be served.

Outbound · MarketDataRequestReject (35=Y)

8=FIXT.1.1|9=...|35=Y|34=61|49=PtradeFIXServer-AU|56=CLIENT|
262=md-sub-001|281=0|58=Unknown symbol: NOSUCH_USDT|10=...

NOTE: To unsubscribe, send 35=V with 263=2 and the same MDReqID as the original subscription.

NewOrderSingle (35=D)

WARNING: Supported order types: MARKET (40=1) and LIMIT (40=2) only. STOP, STOP_LIMIT and other conditional types are rejected with ExecutionReport (35=8, 150=8, 39=8, 103=11 UNSUPPORTED_ORDER_CHARACTERISTIC).

Required fields

Tag Field Req? Notes
11 ClOrdID Y Client-assigned, unique per account. Reuse triggers a duplicate-order reject; see below.
55 Symbol Y Format BASE_QUOTE, e.g. BTC_USDT.
54 Side Y 1 = BUY, 2 = SELL
40 OrdType Y 1 = MARKET, 2 = LIMIT
21 HandlInst Y Required by FIX dictionary. Typical value 1. Server does not branch on this.
38 OrderQty Cond. Required for LIMIT and for MARKET by base quantity. Must be > 0. Mutually exclusive with 152.
152 CashOrderQty Cond. Quote-currency amount for MARKET (e.g. "buy 1000 USDT of BTC"). Must be > 0. Not allowed on LIMIT.
44 Price Cond. Required for LIMIT; must be > 0. Ignored on MARKET (safe to send 44=0 for Java/proto3 clients).
59 TimeInForce N 0 = DAY, 1 = GTC (default), 3 = IOC, 4 = FOK
60 TransactTime Y UTC YYYYMMDD-HH:MM:SS.sss.

Placement flow

Before acknowledging, the gateway runs:

  1. Structural validation — required fields, value ranges, exclusivity of 38/152.
  2. Symbol + trading-rule check against the catalog.
  3. Duplicate-ClOrdID guard — the id is claimed atomically; a collision returns a reject without touching the incumbent order.
  4. Pre-lock of the required balance on the asset service.
  5. Publish to the matching engine.

On success, the gateway forwards the matching engine's first ExecutionReport (150=0 NEW, 39=0 NEW). All subsequent lifecycle events (fills, partial fills, cancels, expirations) are driven by the matching engine and arrive as further ExecutionReports.

Inbound · NewOrderSingle (LIMIT BUY)

8=FIXT.1.1|9=...|35=D|34=70|49=CLIENT|56=PtradeFIXServer-AU|
11=cli-10001|55=BTC_USDT|54=1|21=1|38=0.50|40=2|44=62000.00|59=1|60=20260515-09:05:00.000|10=...

Outbound · ExecutionReport (NEW ack)

8=FIXT.1.1|9=...|35=8|34=71|49=PtradeFIXServer-AU|56=CLIENT|
37=1234567|17=exec-...|11=cli-10001|55=BTC_USDT|54=1|40=2|38=0.50|44=62000.00|
150=0|39=0|14=0|151=0.50|6=0|60=20260515-09:05:00.100|10=...

Duplicate ClOrdID

Sending a NewOrderSingle with a ClOrdID already known to the gateway returns:

Outbound · ExecutionReport (duplicate ClOrdID)

8=FIXT.1.1|9=...|35=8|34=72|49=PtradeFIXServer-AU|56=CLIENT|
37=O-cli-10001-...|17=rejected-...|11=cli-10001|55=BTC_USDT|54=1|40=2|
150=8|39=8|14=0|151=0|6=0|103=6|58=Duplicate ClOrdID: cli-10001|10=...

NOTE: The incumbent live order with this ClOrdID is not affected and remains cancellable. Make sure your ClOrdID generator is collision-free per account.

OrderCancelRequest (35=F)

Cancel a working order by referencing its ClOrdID.

Required fields

Tag Field Req? Notes
41 OrigClOrdID Y The ClOrdID of the original NewOrderSingle.
11 ClOrdID Y A new unique id for this cancel request itself.
55 Symbol Y Echo the symbol of the original order.
54 Side Y Required by the dictionary; not used for routing.
60 TransactTime Y UTC YYYYMMDD-HH:MM:SS.sss

Response semantics

Cancel is asynchronous:

  • The gateway does local validation only (order known, state is cancellable, session is authenticated).
  • On success, it forwards the request to the matching engine and marks the order PENDING_CANCEL locally. No ExecutionReport is produced synchronously.
  • The real ExecutionReport (150=4 Canceled, 39=4 Canceled) arrives once the matching engine confirms.
  • If local validation fails, an OrderCancelReject (35=9) is returned synchronously with a specific CxlRejReason (102).

Cancel-reject reasons

102 Meaning Trigger
1 UNKNOWN_ORDER OrigClOrdID is missing, or the order is not in the gateway's tracked cache.
0 TOO_LATE_TO_CANCEL The order is already in a terminal state (FILLED / CANCELED / REJECTED / EXPIRED).
3 ORDER_ALREADY_IN_PENDING_CANCEL_OR_PENDING_REPLACE_STATUS A previous cancel for the same order is still in flight (double-tap).
99 OTHER Session not authenticated, or downstream publish failed.

NOTE: OrdStatus (39) on 35=9 mirrors the underlying order's current state, not the rejected cancel: 39=0 if the order is still NEW, 39=2 if FILLED, 39=4 if CANCELED, 39=6 if PENDING_CANCEL, 39=8 only when the order was never known to the gateway.

Inbound · OrderCancelRequest

8=FIXT.1.1|9=...|35=F|34=80|49=CLIENT|56=PtradeFIXServer-AU|
41=cli-10001|11=cli-10001-cxl-1|55=BTC_USDT|54=1|60=20260522-09:06:00.000|10=...

Outbound · ExecutionReport (Canceled, driven by matching engine)

8=FIXT.1.1|9=...|35=8|34=81|49=PtradeFIXServer-AU|56=CLIENT|
37=1234567|17=cxl-...|41=cli-10001|11=cli-10001-cxl-1|55=BTC_USDT|54=1|
150=4|39=4|14=0|151=0|6=0|10=...

Outbound · OrderCancelReject (order already terminal)

8=FIXT.1.1|9=...|35=9|34=83|49=PtradeFIXServer-AU|56=CLIENT|
37=1234567|41=cli-10001|11=cli-10001-cxl-2|39=4|434=1|102=0|
58=Order not cancelable in current state|10=...

11 vs 41 on Canceled ER

On both the synchronous OrderCancelReject and the asynchronous ExecutionReport (150=4):

  • 11 ClOrdID — the id of the cancel request itself.
  • 41 OrigClOrdID — the id of the original order.

OrderMassCancelRequest (35=q)

Cancel every working order on the session that matches a given symbol (optionally narrowed to one side). The gateway iterates internally, dispatches one cancel per affected order, and enumerates them in the outbound OrderMassCancelReport (35=r) via the NoAffectedOrders (534) repeating group.

Only MassCancelRequestType = 1 (CANCEL_ORDERS_FOR_A_SECURITY) is supported.

Required fields

Tag Field Req? Notes
11 ClOrdID Y Echoed back in 35=r as both 11 and 1369 MassActionReportID.
530 MassCancelRequestType Y Only 1 supported today.
55 Symbol Y Required when 530=1.
54 Side N Optional. 1 = BUY, 2 = SELL. Omit to sweep both sides.
60 TransactTime Y UTC YYYYMMDD-HH:MM:SS.sss

Response

Outcome Fields
Accepted 35=r · 531=1 · 533=N · one 534/41/535 entry per affected order
Rejected — unsupported 530 35=r · 531=0 · 532=0 MASS_CANCEL_NOT_SUPPORTED
Rejected — missing Symbol 35=r · 531=0 · 532=1 INVALID_OR_UNKNOWN_SECURITY
Rejected — unsupported Side 35=r · 531=0 · 532=99 OTHER

WARNING: 35=r is an ACK of the mass-cancel request, not of each individual cancel outcome. Every affected order still generates its own ExecutionReport (150=4 Canceled) asynchronously from the matching engine — just like a single 35=F. Use the 534 group to know which OrigClOrdIDs to expect.

Inbound · OrderMassCancelRequest

8=FIXT.1.1|9=...|35=q|34=120|49=CLIENT|56=PtradeFIXServer-AU|
11=mc-001|530=1|55=BTC_USDT|54=2|60=20260522-09:10:00.000|10=...

Outbound · OrderMassCancelReport (accepted)

8=FIXT.1.1|9=...|35=r|34=121|49=PtradeFIXServer-AU|56=CLIENT|
11=mc-001|1369=mc-001|530=1|531=1|55=BTC_USDT|533=2|
534=2|41=cli-10001|535=1234567|41=cli-10002|535=1234568|10=...

ExecutionReport (35=8)

The gateway emits an ExecutionReport for each lifecycle transition of your order.

ExecType (150) OrdStatus (39) Meaning
0 NEW 0 NEW Order accepted by the book.
F TRADE 1 PARTIALLY_FILLED A partial fill occurred.
F TRADE 2 FILLED Final fill; the order is closed.
4 CANCELED 4 CANCELED Cancel confirmed by the matching engine.
C EXPIRED C EXPIRED TIF-driven expiration (IOC / FOK unfilled).
8 REJECTED 8 REJECTED Order rejected; carries OrdRejReason (103).

Common fields

Tag Field Notes
37 OrderID Server-assigned order id. Use it to reconcile against back-office / REST.
17 ExecID Unique per ExecutionReport message.
11 ClOrdID Echo of the inbound ClOrdID. On a Canceled ER, this is the cancel-request id; 41 carries the original order id.
55 Symbol Canonical upper-case symbol id.
14 CumQty Cumulative filled base quantity.
151 LeavesQty Remaining open base quantity. Always 0 on terminal status.
6 AvgPx Average fill price. 0 whenever CumQty = 0.
31 / 32 LastPx / LastQty Present only on TRADE ERs (150 ∈ {F, 1, 2}).
60 TransactTime UTC timestamp at emit time.
103 OrdRejReason Present on rejects. See reject reference below.

Coherence guarantees

On every outbound ExecutionReport, the gateway guarantees the following invariants regardless of upstream behaviour:

  • LeavesQty (151) = 0 whenever OrdStatus is terminal (FILLED / CANCELED / REJECTED / EXPIRED).
  • AvgPx (6) = 0 whenever CumQty (14) = 0.
  • ExecType (150) is coerced to mirror OrdStatus (39) when upstream reports NEW alongside a terminal status (this happens for IOC/FOK orders that don't match anything; you receive a single ER with 150=C, 39=C, not a contradictory pair).
  • LastPx (31) / LastQty (32) are stripped on non-TRADE ERs.

You can drive your OMS off (39, 150, 6, 151) without needing to reconcile contradictory upstream signals.

SecurityListRequest (35=x)

Fetch the currently active spot symbol catalog as a single SecurityList (35=y). Useful at session warm-up. Only SecurityListRequestType = 4 (AllSecurities) is supported.

Required fields

Tag Field Req? Notes
320 SecurityReqID Y Echoed in the outbound 35=y.
559 SecurityListRequestType Y Must be integer 4. Any other value → reject.

Response

560 Meaning When
0 VALID_REQUEST Symbols returned in the 146 NoRelatedSym group.
1 INVALID_OR_UNSUPPORTED_REQUEST 559 ≠ 4.
2 NO_INSTRUMENTS_FOUND Catalog is empty (should not occur under normal operation).

Each entry inside 146 carries the canonical upper-case Symbol (55). Additional instrument metadata (lot size, tick size, etc.) should be fetched from the REST catalog endpoint.

Inbound · SecurityListRequest

8=FIXT.1.1|9=...|35=x|34=130|49=CLIENT|56=PtradeFIXServer-AU|
320=sl-001|559=4|10=...

Outbound · SecurityList (accepted)

8=FIXT.1.1|9=...|35=y|34=131|49=PtradeFIXServer-AU|56=CLIENT|
320=sl-001|322=SLR-...|560=0|393=3|893=Y|146=3|
55=BTC_USDT|55=ETH_USDT|55=SOL_USDT|10=...

NOTE: QuickFIX/J note: the constant SecurityListRequestType.SYMBOL = 0 means "by symbol", not "all". Send the integer 4 on the wire.

Reject codes

Session-level Reject (35=3)

Produced by the QuickFIX/J engine before your message reaches business logic. See also Reject (35=3) in Session lifecycle for the message shape and companion fields.

The full set of SessionRejectReason (373) values the gateway can emit under strict validation is below. In practice you will spend most of your time with 0/1/2/5/11.

373 Meaning Cause
0 INVALID_TAG_NUMBER Tag number is not a defined FIX field.
1 REQUIRED_TAG_MISSING A dictionary-required tag is absent from the message.
2 TAG_NOT_DEFINED_FOR_THIS_MESSAGE_TYPE Legal tag used on the wrong 35=.
3 UNDEFINED_TAG Custom / user-defined tag with AllowUnknownMsgFields=N.
4 TAG_SPECIFIED_WITHOUT_A_VALUE Tag present but value empty.
5 VALUE_IS_INCORRECT Field value out of the enum defined by the dictionary.
6 INCORRECT_DATA_FORMAT_FOR_VALUE Value type mismatch (e.g. non-numeric where int is expected, malformed UTC timestamp).
9 COMPID_PROBLEM SenderCompID (49) or TargetCompID (56) does not match the allow-list for this session.
10 SENDINGTIME_ACCURACY_PROBLEM SendingTime (52) is too far from the gateway clock (default window is 2 min).
11 INVALID_MSGTYPE Unknown or unsupported 35= value.
13 TAG_APPEARS_MORE_THAN_ONCE Same tag appears twice in a single message body.
14 TAG_SPECIFIED_OUT_OF_REQUIRED_ORDER Header, body, or trailer tag placed in the wrong section.
15 REPEATING_GROUP_FIELDS_OUT_OF_ORDER Repeating-group entries not delivered in dictionary-declared order.
16 INCORRECT_NUMINGROUP_COUNT_FOR_REPEATING_GROUP NoXxx count disagrees with the actual number of entries.
18 INVALID_UNSUPPORTED_APPLICATION_VERSION ApplVerID (1128) negotiation failed (must resolve to FIX 5.0 SP2).
99 OTHER Catch-all for validation failures not classified above.

Order reject on 35=8

103 Meaning Cause
0 BROKER_EXCHANGE_OPTION Generic validation failure (blank ClOrdID, LIMIT missing / non-positive price, LIMIT with 152, etc.).
1 UNKNOWN_SYMBOL Symbol not in the active catalog.
6 DUPLICATE_ORDER ClOrdID collides with an order already tracked.
11 UNSUPPORTED_ORDER_CHARACTERISTIC Unsupported OrdType (e.g. 40=4 STOP_LIMIT) or TimeInForce.
13 INCORRECT_QUANTITY Missing / non-positive OrderQty, or MARKET with both 38 and 152.
99 OTHER Balance pre-lock failed, downstream publish failed, or session not authenticated.

Business message reject (35=j)

Emitted when an application message exceeds the per-API-key inbound rate limit. The message carries BusinessRejectReason (380) = 99 (Other) and a Text describing the throttle.

Quick reference

You send Server responds
Logon without 553 35=5 Logout · 58=…
Field value not in FIX dictionary enum 35=3 · 373=5 VALUE_IS_INCORRECT
Unknown tag 35=3 · 373=2 INVALID_TAG_NUMBER
Duplicate ClOrdID on 35=D 35=8 · 150=8, 39=8 · 103=6 DUPLICATE_ORDER
35=D with 40=4 STOP_LIMIT 35=8 · 150=8, 39=8 · 103=11 UNSUPPORTED_ORDER_CHARACTERISTIC
LIMIT missing / non-positive Price 35=8 · 103=0 BROKER_EXCHANGE_OPTION
MARKET with neither 38 nor 152, or both 35=8 · 103=13 INCORRECT_QUANTITY
Cancel of unknown order 35=9 · 434=1 · 102=1 UNKNOWN_ORDER
Cancel of already-terminal order 35=9 · 434=1 · 102=0 TOO_LATE_TO_CANCEL
Double-tap cancel 35=9 · 434=1 · 102=3 PENDING_CANCEL_OR_REPLACE
Duplicate MDReqID 35=Y · 281=1 DUPLICATE_MDREQID
35=V unknown symbol 35=Y · 281=0 UNKNOWN_SYMBOL
35=q with 530 ≠ 1 35=r · 531=0 · 532=0 MASS_CANCEL_NOT_SUPPORTED
35=x with 559 ≠ 4 35=y · 560=1 INVALID_OR_UNSUPPORTED_REQUEST
Rate limit exceeded 35=j · 380=99 · 58=Rate limit exceeded…

Field reference

Essential fields consumed or emitted by the gateway. Anything not listed here is either dictionary-only or ignored by the application layer.

Tag Field Notes
8 BeginString FIXT.1.1
34 MsgSeqNum Strictly monotonic per direction; persisted.
35 MsgType See overview table.
49 SenderCompID Your id inbound; PtradeFIXServer-<SITE> outbound.
52 SendingTime UTC YYYYMMDD-HH:MM:SS.sss
56 TargetCompID PtradeFIXServer-<SITE> inbound; your id outbound.
1128 ApplVerID 9 = FIX.5.0SP2
1137 DefaultApplVerID Set on Logon.

Session admin

Tag Field Notes
7 BeginSeqNo Start of resend range.
16 EndSeqNo End of resend range (0 = open-ended).
98 EncryptMethod 0 None
108 HeartBtInt Seconds.
112 TestReqID Echoed on the answering Heartbeat.
141 ResetSeqNumFlag Y / N
553 Username API key. Required on Logon.

Order entry

Tag Field Notes
11 ClOrdID Client-assigned, unique per account.
21 HandlInst Dictionary requires it; typical value 1.
38 OrderQty Base quantity. Mutually exclusive with 152 on MARKET.
40 OrdType 1=MARKET · 2=LIMIT
44 Price LIMIT only. Ignored on MARKET.
54 Side 1=BUY · 2=SELL
55 Symbol BASE_QUOTE
59 TimeInForce 0=DAY · 1=GTC · 3=IOC · 4=FOK
60 TransactTime UTC YYYYMMDD-HH:MM:SS.sss
152 CashOrderQty Quote-currency amount; MARKET only.

Execution report

Tag Field Notes
6 AvgPx 0 when CumQty=0.
14 CumQty Cumulative filled base quantity.
17 ExecID Unique per ER message.
31 / 32 LastPx / LastQty TRADE ERs only.
37 OrderID Server-assigned id.
39 OrdStatus 0NEW · 1PART · 2FILLED · 4CANCELED · 6PENDING_CANCEL · 8REJECTED · CEXPIRED
41 OrigClOrdID Set on Canceled ER (original order id).
103 OrdRejReason See reject reference.
150 ExecType 0NEW · 4CANCELED · 8REJECTED · CEXPIRED · FTRADE
151 LeavesQty 0 on terminal status.

Market data

Tag Field Notes
262 MDReqID Unique per active subscription.
263 SubscriptionRequestType 0Snapshot · 1Snapshot+Updates · 2Unsubscribe
264 MarketDepth 0Full · 1Top · NTop-N
269 MDEntryType 0BID · 1OFFER · 2TRADE
270 MDEntryPx Price per entry.
271 MDEntrySize Size per entry.
281 MDReqRejReason See reject reference.
290 MDEntryPositionNo Depth level, 1-based, per side.