37
$\begingroup$

In my firm we are beginning a new OMS (Order Management System) project and there is a debate whether we use Quickfix or we go for a professional fix engine? Because there is a common doubt that QuickFix is not enough fast and obviously we will not get any technical support. I heard that in BOVESPA it has been used for a while. They are changing it with a paid one now. Well that is enough for me. If they use it I can use it.

Should I choose a professional one over QuickFix? Is it not good enough?

$\endgroup$
  • $\begingroup$ If you need speed (i.e. low-latency) you can't use QuickFIX. CoralFIX for example is 20x faster than QuickFIX/C++ or QuickFIX/J and produces zero garbage for the GC. Disclaimer: I am one of the developers of CoralFIX. $\endgroup$ – rdalmeida Sep 2 '15 at 22:22

12 Answers 12

27
$\begingroup$

In order to answer your question (for you) you would need something to compare to. You would need numbers to know if it is slower/faster, how much, and if it will impact your system overall. Also knowing your performance goals could narrow down the options.

My advice is to take a look at your overall architecture of the sytem you have or intend to build. To just look at QuickFIX is rather meaningless without the whole chain involved in processing information and reacting to it. As an example, say QuickFIX is 100 times faster than some part (in the chain of processing) you have or build. Now, replacing QuickFIX with another part which is 100 times faster than QuickFIX would not change anything because you're still held back by the slowest point. And remember that network hops are usually very expensive compared to in-memory processing of data.

If you for some reason cannot compare different candidates against each other, why not start with e.g. QuickFIX, but make the system in such a way that it can be replaced with something faster later on.

Generally speaking, QuickFIX is not the fastest option, but the key point is that it might not have to be. If performance is very critical and one has resources, you usually end up buying something or building something yourself. Drawbacks here are having resources like time, money and skilled people.

To answer your question better one would need to know other aspects as well, like available resources (money, time, skill), overall system overview, performance expectations and other factors that limit decisions. E.g. if money is not a limiting factor, just find the fastest option and buy it.

$\endgroup$
19
$\begingroup$

I work in a big hedge fund and our DMA is entirely based on quickfixj with hundreds of trades a day and thousands of fills.

Quickfixj sits at the end of the OMS connecting to various counterparties and is in use since 2009, I think. Number of orders vary, possibly 150-450 a day, obviously with a lot more fills coming back than that number. Latency from an order entering the OMS to the fix message being sent is perhaps 150ms -- we are not aiming to be low latency at all though.

Using quickfixj is absolutely pain free.

$\endgroup$
  • $\begingroup$ Welcome to quant.SE! Can you elaborate a bit on your usage of QuickFixJ? How many orders per day? Do you measure order to accept latency? Some informative stats about your usage would be very interesting. $\endgroup$ – Louis Marascio Sep 10 '11 at 12:19
  • 1
    $\begingroup$ Quickfixj sits at the end of the OMS connecting to various counterparties and is in use since 2009, I think. Number of orders vary, possibly 150-450 a day, obviously with a lot more fills coming back than that number. Latency from an order entering the OMS to the fix message being sent is perhaps 150ms -- we are not aiming to be low latency at all though. Using quickfixj is absolutely pain free. $\endgroup$ – jk3000 Sep 10 '11 at 15:58
  • $\begingroup$ Thanks for the additional data! Can you edit you answer and include it there? That way it won't be missed if folks aren't reading comments. I'm out of votes right now, but will up vote you in a few hours. $\endgroup$ – Louis Marascio Sep 10 '11 at 16:00
  • $\begingroup$ Number of orders vary, possibly 150-450 a day. To put things into perspective, a market maker may send 1500--4500 orders per second. $\endgroup$ – chrisaycock Sep 10 '11 at 22:53
  • $\begingroup$ jk3000 refers to "Number of orders vary, possibly 150-450 a day, obviously with a lot more fills coming back than that number". In this context, would this be referring to parent/"meta" orders (an intention to buy 100k AAPL), rather than chrisaycock's individual order book-level orders on a given trading venue, e.g. bid 20 for 100 AAPL GTC on Arca? $\endgroup$ – afekz Jun 19 '18 at 11:26
13
$\begingroup$

How fast do you need? Have you measured round-trip times from the exchange and determined that you need a better solution?

I wouldn't call QuickFix quick; it has a lot of unnecessary overhead (temporary objects, temporary strings, nested functions, etc). But I've used it in projects before without too much trouble.

It is definitely possible to make a much faster FIX engine from scratch. You can use inlined accessors, call writev() instead of concatenating strings, etc. Then there's the standard's requirements, like replaying old FIX messages or handling multiple values per one key. It's a ton of work to do something like that correctly, so you'll need to evaluate just how much pain you're willing to go through.

I haven't used any of the commercial off-the-self engines; hopefully someone else can chime-in with a specific recommendation there. Ideally the cost of that will be a fraction of doing it in-house.

