FIX Order Entry

Market Maker (MM) Interface Specification — FIX 4.4 & FIX 5.0 SP2

Version 2026-08 (rev. 2026-08-27) · Order-entry & drop copy session types · Counterparty-facing

This document describes the FIX order-entry interface ProphetX exposes to market-maker counterparties. It covers session establishment, the supported messages and fields, order lifecycle, price representation, and the full rejection vocabulary. It reflects exactly what the engine accepts and emits today; anything not listed here is unsupported.

1. Session & connectivity

Sessions are FIX order-entry sessions over TCP. Both FIX versions are offered; the version is fixed per session at onboarding, not negotiable on the wire.

ITEMVALUE
FIX versionFIX 4.4 (BeginString=FIX.4.4) or FIX 5.0 SP2 (BeginString=FIXT.1.1, DefaultApplVerID=9)
RoleProphetX is the acceptor; the MM is the initiator
Session identityBeginString:SenderCompID:TargetCompID — stable across reconnects, so undelivered reports survive a disconnect
Logon (35=A)Carries Username(553) = access key and Password(554) = secret key. Credentials are validated on logon; failure ends the connection.
HeartbeatHeartBtInt(108) as configured at onboarding
Sequence numbersStandard FIX; ProphetX maintains its own persistent store, indefinitely — there is no scheduled reset (e.g. at UTC midnight) and no session boundary. Message-level MsgSeqNum(34) is independent of the application-level delivery sequencing described below.

Reconnect & delivery. Execution reports are held in a durable outbox keyed by the persistent session identity, not the TCP connection. A reconnecting session receives any backlog. Every report carries a unique ExecID(17); clients must dedup on it, as a report may be re-sent after a reconnect.

Resetting sequence numbers. Reconnect with ResetSeqNumFlag(141)=Y only when ProphetX's Logon response carries a MsgSeqNum(34) lower than the next inbound number you expect — that means ProphetX's sequence state has been reset — or when you have lost your own store and cannot resume. ProphetX never asserts 141=Y on its own Logon; a reset is always requested by you, or performed by venue operations and coordinated with you out of band beforehand. NextExpectedMsgSeqNum(789) on Logon is not supported and is ignored.

Operator-initiated resets. If venue operations must reset your session, you will be contacted out of band first, and on the wire you will see a Logout (35=5) carrying the fixed Text(58): "Sequence reset by venue operations. Reset your sequence numbers and reconnect with ResetSeqNumFlag(141)=Y." — a published constant you may match on, though the rule above is what your reconnect logic should actually branch on.

Resend. ResendRequest is honoured for messages sent within the last 7 days; older messages are pruned. A request falling partly outside that window is answered with SequenceReset-GapFill over the pruned portion — if you have been disconnected longer than 7 days, reconnect with 141=Y rather than attempting to resume. Execution reports do not depend on FIX resend: they are held in the durable per-session outbox described above and are redelivered on reconnect regardless of sequence numbers.

Rate limiting. Order-entry messages (NewOrderSingle, NewOrderList, OrderCancelRequest, OrderCancelReplaceRequest, OrderStatusRequest, QuoteRequest, MassQuote, QuoteResponse) may be subject to a per-session rate limit, agreed and configured at onboarding; session-layer messages (Logon/Logout/Heartbeat/TestRequest/ResendRequest) are never throttled. Exceeding your limit is answered with BusinessMessageReject (35=j), BusinessRejectReason(380)=0, and the fixed text "rate limit exceeded for this session; retry after backing off" — match on the text, not just the reason code, since 380=0 is the generic "Other" value (see §14). A throttled request never reaches order processing; it is always safe to retry with the same ClOrdID once you have backed off.

2. Identity & accounts

Account(1) carries the submitting user id, and what's required differs by message type:

  • New Order Single (D) / New Order List (E): required. An absent tag, or one that does not match the user id the session is authorized for, is rejected — ExecutionReport, OrdRejReason(103)=15 (unknown account).
  • Order Cancel Request (F) / Order Cancel Replace Request (G): optional. The venue does not route on it here — the order's owner was already settled when its context was created, so an absent tag, or one that matches the session's authorized user, is accepted. A value that conflicts with the session's authorized user is refused, but not as an ExecutionReport: it comes back as a BusinessMessageReject (35=j), BusinessRejectReason(380)=6 (Not Authorized), correlated on BusinessRejectRefID(379).

