.NET SDK reference
Every public member of HFTFeed.Client 1.1.2, the threads your callbacks run on, errors, server logout reasons, limits and troubleshooting.
This page describes version 1.1.2 of HFTFeed.Client. For a step-by-step introduction, start with
Connect with the .NET SDK.
Package
| Item | Value |
|---|---|
| Package id | HFTFeed.Client |
| Version | 1.1.2 |
| Target frameworks | net10.0 and net8.0 (usable from .NET 8 and later; .NET 9 uses the net8.0 build) |
| Dependencies | None |
| Namespace | HFTFeed.Client |
| Public types | HFTFeedClient, HFTFeedSymbol, Md, ConnectionStatus, HFTFeedException, HFTFeedAuthException, HFTFeedLogoutException, HFTFeedThrottledException, HFTFeedTimeoutException |
The assembly also contains public types in the HFTfeed.Fix2.Codec namespace. They are internal building blocks of the
SDK, not part of its supported API, and can change in any release.
HFTFeedClient
public sealed class HFTFeedClient : IDisposable
Constructors
| Constructor | Endpoint |
|---|---|
HFTFeedClient(string email, string password) | fix-server.hftfeed.com, port 9030 |
HFTFeedClient(string email, string password, bool useAlternatePort) | Port 9031 when useAlternatePort is true, otherwise 9030 |
HFTFeedClient(string email, string password, string host, int port) | The host and port you pass |
email and password are your hftfeed.com login. The constructors throw ArgumentNullException when email or
password is null, or host is null or blank. Nothing connects until you call Start.
The default endpoint is also available as constants: HFTFeedClient.DefaultHost ("fix-server.hftfeed.com", a name
since 1.1.2 — 1.1.0 and 1.1.1 held an address), HFTFeedClient.DefaultPort (9030) and
HFTFeedClient.AlternatePort (9031). The host is resolved on every connect, so the machine needs DNS, and a move of
the feed to another address needs no new SDK.
Methods
| Method | What it does |
|---|---|
void Start() | Signs in over HTTPS, connects, logs on and loads the symbol list. Blocks until all of that is done, or throws. Throws HFTFeedThrottledException without connecting when no connection attempt is left. |
Task StartAsync(CancellationToken cancellationToken = default) | The same, asynchronously. |
void Start(string clientId), Task StartAsync(string clientId, CancellationToken cancellationToken = default) | Connects with the SenderCompID you pass (the Quote Sender Comp ID on your Connection page) and skips the HTTPS sign-in. The server still checks your email, password and plan, and that the SenderCompID belongs to your account. Throws ArgumentNullException for a null or empty clientId. |
void Stop() | Sends a FIX Logout, closes the connection, sets DISCONNECTED, stops automatic reconnects and clears the subscription list. Safe to call more than once, and before Start. |
Task StopAsync() | Runs Stop() on a thread-pool thread. |
void Dispose() | Calls Stop() and marks the client as disposed. Starting a disposed client throws ObjectDisposedException. |
HFTFeedSymbol[] GetSymbols() | The symbol list from the last logon. Empty before the first successful Start. |
void Subscribe(string symbolKey) | Starts streaming one symbol. |
void Unsubscribe(string symbolKey) | Stops streaming one symbol. Does nothing for null. |
void SubscribeAll() | Subscribes, in one request, to every symbol from GetSymbols() that isn't subscribed yet. |
void UnsubscribeAll() | Cancels every subscription in one request. |
void RequestSnapshot(string symbolKey) | Asks for one tick with the latest price, delivered on OnNewTick. Does not subscribe. |
Don't call Start on a client that is already connected, and don't call Start, Stop or Dispose from inside a
callback.
Properties
| Property | Type | Description |
|---|---|---|
ConnectionStatus | ConnectionStatus | CONNECTED or DISCONNECTED. Read-only. |
Connected, IsConnected | bool | true while the status is CONNECTED. |
AutoReconnect | bool | Reconnect after an unexpected drop. Default false. See Automatic reconnect. |
HeartbeatSeconds | int | FIX heartbeat interval sent at logon. Default 30. Set it before Start; the server accepts 5 to 60. |
ReuseTickObject | bool | Pass the same Md instance to every OnNewTick call. Default false. See Receiving without allocations. |
BusyPollMicroseconds | int | New in 1.1.1. Opt-in low-latency receive: how many microseconds the receive thread keeps checking the socket after it runs dry, before it waits in the kernel. Keeps one CPU core busy while the feed is active. Default 0 (off). Set it before Start; typical values 1,000 to 50,000. Negative values throw ArgumentOutOfRangeException. See Performance and latency. |
ReceiveBufferSize | int | New in 1.1.1. Kernel receive buffer (SO_RCVBUF) of the feed connection, in bytes. Default 0 keeps the operating system's default. Set it before Start. Negative values throw ArgumentOutOfRangeException. |
TPS | long | Ticks received in the last second. |
TPM | long | Ticks received in the last minute. |
SubscribedSymbolsCount | int | Number of symbols the client considers subscribed. |
Host, Port | string, int | The endpoint this client connects to. |
ClientId | string | The SenderCompID in use. Empty until Start. |
Events
The events are properties of delegate type. Assign a handler with =, or combine handlers with += and -=.
| Event | Argument | Raised when | Thread |
|---|---|---|---|
OnNewTick | Md | A tick arrives. | The receive thread. |
OnConnectionStatus | ConnectionStatus | The status changes. | CONNECTED: the thread that finished connecting (a thread-pool thread, or the reconnect thread). DISCONNECTED: the receive thread, or the thread that called Stop. |
OnSubscribe | string | A subscribe method ran. See Notices. | The thread that called the method; the reconnect thread for Resubscribed. |
OnUnsubscribe | string | An unsubscribe method ran. | The thread that called the method. |
OnError | Exception | The client hit a problem it handled itself. See Reported on OnError. | Whichever thread hit it. |
OnFixMsg | string | Any FIX message is received or sent. Diagnostics only. | The receive thread for incoming messages; the sending thread for outgoing ones. |
Connection lifecycle
What Start does
| Step | Time limit | When it fails |
|---|---|---|
1. Sign in over HTTPS to identitytoolkit.googleapis.com and read the account's SenderCompID and plan. Skipped by Start(clientId). | 20 s | HFTFeedAuthException; OperationCanceledException on timeout |
2. Reserve one of the connections allowed for Host (given back if the connection is not established), then open a TCP connection to Host:Port. | 10 s | HFTFeedThrottledException when no attempt is left (nothing is sent); HFTFeedTimeoutException (Could not connect to …); SocketException when the connection is refused or the network is unreachable |
| 3. Send the FIX Logon and wait for the answer. | 10 s | HFTFeedLogoutException with the server's reason; HFTFeedTimeoutException (Logon did not complete …); HFTFeedException (… closed the connection before the Logon completed …) when the server closes the connection |
| 4. Request the symbol list and wait for it. | 10 s | HFTFeedTimeoutException (SecurityList did not complete …); HFTFeedException when the server closes the connection |
Start() also checks for a free connection attempt before step 1, so a refused call doesn't sign in either. Then the status
becomes CONNECTED and OnConnectionStatus fires. A Logout received during these steps is also passed to OnError. A
Start that throws has already closed its connection and never starts automatic reconnects; you can call Start again.
Stop() from another thread ends a Start in progress, which then throws OperationCanceledException.
Stop and Dispose
Stop() sends a Logout if the connection is open, closes the socket without waiting for the server's reply, sets
DISCONNECTED, cancels automatic reconnects (including an attempt or a wait in progress) and clears the list of subscribed
symbols. Dispose() calls Stop(); it never throws and is safe to call more than once.
Connecting again after Stop
A stopped client can be started again with Start; a disposed one can't. SubscribedSymbolsCount is 0 after Stop(),
and the next Start subscribes to nothing, so call Subscribe or SubscribeAll again once Start has returned. The
symbol list is loaded again at every logon.
Automatic reconnect
With AutoReconnect = true, the client reconnects when the connection closes unexpectedly: a network failure, a server
restart, a heartbeat timeout or any other disconnect that came without a Logout. It waits a random time before each
attempt:
| Attempt | Wait before the attempt |
|---|---|
| 1 | 1 to 2 s |
| 2 | 2 to 4 s |
| 3 | 4 to 8 s |
| 4 | 8 to 16 s |
| 5 and later | 15 to 30 s |
After that wait, an attempt also waits until the connection limit allows another connection.
Each attempt repeats steps 2 to 4 of Start with the SenderCompID from your first Start; it does not repeat the HTTPS
sign-in, but the server checks your login and plan on every logon. After a successful attempt the client raises
OnConnectionStatus(CONNECTED), then subscribes again to every symbol it had subscribed, in one request, and raises
OnSubscribe with Resubscribed: <n> symbols. Failed attempts are reported on OnError.
The client stops retrying when an attempt succeeds, when you call Stop() or Dispose() (which also end an attempt or a
wait in progress), when you set AutoReconnect to false, or when the server answers an attempt with a Logout. It never
reconnects after the server ended a session with a Logout, and it only reconnects sessions that were established: a
Start that fails throws instead.
Connection attempts
The server accepts at most 6 new connections per minute from one IP address. A connection over that limit is closed at once without an answer and gives the address a strike. One strike expires every 10 minutes; 3 strikes block the address for 5 minutes, 6 for an hour and 9 for a day, and the server closes every connection from a blocked address the same way.
The SDK therefore opens at most 5 connections per host in any 60 seconds. The count is shared by every
HFTFeedClient in the process and covers Start and automatic reconnects alike:
- A connection counts from the moment the client starts to open it, so clients connecting at the same time can't overshoot.
- If the TCP connection is not established (connection refused, host unreachable, connect timeout, or cancelled), the attempt never reached the server and no longer counts.
- An established connection counts for 60 seconds whatever happens next: logon refused, closed by the server, or ended
by
Stop(). A connection that completes after the client stopped waiting for it (after the 10-second connect timeout) is counted when it completes.
| Caller | When 5 connections are already in the window |
|---|---|
Start, StartAsync | Throw HFTFeedThrottledException at once, without connecting. RetryAfter is the time until the next of them is 60 seconds old. |
| Automatic reconnect | Waits until another connection is allowed. Stop() and Dispose() end the wait. |
The count is kept per host name exactly as passed to the constructor (ignoring case), not per port: ports 9030 and 9031 share it. It is not shared between processes, and the server counts everything from your IP address, so several programs on one machine or behind one NAT can still go over the server's limit together.
Heartbeats
- The client sends a Heartbeat when it has sent nothing for
HeartbeatSeconds, and answers every TestRequest from the server at once. - The server sends a Heartbeat when it has sent nothing for the heartbeat interval. When it has heard nothing from you for 1.2 intervals it sends a TestRequest, and after 2 intervals it closes the connection without a Logout.
- The server clamps the interval to 5 to 60 seconds, but the client times its own heartbeats from the value you set. Keep
HeartbeatSecondsin that range. - The client does not time out a silent connection by itself. It notices a drop when the socket closes or a send fails.
Symbols
public class HFTFeedSymbol
| Property | Type | Description |
|---|---|---|
SymbolKey | string | The server's numeric symbol id, as text. Use it for Subscribe, Unsubscribe and RequestSnapshot. Ticks carry it in Md.Symbol. |
SymbolName | string | Instrument name, for example EURUSD. |
Digits | double | Number of decimals in the symbol's prices. |
ToString() returns "<SymbolKey> <SymbolName> (<Digits>)". The list contains the symbols the server currently publishes.
It is loaded at every logon, including automatic reconnects.
Subscriptions
Notices
The subscription methods report their local outcome as text on OnSubscribe or OnUnsubscribe. Only the notices that
say Subscribed or Unsubscribed mean a request was sent.
| Notice | Event | Meaning |
|---|---|---|
Subscribed: <key> | OnSubscribe | The subscribe request was sent. |
Already subscribed: <key> | OnSubscribe | The client already lists this key; nothing was sent. |
Wrong symbol key: <key> | OnSubscribe | The key is not in the symbol list (you may have passed a name). Also raised by RequestSnapshot. Nothing was sent. |
Wrong symbol key: <empty> | OnSubscribe | The key was null or empty. |
No symbols available yet | OnSubscribe | SubscribeAll was called before the symbol list arrived. |
Already subscribed: 0 new symbols | OnSubscribe | SubscribeAll found nothing new to subscribe. |
Subscribed: <n> symbols | OnSubscribe | SubscribeAll sent its request; n is the total number of subscribed symbols. |
Resubscribed: <n> symbols | OnSubscribe | Subscriptions were restored after an automatic reconnect. |
Unsubscribed: <key> | OnUnsubscribe | The unsubscribe request was sent. |
Not subscribed: <key> | OnUnsubscribe | The client doesn't list this key; nothing was sent. |
Unsubscribed: <n> symbols | OnUnsubscribe | UnsubscribeAll removed n symbols (0 when there were none). |
When the client is not connected, the methods send nothing and OnError receives
Not connected: call Start() before subscribing.
Server responses
The server does not confirm a subscription: ticks for the symbol start to arrive. Subscribing to a symbol twice, or
unsubscribing from one you don't have, is ignored. A few ticks that were already on their way can still arrive shortly after
Unsubscribe. When the server refuses a request, OnError receives an HFTFeedException with the message
MarketDataRequest rejected: <reason>:
| Reason | Meaning |
|---|---|
Unknown symbol <key> | The server doesn't publish this symbol (any more). |
Too many subscriptions | The session already has 64 subscriptions. |
No data for <key> | RequestSnapshot: the server has no price for this symbol yet. |
The client still lists a refused symbol as subscribed. To try again, call Unsubscribe(key) and then Subscribe(key).
Request rate
The server accepts at most 50 messages per second from a session, counting everything the client sends. Messages over the
limit are refused, and OnError receives Session-level reject: Rate limited; a refused subscribe request still counts as
subscribed in the client. If a session goes over the limit in three different seconds within one minute, the server ends
it with message rate limit. Use SubscribeAll(), or pace individual Subscribe calls.
Ticks
public class Md
| Property | Type | Description |
|---|---|---|
Symbol | string | Symbol key (not the name). |
Bid | double | Best bid, sent with the symbol's Digits decimals. |
Ask | double | Best ask, sent with the symbol's Digits decimals. |
BidSize | double | Size at the bid as reported by the upstream source; 0 when not provided. |
AskSize | double | Size at the ask as reported by the upstream source; 0 when not provided. |
EntryTimeUtc | DateTime | UTC time of the price with millisecond precision: the source's timestamp when available, otherwise the time HFTFeed's server received the price. DateTime.MinValue when absent, or when the date and time lie beyond DateTime.MaxValue. |
ToString() returns "<Symbol> <Bid>/<Ask>". Every tick carries both sides of the book for one symbol. Ticks arrive in the
order the server sent them. When your application reads slowly, the server merges queued updates for a symbol and sends only
the latest price.
Threading model
- The client reads the network on one background thread per connection and calls
OnNewTickon it, one tick at a time. Nothing else is read while a callback runs. - A slow
OnNewTickbacks up the connection. The server then merges queued updates, and if your session's queue stays full for 10 seconds it ends the session withslow consumer. - Other callbacks run on the threads listed under Events, so two callbacks can run at the same time. Make your handlers thread-safe.
- An exception thrown by a callback is caught and passed to
OnError; the client keeps running. Exceptions thrown byOnErroritself are ignored. - The client's public methods can be called from any thread.
Process ticks off the receive thread shows how to hand ticks to a worker.
Receiving without allocations
With ReuseTickObject = true the client's receive path allocates nothing per tick, including while it waits for data;
the SDK's own tests check this over 100,000 ticks and on a live connection. The symbol key string comes from the symbol list, so it is not allocated either. With the default false,
the only allocation per tick is the new Md. Setting OnFixMsg adds one string per message.
client.ReuseTickObject = true;
client.OnNewTick = tick =>
{
// The same Md instance is passed for every tick: copy the values you need,
// and never keep a reference to it or read it from another thread.
var key = tick.Symbol;
var bid = tick.Bid;
var ask = tick.Ask;
OnQuote(key, bid, ask); // your own method
};
Tick rates
TPS and TPM count the ticks the client received in the last second and the last minute, whether or not OnNewTick is
set. Reading them is cheap and safe from any thread:
using var monitor = new Timer(
_ => Console.WriteLine($"{client.TPS} ticks/s, {client.TPM} ticks/min, {client.SubscribedSymbolsCount} symbols"),
null, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5));
Raw FIX messages
OnFixMsg receives the text of every FIX message the client receives or sends, with the SOH () separators left in
place, and a note when an incoming sequence number is not the expected one. It builds a string for every message, so use it
only while debugging. The outgoing Logon contains your password in tag 554; mask it before you log anything:
client.OnFixMsg = raw =>
{
var start = raw.IndexOf("554=", StringComparison.Ordinal);
if (start >= 0)
{
start += 5;
var end = raw.IndexOf('', start);
raw = raw[..start] + "***" + (end >= 0 ? raw[end..] : "");
}
Console.WriteLine(raw.Replace('', '|'));
};
The FIX protocol reference explains every message you will see.
Exceptions
HFTFeedException derives from Exception. HFTFeedAuthException, HFTFeedLogoutException,
HFTFeedThrottledException and HFTFeedTimeoutException derive from HFTFeedException. HFTFeedLogoutException adds:
Text: the server's reason (FIX tag 58). The exception'sMessageisServer logout:followed byText.IsTooManySessions:truewhenTextcontainstoo many sessions.
HFTFeedThrottledException (new in 1.1.1) adds RetryAfter, a TimeSpan: how long until the next connection attempt is
allowed.
Thrown by Start
| Exception and message | Cause and what to do |
|---|---|
HFTFeedAuthException: Authorization failed: followed by the sign-in service's reason | Wrong email or password, a disabled account, too many sign-in attempts, or the sign-in service could not be reached. Check that you can sign in on hftfeed.com with the same login, and that HTTPS to identitytoolkit.googleapis.com is allowed. |
HFTFeedAuthException: No active HFTFeed subscription. Renew at https://hftfeed.com. | The account has no active plan. Choose one on the pricing page. |
HFTFeedAuthException: HFTFeed subscription expired. Renew at https://hftfeed.com. | The plan has ended. Renew it on the Subscriptions page. |
HFTFeedAuthException: Authorization failed: the account has no senderCompId claim. | No SenderCompID has been assigned to the account yet. Contact support if this persists after you have an active plan. |
HFTFeedAuthException: Authorization failed: no ID token returned. or … malformed ID token. | An unexpected answer from the sign-in service. Try again; contact support if it persists. |
HFTFeedLogoutException: Server logout: <reason> | The server refused the logon. See Server logout reasons. |
HFTFeedTimeoutException: Could not connect to <host>:<port> within 10000 ms. | No TCP connection within 10 seconds, usually a firewall. Allow the port, or use port 9031. |
HFTFeedTimeoutException: Logon did not complete within 10000 ms against <host>:<port>. or SecurityList did not complete … | The server did not answer in time. Try again after a pause. |
HFTFeedThrottledException: Connection attempt to <host> not made: the server allows 6 connection attempts per minute per IP address and bans addresses that exceed it, so this SDK allows 5 per 60 s, and this process has used them. Wait <n> s before calling Start again. | Your process opened (or is opening) 5 connections to this host in the last 60 seconds. Nothing was sent. Wait RetryAfter, then call Start again. See Connection attempts. |
HFTFeedException: <host>:<port> closed the connection before the Logon completed, without a Logout. … (or the SecurityList) | The server closed the connection without an answer: your IP address made more than 6 connection attempts in a minute, or is temporarily blocked. Wait a few minutes before you try again. |
SocketException | The connection was refused or the network is unreachable. |
OperationCanceledException (including TaskCanceledException) | Your cancellation token fired, or the HTTPS sign-in took longer than 20 seconds. |
ObjectDisposedException | The client was disposed. Create a new one. |
Reported on OnError
| Message | Meaning |
|---|---|
Server logout: <reason> (HFTFeedLogoutException) | The server ended the session. See Server logout reasons. |
Not connected: call Start() before subscribing. | A subscription method was called while disconnected. Nothing was sent. |
MarketDataRequest rejected: <reason> | The server refused a subscription or snapshot request. See Server responses. |
Session-level reject: <reason> | The server refused a message, for example Rate limited. |
Not connected: no socket. | A message could not be sent because the connection had already closed. |
Outbound frame did not fit the send buffer; message dropped. | A request was too large to send. |
Garbled frame from server: …, Receive buffer overflow: … | Corrupted data was received and skipped. |
SocketException, ObjectDisposedException, HFTFeedTimeoutException | The connection failed, or a reconnect attempt failed. |
<host>:<port> closed the connection before the Logon completed … | A reconnect attempt was closed by the server without an answer. The client keeps retrying within the connection attempts limit. |
| Any other exception | Thrown by one of your own callbacks. |
Server logout reasons
The server ends or refuses a session with a FIX Logout that carries a reason. The SDK passes it to OnError as an
HFTFeedLogoutException (and throws it from Start during logon). It never reconnects automatically after a Logout.
Reason (Text) | Meaning | What to do |
|---|---|---|
Invalid credentials: Authentication failed | Wrong email or password. Also sent while the account is temporarily locked after repeated failed logons. | Fix the login, then wait a few minutes before trying again. |
Invalid credentials: senderCompId mismatch | The SenderCompID doesn't belong to this account. | Use the Quote Sender Comp ID from the Connection page, or Start() without an argument. |
Invalid credentials: no subscription | The account has no plan. | Choose a plan. |
Invalid credentials: subscription expired | The plan has ended. | Renew it. |
Invalid credentials: subscription not active | The plan is not active. | Check the Subscriptions page. |
Invalid credentials: Authentication timeout | The server could not verify your login in time. | Try again after a short pause. |
Invalid credentials: Authentication error (sometimes followed by more detail) | The server hit an error while verifying your login. | Try again after a short pause; contact support if it persists. |
Invalid credentials: Authentication failed: … (with detail) | Your login could not be verified. | Contact support. |
too many sessions | The account already has a live session, on either port. | Stop the other session. See Handle errors. |
capacity | The server has reached its connection limit. | Try again later. |
draining | The server is not accepting new sessions during maintenance. Existing sessions keep streaming. | Try again in a few minutes. |
subscription expired, renew at hftfeed.com | The plan ended while you were connected. The server checks this every minute. | Renew, then start a new client. |
access revoked | Access was removed, or the account was disabled, while you were connected. | Contact support. |
slow consumer | Your application did not read data fast enough for 10 seconds. | Make OnNewTick faster, then start a new client. |
message rate limit | More than 50 messages per second in three different seconds within one minute. | Pace your requests. |
MsgSeqNum too low | A message arrived with a sequence number lower than expected. | Should not happen with the SDK; contact support. |
kicked by admin | HFTFeed closed the session. | Contact support. |
Session disconnected | The server's reply to your own Logout. | Nothing. |
Disconnects without a logout
In these cases the connection simply closes and the status changes to DISCONNECTED:
- a network failure or a server restart;
- the server heard nothing from the client for two heartbeat intervals;
- the connection broke the protocol rules on the FIX protocol page;
- your IP address opened more than 6 connections in a minute, or is temporarily blocked. The server closes such
connections at once without an answer, so
StartthrowsHFTFeedExceptionwith… closed the connection before the Logon completed …, and a reconnect attempt reports the same onOnError.
AutoReconnect applies only to a session that was established. The first case is the one it is for; the SDK's
connection attempts limit keeps its own retries below the server's limit.
Limits
| Limit | Value | When exceeded |
|---|---|---|
| Live sessions per account | 1, across both ports | Logout too many sessions |
| Subscriptions per session | 64 | MarketDataRequest rejected: Too many subscriptions |
| Messages you send per second | 50 | Session-level reject: Rate limited; Logout message rate limit after three such seconds within a minute |
| New connections per IP address | 6 per minute | Connection closed without an answer, and a strike; 3, 6 or 9 strikes block the address for 5 minutes, an hour or a day, and one strike expires every 10 minutes |
| Connections the SDK opens per host | 5 in any 60 seconds, per process; refused or unanswered attempts don't count | Start throws HFTFeedThrottledException; automatic reconnects wait |
| 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 |
| Heartbeat interval | 5 to 60 seconds | Clamped by the server |
| Silence before the server disconnects | 2 heartbeat intervals | Connection closed without a Logout |
| Slow reading | Queue full for 10 seconds | Logout slow consumer |
HFTFeed may adjust these limits. When you reach one, the reason in the error or Logout tells you which.
Performance and latency
- Run close to the server. The feed server is in the LD4 data center near London, and network distance adds more delay than anything in your process.
- Keep
OnNewTickfast. The client reads the next message only after your callback returns. Copy the values and hand them to a worker. - Avoid garbage. Set
ReuseTickObject = trueand copy values into structs, so the receive path creates no objects per tick and the garbage collector has less to do. - Leave
OnFixMsgunset in production; it creates a string for every message. - Resolve symbols once. Build your key-to-symbol lookup after
Start()instead of searchingGetSymbols()per tick. - Subscribe only to what you use. Every extra symbol is extra data to read and handle.
- TCP is set up for you. The client disables Nagle's algorithm, so requests leave immediately. On Linux and macOS the receive thread waits for data in a plain blocking receive, without allocating.
- Busy polling, if you have a core to spare. With
BusyPollMicrosecondsgreater than 0, the receive thread keeps checking the socket for that many microseconds after it runs dry before it waits in the kernel, so a tick that arrives in that window is read without a thread wake-up. While the feed is active this keeps one CPU core busy. Typical values are 1,000 to 50,000; set it beforeStart. - A larger receive buffer for bursts.
ReceiveBufferSizesets the kernel receive buffer before connecting. It absorbs longer bursts while yourOnNewTickhandler is occasionally slow; it does not lower latency. - Warm up before you measure. .NET compiles code the first time it runs, so the first ticks after start take longer to handle. Measure after a warm-up period, with a Release build.
- Synchronize your clock (NTP or PTP) before you compare
EntryTimeUtcwith local time.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
Could not connect to fix-server.hftfeed.com:9030 … or a SocketException | A firewall or proxy blocks the port, or the name does not resolve. | Allow DNS and outbound TCP to port 9030, or use port 9031 (useAlternatePort: true). |
Authorization failed: … | Wrong login, an account created with Google sign-in that has no password, or no HTTPS access to identitytoolkit.googleapis.com. | Check that you can sign in on hftfeed.com with email and password; add a password under Settings → Profile → Authentication if needed; allow the HTTPS connection. |
No active HFTFeed subscription or subscription expired | No active plan. | Check the Subscriptions page. |
too many sessions | Another program, a second client in the same program, or an earlier run that never called Stop() holds the session. | Stop the other session. After a crash, wait up to two heartbeat intervals (60 seconds by default) and try again. |
Start throws … closed the connection before the Logon completed … | Your IP address is temporarily blocked, or made more than 6 connection attempts in a minute. Other programs and machines behind the same address count too. | Wait at least 5 minutes, fix the cause, and retry more slowly. |
HFTFeedThrottledException: Connection attempt to … not made … | Your process already opened 5 connections to the server in the last 60 seconds, for example from a retry loop or several clients. | Wait RetryAfter, then call Start again. |
| After a drop, reconnecting takes several seconds | Automatic reconnects wait 1 to 2 seconds before the first attempt, longer after each failure, and never exceed the connection-attempt limit. | Nothing to fix; follow OnConnectionStatus and OnError. |
| Connected, but no ticks | No subscription was sent (check OnSubscribe for Wrong symbol key), the server refused it (check OnError), OnNewTick is not set, or the market is closed. | Subscribe with SymbolKey, read both events, and check TPS. |
Ticks show 1013 instead of EURUSD | Md.Symbol is the symbol key. | Map keys to names with GetSymbols(). |
| Some symbols never tick after subscribing to many | Too many subscriptions or Rate limited on OnError. | Stay within 64 symbols, pace your requests, then Unsubscribe and Subscribe the missing keys. |
Logout slow consumer | Your callbacks are too slow. | Hand ticks to a worker queue. |
No ticks after calling Start again on a stopped client | Stop() cleared the subscriptions. | Call Subscribe or SubscribeAll again after Start. |
| A stored tick changes its values | ReuseTickObject is true. | Copy the values inside the callback. |
| Prices print with too few decimals, or with commas | Default double formatting and your culture settings. | Format with "F" + (int)Digits and CultureInfo.InvariantCulture. |
EntryTimeUtc is 0001-01-01 | The message carried no time. | Treat DateTime.MinValue as unknown. |
| A 1.0.x application cannot connect | 1.0.x uses an address that no longer reaches the feed. | Upgrade to 1.1.2. |
Still stuck? Contact support with your SDK version, the time of the problem in UTC, your SenderCompID
(client.ClientId) and the messages OnError reported. Never send your password.