I'm a bit surprised by all the chatter about garbage collection because it's not as much an issue as it sounds.
The thing is not to do allocations (i.e. GC) on the _critical path_.
In a trading strategy you react to a stream of market data. It appears constant to the human eye, but in fact it's a series of "blips", sporadic events.
When you get a new message you need to react as fast as possible. The fastest code is, of course, no code, so it doesn't really matter if it's not written in C++, C# or PHP. Here you're just going to do the very minimum required. You will find that generally there is no difference in the code compiled whether it' done by the C# JIT, the Java JIT or a C++ AOT compiler, because the code is simple: you read a few fields from the message and select a pre-computed outcome to decide whether or not to send a (buy|sell) order.
Now, after that event has been handled (and perhaps you sent an order), you need to recompute stuff. You generally have plenty of time (a few milliseconds) before the next event arrives, and that's where you want to do all your fancy calculations, and here a high-productivity language like Java or C# helps, just because it's quicker to iterate and deploy modified trading strategies (typically deployed daily, or at least weekly).
Many people assume that you need to do all your fancy calculations very rapidly right after a message arrives. But you don't have to because the message is not completely random. The order book is not going to change completely after one message. You can pre-compute a few likely scenarios, and when a message arrives and confirms one of those scenarios, you just mechanically go with the precomputed result.
However, we moved away from “pure C#” about 10 years ago, to use FPGAs, especially in the ultra low latency stuff.
A lot of strategies can still be profitable with C#, colo’ed servers and kernel bypass NICs.
- Until late in it's lifecycle, .net runtime performance was worse than JVM.
- Also, the Windows TCP stack, re-architected with Vista, had severe latency issues, which probably led to wholesale abandonment of that platform for low-latency applications. Some of these problems were fixed in Windows 8, but it was probably too late by then.
(These two points are based on my own experience with Windows/CLR/JVM in the mid/late 2000s and some anecdotes I heard second-hand. So I can't really cite any public sources for them)
I'm sure the fact that you can customize Linux to the extreme and the lack of .Net on Linux in those days probably had a lot to do with the choice of Java, in addition to the above.
However, based on my reading of blogs like Mechanical Sympathy [1] a while ago (~8-10 years), there does seem to have been some demand for .Net-based solutions in the HFT space. They had code for both Java and C# in their public code.