The Parties(453) repeating group is optional and used for attribution:

PARTYROLE (452)PARTYID (448)MEANING
1 — Executing Firmfirm idExecuting firm / FCM identifier
24 — Customer Accountcustomer idEnd-customer account identifier

PartyIDSource(447) is proprietary (D). For pure MM flow the Parties group may be omitted.

3. Price representation

ProphetX is a sports prediction market; a price is a probability, expressible in several conventions. A custom tag selects the convention.

FIELDTAGNOTES
PriceFormat6001 (custom)Required on every order-entry message (single, list, replace). Selects how Price(44) is interpreted.
VALUEFORMATEXAMPLE (≈0.65 PROB)CONSTRAINT
1Cents (0–100)650 < p < 100
2American odds-186Must convert to an exact integer; |odds| ≥ 100
3Decimal odds1.5385> 1
4Probability0.650 < p < 1

Inbound vs outbound format differ independently. The MM chooses the inbound format per message via tag 6001. The outbound format — how ProphetX reports Price, LastPx and AvgPx back on Execution Reports — is fixed per session at onboarding, and is not necessarily the same as the inbound format. Prices are never float-rounded; they are converted in exact decimal. A limit price that does not convert to exact integer American odds is rejected.

4. Supported messages

Inbound (MM → ProphetX)

MSGTYPEMESSAGEPURPOSE
DNewOrderSinglePlace a limit or market order
ENewOrderListPlace a batch of limit orders
FOrderCancelRequestCancel a working order
GOrderCancelReplaceRequestReplace a working limit order
HOrderStatusRequestQuery an order's current state
RQuoteRequestRequest an indicative estimate for a market order
iMassQuoteSubmit a parlay price ladder — see §12
AJQuoteResponseAnswer a parlay last look — see §12

Outbound (ProphetX → MM)

MSGTYPEMESSAGEWHEN
8ExecutionReportEvery order acknowledgement, fill, and terminal state, including the parlay last look
9OrderCancelRejectA cancel or replace request that could not be applied
jBusinessMessageRejectMalformed / unroutable request, or an internal failure
SQuoteResponse to a QuoteRequest
3RejectSession-level rejection of a structurally invalid message

5. New Order — Single (D)

FIELDTAGREQNOTES
ClOrdID11YClient order id, unique per session
Account1YSubmit user id (see §2)
Symbol55YLine / instrument identifier
Side54YBuy (1) only. Sell (2) is rejected.
OrdType40Y2 = Limit, 1 = Market
OrderQty38YStake
Price44CRequired for limit orders; must not be set on a market order (except as carried by a quote)
PriceFormat6001YSee §3
TimeInForce59N1 = GTC or 4 = FOK only. Day/IOC rejected. An absent tag defaults to GTC, not Day — a deviation from the FIX default, so a client relying on it would get a resting order. The acknowledgement always states the TIF applied.
ExecInst18NE = take-only, 6 = make-only
QuoteID117CMarket orders: references a prior Quote (see §11)
Parties453…NFirm / customer attribution (see §2)
TransactTime60NClient's send time

A successful place is acknowledged immediately with a PendingNew Execution Report (ExecType=A) carrying the assigned OrderID(37). This is provisional — see §7.

6. New Order List (E)

A batch of limit orders in one message. The price format (tag 6001) is set once at the list level and applies to every order; per-order fields (ClOrdID, Symbol, OrderQty, Price, and optionally Side / TimeInForce / ExecInst) are carried in the NoOrders(73) group.

  • Each order is acknowledged independently with its own PendingNew (or reject).
  • A per-order validation failure rejects only that entry; the rest proceed.

Maximum 20 orders per list. A list of more than 20 orders (or an empty list) is rejected in full — every order in it comes back rejected, not just the ones past the twentieth. ProphetX forwards the list to the matching service as a single batch, and that service caps the batch at 20; the limit is all-or-nothing, so keep each NewOrderList to 20 orders or fewer. Within a valid (≤20) list, individual orders still succeed or fail independently.

7. Order lifecycle

The synchronous acknowledgement is provisional. The terminal acceptance comes from the matching engine as a separate, unsolicited Execution Report.

