{"id":16504741,"url":"https://github.com/jamesdbrock/hffix","last_synced_at":"2025-04-05T13:10:01.498Z","repository":{"id":15632070,"uuid":"18368940","full_name":"jamesdbrock/hffix","owner":"jamesdbrock","description":"Financial Information Exchange Protocol C++ Library","archived":false,"fork":false,"pushed_at":"2024-04-18T00:54:49.000Z","size":29641,"stargazers_count":291,"open_issues_count":18,"forks_count":92,"subscribers_count":33,"default_branch":"master","last_synced_at":"2025-03-29T12:11:14.014Z","etag":null,"topics":["c-plus-plus","fixprotocol"],"latest_commit_sha":null,"homepage":"http://jamesdbrock.github.io/hffix","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jamesdbrock.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2014-04-02T14:20:33.000Z","updated_at":"2025-03-16T22:06:09.000Z","dependencies_parsed_at":"2024-04-19T18:16:00.222Z","dependency_job_id":null,"html_url":"https://github.com/jamesdbrock/hffix","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesdbrock%2Fhffix","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesdbrock%2Fhffix/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesdbrock%2Fhffix/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesdbrock%2Fhffix/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jamesdbrock","download_url":"https://codeload.github.com/jamesdbrock/hffix/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247339158,"owners_count":20923014,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c-plus-plus","fixprotocol"],"created_at":"2024-10-11T15:06:25.301Z","updated_at":"2025-04-05T13:10:01.468Z","avatar_url":"https://github.com/jamesdbrock.png","language":"C++","readme":"High Frequency FIX — C++ Library for Financial Information Exchange Protocol {#mainpage}\n==========================================================================\n\n## Introduction\n\nThe High Frequency FIX Parser library is an open source implementation of\n\u003ca href=\"https://www.fixtrading.org/standards/\"\u003etagvalue FIX (classic FIX)\u003c/a\u003e\nintended for use by developers of high frequency, low latency financial software.  The purpose of the library is to do fast, efficient encoding and decoding of FIX in place, at the location of the I/O buffer. The library does not use intermediate message objects, and it does **no memory allocation** on the free store (the “heap”).\n\n*hffix* library is not certified by any industry-leading committees. It is not an “engine.” It is not an “adaptor.” It has no threading, no I/O, no object-oriented subtyping.  It is just a superfast parser and serializer in plain modern generic-iterator-style C++98.\n\n## Hello, FIX! Quick Start\n\nThe main repository is at \u003chttps://github.com/jamesdbrock/hffix\u003e\n\n### fixprint\nTo see an example of the library in action, enter these four commands at your shell prompt. This example uses the `fixprint` utility which comes with the *hffix* library. The result will be a colorized and pretty-printed FIX 5.0 test data set.\n\n    git clone https://github.com/jamesdbrock/hffix.git\n    cd hffix\n    make fixprint\n    util/bin/fixprint --color \u003c test/data/fix.5.0.set.2 | less -R\n\n\n### Usage\n\nThe library is header-only, so there is nothing to link. To use the `hffix.hpp` library for C++ FIX development, place the two header files in your include path and `#include \u003chffix.hpp\u003e`.\n\n* `hffix/include/hffix.hpp`\n* `hffix/include/hffix_fields.hpp`\n\n### Documentation\n\nFull Doxygen is on the internet at \u003chttps://jamesdbrock.github.io/hffix\u003e\n\nTo build the Doxygen html documentation in the `doc/html` directory and view it:\n\n    git clone https://github.com/jamesdbrock/hffix.git\n    cd hffix\n    make doc\n    xdg-open doc/html/index.html\n\n## Library Design\n\nHigh Frequency FIX Parser tries to follow the\n\u003ca href=\"https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md\"\u003eC++ Core Guidelines\u003c/a\u003e and the\n\u003ca href=\"http://www.boost.org/development/requirements.html\"\u003eBoost Library Requirements and Guidelines\u003c/a\u003e.  It is modern platform-independent header-only C++98 and depends only on the C++ Standard Library.  It is patterned after the C++ Standard Template Library, and it models each FIX message with Container and Iterator concepts. It employs compile-time generic templates but does not employ object-oriented inheritance.\n\n### Speed\n\nThe design criteria for High Frequency FIX Parser are based on our experience passing messages to various FIX hosts for high frequency quantitative trading at \u003ca href=\"http://www.t3live.com\"\u003eT3 Trading Group, LLC\u003c/a\u003e. These design criteria follow from the observation that the latency of a trading system depends on the following list of considerations, in descending order of importance.\n\n1. __Network architecture.__ Most of the latency will be in the network between us and our peer, outside of our control. We should do everything we can to exert some control over the network to shorten our path.\n2. __Operating System I/O syscall usage.__ We should be very careful about which syscalls we're using to do network I/O. Perhaps use an OS bypass NIC.\n3. __Operating System thread usage.__ We should be running a single pinned operating system thread per core with a multiplexed event loop like *Boost Asio* or *libuv* for waiting on I/O events.\n4. __Userspace runtime memory usage.__ Memory allocations can trigger a page fault and a syscall. Complicated object-oriented designs with lots of pointer indirections lead to cache misses and branch prediction failures.\n5. __Userspace algorithms.__ This is the easiest stuff to measure and the most fun to discuss, so a lot of attention is focused here, but it's only important if we get all the other considerations right first.\n\nThe *hffix* library assumes that the library user will want to make their own choices about considerations __2__ and __3__, and the *hffix* library focuses on providing good answers for consideration __4__. It does this by using only stack memory and I/O buffer memory, and never allocating on the free store.\n\nIn contrast, the popular alternative *QuickFix* library forces the user to use the *QuickFix* solution to considerations __2__ and __3__ for threads and sockets, and most of *QuickFix*'s choices about threads and sockets are not great. *QuickFix* also has an inefficient object-oriented design for consideration __4__.\n\nSee also \u003ca href=\"https://www.youtube.com/watch?v=NH1Tta7purM\"\u003eCppCon 2017: Carl Cook “When a Microsecond Is an Eternity: High Performance Trading Systems in C++”\u003c/a\u003e\n\n### Specs Included\n\nAll of the Financial Information Exchange (FIX) protocol specification versions supported by the library are bundled into the the distribution, in the `fixspec` directory. As a convenience for the developer, the High Frequency FIX Parser library includes a program which parses the FIX protocol specification documents and generates the `include/hffix_fields.hpp` file. That file `hffix::tag` enums and an `hffix::dictionary_init_field` function which allows fields to be referred to by name instead of number during both compile-time and run-time.\n\n### Platforms\n\nThe library is platform-independent C++98, and is tested on Linux\nwith *gcc* and *clang* on\n[Github Actions](https://github.com/jamesdbrock/hffix/actions/workflows/ci.yml).\n\n\n### License\n\nThe main High Frequency FIX Parser Library is distributed under the open source FreeBSD License, also known as the Simplified BSD License.\n\nSome extra components are under the Boost Software License.\n\nIncluded FIX specs are copyright FIX Protocol, Limited.\n\n## Features\n\n### Serial Message Field Access\n\nFor reading FIX messages, High Frequency FIX Parser presents an STL-style\n\u003ca href=\"https://en.cppreference.com/w/cpp/named_req/ForwardIterator\"\u003eimmutable Forward Iterator\u003c/a\u003e\ninterface. Writing fields is done serially with an interface similar to an STL-style\n\u003ca href=\"https://en.cppreference.com/w/cpp/named_req/SequenceContainer\"\u003eBack Insertion Sequence Container\u003c/a\u003e.\nReading and writing are done directly on the I/O buffer, without any intermediate objects.\n\nThe disadvantage of this implementation is that the message API provides serial access to fields, not random access. Of course, when we're writing a message, random access isn't important, just write out the fields in order. When we're reading a message, it's easy enough to pretend that we have random access by using iterator algorithms like `std::find`. A convenience algorithm `hffix::message_reader::find_with_hint` is provided by this library for efficiently reading fields when you know approximately what field order to expect. See the examples below for how this works out in practice.\n\nThe advantage is that this enables the High Frequency FIX Parser library to completely avoid free store memory allocation.\nThe library performs all memory allocation on the stack, and the library never requires developers using the library to allocate anything on the free store with `new` or `malloc`.\n\nField values in the FIX protocol are always encoded on the wire as ASCII, and High Frequency FIX Parser exposes field values to the developer as iterator range `char const* begin(), char const* end()`. High Frequency FIX Parser also provides a complete set of conversion functions to native C++ types for *ints*, *decimal floats*, *dates* and *times*, et cetera — see documentation for `hffix::message_writer` and `hffix::field_value`.\n\n### Exceptions\n\nSome functions in this library may throw `std::logic_error` if a precondition is not met by the programmer, so you can usually prevent the library from throwing exceptions by meeting the precondition. All methods, functions, constructors, and destructors provide the No-Throw exception guarantee unless they are documented to throw exceptions, in which case they provide the Basic exception guarantee. See documentation for details.\n\n### Thread Safety\n\nHigh Frequency FIX Parser is not thread-aware at all and has no threads, mutexes, locks, or atomic operations.\n\nAll `const` methods of the `hffix::message_reader` are safe for concurrent calls.\n\nThe `hffix::message_writer` is not safe for concurrent calls.\n\n`hffix::message_reader` and `hffix::message_writer` have no storage of their own, they read and write fields directly on an I/O buffer. The developer must guarantee that the buffer endures while fields are being read or written.\n\n### FIX Sessions\n\nManaging sessions requires making choices about sockets and threads.  High Frequency FIX Parser does not manage sessions.  It is intended for developers who want a FIX parser with which to build a session manager for a high-performance trading system that already has a socket and threading architecture.\n\nFIX has transport-layer features mixed in with the messages, and most FIX hosts have various quirks in the way they employ the administrative messages. To manage a FIX session your application will need to match the the transport-layer and administrative features of the other FIX host. High Frequency FIX Parser has the flexibility to express any subset or proprietary superset of FIX.\n\nSee also [FIX Session-level Test Cases and Expected Behaviors](http://www.fixtradingcommunity.org/pg/file/fplpo/read/30489/fix-sessionlevel-test-cases-and-expected-behaviors)\n\n### Numerics\n\nNo native floating-point numeric types (`double`, `float`) are employed by the library.\nASCII-encoded decimal numbers are represented by integral mantissa and exponent.\nSee `hffix::message_writer::push_back_decimal()` and `hffix::field_value::as_decimal()`.\nAs with every FIX data type, the High Frequency FIX library user has the option to serialize\nand deserialize numeric fields themself rather than use these methods.\n\n### Encryption\n\nHigh Frequency FIX Parser supports the binary data field types such as *SecureData*, but it does not implement any of the *EncryptMethods* suggested by the FIX specifications. If you want to encrypt or decrypt some data you'll have to do the encryption or decryption yourself.\n\n### CheckSum\n\nHigh Frequency FIX Parser will calculate the *CheckSum* field for all messages that you encode.  It can validate the *CheckSum* of messages decoded, but does not do that calculation unless you explicitly ask for it.\n\n### Sequence Numbers\n\nThe *MsgSeqNum* field in the FIX Standard Header is exposed for reading and writing.\n\n### Administrative Messages\n\nThe administrative messages *Logon*, *Logout*, *ResendRequest*, *Heartbeat*, *TestRequest*, *SeqReset-Reset* and *SeqReset-GapFill* don't get special treatment in High Frequency FIX Parser. Any administrative message can be encoded or decoded like any other message.\n\n### User-Defined Fields and Custom Tags\n\nHigh Frequency FIX Parser does not enforce the data type of the Field Definitions for content fields in the FIX spec, so the developer is free to read or write any tag number with any field data type. See `hffix::message_writer` and `hffix::field_value` documentation under Extension for details.\n\n\n## Using High Frequency FIX Parser\n\n### Writing a Message Example\n\nThis example program is in the *hffix* repository at `test/src/writer01.cpp`.\n\nIt writes a _Logon_ message and a _New Order - Single_ message to `stdout`.\n\n~~~cpp\n// We want Boost Date_Time support, so include these before hffix.hpp.\n#include \u003cboost/date_time/posix_time/posix_time_types.hpp\u003e\n#include \u003cboost/date_time/gregorian/gregorian_types.hpp\u003e\n\n#include \u003chffix.hpp\u003e\n#include \u003ciostream\u003e\n\nusing namespace boost::posix_time;\nusing namespace boost::gregorian;\n\nint main(int argc, char** argv)\n{\n    int seq_send(1); // Sending sequence number.\n\n    char buffer[1 \u003c\u003c 13];\n\n    ptime tsend(date(2017,8,9), time_duration(12,34,56));\n\n    // We'll put a FIX Logon message in the buffer.\n    hffix::message_writer logon(buffer, buffer + sizeof(buffer));\n\n    logon.push_back_header(\"FIX.4.2\"); // Write BeginString and BodyLength.\n\n    // Logon MsgType.\n    logon.push_back_string    (hffix::tag::MsgType, \"A\");\n    logon.push_back_string    (hffix::tag::SenderCompID, \"AAAA\");\n    logon.push_back_string    (hffix::tag::TargetCompID, \"BBBB\");\n    logon.push_back_int       (hffix::tag::MsgSeqNum, seq_send++);\n    logon.push_back_timestamp (hffix::tag::SendingTime, tsend);\n    // No encryption.\n    logon.push_back_int       (hffix::tag::EncryptMethod, 0);\n    // 10 second heartbeat interval.\n    logon.push_back_int       (hffix::tag::HeartBtInt, 10);\n\n    logon.push_back_trailer(); // write CheckSum.\n\n    // Now the Logon message is written to the buffer.\n\n    // Add a FIX New Order - Single message to the buffer, after the Logon\n    // message.\n    hffix::message_writer new_order(logon.message_end(), buffer + sizeof(buffer));\n\n    new_order.push_back_header(\"FIX.4.2\");\n\n    // New Order - Single\n    new_order.push_back_string    (hffix::tag::MsgType, \"D\");\n    // Required Standard Header field.\n    new_order.push_back_string    (hffix::tag::SenderCompID, \"AAAA\");\n    new_order.push_back_string    (hffix::tag::TargetCompID, \"BBBB\");\n    new_order.push_back_int       (hffix::tag::MsgSeqNum, seq_send++);\n    new_order.push_back_timestamp (hffix::tag::SendingTime, tsend);\n    new_order.push_back_string    (hffix::tag::ClOrdID, \"A1\");\n    // Automated execution.\n    new_order.push_back_char      (hffix::tag::HandlInst, '1');\n    // Ticker symbol OIH.\n    new_order.push_back_string    (hffix::tag::Symbol, \"OIH\");\n    // Buy side.\n    new_order.push_back_char      (hffix::tag::Side, '1');\n    new_order.push_back_timestamp (hffix::tag::TransactTime, tsend);\n    // 100 shares.\n    new_order.push_back_int       (hffix::tag::OrderQty, 100);\n    // Limit order.\n    new_order.push_back_char      (hffix::tag::OrdType, '2');\n    // Limit price $500.01 = 50001*(10^-2). The push_back_decimal() method\n    // takes a decimal floating point number of the form mantissa*(10^exponent).\n    new_order.push_back_decimal   (hffix::tag::Price, 50001, -2);\n    // Good Till Cancel.\n    new_order.push_back_char      (hffix::tag::TimeInForce, '1');\n\n    new_order.push_back_trailer(); // write CheckSum.\n\n    //Now the New Order message is in the buffer after the Logon message.\n\n    // Write both messages to stdout.\n    std::cout.write(buffer, new_order.message_end() - buffer);\n\n    return 0;\n}\n~~~\n\n\n### Reading a Message Example\n\nThis example program is in the *hffix* repository at `test/src/reader01.cpp`.\n\nIt reads messages from `stdin`. If it finds a _Logon_ message or a _New Order - Single_ message, then it prints out some information about their fields.\n\n~~~cpp\n#include \u003ciostream\u003e\n#include \u003ccstdio\u003e\n#include \u003cmap\u003e\n\n// We want Boost Date_Time support, so include these before hffix.hpp.\n#include \u003cboost/date_time/posix_time/posix_time.hpp\u003e\n#include \u003cboost/date_time/gregorian/gregorian.hpp\u003e\n\n#include \u003chffix.hpp\u003e\n\nconst size_t chunksize = 4096; // Choose a preferred I/O chunk size.\n\nchar buffer[1 \u003c\u003c 20]; // Must be larger than the largest FIX message size.\n\nint main(int argc, char** argv)\n{\n    int return_code = 0;\n\n    std::map\u003cint, std::string\u003e field_dictionary;\n    hffix::dictionary_init_field(field_dictionary);\n\n    size_t buffer_length(0); // The number of bytes read in buffer[].\n\n    size_t fred; // Number of bytes read from fread().\n\n    // Read chunks from stdin until 0 is read or the buffer fills up without\n    // finding a complete message.\n    while ((fred = std::fread(\n                    buffer + buffer_length,\n                    1,\n                    std::min(sizeof(buffer) - buffer_length, chunksize),\n                    stdin\n                    )\n          )) {\n\n        buffer_length += fred;\n        hffix::message_reader reader(buffer, buffer + buffer_length);\n\n        // Try to read as many complete messages as there are in the buffer.\n        for (; reader.is_complete(); reader = reader.next_message_reader()) {\n            if (reader.is_valid()) {\n\n                // Here is a complete message. Read fields out of the reader.\n                try {\n                    if (reader.message_type()-\u003evalue() == \"A\") {\n                        std::cout \u003c\u003c \"Logon message\\n\";\n\n                        hffix::message_reader::const_iterator i = reader.begin();\n\n                        if (reader.find_with_hint(hffix::tag::SenderCompID, i))\n                            std::cout\n                                \u003c\u003c \"SenderCompID = \"\n                                \u003c\u003c i++-\u003evalue() \u003c\u003c '\\n';\n\n                        if (reader.find_with_hint(hffix::tag::MsgSeqNum, i))\n                            std::cout\n                                \u003c\u003c \"MsgSeqNum    = \"\n                                \u003c\u003c i++-\u003evalue().as_int\u003cint\u003e() \u003c\u003c '\\n';\n\n                        if (reader.find_with_hint(hffix::tag::SendingTime, i))\n                            std::cout\n                                \u003c\u003c \"SendingTime  = \"\n                                \u003c\u003c i++-\u003evalue().as_timestamp() \u003c\u003c '\\n';\n\n                        std::cout\n                            \u003c\u003c \"The next field is \"\n                            \u003c\u003c hffix::field_name(i-\u003etag(), field_dictionary)\n                            \u003c\u003c \" = \" \u003c\u003c i-\u003evalue() \u003c\u003c '\\n';\n\n                        std::cout \u003c\u003c '\\n';\n                    }\n                    else if (reader.message_type()-\u003evalue() == \"D\") {\n                        std::cout \u003c\u003c \"New Order Single message\\n\";\n\n                        hffix::message_reader::const_iterator i = reader.begin();\n\n                        if (reader.find_with_hint(hffix::tag::Side, i))\n                            std::cout \u003c\u003c\n                                (i++-\u003evalue().as_char() == '1' ?\"Buy \":\"Sell \");\n\n                        if (reader.find_with_hint(hffix::tag::Symbol, i))\n                            std::cout \u003c\u003c i++-\u003evalue() \u003c\u003c \" \";\n\n                        if (reader.find_with_hint(hffix::tag::OrderQty, i))\n                            std::cout \u003c\u003c i++-\u003evalue().as_int\u003cint\u003e();\n\n                        if (reader.find_with_hint(hffix::tag::Price, i)) {\n                            int mantissa, exponent;\n                            i-\u003evalue().as_decimal(mantissa, exponent);\n                            std::cout \u003c\u003c \" @ $\" \u003c\u003c mantissa \u003c\u003c \"E\" \u003c\u003c exponent;\n                            ++i;\n                        }\n\n                        std::cout \u003c\u003c \"\\n\\n\";\n                    }\n\n                } catch(std::exception\u0026 ex) {\n                    std::cerr \u003c\u003c \"Error reading fields: \" \u003c\u003c ex.what() \u003c\u003c '\\n';\n                }\n\n            } else {\n                // An invalid, corrupted FIX message. Do not try to read fields\n                // out of this reader. The beginning of the invalid message is\n                // at location reader.message_begin() in the buffer, but the\n                // end of the invalid message is unknown (because it's invalid).\n                //\n                // Stay in this for loop, because the\n                // messager_reader::next_message_reader() function will see\n                // that this message is invalid and it will search the\n                // remainder of the buffer for the text \"8=FIX\", to see if\n                // there might be a complete or partial valid message anywhere\n                // else in the remainder of the buffer.\n                //\n                // Set the return code non-zero to indicate that there was\n                // an invalid message, and print the first 64 chars of the\n                // invalid message.\n                return_code = 1;\n                std::cerr \u003c\u003c \"Error Invalid FIX message: \";\n                std::cerr.write(\n                    reader.message_begin(),\n                    std::min(\n                        ssize_t(64),\n                        buffer + buffer_length - reader.message_begin()\n                        )\n                    );\n                std::cerr \u003c\u003c \"...\\n\";\n            }\n        }\n        buffer_length = reader.buffer_end() - reader.buffer_begin();\n\n        if (buffer_length \u003e 0)\n            // Then there is an incomplete message at the end of the buffer.\n            // Move the partial portion of the incomplete message to buffer[0].\n            std::memmove(buffer, reader.buffer_begin(), buffer_length);\n    }\n\n    return return_code;\n}\n~~~\n\n### Running the Examples\n\nThe writer example can be piped to the reader example. Running these commands:\n\n    make examples\n    test/bin/writer01 | test/bin/reader01\n\nShould produce output like this:\n\n\u003cpre style=\"white-space:pre-wrap;background-color:#171717;padding:1em;\"\u003e\n\u003cspan style=\"color: #F5F1DE\"\u003eLogon message\nSenderCompID = AAAA\nMsgSeqNum =    1\nSendingTime =  2014-Sep-26 15:27:38.789000\nThe next field is EncryptMethod = 0\u003cbr/\u003e\nNew Order Single message\nBuy OIH 100 @ $50001E-2\n\u003c/span\u003e\n\u003c/pre\u003e\n\n\nTo examine the output from `test/bin/writer01` program, you can also use `util/bin/fixprint`, like this:\n\n    make examples\n    make fixprint\n    test/bin/writer01 | util/bin/fixprint --color\n\nWhich will produce output like this:\n\n\u003cpre style=\"white-space:pre-wrap;background-color:#171717;padding:1em;\"\u003e\n\u003cspan style=\"color: #F5F1DE\"\u003eFIX.4.2 \u003c/span\u003e\u003cspan style=\"color: #aa5500\"\u003eMsgType_35=\u003c/span\u003e\u003cspan style=\"color: #aa0000\"\u003eA_Logon \u003c/span\u003e\u003cspan style=\"color: #aa5500\"\u003eSenderCompID_49=\u003c/span\u003e\u003cspan style=\"color: #F5F1DE\"\u003eAAAA \u003c/span\u003e\u003cspan style=\"color: #aa5500\"\u003eTargetCompID_56=\u003c/span\u003e\u003cspan style=\"color: #F5F1DE\"\u003eBBBB \u003c/span\u003e\u003cspan style=\"color: #aa5500\"\u003eMsgSeqNum_34=\u003c/span\u003e\u003cspan style=\"color: #F5F1DE\"\u003e1 \u003c/span\u003e\u003cspan style=\"color: #aa5500\"\u003eSendingTime_52=\u003c/span\u003e\u003cspan style=\"color: #F5F1DE\"\u003e20140928-07:12:06.000 \u003c/span\u003e\u003cspan style=\"color: #aa5500\"\u003eEncryptMethod_98=\u003c/span\u003e\u003cspan style=\"color: #F5F1DE\"\u003e0 \u003c/span\u003e\u003cspan style=\"color: #aa5500\"\u003eHeartBtInt_108=\u003c/span\u003e\u003cspan style=\"color: #F5F1DE\"\u003e10\u003c/span\u003e\n\u003cspan style=\"color: #F5F1DE\"\u003eFIX.4.2 \u003c/span\u003e\u003cspan style=\"color: #aa5500\"\u003eMsgType_35=\u003c/span\u003e\u003cspan style=\"color: #aa0000\"\u003eD_NewOrderSingle \u003c/span\u003e\u003cspan style=\"color: #aa5500\"\u003eSenderCompID_49=\u003c/span\u003e\u003cspan style=\"color: #F5F1DE\"\u003eAAAA \u003c/span\u003e\u003cspan style=\"color: #aa5500\"\u003eTargetCompID_56=\u003c/span\u003e\u003cspan style=\"color: #F5F1DE\"\u003eBBBB \u003c/span\u003e\u003cspan style=\"color: #aa5500\"\u003eMsgSeqNum_34=\u003c/span\u003e\u003cspan style=\"color: #F5F1DE\"\u003e2 \u003c/span\u003e\u003cspan style=\"color: #aa5500\"\u003eSendingTime_52=\u003c/span\u003e\u003cspan style=\"color: #F5F1DE\"\u003e20140928-07:12:06.000 \u003c/span\u003e\u003cspan style=\"color: #aa5500\"\u003eClOrdID_11=\u003c/span\u003e\u003cspan style=\"color: #F5F1DE\"\u003eA1 \u003c/span\u003e\u003cspan style=\"color: #aa5500\"\u003eHandlInst_21=\u003c/span\u003e\u003cspan style=\"color: #F5F1DE\"\u003e1 \u003c/span\u003e\u003cspan style=\"color: #aa5500\"\u003eSymbol_55=\u003c/span\u003e\u003cspan style=\"color: #F5F1DE\"\u003eOIH \u003c/span\u003e\u003cspan style=\"color: #aa5500\"\u003eSide_54=\u003c/span\u003e\u003cspan style=\"color: #F5F1DE\"\u003e1 \u003c/span\u003e\u003cspan style=\"color: #aa5500\"\u003eTransactTime_60=\u003c/span\u003e\u003cspan style=\"color: #F5F1DE\"\u003e20140928-07:12:06.000 \u003c/span\u003e\u003cspan style=\"color: #aa5500\"\u003eOrderQty_38=\u003c/span\u003e\u003cspan style=\"color: #F5F1DE\"\u003e100 \u003c/span\u003e\u003cspan style=\"color: #aa5500\"\u003eOrdType_40=\u003c/span\u003e\u003cspan style=\"color: #F5F1DE\"\u003e2 \u003c/span\u003e\u003cspan style=\"color: #aa5500\"\u003ePrice_44=\u003c/span\u003e\u003cspan style=\"color: #F5F1DE\"\u003e500.01 \u003c/span\u003e\u003cspan style=\"color: #aa5500\"\u003eTimeInForce_59=\u003c/span\u003e\u003cspan style=\"color: #F5F1DE\"\u003e1\u003c/span\u003e\n\u003c/pre\u003e\n\n\n## Dates and Times Type Support\n\n### Boost Date_Time\n\nIf the \u003ca href=\"http://www.boost.org/doc/html/date_time.html\"\u003eBoost Date_Time\u003c/a\u003e library is available in your build environment, `boost::posix_time::ptime`, `boost::posix_time::time_duration`, and `boost::gregorian::date` will be automatically supported for the various FIX date and time field types.\nSee `hffix::message_writer` and `hffix::field_value` documentation for details.\n\nTo enable High Frequency FIX Parser support for the Boost Date_Time library types, include the Boost libraries before the hffix.hpp library, like this:\n\n~~~cpp\n#include \u003cboost/date_time/posix_time/posix_time_types.hpp\u003e\n#include \u003cboost/date_time/gregorian/gregorian_types.hpp\u003e\n#include \u003chffix.hpp\u003e\n~~~\n\nTo prevent High Frequency FIX Parser support for the Boost Date_Time library, `#define HFFIX_NO_BOOST_DATETIME` before including `hffix.hpp`:\n\n~~~cpp\n#define HFFIX_NO_BOOST_DATETIME\n#include \u003chffix.hpp\u003e\n~~~\n\n### `std::chrono`\n\nIf you are building under C++11 or higher then the `std::chrono::time_point` and\n`std::chrono::duration` types are supported for the various FIX date and time field types.\nSee `hffix::message_writer` and `hffix::field_value` documentation for details.\n\n\n## Test\n\nSample data sources, discovered by Googling.\n\n* `test/data/fix.4.1.set.1`    http://fixparser.targetcompid.com/\n* `test/data/fix.5.0.set.1`    https://www.jse.co.za/content/JSETechnologyDocumentItems/03.%20JSE%20Indices.recv.log.txt\n* `test/data/fix.5.0.set.2`    http://blablastreet.com/workshop/TestSocketServer/TestSocketServer/bin/Debug/store/FIXT.1.1-ATP1CMEMY-OMSCMEMY.body\n\nThe Chicago Mercantile Exchange is also a good source of sample data files, but the files are too big to include in this repository. The script `test/curl.cme.data.sh` shows how to download them. Run `curl.cme.data.sh` in the `test/` directory.\n\n## Cookbook\n\n### Multi-threaded Sending\n\nQ: I have a bunch of different threads serializing and sending FIX messages out one socket. When each message is sent it needs a *MsgSeqNum*, but at serialization time I don't know what the *MsgSeqNum* will be, I only know that at sending time.\n\nA: That multi-threading model is not a good choice for your software. The performance penalty for that threading model is much greater than the performance advantage of this non-allocating parser library. You should consider redesigning to use a single-threaded simultaneous-wait event loop like *libev* or *Boost Asio*. If you insist on multi-threading, then you could do something like this code example.\n\n~~~cpp\nhffix::message_writer m;\nm.push_back_string(hffix::tag::MsgSeqNum, \"00000000\"); // Make a placeholder value over which you can later paste your sequence number.\n\n// This thread_safe_send() function will correctly sequence FIX messages if two threads are racing to call thread_safe_send().\nvoid thread_safe_send(hffix::message_writer const\u0026 w) {\n  lock l(send_mutex_); // Serialize access to this function.\n  hffix::message_reader r(w); // Construct a reader from the writer.\n  hffix::message_reader::const_iterator i = std::find_if(r.begin(), r.end(), hffix::tag_equal(hffix::tag::MsgSeqNum)); // Find the MsgSeqNum field.\n  if (i != r.end()) {\n    std::snprintf(const_cast\u003cchar*\u003e(i-\u003evalue().begin()), i-\u003evalue().size(), \"%.8i\", next_sequence_number++); // Overwrite the \"00000000\" string with the next_sequence_number.\n    write(fd, w.message_begin(), w.message_size()); // Send the message to the socket.\n  }\n}\n~~~\n\n### FIX Repeating Groups\n\nFrom *FIX-50_SP2_VOL-1_w_Errata_20110818.pdf* page 21:\n\n\u003cblockquote\u003eIf the repeating group is used, the first field of the repeating group is required. This allows\nimplementations of the protocol to use the first field as a \"delimiter\" indicating a new repeating group\nentry. The first field listed after the NoXXX, then becomes conditionally required if the NoXXX field\nis greater than zero.\u003c/blockquote\u003e\n\nThe beginning of each Repeating Group is marked by a field with a “NoXXX” field. By convention, Repeating Groups are usually located at the end of the message, so the end of the message marks the end of the Repeating Group. In this example we assume that the convention holds, and the repeating group is at the end of the message. If the repeating group were not at the end of the message then we'd have to pay attention to the value of the “NoXXX” fields, which is left as an exercise for the reader.\n\nThis is an example of iterating over the nested Repeating Groups when reading a *Mass Quote* message.\nThe *Mass Quote* message has *QuoteSet* Repeating Groups, and nested inside those groups are *QuoteEntry* Repeating Groups, see *fix-42-with_errata_20010501.pdf* page 52.\nIn each repeated *QuoteSet* Group, `hffix::tag::QuoteSetID` is always the first field. In each repeated *QuoteEntry* Group, `hffix::tag::QuoteEntryID` is always the first field.\n\n~~~cpp\nhffix::message_reader r;\n\nhffix::message_reader::const_iterator group1_begin = std::find_if(r.begin(), r.end(), hffix::tag_equal(hffix::tag::QuoteSetID));\nhffix::message_reader::const_iterator group1_end;\n\nfor (; group1_begin != r.end(); group1_begin = group1_end) {\n    group1_end = std::find_if(group1_begin + 1, r.end(), hffix::tag_equal(hffix::tag::QuoteSetID));\n\n    // This loop body will be entered once for each QuoteSet Repeating Group.\n    //\n    // group1_begin will point to the first field in the QuoteSet group, which is always hffix::tag::QuoteSetID.\n    // group1_end   will point past-the-end of the QuoteSet group.\n\n    hffix::message_reader::const_iterator group2_begin = std::find_if(group1_begin, group1_end, hffix::tag_equal(hffix::tag::QuoteEntryID));\n    hffix::message_reader::const_iterator group2_end;\n\n    for (; group2_begin != group1_end; group2_begin = group2_end) {\n        group2_end = std::find_if(group2_begin + 1, group1_end, hffix::tag_equal(hffix::tag::QuoteEntryID));\n\n        // This loop body will be entered once for each QuoteEntry Repeating Group.\n        //\n        // group2_begin will point to the first field of the QuoteEntry group, which is always QuoteEntryID.\n        // group2_end   will point past-the-end of the QuoteEntry group.\n    }\n}\n~~~\n\n\n\n## Support\n\nPlease make an issue on this repository if you have any questions about how the\nlibrary works or suggestions about how to improve it.\nIf you want to talk privately then email me at \u003cjamesbrock@gmail.com\u003e.\n\n\n## Contributing\n\n### Makefile\n\nOur build system is `make`. The `Makefile` provides targets and pseudo-targets\nfor various parts of the library.\n\n`make test` to run the test suite.\n\n`make doc` to build the documentation.\n\n### Nix\n\nWe have a `flake.nix`.\n\n```\nnix flake show github:jamesdbrock/hffix\n```\n\n#### Development\n\nThe `flake.nix` declares a *Nix* shell development environment which provides all\ndependencies for every target in the `Makefile`, including *Doxygen*.\nEnter the *Nix* shell by\n[installing *Nix*](https://nixos.org/download.html)\nand then running `nix develop` in this directory. From the `nix develop` prompt,\nyou will be able to build all `Makefile` targets.\n\n#### Package\n\nThe *Nix* `hffix` package will provide the `hffix` C++ library.\n\n#### Apps\n\nRun the `fixprint` utility:\n\n```\nnix run github:jamesdbrock/hffix#fixprint\n```\n\n### Pull Requests\n\nPull requests welcome!\n\nIf you want to submit a bugfix pull request, then I would be grateful if you would\nbreak the pull request up into two commits:\n\n1. A commit that adds a test which fails because of the bug.\n2. A commit that fixes the bug and causes the new test to pass.\n\n## Notes on the Design of FIX Protocol\n\n### The *Logon* - *Resend Request* Race Condition\n\nWhen a FIX client connects to a FIX server, the client doesn't know what sequence number to use for the *Logon* message.\n\nEither the client can choose to reset both sequence numbers, in which case the client may miss messages, or not, in which case the client is subject to the *Resend Request* race condition.\n\nAfter *Logon* response from the server, the client may begin sending messages, but the client has to wait some amount of time because the server may send *Resend Request*. If the client sends any message to the server while the server is preparing to send *Resend Request*, then the server's response is not defined by the *FIX* specification, and some servers implementations may seize up in confusion at that point.\n\n\n## C++03|11|14|17|20\n\nThis library only depends on C++98.\n\nThe library was designed with the intention of interacting well with C++11 features such as, for example, `auto`, or anonymous inline functions passed as the `UnaryPredicate` to `hffix::find_with_hint`. All the classes own no resources and are optimized for pass-by-value so move semantics are\nmostly irrelevent.\n\n`std::chrono` is supported in a `-std=c++11` build environment.\n\n`std::string_view` is supported in a `-std=c++17` build environment.\n\n## Change Log\n\n\u003ctable\u003e\n\u003ccaption\u003eChange Log\u003c/caption\u003e\n\n\u003ctr\u003e\n\u003cth\u003e2024-04-18\u003c/th\u003e\n\u003cth\u003ev1.4.1\u003c/th\u003e\n\u003ctd\u003e\nFix for `std::basic_string_view\u003cchar\u003e::const_iterator` not being convertible\nto `const char *` in Windows (#56)\n\u003c/td\u003e\n\u003c/tr\u003e\n\n\u003ctr\u003e\n\u003cth\u003e2024-02-19\u003c/th\u003e\n\u003cth\u003ev1.4.0\u003c/th\u003e\n\u003ctd\u003e\n\nAdd `hffix::message_writer::push_back_header()` for `string_view`,\nand `hffix::field_value::as_string_view()`\nby [Slawomir Kuzniar @skuzniar](https://github.com/skuzniar)\n(#51)\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\n\u003ctr\u003e\n\u003cth\u003e2023-04-28\u003c/th\u003e\n\u003cth\u003ev1.3.0\u003c/th\u003e\n\u003ctd\u003e\n\nAdd `hffix::msg_type` to `hffix_fields.hpp` (#47)\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\n\u003ctr\u003e\n\u003cth\u003e2022-05-22\u003c/th\u003e\n\u003cth\u003ev1.2.1\u003c/th\u003e\n\u003ctd\u003e\n\nBugfix: `MaxMessageSize` is not a data length field (#45)\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\n\u003ctr\u003e\n\u003cth\u003e2021-10-11\u003c/th\u003e\n\u003cth\u003ev1.1.1\u003c/th\u003e\n\u003ctd\u003e\n\nBugfix: `message_reader::prefix_size()` return `size_t` instead of `ssize_t`.\u003c/td\u003e\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\n\u003ctr\u003e\n\u003cth\u003e2021-05-17\u003c/th\u003e\n\u003cth\u003ev1.1.0\u003c/th\u003e\n\u003ctd\u003e\n\nAdded support for nanosecond-precision timestamps, by [Evan Wies @neomantra](https://github.com/neomantra)\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\n\u003ctr\u003e\n\u003cth\u003e2020-10-11\u003c/th\u003e\n\u003cth\u003ev1.0.1\u003c/th\u003e\n\u003ctd\u003e\n\nChanged the `message_reader` copy-assignment operator so that Address Sanitizer doesn't complain that `ERROR: AddressSanitizer: stack-use-after-scope`.\nBy [Michiel van Slobbe @mvanslobbe](https://github.com/mvanslobbe)\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\n\u003cth\u003e2020-08-15\u003c/th\u003e\n\u003cth\u003ev1.0.0\u003c/th\u003e\n\u003ctd\u003e\n\nVersion 1.\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\n\u003ctr\u003e\n\u003cth\u003e 2018-12-09\u003c/th\u003e\n\u003cth\u003e\u003c/th\u003e\n\u003ctd\u003e\n\nAdded support for `std::chrono`, by [@msherman13](https://github.com/msherman13)\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003cth\u003e2018-12-09\u003c/th\u003e\n\u003cth\u003e\u003c/th\u003e\n\u003ctd\u003e\n\nReplace parsing of all the old FIX specs with parsing of\nthe FIX Repository https://www.fixtrading.org/standards/fix-repository/\nto generate `hffix_fields.hpp`.\n\nThis results in a lot more `length_fields` in `hffix_fields.hpp`, so change\nthe algorithm for `is_tag_a_data_length()`.\n\nKeep all the old FIX spec documents in the repo for reference.\n\n#### Breaking Changes\n\nSome field names in `hffix::tag` were from the abbreviated\nFIX field name because the old specs were weird and difficult to parse.\nField names now come from the FIX Repository and so all of the\n`hffix::tag` field names have become full field names. If your code fails\nto compile because it can't find, for example, `hffix::tag::NoReltdSym`,\nthen change the symbol to `hffix::tag::NoRelatedSym`.\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003cth\u003e2018-10-24\u003c/th\u003e\n\u003cth\u003e\u003c/th\u003e\n\u003ctd\u003e\n\nReplace the Python `codegen` spec parser with a Haskell\n`spec-parse-fields` spec parser.\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003cth\u003e2017-09-12\u003c/th\u003e\n\u003cth\u003e\u003c/th\u003e\n\u003ctd\u003e\n\nAdded support for `std::string_view`, by [Arvid Norberg @arvidn](https://github.com/arvidn)\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n## Contributors\n\nThank you to the following contributors, who mostly don't show up in the Github\n*Contributors* list because of my habit of adding “cleanup” commits to other\npeople's pull requests.\n\n- [Arvid Norberg @arvidn](https://github.com/arvidn)\n- [@msherman13](https://github.com/msherman13)\n- [@j0nnyw](https://github.com/j0nnyw)\n- [Kyle Roth @kylrth](https://github.com/kylrth)\n- [Adam Kelly @aqk](https://github.com/aqk)\n- [Michiel van Slobbe @mvanslobbe](https://github.com/mvanslobbe)\n- [Evan Wies @neomantra](https://github.com/neomantra)\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamesdbrock%2Fhffix","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjamesdbrock%2Fhffix","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamesdbrock%2Fhffix/lists"}