$\endgroup$
  • 1
    $\begingroup$ Care to elaborate on "But I've used it in projects before without too much trouble."? I'm also curious on what optimization level you had the compiler at whilst using QuickFix. $\endgroup$ – Mohamed Bana Feb 19 '11 at 13:53
9
$\begingroup$

I have not tested QuickFIX performance but I thought I'd share performance numbers from two open source FIX engines I have written.

Libtrading, a FIX engine written in C, has 16 μs round-trip time for NewOrderSingle-ExecutionReport ping-pong test. The test is being run on a 2-way 2.7GHz Sandy Bridge i7 CPU running Fedora 19 with Linux 3.11.6 with both client and server running on the same machine. The numbers include time spent in the Linux TCP/IP stack which is around 5 μs RTT on the machine. This translates to roughly 6 μs overhead per FIX message.

Falcon, an experimental FIX engine written in Java, has 23 μs round-trip time for similar test where the server is actually provided by libtrading. This is around 9 μs per-message overhead which is 50% more than the C FIX engine.

$\endgroup$
8
$\begingroup$

Quickfix derivative with a large number of optimizations, much faster than the current release, especially for short messages. Includes sample application that measures latency over the loopback interface.

https://github.com/akorobka/quickfix/tree/quickerfix

Summary of the improvements

There are several things that have an adverse impact on the performance of the current reference implementation.

Most of them have to do with a large amount of redundant object copying, implicit type conversions and small block memory allocations. These changes try to reduce these as much as possible through a redesign of the field object, use of more efficient field containers (Boost, Google Sparsehash) with a custom pool allocator, and streamlined Tx/Rx pipelines.

Other changes are basically brute force optimizations using more efficient serialization/deserialization code, each contributing 0-20% to the total speedup.

Extensions

Each field type defines a nested Pack type that can be used for in-place field construction when adding a field to the message,

msg.setField( FIX::ClOrdID::Pack( "4" ) );

Double field constructors get an optional bool argument that specifies whether the value should be rounded.

msg.setField( FIX::DoubleField( field, value, precision, true ) );
msg.setField( FIX::Price( value, precision, true ) );
msg.setField( FIX::Price::Pack( value, precision, true ) );

$\endgroup$
  • $\begingroup$ Thanks, I like it. Did you make use of move semantics of C++11 ? $\endgroup$ – ali_bahoo Nov 7 '13 at 21:01
  • $\begingroup$ It's still C++03 only. $\endgroup$ – Alexander Korobka Nov 20 '13 at 19:07
  • $\begingroup$ I know this is an old thread. My apologies. But I was trying to run Alexender's code against Quickfix latest version. The Engine and Client are running on the same machine. Still I am seeing that the Execution report for a Limit order being processed by the Alexender's engine in about 26ms (in release mode with VS2015). Pls let me know what I am doing wrong or missing here. I was expecting much less latency $\endgroup$ – XMarshall Dec 15 '16 at 16:55
  • $\begingroup$ To get the lowest latency you need to turn off validation, FIX logging and message persistence. Also make sure your system has enough memory and there is no other system load. $\endgroup$ – Alexander Korobka Jan 19 '17 at 20:41
6
$\begingroup$

Forget about BOVESPA nobody in Brazil is really doing anything that relies on speed and stability. I can say that from my personal experience. I would say that depending on your demands QuickFIX can be as good as FIX.

$\endgroup$
5
$\begingroup$

Compared to commercial offerings, Quickfix isn't that bad - considering you can pay $10000's for the very best ULL engines.

I have conducted side by side testing of Quickfix and Fix8 measuring encode/decode latency for NewOrderSingle(D) messages, see here.

