Overview
Reflector contains a monolithic FIX message parser which interprets sequences of bytes and translates them into possible order actions.
It is compatible with all current FIX protocol versions without needing to differentiate them. It handles all current FIX venues (except RBS RFQ) while rarely differentiating them. It performs deserialization, field parsing, order action interpretation, and constraint/error checking all in one go. It preserves all field locations, so that it can write back to arbitrary fields later if necessary. Since this is a real time application, Reflector does all this without touching the heap.
Every Session Type except DATA requires inspection by the FIX Parser: LOGON, PASS_TKR, PASS_MKR, TAKER, MAKER, & COPY.
The messages within each SessionType are separated further by their direction of transit:
- Outbound messages are requests, since the whole objective of this mechanism is to constrain the trader under the weight of risk limits.
- Inbound messages are updates, as the venue is, by definition, a source of truth.
Discipline
Reflector is only allowed to alter the semantics of outbound FIX messages.
When it alters them, it always alters in the direction of voiding an order action (TAKER), voiding an execution (MAKER), or changing passwords (LOGON, PASS_TKR, PASS_MKR). Reflector shall never change the identity of a quote, order, or execution. On inbound FIX messages, the only fields that Reflector is allowed to alter are Text[58] and Checksum[10]. This is predicated on the assumption that text fields have no semantics.
Parser behaviour necessarily varies depending on the
Session Type
Logon
Outbound
On the outbound direction of a session in logon state, the only allowed messages are Logon[A] and Logout[5]. Logon[A] messages are inspected. Logout[5] messages are ignored. If any other message is received, the result is session termination. On an outbound Logon[A] message, a credential is deduced and looked up using the ordered triple { ExchangeCode, COMP_ID, SUB_ID }.
If a credential is not found, or if the credential is disabled, or if any risk pools containing the credential is in a UNPLUGGED state, or if password translation is enabled and password match failed, then the session is terminated. Otherwise, the message passes through.
| Flag | Presence | Field | Type |
|---|---|---|---|
| COMP_ID | Required | SenderCompID[49] | STRING |
| SUB_ID | Optional | SenderSubID[50] | STRING |
| PASSWORD | Optional | Password[554] | STRING |
| NEW_PASSWORD | Optional | NewPassword[925] | STRING |
Password Translation
Password translation is an optional feature where the trader is not provided the venue's FIX logon password. Instead, the trader is provisioned a different password of the same length. On logon, Reflector checks for the fake password. Upon matching, it overwrites the fake password with the real password.
UserRequest[BE]
Inbound
On the inbound direction of a session in logon state, the only allowed messages are Logon[A] and Logout[5]. Logon[A] messages are inspected. Logout[5] messages are ignored. If any other message is received, the result is session termination.
On an inbound Logon[A] message, a credential is deduced and looked up using the ordered triple { ExchangeCode, COMP_ID, SUB_ID }. If a credential is not found, or if the credential is disabled, or if any risk pools containing the credential is in a UNPLUGGED state, the session is terminated. Otherwise, the message passes through, and the session is bound to the credential, inheriting its SessionType.
| Flag | Presence | Field | Type |
|---|---|---|---|
| COMP_ID | Required | SenderCompID[49] | STRING |
| SUB_ID | Optional | SenderSubID[50] | STRING |
Password Change
Outbound
EBS & Reuters have a unique password changing process whereby traders must log in to change passwords with a UserRequest[BE] message. The SessionTypes PASS_TKR & PASS_MKR handle this contingency for PBs who do not wish for their clients to know the real logon passwords:
| Message Name | MsgType[35] | Action | Explanation |
|---|---|---|---|
| Logon | A | Drop session | Outbound risk message with risk implications is banned. |
| NewOrderSingle | D | Drop session | Outbound risk message with risk implications is banned. |
| QuoteResponse | AJ | Drop session | Outbound risk message with risk implications is banned. |
| NewOrderList | E | Drop session | Outbound risk message with risk implications is banned. |
| NewOrderMultileg | AB | Drop session | Outbound risk message with risk implications is banned. |
| ExecutionReport | 8 | Drop session | Outbound risk message with risk implications is banned. |
| ExecutionAcknowledgement | BN | Drop session | Outbound risk message with risk implications is banned. |
| Logout | 5 | Change session type |
|
| everything else | - | Change new password |
|
Inbound
Inbound messages on tcp sessions in password changing mode are completely unscreened with one exception: on detection of Logon[A] message, the stream terminates immediately.
Taker
On an outbound taker stream, potential order actions are inspected.
| Message Name | MsgType[35] | Action | Explanation |
|---|---|---|---|
| Logon | A | Drop session | Trader already logged on |
| ExecutionReport | 8 | Drop session | Maker exec submission |
| NewOrderSingle | D | Inspect | New order submission request |
| QuoteResponse | AJ | Inspect | New order submission request |
| OrderCancelReplaceRequest | G | Inspect | Existing order modication request |
| NewOrderList | E | Overwrite | Not yet implemented |
| NewOrderMultileg | AB | Overwrite | Not yet implemented |
| Quote | S | Overwrite | Illegal |
| MassQuote | i | Overwrite | Illegal |
| OrderMassActionRequest | CA | Inspect | Block unsupported actions |
OrderCancelRequest[F]
Notably missing from this list is OrderCancelRequest[F]. It is omitted because it has no risk implications.
Outbound
NewOrderSingle[D], QuoteResponse[AJ], & OrderCancelReplaceRequest[G]
| Flag | Presence in D | Presence in AJ | Presence in G | Field | Type |
|---|---|---|---|---|---|
| POSS_DUPE | Optional | Optional | Optional | PossDupFlag[43], PossResend[97] | BOOL |
| SEQ_NUM | Required | Required | Required | MsgSeqNum[34] | INT |
| ACCOUNT | Optional | Optional | Optional | Account[1], PartyRole[452], etc | STRING |
| ALLOC_ACCT | BANNED | BANNED | BANNED | AllocAccount[79] | STRING |
| ORD_TYPE | Required | - | Optional | OrdType[40] | ENUM |
| QUOTE_RESP_TYPE | - | Required | - | QuoteRespType[694] | ENUM |
| ORIG_ORDER_ID | - | - | Optional | OrigClOrdID[41] | STRING |
| ORDER_ID | Required | Optional | Required | ClOrdID[11] | STRING |
| QUOTE_RESP_ID | - | Optional | - | QuoteRespID[693] | STRING |
| SYMBOL | Required | Required | Required | Symbol[55], SecurityID[48] | STRING, INT |
| CURRENCY | Optional | Required | Optional | Currency[15] | STRING |
| SIDE | Required | Required | Required | Side[54] | ENUM |
| CONTRACT_MULTIPLIER | Optional | Optional | Optional | ContractMultiplier[231] | FLOAT |
| PRICE | Optional | Optional | Required | Price[44] | FLOAT |
| PRICE | - | Optional | - | BidPx[132], OfferPx[133] | FLOAT |
| PRICE_TWO | BANNED | BANNED | BANNED | Price2[640] | FLOAT |
| PRICE_TWO | - | BANNED | - | BidPx2[. . . ], OfferPx2[. . .] | FLOAT |
| QUANTITY | Required | Optional | Required | OrderQty[38] | FLOAT |
| QUANTITY | - | Optional | - | BidSize[134], BidSize[135] | FLOAT |
| QUANTITY_TWO | BANNED | BANNED | BANNED | OrderQty2[192] | FLOAT |
| QUANTITY_TWO | - | BANNED | - | BidSize2[. . . ], BidSize2[. . . ] | FLOAT |
| SETTLE_DATE | Optional | Optional | Optional | SettlDate[64] | DATE |
| SETTLE_DATE_TWO | BANNED | BANNED | BANNED | SettlDate2[193] | DATE |
| NUM_LEGS | Optional | Optional | Optional | NoLegs[555] | INT |
Processing Sequence
On an outbound risk-carrying Taker message, the parser acts as if the following events occur in sequence:
- Attributes are read in.
- Venue-specific patches are applied.
- Unsupported features: If any of the following conditions hold, the order action will be blocked. Unless specified, the stated reason for rejection will be serialized as (Z_UNSUPPORTED):
- If OrdType[40] has value FOREX_SWAP[G]
- If any of these fields are present: Price2[640], OrderQty2[192], SettlDate2[193], AllocAccount[79]
- If Symbol[55] (SecurityID[48] in LMAX44) did not resolve to a valid currency pair (Z_PRODUCT_UNKNOWN)
- If NoLegs[555] is present and contains any nonzero value
- Sanity: If any of the following conditions hold, the order action will be blocked. Unless specified, the stated reason for rejection will be serialized as (Z_NON_CONFORMING):
- If PossDupFlag[43] or PossResend[97] is present and has value Y
- If any of the required fields are missing
- If account resolution failed on a credential with multiple overloaded accounts set up (Z_ACCOUNT_UNKNOWN)
- For non-market orders, if Price[44] is missing or more than a factor of 2 outside of reference rate (Z_PRICE_RANGE)
- If OrderQty[38] did not contain a positive scalar amount (Z_QUANTITY_RANGE)
- If Currency[15] is missing on an order referencing a quote (Z_DEALT_CCY_UNKNOWN)
- If Currency[15] is present but did not refer to either of the currencies in the symbol (Z_DEALT_CCY_UNKNOWN)
- For Spot orders, if a settle date cannot be computed for the state symbol (Z_SETTLE_DATE_UNKNOWN)
- For non-Spot orders, if settle date computation failed sanity checks (Z_SETTLE_DATE_UNKNOWN)
- If Side[54] contained a value other than BUY[1] or SELL[2]
- A speculative order state is constructed.
Order state is sent to the Risk Instance for assessment. On failure, order action will be blocked with whichever reason it provides.