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

SettingValue
Hostfix-server.hftfeed.com (a name, so a server move does not break your config; your FIX host needs DNS)
Port9030, or 9031 if your network blocks 9030 (same feed, same login)
TransportPlain 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.com and your-password are 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)NameSent by
ALogonYou, then the server as its answer
0HeartbeatBoth
1TestRequestBoth
2ResendRequestBoth
4SequenceResetBoth
5LogoutBoth
xSecurityListRequestYou
ySecurityListServer
VMarketDataRequestYou
WMarketDataSnapshotFullRefreshServer
YMarketDataRequestRejectServer
3RejectServer

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|
TagValue
98 EncryptMethod0
108 HeartBtIntHeartbeat interval in seconds. The server uses 5 to 60 (values outside are clamped) and 30 when the tag is missing.
141 ResetSeqNumFlagY. 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 UsernameYour hftfeed.com email
554 PasswordYour 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 with MsgSeqNum too low. Messages with 43=Y and 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|
TagMeaning
320 SecurityReqIDYour id, echoed
322 SecurityResponseIDresponse: followed by your id
560 SecurityRequestResult0
146 NoRelatedSymNumber of symbols. Each symbol then repeats the three tags below.
55 SymbolSymbol 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.

TagValue
262 MDReqIDYour id. The server echoes it in snapshots and rejects.
263 SubscriptionRequestType1 subscribe, 2 unsubscribe, 0 one snapshot
264 MarketDepth1. The feed is top of book.
267 NoMDEntryTypes, 269 MDEntryType267=2 followed by 269=0 and 269=1. The server always sends both bid and ask.
146 NoRelatedSymNumber of symbols that follow
55 SymbolRepeated 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|
TagMeaning
262 MDReqIDThe MDReqID of the request that subscribed the symbol
55 SymbolSymbol key (numeric), even if you subscribed by name
268 NoMDEntries2. Each entry repeats the tags below.
269 MDEntryType0 bid, 1 ask
270 MDEntryPxPrice, printed with exactly the symbol's number of decimals (tag 1008)
271 MDEntrySizeSize as reported by the upstream source, up to 8 decimals without trailing zeros. Present only when greater than zero.
272 MDEntryDateUTC date, yyyyMMdd
273 MDEntryTimeUTC 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>0The symbol is not in the symbol list.
Too many subscriptions4The session already has 64 subscriptions.
Unsupported SubscriptionRequestType4263 was not 0, 1 or 2.
No symbols4The request contained no Symbol (55).
No data for <value>not sentSnapshot 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
99Rate limitedYou sent more than 50 messages in one second; the message was dropped.
11Unsupported message typeThe server does not handle this MsgType.
11Already logged onA Logon was sent on a live session.

RefSeqNum (45) and RefMsgType (372) identify the refused message.

Limits

LimitValueWhen exceeded
Live sessions per account1, across both portsLogout too many sessions
Subscriptions per session64Reject Too many subscriptions
Messages you send per second50Reject Rate limited; Logout message rate limit after three such seconds within a minute
Time from connecting to Logon5 secondsConnection closed
Largest message you can send4,096 bytesConnection closed
Malformed messages (bad length or checksum)3 per sessionConnection closed
Silence from you2 heartbeat intervalsConnection closed
Slow readingQueue full for 10 secondsLogout slow consumer
New connections per IP address6 per minuteConnection closed without an answer
Failed logonsA few in a short time; 10 per hourAccount 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 disconnectedAnswer to your own Logout
Invalid credentials: Authentication failedWrong email or password, a Logon without 553 or 554, or an account temporarily locked after failed logons
Invalid credentials: senderCompId mismatchSenderCompID (49) is not the one assigned to the account
Invalid credentials: no subscriptionThe account has no plan
Invalid credentials: subscription expiredThe plan has ended
Invalid credentials: subscription not activeThe 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 sessionsThe account already has a live session
capacityThe server is at its connection limit (sent right after you connect)
drainingThe server is not accepting new sessions during maintenance (sent right after you connect)
subscription expired, renew at hftfeed.comThe plan ended during the session
access revokedAccess was removed during the session
slow consumerThe client did not read fast enough
message rate limitToo many messages per second, repeatedly
MsgSeqNum too lowMsgSeqNum lower than expected without PossDupFlag
kicked by adminHFTFeed 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.40 is 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 NoRelatedSym group of SecurityList.

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.