FIX Protocol
The FIX 4.4 messages, fields and session rules you need to connect your own FIX client to HFTFeed.
Introduction
HFTFeed streams market data over FIX 4.4, the industry-standard tag=value protocol, on a plain TCP connection. Use this page if you write your own FIX client or use a FIX engine such as QuickFIX. If you work in .NET, the .NET SDK does all of this for you.
A session lets you:
- log on with your hftfeed.com email and password and keep the session alive with heartbeats;
- download the symbol list, with each symbol's key, name and number of decimals;
- subscribe and unsubscribe symbols at any time, or ask for a single snapshot;
- receive prices: a full top-of-book snapshot (best bid and best ask) for one symbol per message.
The feed is market data only; it does not accept orders.
Connection details
| Setting | Value |
|---|---|
| Host | fix-server.hftfeed.com (a name, so a server move does not break your config; your FIX host needs DNS) |
| Port | 9030, or 9031 if your network blocks 9030 (same feed, same login) |
| Transport | Plain TCP, no TLS |
| BeginString (8) | FIX.4.4 |
| SenderCompID (49) | The Quote Sender Comp ID on your Connection page |
| TargetCompID (56) | FixServer |
| SenderSubID (50) and TargetSubID (57) | QUOTE |
| Username (553) | Your hftfeed.com email |
| Password (554) | Your hftfeed.com password |
| HeartBtInt (108) | 5 to 60 seconds; 30 is a good default |
Your own FIX client needs one outbound connection: TCP to the host and port above. Nothing else is required, and no Google or web endpoint has to be reachable from your FIX host (our .NET SDK makes one extra HTTPS call only to look up your Sender Comp ID for you).
You need an active plan. The SenderCompID must be the one assigned to your account; any other value is refused with
Invalid credentials: senderCompId mismatch. The server checks the Username (553) and Password (554) you send against
your hftfeed.com account at logon and re-checks the plan every 60 seconds, so a removed plan ends the session within a
minute with Logout text access revoked. Because the connection is not encrypted, use a password that you don't use
anywhere else. One account can have one live session at a time, across both ports.
Message format
- In the examples,
|stands for the SOH character (0x01). - The examples are complete messages with a correct BodyLength (9) and CheckSum (10), so you can use them to test your
encoder.
C1234,you@example.comandyour-passwordare placeholders; all times are UTC. - The server writes header fields in this order: 8, 9, 35, 34, 49, 50, 52, 56, 57. SendingTime (52) has the format
yyyyMMdd-HH:mm:ss.fff. - The server copies your SenderSubID (50) into its TargetSubID (57). If you don't send 50, the server leaves 57 out.
| MsgType (35) | Name | Sent by |
|---|---|---|
A | Logon | You, then the server as its answer |
0 | Heartbeat | Both |
1 | TestRequest | Both |
2 | ResendRequest | Both |
4 | SequenceReset | Both |
5 | Logout | Both |
x | SecurityListRequest | You |
y | SecurityList | Server |
V | MarketDataRequest | You |
W | MarketDataSnapshotFullRefresh | Server |
Y | MarketDataRequestReject | Server |
3 | Reject | Server |
Any other message type from you is answered with a Reject (373=11, 58=Unsupported message type).
Session
Logon
Send a Logon as your first message, within 5 seconds of connecting. Any other first message, or none, closes the connection.
8=FIX.4.4|9=131|35=A|34=1|49=C1234|50=QUOTE|52=20260916-09:30:00.000|56=FixServer|57=QUOTE|98=0|108=30|141=Y|553=you@example.com|554=your-password|10=126|
| Tag | Value |
|---|---|
| 98 EncryptMethod | 0 |
| 108 HeartBtInt | Heartbeat interval in seconds. The server uses 5 to 60 (values outside are clamped) and 30 when the tag is missing. |
| 141 ResetSeqNumFlag | Y. The server resets sequence numbers at every logon: your Logon is 1 and your next message is 2; the server's Logon answer is 1. |
| 553 Username | Your hftfeed.com email |
| 554 Password | Your hftfeed.com password |
The server checks your login, your plan and your SenderCompID, then answers with its own Logon:
8=FIX.4.4|9=93|35=A|34=1|49=FixServer|50=QUOTE|52=20260916-09:30:00.048|56=C1234|57=QUOTE|98=0|108=30|141=Y|10=069|
If it refuses, it sends a Logout with the reason and closes the connection:
8=FIX.4.4|9=96|35=5|34=1|49=FixServer|50=QUOTE|52=20260916-09:30:00.049|56=C1234|57=QUOTE|58=too many sessions|10=096|
A second Logon on a live session is answered with a Reject (58=Already logged on).
Heartbeats and test requests
Send a Heartbeat whenever you have sent nothing for HeartBtInt seconds:
8=FIX.4.4|9=75|35=0|34=6|49=C1234|50=QUOTE|52=20260916-09:30:30.000|56=FixServer|57=QUOTE|10=234|
The server sends a Heartbeat when it has sent nothing for HeartBtInt seconds. When it has heard nothing from you for 1.2 intervals, it sends a TestRequest:
8=FIX.4.4|9=85|35=1|34=7|49=FixServer|50=QUOTE|52=20260916-09:30:36.000|56=C1234|57=QUOTE|112=TEST1|10=054|
Answer it with a Heartbeat that echoes TestReqID (112):
8=FIX.4.4|9=85|35=0|34=7|49=C1234|50=QUOTE|52=20260916-09:30:36.001|56=FixServer|57=QUOTE|112=TEST1|10=054|
After 2 intervals without any message from you, the server closes the connection without a Logout. You can send a TestRequest too; the server answers with a Heartbeat that echoes your 112.
Sequence numbers
- Increase MsgSeqNum (34) by one for every message you send.
- If your number is higher than the server expected, the server still processes the message and sends a ResendRequest for the missing range. You don't need to resend anything.
8=FIX.4.4|9=84|35=2|34=8|49=FixServer|50=QUOTE|52=20260916-09:30:40.000|56=C1234|57=QUOTE|7=6|16=0|10=111|
- If your number is lower than expected and PossDupFlag (43) is not
Y, the server logs you out withMsgSeqNum too low. Messages with43=Yand a low number are ignored. - If you send a ResendRequest, the server does not replay old messages. It answers with a SequenceReset-GapFill that moves your expected number past its current one:
8=FIX.4.4|9=87|35=4|34=9|49=FixServer|50=QUOTE|52=20260916-09:30:41.000|56=C1234|57=QUOTE|123=Y|36=10|10=043|
Logout
Send a Logout to end the session:
8=FIX.4.4|9=75|35=5|34=8|49=C1234|50=QUOTE|52=20260916-09:30:59.000|56=FixServer|57=QUOTE|10=252|
The server answers and closes the connection:
8=FIX.4.4|9=100|35=5|34=10|49=FixServer|50=QUOTE|52=20260916-09:30:59.001|56=C1234|57=QUOTE|58=Session disconnected|10=237|
Symbol list
Request the list with a SecurityListRequest. SecurityReqID (320) is your own id; SecurityListRequestType (559) is 0.
8=FIX.4.4|9=87|35=x|34=2|49=C1234|50=QUOTE|52=20260916-09:30:00.050|56=FixServer|57=QUOTE|320=2|559=0|10=073|
The server answers with one SecurityList that contains every symbol it publishes. This example is shortened to two symbols:
8=FIX.4.4|9=162|35=y|34=2|49=FixServer|50=QUOTE|52=20260916-09:30:00.051|56=C1234|57=QUOTE|320=2|322=response:2|560=0|146=2|55=1013|1007=EURUSD|1008=5|55=2001|1007=XAUUSD|1008=2|10=051|
| Tag | Meaning |
|---|---|
| 320 SecurityReqID | Your id, echoed |
| 322 SecurityResponseID | response: followed by your id |
| 560 SecurityRequestResult | 0 |
| 146 NoRelatedSym | Number of symbols. Each symbol then repeats the three tags below. |
| 55 Symbol | Symbol key: the numeric id that snapshots carry |
| 1007 (custom) | Symbol name, for example EURUSD |
| 1008 (custom) | Number of decimals in the symbol's prices |
You can request the list again at any time, for example after reconnecting.
Market data
MarketDataRequest
One MarketDataRequest subscribes, unsubscribes or asks for a snapshot, for one or more symbols.
| Tag | Value |
|---|---|
| 262 MDReqID | Your id. The server echoes it in snapshots and rejects. |
| 263 SubscriptionRequestType | 1 subscribe, 2 unsubscribe, 0 one snapshot |
| 264 MarketDepth | 1. The feed is top of book. |
| 267 NoMDEntryTypes, 269 MDEntryType | 267=2 followed by 269=0 and 269=1. The server always sends both bid and ask. |
| 146 NoRelatedSym | Number of symbols that follow |
| 55 Symbol | Repeated once per symbol: the symbol key, or the exact (case-sensitive) symbol name |
Subscribe to one symbol:
8=FIX.4.4|9=125|35=V|34=3|49=C1234|50=QUOTE|52=20260916-09:30:00.060|56=FixServer|57=QUOTE|262=3|263=1|264=1|267=2|269=0|269=1|146=1|55=1013|10=001|
Subscribe to several symbols:
8=FIX.4.4|9=133|35=V|34=3|49=C1234|50=QUOTE|52=20260916-09:30:00.060|56=FixServer|57=QUOTE|262=3|263=1|264=1|267=2|269=0|269=1|146=2|55=1013|55=2001|10=108|
Subscribe by name (snapshots still carry the numeric key):
8=FIX.4.4|9=127|35=V|34=3|49=C1234|50=QUOTE|52=20260916-09:30:00.060|56=FixServer|57=QUOTE|262=3|263=1|264=1|267=2|269=0|269=1|146=1|55=EURUSD|10=022|
Unsubscribe from one symbol, or from several:
8=FIX.4.4|9=125|35=V|34=4|49=C1234|50=QUOTE|52=20260916-09:30:05.000|56=FixServer|57=QUOTE|262=4|263=2|264=1|267=2|269=0|269=1|146=1|55=1013|10=003|
8=FIX.4.4|9=133|35=V|34=4|49=C1234|50=QUOTE|52=20260916-09:30:05.000|56=FixServer|57=QUOTE|262=4|263=2|264=1|267=2|269=0|269=1|146=2|55=1013|55=2001|10=110|
Ask for one snapshot with the latest price, without subscribing:
8=FIX.4.4|9=125|35=V|34=5|49=C1234|50=QUOTE|52=20260916-09:30:06.000|56=FixServer|57=QUOTE|262=5|263=0|264=1|267=2|269=0|269=1|146=1|55=1013|10=004|
Good to know:
- The server does not confirm a subscription; snapshots simply start to arrive. Snapshots carry the MDReqID of the request that subscribed the symbol.
- Subscribing to a symbol you already have, or unsubscribing from one you don't, is ignored.
- A session can hold up to 64 subscriptions.
- A snapshot request (
263=0) is answered with one snapshot that carries that request's MDReqID, or with a reject when the server has no price for the symbol yet. - When a request names several symbols, each refused symbol gets its own reject and the others are processed.
MarketDataSnapshotFullRefresh
Every price update is one snapshot for one symbol, with both sides of the book:
8=FIX.4.4|9=191|35=W|34=3|49=FixServer|50=QUOTE|52=20260916-09:30:00.075|56=C1234|57=QUOTE|262=3|55=1013|268=2|269=0|270=1.16428|272=20260916|273=09:30:00.074|269=1|270=1.16431|272=20260916|273=09:30:00.074|10=201|
When the upstream source provides sizes, the entries also carry MDEntrySize (271):
8=FIX.4.4|9=205|35=W|34=4|49=FixServer|50=QUOTE|52=20260916-09:30:00.081|56=C1234|57=QUOTE|262=3|55=2001|268=2|269=0|270=2650.15|271=1.5|272=20260916|273=09:30:00.080|269=1|270=2650.40|271=2|272=20260916|273=09:30:00.080|10=047|
| Tag | Meaning |
|---|---|
| 262 MDReqID | The MDReqID of the request that subscribed the symbol |
| 55 Symbol | Symbol key (numeric), even if you subscribed by name |
| 268 NoMDEntries | 2. Each entry repeats the tags below. |
| 269 MDEntryType | 0 bid, 1 ask |
| 270 MDEntryPx | Price, printed with exactly the symbol's number of decimals (tag 1008) |
| 271 MDEntrySize | Size as reported by the upstream source, up to 8 decimals without trailing zeros. Present only when greater than zero. |
| 272 MDEntryDate | UTC date, yyyyMMdd |
| 273 MDEntryTime | UTC time, HH:mm:ss.fff: the source's timestamp when it provides one, otherwise the time HFTFeed's server received the price. 272 and 273 are left out when no time is known. |
The server never sends incremental refreshes (35=X); every snapshot replaces the previous one. Keep reading the socket
continuously: if your client falls behind, the server merges queued updates so you get the latest price per symbol, and if
your session's queue stays full for 10 seconds it logs you out with slow consumer.
MarketDataRequestReject
8=FIX.4.4|9=110|35=Y|34=5|49=FixServer|50=QUOTE|52=20260916-09:30:06.001|56=C1234|57=QUOTE|262=5|281=0|58=Unknown symbol 9999|10=167|
8=FIX.4.4|9=113|35=Y|34=5|49=FixServer|50=QUOTE|52=20260916-09:30:06.001|56=C1234|57=QUOTE|262=5|281=4|58=Too many subscriptions|10=195|
8=FIX.4.4|9=101|35=Y|34=5|49=FixServer|50=QUOTE|52=20260916-09:30:06.001|56=C1234|57=QUOTE|262=5|58=No data for 1013|10=183|
| Text (58) | MDReqRejReason (281) | Meaning |
|---|---|---|
Unknown symbol <value> | 0 | The symbol is not in the symbol list. |
Too many subscriptions | 4 | The session already has 64 subscriptions. |
Unsupported SubscriptionRequestType | 4 | 263 was not 0, 1 or 2. |
No symbols | 4 | The request contained no Symbol (55). |
No data for <value> | not sent | Snapshot request for a symbol that has no price yet. |
Reject
The server refuses a message it won't process with a session-level Reject:
8=FIX.4.4|9=110|35=3|34=6|49=FixServer|50=QUOTE|52=20260916-09:30:07.000|56=C1234|57=QUOTE|45=57|372=V|373=99|58=Rate limited|10=230|
| SessionRejectReason (373) | Text (58) | Meaning |
|---|---|---|
99 | Rate limited | You sent more than 50 messages in one second; the message was dropped. |
11 | Unsupported message type | The server does not handle this MsgType. |
11 | Already logged on | A Logon was sent on a live session. |
RefSeqNum (45) and RefMsgType (372) identify the refused message.
Limits
| Limit | Value | When exceeded |
|---|---|---|
| Live sessions per account | 1, across both ports | Logout too many sessions |
| Subscriptions per session | 64 | Reject Too many subscriptions |
| Messages you send per second | 50 | Reject Rate limited; Logout message rate limit after three such seconds within a minute |
| Time from connecting to Logon | 5 seconds | Connection closed |
| Largest message you can send | 4,096 bytes | Connection closed |
| Malformed messages (bad length or checksum) | 3 per session | Connection closed |
| Silence from you | 2 heartbeat intervals | Connection closed |
| Slow reading | Queue full for 10 seconds | Logout slow consumer |
| New connections per IP address | 6 per minute | Connection closed without an answer |
| Failed logons | A few in a short time; 10 per hour | Account and IP address blocked for 5 minutes, longer if failures continue; 10 failures in an hour lock the account for 15 minutes |
Connections closed without an answer, and repeated violations of these limits, count against your IP address and can block it for a while. Don't retry in a tight loop. HFTFeed may adjust the limits; the reason text tells you which one you reached.
Logout reasons
The server puts its reason in Text (58). The .NET SDK reference explains what to do about each one.
| Text (58) | Meaning |
|---|---|
Session disconnected | Answer to your own Logout |
Invalid credentials: Authentication failed | Wrong email or password, a Logon without 553 or 554, or an account temporarily locked after failed logons |
Invalid credentials: senderCompId mismatch | SenderCompID (49) is not the one assigned to the account |
Invalid credentials: no subscription | The account has no plan |
Invalid credentials: subscription expired | The plan has ended |
Invalid credentials: subscription not active | The plan is not active |
Invalid credentials: Authentication timeout, Invalid credentials: Authentication error… | The server could not verify the login; try again after a pause |
too many sessions | The account already has a live session |
capacity | The server is at its connection limit (sent right after you connect) |
draining | The server is not accepting new sessions during maintenance (sent right after you connect) |
subscription expired, renew at hftfeed.com | The plan ended during the session |
access revoked | Access was removed during the session |
slow consumer | The client did not read fast enough |
message rate limit | Too many messages per second, repeatedly |
MsgSeqNum too low | MsgSeqNum lower than expected without PossDupFlag |
kicked by admin | HFTFeed closed the session |
Tips
- A FIX viewer such as fixparser.targetcompid.com makes raw messages easier to read.
- Map Symbol (55) in snapshots to names with the SecurityList; don't hard-code keys.
- Parse prices as numbers. They always carry the symbol's number of decimals, so
2650.40is a normal value. - You can subscribe to many symbols in one message; the server still sends one snapshot per symbol.
- Stop reading only when you close the connection.
QuickFIX users: data dictionary
HFTFeed's SecurityList (35=y) repeats a group with the custom tags 1007 and 1008. Snapshots (35=W) use standard
tags only. QuickFIX/n and QuickFIX/J need a data dictionary that knows those two tags: without one
(UseDataDictionary=N) or with the stock FIX44.xml, QuickFIX answers the SecurityList with
Reject 373=13 "Tag appears more than once".
Copy the stock FIX44.xml and extend it:
- add the fields 1007 (STRING) and 1008 (INT);
- add 1007 and 1008 to the
NoRelatedSymgroup ofSecurityList.
Nothing has to be added for MarketDataSnapshotFullRefresh: a stock FIX44.xml accepts every snapshot we send.
Point DataDictionary at your copy and keep UseDataDictionary=Y. Also set ResetOnLogon=Y (the server resets sequence
numbers at every logon), SenderSubID=QUOTE and TargetSubID=QUOTE, and add Username (553) and Password (554) to the
outgoing Logon in your application's ToAdmin callback. With this setup, QuickFIX/n with its strict default validation
accepts every message the server sends.
Changes on 24 September 2026
Two custom tags were withdrawn: 1009 (in SecurityList) and 1010 (in every snapshot). Both named the upstream venue behind a price, which is not part of the product. Nothing else about the layout changed, and no standard tag moved.
If your data dictionary declares 1009 or 1010, leave it as it is — declaring a tag the server no longer sends is harmless. If your application read either tag, it will now see no value; treat that as permanent.
Changes on 11 September 2026
Since 11 September 2026 both ports are served by our second-generation FIX server. Your login, your SenderCompID, the symbol keys and the message layout did not change. Additions:
- the Logon answer carries
141=Y; - snapshots echo your MDReqID (262) and carry 271, 272 and 273 when known;
- prices are printed with exactly the symbol's number of decimals.
fix-server.hftfeed.com points at the feed again. It was unreachable between 11 and 17 September 2026, and clients
configured with it could not connect during those six days; it has had its own DNS record since. Configure the name,
not an address: the address behind it can change, the name will not.