place (35=D)
   │
   ▼
PendingNew (ExecType=A, OrdStatus=A)  ← provisional: order id delivered
   │
   ├─────────────► New (ExecType=0, OrdStatus=0)  ← terminal acceptance (order is working)
   │                  │
   │                  ├──► Trade (ExecType=F)      ← one per fill; partial (OrdStatus=1) or full (2)
   │                  ├──► Canceled (ExecType=4)   ← on cancel / void / wipe
   │                  └──► (Filled, OrdStatus=2, on last fill)
   │
   └─────────────► Rejected (ExecType=8, OrdStatus=8)  ← matching engine refused the order

Provisional vs terminal. A PendingNew means "accepted for processing," not "working." The matching engine can still reject a provisionally-accepted order; that arrives as a terminal Rejected (ExecType=8). Do not treat an order as live until its New arrives.

Quantity reconstruction. Fill reports carry the last-fill quantity (LastQty) and price (LastPx). Cumulative fields are reconstructed by ProphetX: CumQty accumulates across fills, LeavesQty = OrderQty − CumQty, and AvgPx is the quantity-weighted average. These stay monotonic even if fills are delivered out of order.

Report ordering. Under load a fill may be delivered before the New for the same order. TransactTime(60) is sourced from the underlying event (microsecond precision) and reflects the true sequence — order your view by TransactTime, not by arrival, and dedup on ExecID(17).

8. Execution Report (8)

FIELDTAGNOTES
ClOrdID11The order this report concerns
OrigClOrdID41On a Replaced report: the order that was replaced
OrderID37ProphetX order id; NONE when no order exists
ExecID17Unique per report — dedup key
ExecType150See vocabulary below
OrdStatus39See vocabulary below
Side / Symbol54 / 55Echoed
OrderQty38Original order quantity
Price44In the session's outbound format (§3)
LastQty / LastPx32 / 31Fill reports only
CumQty / LeavesQty / AvgPx14 / 151 / 6Reconstructed (§7)
TransactTime60Event time, microsecond precision (YYYYMMDD-HH:MM:SS.ffffff)
OrdRejReason103On a Rejected report (§13)
Text58Human-readable detail

ExecType (150)

VALUEMEANING
APendingNew — provisional acknowledgement
0New — terminal acceptance (order working)
FTrade — a fill
5Replaced
4Canceled
8Rejected
CExpired — reserved; not currently produced by any order type on this interface
IOrderStatus — response to a status request

OrdStatus (39)

VALUEMEANING
APendingNew
0New
1Partially filled
2Filled
5Replaced
4Canceled
8Rejected
CExpired — reserved; not currently produced

Correlating a Canceled report. A cancellation the venue originates — a void or a wipe — has no request behind it, and the matching-engine event that drives it does not carry the id of any request. ProphetX therefore reports ClOrdID(11) = the ORDER's client order id and omits OrigClOrdID(41), including when the cancellation followed your Cancel Request. A client correlating strictly per FIX — expecting tag 11 to echo the request — will not match these reports. Correlate a cancellation on OrderID(37) or on the order's own ClOrdID. Raise this at onboarding if your stack requires the strict form.

9. Cancel & Replace (F / G)

OrderCancelRequest (F)

FIELDTAGREQNOTES
OrigClOrdID41YThe order to cancel
ClOrdID11YNew id for this request
OrderID37NProphetX order id, if known
Account1NSee §2 — optional, but must not conflict with the session's authorized user
Symbol / Side55 / 54YEchoed for correlation

A successful cancel terminates the order with a Canceled Execution Report (ExecType=4, LeavesQty=0).

OrderCancelReplaceRequest (G) — limit only

Replace changes the price and/or quantity of a working limit order. Market-order replace is not supported and is cancel-rejected. A successful replace is answered as one Replaced Execution Report (ExecType=5, OrdStatus=0, CumQty=0), with OrigClOrdID(41) naming the replaced order. The replacement starts fresh; cumulative quantity does not carry across.

Account(1) is optional here too — see §2.

Timing. An order can only be replaced once it is working (has received its New). A replace issued while the order is still being placed is transiently refused and retried briefly; if the order is not yet open it will be cancel-rejected. Replace after the order opens.

OrderCancelReject (9)

A cancel or replace that cannot be applied is answered with MsgType 9 — not an Execution Report.

