{"id":15068167,"url":"https://github.com/robaho/cpp_orderbook","last_synced_at":"2025-07-13T00:32:23.941Z","repository":{"id":244849011,"uuid":"816452222","full_name":"robaho/cpp_orderbook","owner":"robaho","description":"a financial exchange in C++","archived":false,"fork":false,"pushed_at":"2024-10-15T22:13:43.000Z","size":3718,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-10-20T08:16:09.656Z","etag":null,"topics":["cpp20","exchange","fix","fixprotocol","trading"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/robaho.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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,"publiccode":null,"codemeta":null}},"created_at":"2024-06-17T19:32:29.000Z","updated_at":"2024-10-15T22:13:47.000Z","dependencies_parsed_at":"2024-10-17T03:10:01.289Z","dependency_job_id":null,"html_url":"https://github.com/robaho/cpp_orderbook","commit_stats":null,"previous_names":["robaho/cpp_orderbook"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robaho%2Fcpp_orderbook","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robaho%2Fcpp_orderbook/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robaho%2Fcpp_orderbook/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robaho%2Fcpp_orderbook/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/robaho","download_url":"https://codeload.github.com/robaho/cpp_orderbook/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225844827,"owners_count":17533160,"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":["cpp20","exchange","fix","fixprotocol","trading"],"created_at":"2024-09-25T01:31:54.398Z","updated_at":"2025-07-13T00:32:23.931Z","avatar_url":"https://github.com/robaho.png","language":"C++","readme":"## Summary\n\nThis is an ultra high pergormance C++ implementation of a financial exchange order book capable of processing more than 5M orders per second per cpu core. It is inspired by the Go version in [go-trader](https://github.com/robaho/go-trader).\n\nIt uses [cpp_fixed](https://github.com/robaho/cpp_fixed) to perform fixed decimal point integer math.\n\nIt supports limit and market orders.\n\nSee [cpp-trader](https://github.com/robaho/cpp-trader) for a financial exchange utilizing this. \n\n## Building\n\nClone [cpp_fixed](https://github.com/robaho/cpp_fixed) at the same directory level. The location of `cpp_fixed` can be set via `INCLUDES` in the `Makefile`.\n\nYou need the [Boost Unit Testing Framework](https://www.boost.org/doc/libs/1_87_0/libs/test/doc/html/index.html) installed.\n\nIt builds using `make` and by default with CLang. There is `Makefile.gcc` to use GCC instead.\n\n## Testing\n\nuse `make run_tests` to run all of the test cases.\n\n## Usage\n\nSee `exchange.h` for the public api. `orderbook.h` is the internal single threaded order book management.\n\n## Performance\n\n\u003cdetails\u003e\n    \u003csummary\u003e view performance details \u003c/summary\u003e\n\u003cbr\u003e\nThe PriceLevels implementation can be chosen by modifying the [typedef xxxxx PriceLevels;](https://github.com/robaho/cpp_orderbook/blob/1b57f00fe031a09c28ab0df4dcacf1f6f29e48d7/pricelevels.h#L243) in `pricelevels.h` and rebuilding.\n\n\u003cpre\u003e\n\nUsing dequeue:\n\ninsert orders 1000 levels, usec per order 0.171672, orders per sec 5825061\ninsert orders 1000 levels with trade match % 0\ninsert orders 1000 levels, usec per order 0.231113, orders per sec 4326883\ninsert orders 1000 levels with trade match % 31\ncancel orders 1000 levels, usec per order 0.231527, orders per sec 4319150\ninsert orders 10 levels, usec per order 0.125911, orders per sec 7942117\ninsert orders 10 levels with trade match % 0\ninsert orders 10 levels, usec per order 0.187032, orders per sec 5346690\ninsert orders 10 levels with trade match % 33\ncancel orders 10 levels, usec per order 0.157627, orders per sec 6344090\n\nUsing vector:\n\ninsert orders 1000 levels, usec per order 0.14516, orders per sec 6888964\ninsert orders 1000 levels with trade match % 0\ninsert orders 1000 levels, usec per order 0.219419, orders per sec 4557484\ninsert orders 1000 levels with trade match % 31\ncancel orders 1000 levels, usec per order 0.185811, orders per sec 5381812\ninsert orders 10 levels, usec per order 0.114813, orders per sec 8709837\ninsert orders 10 levels with trade match % 0\ninsert orders 10 levels, usec per order 0.163958, orders per sec 6099119\ninsert orders 10 levels with trade match % 33\ncancel orders 10 levels, usec per order 0.121652, orders per sec 8220169\n\nUsing vector with structs:\n\ninsert orders 1000 levels, usec per order 0.148432, orders per sec 6737078\ninsert orders 1000 levels with trade match % 0\ninsert orders 1000 levels, usec per order 0.355023, orders per sec 2816722\ninsert orders 1000 levels with trade match % 31\ncancel orders 1000 levels, usec per order 0.189536, orders per sec 5276042\ninsert orders 10 levels, usec per order 0.0958039, orders per sec 10437988\ninsert orders 10 levels with trade match % 0\ninsert orders 10 levels, usec per order 0.133279, orders per sec 7503046\ninsert orders 10 levels with trade match % 33\ncancel orders 10 levels, usec per order 0.124691, orders per sec 8019825\n\nUsing map:\n\ninsert orders 1000 levels, usec per order 0.148093, orders per sec 6752518\ninsert orders 1000 levels with trade match % 0\ninsert orders 1000 levels, usec per order 0.262041, orders per sec 3816202\ninsert orders 1000 levels with trade match % 31\ncancel orders 1000 levels, usec per order 0.207532, orders per sec 4818534\ninsert orders 10 levels, usec per order 0.117244, orders per sec 8529235\ninsert orders 10 levels with trade match % 0\ninsert orders 10 levels, usec per order 0.195957, orders per sec 5103173\ninsert orders 10 levels with trade match % 33\ncancel orders 10 levels, usec per order 0.123975, orders per sec 806614\n\nUsing map with structs:\n\ninsert orders 1000 levels, usec per order 0.145034, orders per sec 6894920\ninsert orders 1000 levels with trade match % 0\ninsert orders 1000 levels, usec per order 0.226345, orders per sec 4418032\ninsert orders 1000 levels with trade match % 31\ncancel orders 1000 levels, usec per order 0.202022, orders per sec 4949955\ninsert orders 10 levels, usec per order 0.117999, orders per sec 8474676\ninsert orders 10 levels with trade match % 0\ninsert orders 10 levels, usec per order 0.173564, orders per sec 5761556\ninsert orders 10 levels with trade match % 33\ncancel orders 10 levels, usec per order 0.123793, orders per sec 8078001\n\u003c/pre\u003e\n\u003c/details\u003e\n\nRunning OSX on a 4 GHz Quad-Core Intel Core i7 with a single instrument.\n\n```\nInsert orders at 5.5M - 10.5M per second\nInsert orders with 30% trade match, 4M - 8M per second\nCancel orders at 4M - 8.5M per second\n```\n_The number of price levels is the dominating factor._\n\nRunning same hardware with an instrument per core:\n```\nInsert orders at less than 50 nanoseconds per insert, 22M+ orders per second.\nInsert orders with 31% trade match at less than 65 nanoseconds per insert/match, 10M+ orders per second.\nCancel orders at less than 70 nanoseconds per cancel, at 13M+ cancels per second.\n```\n\nThe test is fully cpu bound, and achieves a near 100% speedup per core. This is made possible using a few highly efficient lock-free structures.\n\nSee `benchmark_test.cpp` and `benchmark_multithread_test.cpp` for the performance tests.\n\n## Motivation\n\n\u003cdetails\u003e\n    \u003csummary\u003eWhy did I do this?\u003c/summary\u003e\n\u003cbr/\u003e\nLater revisions (including many micro-optimizations) of this project were born out of a job rejection in an effort to see \"just how fast I could go\". An order book is a fairly common exercise when interviewing in fintech. Having written multiple production grade orderbook implementations in my career, I was baffled at the rejection.\n\nI was lucky enough to have feedback through a secondary source that listed items like \"used string\", and \"used dynamic memory\". Where the reviewer errored is that they did not go deep enough to understand _how_ they were being used. Almost all string usages were references at near zero cost, except for the callbacks where copies were used for safety. The dynamic memory solution uses a custom arena allocator - again a near zero cost - but it makes the solution more complex.\n\nA review of performance details above makes it clear that the optimal data structure is dependent upon the distribution of the operations performed and the typical size of the order book. If you're implementing an exchange, you need to account for every price level, if you're a buy side firm, normally 10 levels on either side is sufficient to implement most strategies. As with all engineering, the optimum solution is based on the particular usage and constraints.\n\nThe interview exercise provided no guidelines on these parameters, and the test data was blind. My solution was rejected as inefficient. As I considered the solution _fast enough_ in the general case, I decided to keep the code \"clean\", and I focused on other areas like test cases and documentation. For instance, the reason a cancel in the current solution is \"super fast\" is because the Order maintains pointers back into the OrderList for fast removal - which is somewhat brittle and not intuitively obvious - it doesn't _read well_ BUT IT'S **FAST!**\n\nThe real problem is that when you create a \"production grade\" solution with auditing, logging, and all sorts of IO, the cost of those elements dwarf any speed gains achieved via the micro-optimizations, and getting those right - which many developers can't do - often leads to 10x performance improvements over the \"fast\" solution, usually because refactoring a \"simple\" solution is so much easier. Furthermore, making a solution \"safe\" comes at a cost, optimizing engineers know how to balance these - or you can go with the \"unsafe\" solution but be prepared to be the next Knight Capital. \n\nIn my opinion, it's a fairly common blunder in hiring - where the interviewer only accepts/understands the solution they expect to see - a 15 minute conversation might have resulted in a different outcome.\n\nAnyway, I hope this is helpful to others when faced with a similar problem.\n\n\u003c/details\u003e\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frobaho%2Fcpp_orderbook","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frobaho%2Fcpp_orderbook","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frobaho%2Fcpp_orderbook/lists"}