# How fast is QuickFix ?

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?

-

## 12 Answers

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.

-
+1. I like this answer! –  olaker Mar 10 '11 at 13:12

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.

-
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. –  bruce.banner Feb 19 '11 at 13:53

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.

-

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. (:

-

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.

-
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. –  Louis Marascio Sep 10 '11 at 12:19
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. –  jk3000 Sep 10 '11 at 15:58
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. –  Louis Marascio Sep 10 '11 at 16:00
Number of orders vary, possibly 150-450 a day. To put things into perspective, a market maker may send 1500--4500 orders per second. –  chrisaycock Sep 10 '11 at 22:53

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.

-
ty for numbers! –  user5462 Jun 4 '13 at 2:50

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.

-
I noticed a typo in your tables. "Average µs/msg" should read "Average s/msg". –  madilyn Jan 29 '13 at 10:41
Thanks for spotting that. –  dakka Jan 29 '13 at 11:58
You're welcome. Thank you very much for compiling those results. –  madilyn Jan 29 '13 at 12:13

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 ) );

-
Thanks, I like it. Did you make use of move semantics of C++11 ? –  ali_bahoo Nov 7 '13 at 21:01
It's still C++03 only. –  Alexander Korobka Nov 20 '13 at 19:07

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>

-

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!

-
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. –  dmitryme Feb 15 '14 at 14:55

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.

-

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.

You can read more about CoralFIX here and the full details of its benchmark are here.

Disclaimer: I am one of the developers of CoralFIX.

-