FIELDTAGNOTES
CxlRejResponseTo4341 = cancel, 2 = replace — distinguishes the two
CxlRejReason1020 too late, 1 unknown order, 2 other
OrdStatus39The order's current status — the request failed, the order lives on. Rejected(8) only for an unknown order.
Text58Reason detail

10. Order Status (H)

Query by ClOrdID(11) (with Side and Symbol) and/or OrderID(37). Three outcomes:

  • Found — Execution Report with ExecType=I and the order's current state.
  • Unknown order — Execution Report with OrdStatus=Rejected(8), echoing the request's ClOrdID.
  • Malformed request — BusinessMessageReject (35=j).

11. Quote Request (R) / Quote (S)

A QuoteRequest asks for an indicative estimate before placing a market order. Populate the NoRelatedSym(146) group with Symbol(55), Side(54) and OrderQty(38) — exactly one entry; a request naming more than one symbol is not supported. ProphetX replies with a Quote (35=S) carrying the estimated price and available size and a QuoteID(117). To act on it, send a market NewOrderSingle referencing that QuoteID.

The Quote is one-sided, matching the side you requested: OfferPx/OfferSize are populated for a Buy request, BidPx/BidSize for a Sell request. The other side's fields are not returned.

Quotes are indicative and ephemeral — they are not persisted and carry a validity window (ValidUntilTime(62)).

12. Parlays — market maker quoting

A parlay is one instrument with 2–12 legs, one combined price, one stake, and an all-or-nothing payout. It is not a list of orders, so NewOrderList does not apply.

The flow inverts normal order entry: a market maker does not place a parlay order. It quotes, and ProphetX creates an order when a taker accepts. The maker then gets a final option to honour, re-price or walk away — a last look.

Scope. Parlay support is MM-quoting only. Taking parlays over FIX is not offered. Parlay inquiries ("someone wants a price for these legs") continue to arrive over your existing non-FIX channel; only the quote, the last look, and the resulting reports are on FIX.

12.1 The sequence

inquiry for a parlay price          not FIX — existing channel
   │
you quote a price ladder            MassQuote (35=i)          ──▶ ProphetX
   │
taker accepts                       not FIX
   │
LAST LOOK: confirm or walk          ExecutionReport, ExecType=A ◀── ProphetX
   │
you answer                          QuoteResponse (35=AJ)      ──▶ ProphetX
   │
the trade stands                    New, then Trade, then terminals ◀── ProphetX

12.2 Custom tags

PriceFormat(6001) is required on parlay messages that carry a price, exactly as on order entry. The leg group is proprietary: FIX has no field for a per-leg probability, and a tag that is not part of a repeating group's definition cannot be carried inside a standard group.

FIELDTAGNOTES
PriceFormat6001as elsewhere in this spec
NoParlayLegs6101count of the parlay leg group
LegLineID6102the leg's line id, within the group
LegProbability6103the leg's probability, within the group

12.3 MassQuote (35=i) — submitting a ladder

One message quotes one parlay. Several parlays means several messages.

FIELDTAGREQNOTES
QuoteID117YYour id for this submission. A refusal is attributed to it
Account1Yas elsewhere
PriceFormat6001Ythe convention OfferPx is expressed in
NoQuoteSets296Yexactly one set; more than one is refused
QuoteSetID302Ythe parlay id being quoted
NoQuoteEntries295Yone entry per ladder rung, at least one
QuoteEntryID299Yyour id for the rung
OfferPx133Yyour price for the whole parlay
OfferSize135Ymaximum you will risk at that price. Must be > 0
ValidUntilTime62Yexpiry. An offer with no expiry cannot be honoured and is refused
NoLegs / LegSymbol555 / 600Nthe legs, by line id

A refused ladder is answered with a BusinessMessageReject (35=j) whose BusinessRejectRefID(379) is your QuoteID, with the reason in Text(58). A ladder that is accepted is not acknowledged — silence means accepted.

OfferPx must convert to an exact integer in American odds, like every other price in this interface. Sizing and validity windows are enforced by the venue and a breach is refused rather than adjusted.

12.4 The last look — ExecutionReport (8)

When a taker accepts your price, ProphetX asks you to confirm:

