HFTFeed.Client 1.1.1: faster ticks, safer reconnects

HFTFeed.Client 1.1.1 decodes ticks about 2.5x faster, receives without allocating on Linux and macOS, ships a .NET 10 build, paces its reconnects so your IP address never gets banned, and fixes restarting a stopped client.

·5 min read
Cover Image for HFTFeed.Client 1.1.1: faster ticks, safer reconnects

HFTFeed.Client 1.1.1 is on NuGet. It builds on 1.1.0 with a faster receive path and two fixes we recommend to everyone: reconnects that respect the feed server's connection limit, and a client you can stop and start again.

dotnet add package HFTFeed.Client --version 1.1.1

The upgrade is source-compatible with 1.1.0. Read the two behaviour changes below before you deploy.

Faster ticks

  • About 2.5x faster decoding. Market-data snapshots are now decoded in a single pass that applies the feed server's own framing rules; every other message still goes through the server's parser. On .NET 8 the cost per tick fell from about 314 ns to about 125 ns.
  • No allocations while receiving on Linux and macOS. 1.1.0 allocated around 190 bytes per tick on those systems at typical feed rates and took an extra thread hop on every wake-up. 1.1.1 waits in one plain recv call and allocates nothing. On our loopback test rig the median receive latency dropped from 35 µs to 28 µs at 1,000 ticks per second, and from 14 µs to 9 µs at 10,000. Your own numbers depend on your machine and network.
  • Rate counters are cheaper. TPS and TPM read the clock once per socket read instead of twice per tick, and still count the trailing second and minute.

With ReuseTickObject = true the receive path stays allocation-free end to end, as in 1.1.0.

Built for .NET 10

The package now contains a native .NET 10 build next to the .NET 8 one, and both are tested on every release. NuGet picks the right build for your project; .NET 9 applications use the .NET 8 build.

Two new options for low-latency setups

  • BusyPollMicroseconds: when set, the receive thread keeps checking the socket for up to that many microseconds after it runs dry, so a tick that arrives in that window is handled without a thread wake-up. It keeps one CPU core busy while the feed is active, so use it only on a machine with a core to spare. Typical values are 1,000 to 50,000; the default is 0 (off).
  • ReceiveBufferSize: the kernel receive buffer for the feed socket, in bytes. A larger buffer absorbs longer bursts when your OnNewTick handler is occasionally slow. It does not lower latency. The default, 0, keeps your operating system's value.

Set both before Start().

using var client = new HFTFeedClient("you@example.com", "your_password")
{
    ReuseTickObject      = true,
    BusyPollMicroseconds = 20_000,       // only with a spare core
    ReceiveBufferSize    = 4 * 1024 * 1024,
};

Reconnects that never get your IP address banned

The feed server accepts 6 connections per minute per IP address. When an address goes over that limit, the server closes the extra connection without a reply and records a strike. Strikes expire one every 10 minutes, and enough of them ban the address for minutes, an hour or a day.

1.1.0 retried 0.25 to 0.5 seconds after a drop, could make up to eight attempts in the first minute, and treated a connection the server closed for being over the limit as one more failure to retry. Under bad network conditions that could turn into a ban.

1.1.1 opens at most 5 connections per host in any 60 seconds, counted across every HFTFeedClient in your process:

  • Every connection the server accepts counts, whether its logon succeeds or not.
  • An attempt that never reaches the server (connection refused, host unreachable, connect timeout) does not count, so reconnecting while the server restarts is never held back.
  • AutoReconnect waits 1 to 2 seconds after a drop, backs off from there, and waits for a free slot before each retry. Stop() and Dispose() end the wait at once.
  • Start() never waits. When the budget is spent it opens no connection and throws the new HFTFeedThrottledException. Its RetryAfter property says how long to wait.
try
{
    await client.StartAsync();
}
catch (HFTFeedThrottledException ex)
{
    Console.Error.WriteLine($"Too many connection attempts; try again in {ex.RetryAfter.TotalSeconds:F0} s.");
}

The limit is per IP address on the server side, so several processes or machines behind the same NAT still share it. Keep one client per application and share its ticks inside your process.

Stop, then start again

In 1.1.0, Stop() kept the list of subscribed symbols but the next Start() did not send it. Subscribe for those symbols then only reported Already subscribed, and no ticks arrived.

In 1.1.1, Stop() and Dispose() clear the subscription list. After Start(), subscribe again:

client.Stop();

await client.StartAsync();
client.Subscribe("1013");   // sends a new subscription and ticks flow again

AutoReconnect is unchanged: after an unexpected drop it restores your previous subscriptions once per connection.

Smaller fixes

  • A logon that the server ends by closing the connection now fails at once with an HFTFeedException that says so, instead of an HFTFeedTimeoutException after 10 seconds.
  • A failed Start() closes its connection and never starts the reconnect loop. Stop() ends a reconnect attempt that is in progress.
  • A garbled entry date or time beyond DateTime.MaxValue now yields EntryTimeUtc = DateTime.MinValue instead of an exception that dropped the connection.

Upgrade checklist

  1. dotnet add package HFTFeed.Client --version 1.1.1
  2. If your code calls Start() in its own retry loop, catch HFTFeedThrottledException and wait RetryAfter, or let AutoReconnect handle drops for you.
  3. If your code restarts a stopped client, call Subscribe again after Start().

The .NET SDK guide and the API reference cover every option, exception and limit in detail. If you still run 1.0.x, the 1.1.0 post explains what changed there. Version 1.0.x can no longer reach the feed.


Read more about

Cover Image for HFTFeed.Client 1.1.2: the feed has a stable host name
·3 min read·Changelog

HFTFeed.Client 1.1.2 connects to fix-server.hftfeed.com instead of a fixed IP address. Nothing else changed, and from now on the feed can move to another address without anyone having to update their configuration.

Cover Image for HFTFeed.Client 1.1.0: zero dependencies, allocation-free ticks
·5 min read·Changelog

Our .NET SDK is on NuGet with zero dependencies, allocation-free ticks, async start and stop, and opt-in reconnect. 1.0.x can no longer reach the feed, so upgrade today.

Cover Image for FIX Protocol for Dummies: A Simple Guide
·2 min read·Changelog

A beginner-friendly explanation of the FIX Protocol and its importance in financial markets.