$\endgroup$
  • $\begingroup$ I noticed a typo in your tables. "Average µs/msg" should read "Average s/msg". $\endgroup$ – madilyn Jan 29 '13 at 10:41
  • $\begingroup$ You're welcome. Thank you very much for compiling those results. $\endgroup$ – madilyn Jan 29 '13 at 12:13
  • $\begingroup$ @madilyn I don't think that is a typo; the intended unit of measure is "µs/msg". $\endgroup$ – Greg Schmit - Reinstate Monica Mar 12 at 19:24
  • $\begingroup$ @GregSchmit They fixed the typo after my comment (that's why I said "You're welcome", after the author responded - that comment disappeared for some reason), you can use web.archive.org to find the typo prior to my comment. $\endgroup$ – madilyn Apr 3 at 1:40
  • $\begingroup$ @madilyn Oh, sorry, I saw the table on the last link and it said µs/msg and that seemed the right order or magnitude for 486,465 msg/s (2.06 µs/msg, 10^-6 not 10^-3). $\endgroup$ – Greg Schmit - Reinstate Monica Apr 3 at 6:22
4
$\begingroup$

Bovespa is starting to release the new trade platform; take a look for yourself.

The BM&FBOVESPA PUMA Trading System will incorporate all of the functionalities that currently exist in the BM&FBOVESPA trading systems. Its trading speed will be less than a millisecond. In addition, the new platform will allow trading on the following markets: equities in the cash market, futures, options on futures and on actuals, spot US dollar, federal government bonds, private fixed-income securities, and spot commodities.

IMHO, quickfix needs to be patched/improved in order to handle such latency. (:

$\endgroup$
4
$\begingroup$

You should take a look on CoralFIX which is currently the fastest FIX engine in the market. The main problem with most Java FIX engines, commercial and open-source, is that they create a lot of garbage just by parsing bytes into a FixMessage object. And that's not counting the amount of garbage the network I/O layer is creating itself. Garbage leads to latency and variance due to GC overhead, as you probably know.

Whether you need a low-latency trading platform or not, that's a question only you can answer, but one thing is certain: low-latency and low-variance are never bad.

To give you an idea of what low-latency is for FIX, in our latest benchmarks we were able to parse a complete FIX message (with timestamp and everything) in less than 650 nanoseconds. This parsing does not produce any garbage so no GC overhead ever happens.

Of course you must add on top of that the network i/o latencies. That's a different ball game unrelated to FIX. For some network i/o benchmarks in Java you can read this article.

The full details of CoralFIX benchmark can be found here.

Disclaimer: I am one of the developers of CoralFIX.

$\endgroup$
3
$\begingroup$

We use internally optimized version of Quickfix. It gives us ~30 microsecond latency. Commercial products, like Onix or RapidAdvantage FIX will give you twice less.

$\endgroup$
  • $\begingroup$ ty for numbers! $\endgroup$ – user5462 Jun 4 '13 at 2:50
2
$\begingroup$

Most of the answers here are pretty correct. However, when talking about performance we use to forget the foundation of all this: The programmin language and platform.

I will summarize it like this: Need high-performance? Go for C (C++ in this case, since there is no pure C version of QuickFix). Choosing QuickFixJ, QuickFix .NET or any other implementation won't never be as fast as a pure C implementation of the FIX Protocol.

I am working on it by the way, and surprised that nobody did before (mainly for the HFT business)

Happy New Year!

$\endgroup$
  • $\begingroup$ absolutely agree, I'd say, if you want to make ultra low latency solution forget about design rules. Code should be very straightforward. And C is a better solution for this. E.g. just for comparison: I have a FIX parser written in C with some tricks in memory management and it takes about 1 microsecond for parsing-checking-encoding back for 1 ExecutionReport message. QuickFIX solution do only encoding for > 10 microseconds. $\endgroup$ – dmitryme Feb 15 '14 at 14:55
1
$\begingroup$

I ran the performance test code included in QuickFix C++ and got the results below. As far as I can tell, this looks excellent. And I am running a commodity home desktop not a high-end trading server used by big shops. The build was done with VS 2012 at full optimization.

G:\projects\quickfix\test\release\pt>pt.exe -p 15000 -c 1000000

Converting integers to strings:

num: 1000000, seconds: 0.016, num_per_second: 6.25e+007

Converting strings to integers:

num: 1000000, seconds: 0, num_per_second: 1.#INF

Converting doubles to strings:

num: 1000000, seconds: 0.5, num_per_second: 2e+006

Converting strings to doubles:

num: 1000000, seconds: 0.219, num_per_second: 4.56621e+006

Creating Heartbeat messages:

num: 1000000, seconds: 0.75, num_per_second: 1.33333e+006

Identifying message types:

num: 1000000, seconds: 0.062, num_per_second: 1.6129e+007

Serializing Heartbeat messages to strings:

num: 1000000, seconds: 0.516, num_per_second: 1.93798e+006

Serializing Heartbeat messages from strings:

num: 1000000, seconds: 1.094, num_per_second: 914077

Creating NewOrderSingle messages:

num: 1000000, seconds: 2.312, num_per_second: 432526

Serializing NewOrderSingle messages to strings:

num: 1000000, seconds: 0.75, num_per_second: 1.33333e+006

Serializing NewOrderSingle messages from strings:

num: 1000000, seconds: 3.188, num_per_second: 313676

Creating QuoteRequest messages:

num: 1000000, seconds: 41.547, num_per_second: 24069.1

Serializing QuoteRequest messages to strings:

num: 1000000, seconds: 3.734, num_per_second: 267809

Serializing QuoteRequest messages from strings:

num: 1000000, seconds: 26.672, num_per_second: 37492.5

Reading fields from QuoteRequest message:

num: 1000000, seconds: 15.89, num_per_second: 62932.7

Storing NewOrderSingle messages:

num: 1000000, seconds: 3.485, num_per_second: 286944

Validating NewOrderSingle messages with no data dictionary:

num: 1000000, seconds: 0.11, num_per_second: 9.09091e+006

Validating NewOrderSingle messages with data dictionary:

G:\projects\quickfix\test\release\pt>

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.