FIELDTAGVALUE
ExecType150A — PendingNew
OrdStatus39A — PendingNew
OrderID37the parlay order id — the handle you answer with
ClOrdID11NONE — see below
Symbol55the parlay id
OrderQty38the stake on your side of the trade
Price44the price on your side, in this session's outbound format

These reports are unsolicited. You never sent a request, so there is no ClOrdID of yours to echo and tag 11 carries the sentinel NONE. Correlate a parlay on OrderID(37). This applies to every report for the order, not just the prompt.

You must answer before ValidUntilTime. The venue's confirmation window runs from when it created the order, so the time available to you is slightly less than the value shown; answer promptly rather than at the limit.

12.5 QuoteResponse (35=AJ) — answering

FIELDTAGREQNOTES
QuoteRespID693YYour id for this answer. A refusal is attributed to it
QuoteID117Ythe OrderID(37) from the prompt — the order you are answering
QuoteRespType694Y1 accept as offered · 2 accept re-priced (counter) · 6 pass
PriceFormat6001Y on acceptthe convention any counter price is in
OfferPx133Ncounter price. Omit to accept the price offered
OrderQty38Ncounter stake. Omit to accept the stake offered
Parlay leg group6101/6102/6103Y on accepta probability for every leg
Text58Nfree-text reason, useful on a pass

A pass (694=6) needs nothing else — no price format, no legs.

An acceptance must carry a probability for every leg. The venue re-derives the parlay price from them and refuses the whole confirmation if they do not reconstruct it: the product of your leg probabilities must land on the odds ladder beside the taker's price. Note that a counter does not change what the legs must justify — the taker keeps the price it accepted — so the same leg probabilities apply whether you accept or counter.

A counter can only move in the taker's favour, and only within a tolerance the venue configures. A counter outside either bound is refused with the reason in Text(58). In practice a counter re-prices how much of the taker's stake your risk covers rather than changing the contract price, so countering the stake is the direct lever.

Refusals arrive as BusinessMessageReject (35=j) with BusinessRejectRefID(379) = your QuoteRespID. The order stays open for another answer if you are still inside the window.

12.6 Reports after you accept

VENUE EVENTREPORTS
your acceptance is recordedNew (ExecType=0), then Trade (ExecType=F)
you took everything offeredTrade with OrdStatus=2 Filled, LeavesQty=0
you took less than offeredTrade with OrdStatus=1 PartiallyFilled, then a Canceled releasing the remainder
you passed, or the venue refusedRejected (ExecType=8) with the reason in Text(58)
the parlay is voidedCanceled (ExecType=4)
the parlay settlesno report — settlement is outside this interface

New and Trade arrive together because your leg has no separate accepted-but-unfilled state at the venue: recording your acceptance is also the trade.

12.7 Order Status for a parlay

OrderStatusRequest(H) is supported for parlay orders. Query by OrderID(37) — the parlay order id from the prompt. Querying by ClOrdID will not work, since a parlay has none of yours.

12.8 Not supported for parlays

NOT SUPPORTEDBEHAVIOUR
Cancel (35=F)refused as OrderCancelReject (9), CxlRejResponseTo=1, carrying the order's current status. The venue has no cancel route for a parlay
Replace (35=G)refused as OrderCancelReject (9), CxlRejResponseTo=2
Taking parlaysquoting only; see the scope note above
Several price sets on one acceptanceonly one set of leg probabilities is expressible
Per-leg prices on a ladderlegs on a MassQuote carry line ids only, not prices
MassQuoteAcknowledgement (35=b)not sent; an accepted ladder is silent and a refused one is a 35=j

13. Drop Copy Sessions

A drop copy session is a separate, outbound-only FIX session that receives a real-time copy of the ExecutionReport stream generated by one of your order-entry sessions — typically used by a back office, risk, or clearing system that needs visibility into trading activity without holding order-entry access itself.

13.1 Establishing a drop copy session

A drop copy session is a distinct session set up at onboarding — its own SenderCompID/TargetCompID, connected and authenticated exactly like an order-entry session (§1). It is bound to the same account as the trading desk it mirrors: your back office logs on using the trading desk's own credentials, since ProphetX does not currently offer a separate identity for a drop copy connection. Which order-entry session it mirrors is configured as a subscription at onboarding; raise this with ProphetX integration support alongside your order-entry session details.

A single trading session's flow can be sharded across a fleet of several drop copy sessions for scale. Raise expected volume with integration support if you need this.

13.2 What a drop copy session can do

Nothing, inbound. A drop copy session is receive-only: any application message you send on it — an order, a cancel, a status request, anything — is refused with BusinessMessageReject (35=j), BusinessRejectReason(380)=6 (Not Authorized). Use it only to receive; place, cancel, and query orders on the trading session itself. Session-level messages (Logon, Heartbeat, TestRequest, ResendRequest, Logout) work normally.

13.3 What is mirrored

MIRROREDNOT MIRRORED
ExecutionReport (8) — every type, including PendingNew and RejectedExecutionReport with ExecType=I (OrderStatus responses)
OrderCancelReject (9)BusinessMessageReject (j)
Quote (S)

Only reports produced by activity on this FIX interface are mirrored. An order placed through a channel other than FIX order entry produces no report here to copy — a drop copy session mirrors your FIX order-entry stream, not a complete account activity feed.

13.4 Identifying a copy

Every copied report carries the same ExecID(17) as the report sent to the trading session — reconcile the two streams on ExecID. Two fields identify the copy and attribute it, and are not present on the primary (trading-session) stream:

FIELDTAGVALUE
OnBehalfOfCompID115The TargetCompID of the trading session this report belongs to
Account1The order's sub-account, or the trading session's own account if the order carried none

13.5 Delivery independence

A drop copy session has its own delivery sequence, entirely independent of the trading session it mirrors. If your back-office connection is slow, offline, or backlogged, it never delays or blocks execution reports to your trading session. Reconnecting recovers any backlog the same way an order-entry session does (§1).

14. Rejection reference

Which message answers a rejection depends on where it fails:

SITUATIONANSWERREASON FIELD
New order refused (business)ExecutionReport, ExecType=8OrdRejReason(103)
Cancel / replace refusedOrderCancelReject (35=9)CxlRejReason(102)
Malformed / unroutable / internal failureBusinessMessageReject (35=j)BusinessRejectReason(380)
Structurally invalid messageSession Reject (35=3)SessionRejectReason(373)

BusinessRejectReason (380)

VALUEMEANING
0Other — includes exceeding the per-session rate limit (§1); Text(58) carries the detail
4Application not available — a transient internal/downstream failure; safe to retry
6Not Authorized — e.g. a conflicting Account(1) on cancel/replace (§2), or any application message sent on a drop copy session (§13.2)

OrdRejReason (103)

VALUEMEANING
1Unknown symbol / line
2Exchange closed / market not open
3Order exceeds limit (stake / exposure)
6Duplicate order (reused ClOrdID with different economics)
13Incorrect quantity (below min / above max stake)
15Unknown account (tag 1 missing or not authorized)
18Invalid price increment (e.g. non-integer American odds)
99Other — see Text(58)

Duplicate handling. Reusing a ClOrdID with identical economics is treated as a benign redelivery and re-acknowledged idempotently (the original ExecID repeats, so it dedups). Reusing one with different economics is rejected as a duplicate (OrdRejReason=6).

15. Not supported

Parlay-specific exclusions are in §12.8.

  • Sell orders — Side must be Buy.
  • TimeInForce other than GTC or FOK — Day and IOC are rejected.
  • Non-integer American odds — a price that does not convert to an exact integer is rejected, never rounded.
  • Market-order replace — only limit orders may be replaced.
  • Price on a market order — market orders act on a QuoteID, not an explicit price.

ProphetX FIX Order Entry — Market Maker Specification. Generated from the fix-engine implementation, 2026-07; §2 corrected 2026-08 to match the Account(1) cancel/replace behavior landed that month; 2026-08-18: re-verified against the current implementation end to end, added §13 Drop Copy Sessions, corrected §8's ExecType/OrdStatus vocabulary (Expired is reserved but not currently produced) and §11's Quote Request (single-symbol request, one-sided response); 2026-08-27: re-verified against main — added §1's sequence-reset/resend counterparty rules (the scheduled UTC-midnight reset was removed) and per-session rate limiting, and added the §14 BusinessRejectReason(380) value table.

For onboarding details (endpoints, credentials, session CompIDs, and the configured outbound price format) contact ProphetX integration support.


Did this page help you?