[
  {
    "path": ".gitignore",
    "content": "# Compiled Object files\n*.slo\n*.lo\n*.o\n*.obj\n*.iobj\n\n# Compiled Dynamic libraries\n*.so\n*.dylib\n*.dll\n\n# Compiled Static libraries\n*.lai\n*.la\n*.a\n*.lib\nlib/\n\n# Compiled executables\n*.exe\n/bin\n/Output\n\nMakefile*\n.depend*\n*.sln\nmake\n\n# Artifacts\n*.swp\n\n#visual studio work files\n*vcproj*\n*vcxproj*\nDebug\nRelease\n*.pdb\n*.ipdb\n*.ilk\n.vs/\n*.VC.*\n\n# test output files\n*.log\n\n#helper/customized commands\n# (use single letter names and don't add to repo)\n?.cmd\n?.bat\n\n#a place to hide documents that should not go into the repo:\ndoc/NotGitWorthy/\n"
  },
  {
    "path": "PERFORMANCE.md",
    "content": "Performance Test Results, Inserts Per Second\n============================================\n(newest results on top)\n \n<table>\n  <tr>\n    <th>5 Level Depth</th>\n    <th>BBO Only</th>\n    <th>Order Book Only</th>\n    <th>Note</th>\n  </tr>\n  <tr>\n    <td>2,062,158</td>\n    <td>2,139,950</td>\n    <td>2,494,532</td>\n    <td>Now testing on a modern laptop (2.4 GHZ i7).</td>\n  </tr>\n  <tr>\n    <td>1,231,959</td>\n    <td>1,273,510</td>\n    <td>1,506,066</td>\n    <td>Handling all or none order condition.</td>\n  </tr>\n  <tr>\n    <td>1,249,544</td>\n    <td>1,305,482</td>\n    <td>1,531,998</td>\n    <td>Remove callbacks_added method.  Caller can invoke equivalent if necessary.</td>\n  </tr>\n  <tr>\n    <td>1,222,000</td>\n    <td>1,279,711</td>\n    <td>1,495,714</td>\n    <td>Use vector for callback container.</td>\n  </tr>\n  <tr>\n    <td>1,250,616</td>\n    <td>1,264,227</td>\n    <td>1,463,738</td>\n    <td>Union in callback.  For clarity of purpose, not for performance.</td>\n  </tr>\n  <tr>\n    <td>1,267,135</td>\n    <td>1,270,188</td>\n    <td>1,469,246</td>\n    <td>Combine 2 fill callbacks into one.</td>\n  </tr>\n  <tr>\n    <td>1,233,894</td>\n    <td>1,237,154</td>\n    <td>1,434,354</td>\n    <td>Store excess depth levels in depth to speed repopulation.</td>\n  </tr>\n  <tr>\n    <td>58,936</td>\n    <td>153,839</td>\n    <td>1,500,874</td>\n    <td>Removed spuroious insert on accept of completely filled order.</td>\n  </tr>\n  <tr>\n    <td>38,878</td>\n    <td>124,756</td>\n    <td>1,495,744</td>\n    <td>Initial run with all 3 tests.</td>\n  </tr>\n</table>\n\n"
  },
  {
    "path": "README.md",
    "content": "# Liquibook\n\nOpen source order matching engine\n\nLiquibook provides the low-level components that make up an order matching engine. \n\nOrder matching is the process of accepting buy and sell orders for a security (or other fungible asset) and matching them to allow \ntrading between parties who are otherwise unknown to each other.\n\nAn order matching engine is the heart of every financial exchange, \nand may be used in many other circumstances including trading non-financial assets, serving as a test-bed for trading algorithms, etc.\n\nA typical Liquibook-based application might look something like this:\n![Market Application](doc/Images/MarketApplication.png)\n\nIn addition to the order matching process itself, Liquibook can be configured\nto maintain an \"depth book\" that records the number of open orders and total quantity\nrepresented by those orders at individual price levels.  \n\n#### Example of an depth book\n* Symbol XYZ: \n  * Buy Side: \n    * $53.20 per share: 1203 orders; 150,398 shares.\n    * $53.19 per share: 87 orders; 63,28 shares\n    * $52.00 per share 3 orders; 2,150 shares\n  * Sell Side\n    * $54.00 per share 507 orders; 120,700 shares\n    * etc...            \n\n## Order properties supported by Liquibook.\n\nLiquibook is aware of the following order properties.\n\n* Side: Buy or Sell\n* Quantity\n* Symbol to represent the asset to be traded\n  * Liquibook imposes no restrictions on the symbol.  It is treated as a simple character string.\n* Desired price or \"Market\" to accept the current price defined by the market.\n  * Trades will be generated at the specified price or any better price (higher price for sell orders, lower price for buy orders)\n* Stop loss price to hold the order until the market price reaches the specified value.\n  * This is often referred to as simply a stop price.\n* All or None flag to specify that the entire order should be filled or no trades should happen.\n* Immediate or Cancel flag to specify that after all trades that can be made against existing orders on the market have been made, the remainder of the order should be canceled.\n  * Note combining All or None and Immediate or Cancel produces an order commonly described as Fill or Kill.\n\nThe only required properties are side, quantity and price.  Default values are available for the other properties.\n\nThe application can define addtional properties on the order object as necessary.  These properties will have no impact on the behavior of Liquibook.\n \n## Operations on Orders\n\nIn addition to submitting orders, traders may also submit requests to cancel or modify existing orders.  (Modify is also know as cancel/replace)\nThe requests may succeed or fail depending on previous trades executed against the order.\n  \n## Notifications returned to the application.\n\nLiquibook will notify the application when significant events occur to allow the application to actually execute the trades identified by Liquibook, and to allow the application to publish market data for use by traders.\n\nThe notifications generated include:\n\n* Notifications intended for trader submitting an order:\n  * Order accepted \n  * Order rejected\n  * Order filled (full or partial)\n  * Order replaced\n  * Replace request rejected\n  * Order canceled\n  * Cancel request rejected.\n* Notifications intended to be published as Market Data\n  * Trade\n    * Note this should also trigger the application to do what it needs to do to make the trade happen.\n  * Security changed\n    * Triggered by any event that effects a security\n      * Does not include rejected requests.\n  * Notification of changes in the depth book (if enabled)\n    * Depth book changed\n    * Best Bid or Best Offer (BBO) changed.\n\n\n## Performance\n* Liquibook is written in C++ using modern, high-performance techniques. This repository includes\nthe source of a test program that can be used to measure Liquibook performance.\n  * Benchmark testing with this program shows sustained rates of  \n__2.0 million__ to __2.5 million__ inserts per second. \n\nAs always, the results of this type of performance test can vary depending on the hardware and operating system on which you run the test, so use these numbers as a rough order-of-magnitude estimate of the type of performance your application can expect from Liquibook. \n\n## Works with Your Design\n* Allows an application to use smart or regular pointers to orders.\n* Compatible with existing order model, \n  * Requires a trivial interface which can be added to or wrapped around an existing Order object.\n* Compatible with existing identifiers for securities, accounts, exchanges, orders, fills\n\n## Example\nThis repository contains two complete example programs.  These programs can be used to evaluate Liquibook to see if it meets your needs. They can also be used as models for your application or even incorporated directly into your application thanks to the liberal license under which Liquibook is distributed.\n\nThe examples are:\n* Depth feed publisher and subscriber\n  * Generates orders that are submitted to Liquibook and publishes the resulting market data.\n  * Uses [QuickFAST](https://github.com/objectcomputing/quickfast) to publish the market data\n\n* Manual Order Entry\n  * Allows orders and other requests to be read from the console or submitted by a script (text file)\n  * Submits these to Liquibook.\n  * Displays the notifications received from Liquibook to the console or to a log file.\n  * [Detailed instructions are in the README_ORDER_ENTRY.md file.]( README_ORDER_ENTRY.md)\n\n# Building Liquibook\nThe good news is you don't need to build Liquibook.  The core of Liquibook is a header-only library, so you can simply\nadd Liquibook/src to your include path then `#include <book/order_book.h>` to your source, and Liquibook will be available\nto be used in your application.\n\nHowever, this repository includes tests and example programs for Liquibook.  These programs need to be compiled and built in order to run them.  The remainder of this section describes how to do this.\n\n## Dependencies\nLiquibook has no runtime dependencies.  It will run in any environment that can run C++ programs.\n\nTo build the Liquibook test and example programs from source you need to create makefiles (for linux, et al.) or Project and Solution files for Windows Visual Studio.\n\nLiquibook uses MPC to create these platform-dependent files from a common build definition:\n* [MPC](https://github.com/objectcomputing/MPC) for cross-platform builds.\n\n  MPC itself is written in perl, so your environment needs a working Perl compiler.  Most linux systems already have this. If you need a Perl compiler on Windows, OCI recommends [Active State Perl V5.x or later](http://www.activestate.com/)\n\nIf you wish to build the unit tests for Liquibook, you will also need the boost test library:\n* [BOOST](http://www.boost.org/) (optional) for unit testing.\n\nOne of the example programs (publish and subscribe to market data) uses QuickFAST to encode and decode market data messages.  If you wish to run this example you need QuickFAST:\n* [QuickFAST](https://github.com/objectcomputing/quickfast) (optional) for building the example depth feed publisher/subscriber.\n\n  QuickFAST his its own dependencies which are described on its web page.\n\n## Submodule Note\nThe Assertive test framework was used in previous versions, but it is no longer needed.  \nIf you have imported this submodule to support previous versions, you may delete the liquibook/test/unit/assertiv directory.\n\n## Getting ready to build the tests and example programs.\n\n### Boost Test\nIf you want to run the Liquibook unit tests (highly recommended!) you should install and/or build boost test before trying to build Liquibook.  Boost test is used in the multifile-test mode rather than simple header-only mode so the compiled boost test library must be available.\n\nPlease follow the instructions on the [boost web site](http://www.boost.org/) for building/installing the library in your environment.\nWhen you are done you should export the $BOOST_ROOT environment varialble.  \n\nBecause of the many boost build options, please check to be sure that the include files and library files are in the expected locations.\nMPC expects to find:\n*  Include files in $BOOST_ROOT/include/boost\n*  Library files in $BOOST_ROOT/lib\n\n\nIf you prefer not to install boost you can edit the liquibook.features file to change the appropriate line to say `boost=0`  This will disable building the unit tests.\n\n### QuickFAST\nThe publish and subscribe example program uses QuickFAST.  If you want to run this example program, please see the [QuickFAST web site](https://github.com/objectcomputing/quickfast) to download and build this library.\n\nSet the environment variable $QUICKFAST_ROOT to point to the location where you installed and build QuickFAST.\n\nBefore running MPC you should also edit the file liquibook.features to set the value QuickFAST=1\n\nIf you do not plan to run this example program, set the environment variable QUICKFAST_ROOT to liquibook/noQuickFAST.\n\n## Building Liquibook on Linux\n\nThe env.sh script uses the readlink program which is present on most Linux/Unix systems. \nIf you don't have readlink, set the $LIQUIBOOK_ROOT environment variable the directory containing liquibook before running env.sh\n\nOpen a shell and type:\n\n<pre>\n$ cd liquibook\n$ . ./env.sh\n$ $MPC_ROOT/mwc.pl -type make liquibook.mwc\n$ make depend\n$ make all\n</pre>\n\n### Output from build\n* The Liquibook test and example libraries will be in $LIQUIBOOK_ROOT/lib\n* The Liquibook example programs will be in $LIQUIBOOK_ROOT/bin\n* The Liquibook test programs will be in $LIQUIBOOK_ROOT/bin/test\n\n## Building Liquibook examples and test programs with Visual Studio\n\nUse the following commands to set up the build environment and create Visual Studio project and solution files.\nNote if you are using MinGW or other linux-on-Windows techniques, follow the Linux instructions; however, OCI does not normally test this.\n\n<pre>\n> cd liquibook\n> copy winenv.bat w.bat #optional if you want to keep the original\n                        # note that single character batch file names are ignored in \n                        # .getignore so the customized\n                        # file will not be checked into the git repository (a good thing.)\n> edit w.bat            # edit is your choice of text editor\n                        # follow the instructions in the file itself.\n> w.bat                 # sets and verifies environment variables\n> mpc.bat               # generate the visual studio solution and project files.\n</pre>\n\nThen:\n* Start Visual Studio from the command line by typing liquibook.sln or \n* Start Visual Studio from the Windows menu and use the menu File|Open|Project or Solution to load liquibook.sln.\n\n## For any platform\n\nLiquibook should work on any platform with a modern C++ compiler (supporting at least C++11.)  \n\nThe MPC program used to create the build files and the Boost library used in the tests and some of the examples support a wide variety of platforms.  \n\nSee the [MPC documentation](https://github.com/objectcomputing/MPC) for details about using MPC in your enviornment.\n\nSee the [Boost website](http://www.boost.org/) for details about using Boost in your environment.\n"
  },
  {
    "path": "README_ORDER_ENTRY.md",
    "content": "# Manual Order Entry -- Liquibook example program\n\nThis program accepts requests typed from the console or read from a script file and applies them to\none or more order books.  It displays the results of the callbacks generated by Liquibook in\nresponse to those requests.\n\n## The Command Line\n\nThe mt_order_entry command accepts two command line options.  Both are optional.\n\nParameter:\n\n* script_file_name  \n  The name of a script file.\n  * The script file contains a series of requests -- one per line.  See below for the syntax of these requests.\n  * If you don't want a script file, but you want to specify a log file, use a single hyphen (-) for the script file name.  The commands will be read from the console.\n* log_file_name  \n  The name of a file to which output should be written.  \n  * Prompts (if any) will still be written to the console.\n\n## Request syntax\nRequests are read from the console or from a script file.\n\nAn empty line or a line beginning with a hash (#) is considered a comment and will be ignored.\nOther lines read are in the format:\n\n   REQUEST [parameters]* [;]\n\nThat is: a one word request followed by parameters as necessary and terminated in a semicolon.  \n\nThe semicolon may be optional for some commands, but it can always be included if desired.\nThe stand-alone word \"END\" may be substituted for a semicolon.\n\nIf a request accepts optional parameters, or if not all required parameters are provided, the \nconsole user will be prompted for additional parameters until a semicolon is entered.\nThis prompting will happen even if the input is being read from a file, so the requests coming\nin from a script file should be complete and should be terminated with a semicolon.\n   \n####For example:\n<pre>\n   > BUY 100 GOOG 850 AON;\n       ADDING order:  [#2 BUY 100 GOOG $850 AON Last Event:{Submitted BUY 100 GOOG @850}]\n   > BUY              (incomplete request)\n   Quantity: 100      (prompt for parameters)\n   Symbol: GOOG\n   Limit Price or MKT: 800\n   AON, or IOC, or STOP, or END: ;\n       ADDING order:  [#3 BUY 100 GOOG $800 Last Event:{Submitted BUY 100 GOOG @800}]  \n</pre>       \n## Requests\n\nMost requests can be spelled out or abbreviated to their first character.  \nParameters accepted by each request will be explained later in this document.\nRequests are not case sensitive.  Even though they are shown here in ALL CAPS\na BUY request may be entered as BUY, buy, b, or even Buy.\n<pre>\n* BUY or B      : Enter a new order to buy a security.\n* SELL or S     : Enter a new order to sell a security.\n* CANCEL or C   : Request that an existing order be canceled.\n* MODIFY or M   : Request that an existing order be modified.\n* DISPLAY or D  : Display information about existing orders\n* FILE or F     : Open or close a script file.\n* ?             : Display help for requests\n* QUIT          : Exit the program.\n</pre>\n   \n## Symbols\n\nLiquibook itself imposes no limitations on symbol.  It accepts an arbitrary string of characters \n(actually of 8 bit octets so UTF-8 or other encodings are supported with no special effort.)\n\nThe manual entry program has a few restrictions on the symbols to ease parsing: \n\n    * The symbol may not include spaces.\n    * The symbol may not begin with a plus sign (+) or exclamation mark(!)\n    * The symbol should not be ALL.\n    * The symbol should not be a single asterisk (*)\n\nIt is important to stress that these restrictions apply only to the example program, not to Liquibook itself.\n\nDisallowing spaces obviously makes parsing the incoming request easier.  \nUsing \"ALL\" and \"*\" would confict with the DISPLAY command parsing.\n  \nThe restriction against leading plus signs and exclamation marks requires more explanation.\n\nLiquibook uses a separate order book for each security.  When a new symbol is encountered (representing a new security)\nthe manual entry program will create a new order book for the symbol.  It needs to know whether to create\na simple order book, or a depth book.  \n\n* If the new symbol is prefixed by a plus sign(+), then a simple\norder book is created. \n* If it is prefixed by an exclamation mark (!) then a depth book is created.  \n* If neither of these prefixes is present then manual entry will prompt the console user to determine what\ntype of book to create.\n\nFor example:\n<pre>\n    > buy 100 ibm 50;\n    New Symbol IBM.\n    Add [S]imple book, or [D]epth book, or 'N' to cancel request.\n    [SDN}: d\n    Create new depth order book for IBM\n    ADDING order:  [#1 BUY 100 IBM $50 Last Event:{Submitted BUY 100 IBM @50}]\n            Accepted: [#1 BUY 100 IBM $50 Open: 100 Last Event:{Accepted }]\n            Book Change:  IBM\n            Depth Change:  IBM Changed Change Id: 1 Published: 0\n            BIDS:\n            Price 50 Count: 1 Quantity: 100 Change id#: 1\n            BBO Change:  IBM Changed Change Id: 1 Published: 0\n    > buy 200 t 78;\n    New Symbol T.\n    Add [S]imple book, or [D]epth book, or 'N' to cancel request.\n    [SDN}: s\n    Create new order book for T\n    ADDING order:  [#2 BUY 200 T $78 Last Event:{Submitted BUY 200 T @78}]\n            Accepted: [#2 BUY 200 T $78 Open: 200 Last Event:{Accepted }]\n            Book Change:  T\n    > buy 50 r 99;\n    New Symbol R.\n    Add [S]imple book, or [D]epth book, or 'N' to cancel request.\n    [SDN}: n\n    Request ignored\n    Cannot process command BUY 50 R 99 ;\n</pre>\n\nSince console  prompting does not play well with scripting, it is important that symbols used in scripts\nhave the appropriate prefix the first time they appear.\n\nIt is acceptable to have a + or ! prefix on a symbol for which a book already exists.  The prefix will be ignored\nand the existing book will be used.\n\n## Prices\n\nLiquibook uses integers for prices.  It does care what currency unit is actually being used as long as all orders for a\nparticular security use the same units.   \n\nBecause Liquibook uses integers the prices must be expressed in terms of the \"atomic currency unit\"  For example\nif prices are in US Dollars, then the atomic currency unit is often a penny, so fifteen dollars would be expressed to\nLiquibook as 1500.\n\nIn most cases where a price is needed, the word MARKET (or the abbreviation MKT) is accepted indicating that no limit price is specified for this order, and a trade can be generated at the price specified for the counter order, or at the current market price for the security if both sides of the trade specify MARKET price.\n\n## Order Identity\n\nLiquibook uses the memory address of the applications order object as an identifier for the order. [This may be changed in the future because it\nimposes some odd restrictions on object lifetime.]  The manual entry program needs a way for the console user (or script)\nto identify orders, and the memory address is obviously not available for this purpose.\n\nThus the order entry program assigns an order id to each order.  Whenever an order is displayed the order ID appears after a hash sign(#).\nSo for example if a new order is added, and the response is:\n\n      ADDING order:  [#1 BUY 100 IBM $50 Last Event:{Submitted BUY 100 IBM @50}]\n\nThis order may be referred to in following commands by using the order id 1. When an order is read from the console or from a script,\nan optional # can prefix the order id.  Thus:  \"Cancel #1\" and \"CANCEL 1\" refer to the same order.\n\nOrder ID's may also be entered with a leading minus sign.  These order IDs are relative to the NEXT order id that will be used.  \nThus \"Cancel -1\" would cancel the most recent order entered.  \"Cancel -2\" would cancel the order before that, and so on.\n\n## Details of specific Requests\n   \n### BUY or B \nEnter a new order to buy a security.\n\nSyntax:  BUY quantity symbol price [AON | IOC | STOP price]* ;\n\nParameters:\n* *quantity* is number of shares (or other tradable units) to buy.\n* *symbol* is an arbitrary character string.\n  * See the **Symbol** section above for information about this string.\n* *price* is the highest price the trader is willing to pay for each tradable unit of the security, or MARKET to accept any trade.\n  * See the **Price** section above for details about expressing prices.\n* AON  This optional parameter sets the All-Or-None condition for this order.\n* IOC  This optional parameter sets the Immediate-Or-Cancel condition for this order.\n* STOP price  This optional parameter sets a STOP LOSS price for this order using the same currency units as the price parameter.\n\nThe traling semicolon (or the word END) is required for a BUY request.\n\nZero or more trades may be triggered by entering a BUY order.\n\n### SELL or S\nEnter a new order to sell a security.\n\nSyntax:  SELL quantity symbol price [AON | IOC | STOP price]* ;\n\nParameters:\n* *quantity* is number of shares (or other tradable units) to be sold.\n* *symbol* is an arbitrary character string.\n  * See the **Symbol** section above for information about this string.\n* *price* is the lowest price the trader is willing to accept for each tradable unit of the security, or MARKET to accept any trade.\n  * See the **Price** section above for details about expressing prices.\n* AON  This optional parameter sets the All-Or-None condition for this order.\n* IOC  This optional parameter sets the Immediate-Or-Cancel condition for this order.\n* STOP price  This optional parameter sets a STOP LOSS price for this order using the same currency units as the price parameter.\n\nThe traling semicolon (or the word END) is required for a SELL request.\n\nZero or more trades may be triggered by entering a SELL order.\n\n### CANCEL or C\nRequest that an existing order be canceled.\n\nParameter:\n* orderid, or #orderid, or -relative_order_id.\n  * See the **Order Identity** section above for details. \n  \nNo trades will be triggered by entering a CANCEL request.\n\nThe traling semicolon (or the word END) is optional for a CANCEL request. The request is considered complete after one required parameter.\n\nThe request may be rejected if the order has already been filled.\n\n### MODIFY or M\n\nRequest that an existing order be modified.\n\nParameters:\n* orderid, or #orderid, or -relative_order_id.\n  * See the **Order Identity** section above for details. \n* PRICE new_price\n  * See the **Price** section above for details about expressing prices.\n  * Prices may be increased or decreased.\n  * PRICE is optional.  If it is not specified the existing price will be unchanged.\n* QUANTITY new_initial_quantity\n  * Note this is NOT the new quantity to be open (that's a moving target).  Nor is it a delta to quantity (although that's how Liquibook expresses it internally.)\n  * QUANTITY is optional.  If it is not specified the existing quantity will be unchanged.\n\nThe traling semicolon (or the word END) is required for a MODIFY request.\n\nZero or more trades may be triggered by entering a MODIFY request.\n\nThe request may be rejected if the order has already been filled, or if no changes are requested.\n\n### DISPLAY or D\nDisplay information about existing orders\n\nParameters:\n* * this optional first parameter (a single asterisk(*)) requests a more verbose display.\n* order_id or symbol or ALL.\n  * One of these must appear.\n  * See the **Order Identity** section above for a description of the ways in which order ID can be expressed.\n  * A symbol will display all orders related to a specific symbol.\n  * The literal word ALL will display information about all known symbols.\n\n### FILE or F\nOpen or close a script file.\n\nParameter:\n* If this command appears in a script file, no parameter is allowed. This is considered to be a request to close the script file.\n* filename    If this command is entered from the console, the filename is the name of a script file from which future commands should com.\n\nCommands will be read from the script file until:\n* The \"FILE\" command appears in the script file,\n* End-of-file on the script file.\n* The \"QUIT\" command appears in the script file.\n\nIf the script file was originally opened by a FILE command entered from the console, and the script exits because of-\na FILE command or end-of-file, then control returs to the console.\nIf the script file was opened from the command line (see the **The Command Line** section), or the QUIT command appears in the script file, then the program exits.\n\n### HELP or ?\nDisplay help for requests\n\nDisplays a brief form of the information in this document.\n\n### QUIT\nExit the program.\n\n\n"
  },
  {
    "path": "doc/settAug2013/liquibook_sett.html",
    "content": "<!DOCTYPE HTML>\n<head>\n    <meta charset=\"utf-8\">\n\n    <meta name=\"description\" content=\"Building a Market Data Feed With Liquibook\"/>\n    <meta name=\"keywords\" content=\"SETT, OCI, finance, order book\"/>\n    <meta name=\"author\" content=\"Jeff Schmitz\"/>\n    <title>SETT August 2013 - Building a Market Data Feed With Liquibook</title>\n\n    <link rel=\"alternate\" type=\"application/rss+xml\" title=\"RSS\" href=\"http://ociweb.com/sett/rss.xml\"/>\n    <link href=\"styles/SETT.css\" rel=\"stylesheet\" type=\"text/css\"/>\n\n    <!-- stylings for this article only -->\n    <style type=\"text/css\">\n        table {\n            border-collapse: collapse;\n            border-width: 3px;\n        }\n\n        table, th, td {\n            border: 2px solid black;\n        }\n\n        td {\n            font-size: 10pt;\n        }\n\n        th {\n            font-size: 9pt;\n        }\n\n        tr {\n            text-align: left;\n        }\n    </style>\n\n    <!--Used for syntax highlighting.  -->\n    <link href=\"http://alexgorbatchev.com/pub/sh/current/styles/shCore.css\" rel=\"stylesheet\" type=\"text/css\"/>\n    <link href=\"http://alexgorbatchev.com/pub/sh/current/styles/shThemeDefault.css\" rel=\"stylesheet\" type=\"text/css\"/>\n</head>\n<body>\n<div class=\"header\">\n    <div>\n        <div class=\"left\">\n            <a href=\"http://twitter.com/ObjectComputing\" class=\"twitter-follow-button\">Follow @ObjectComputing</a>\n        </div>\n        <div class=\"right quicklinks\">\n            <a href=\"http://www.ociweb.com/\">Home</a> |\n            <a href=\"http://www.ociweb.com/sett/index.html\"> Software Engineering Tech Trends Archive</a> |\n            <a href=\"http://www.ociweb.com/training\">OCI Educational Services</a>\n        </div>\n    </div>\n    <div class=\"headimage_container\">\n        <div class=\"headerimage_leftlogo\">\n            <a href=\"http://www.ociweb.com/\">\n                <img alt=\"\" src=\"./images/OCILogo.png\" height=\"120\" width=\"180\"/></a>\n        </div>\n        <div class=\"headimage_left\"><img alt=\"\" src=\"images/Left.png\"/></div>\n        <div class=\"headimage_right\">\n            <img alt=\"\" src=\"images/Right.png\"/>\n        </div>\n    </div>\n    <div class=\"lower_header\">\n        <div class=\"left\">\n            <img alt=\"\" src=\"images/SETT.png\" height=\"34\" width=\"377\"/>\n        </div>\n        <div class=\"right social\">\n            <!-- AddThis Button BEGIN -->\n<div class=\"addthis_toolbox addthis_default_style\">\n    <a class=\"addthis_button_tweet\"></a>\n    <a id=\"plusone\" class=\"addthis_button_google_plusone\"></a>\n    <a class=\"addthis_button_dzone\"></a>\n    <a class=\"addthis_button_reddit\"></a>\n    <a class=\"addthis_button_digg\"></a>\n    <a id=\"addthis\" class=\"addthis_counter addthis_pill_style\"></a>\n    <a href=\"http://ociweb.com/sett/rss.xml\"><span class=\"rssRow\">RSS</span></a>\n</div>\n<script type=\"text/javascript\">\n    document.getElementById(\"plusone\").setAttribute(\"g:plusone:size\", \"medium\");\n    document.getElementById(\"addthis\").setAttribute(\"addthis:ui_delay\", \"500\");\n</script>\n<script type=\"text/javascript\" src=\"//s7.addthis.com/js/300/addthis_widget.js#pubid=ra-51702ff71314f8ed\"></script>\n<!-- AddThis Button END -->\n\n        </div>\n    </div>\n</div>\n\n<h1>Building a Market Data Feed with Liquibook</h1>\n\n<p class=\"author\">\n    by<br/>\n\n    Jeff Schmitz, Principal Software Engineer\n    <br/>Object Computing, Inc. (OCI)\n</p>\n\n<h2>Introduction</h2>\n\n<p>\n  The financial industry relies heavily on systems to disseminate and interpret\n  market data. Both trading decisions and analytics are based on the current\n  state of the market for a particular security.  A typical trading exchange\n  involves multiple parties, and in a conceptual view looks like this:\n</p>\n\n<div class=\"figure\">Figure 1: Conceptual View of Exchange</div>\n<img src=\"settAug2013_files/Exchange.png\"/>\n\n<p>\n  Building such an exchange is a complex undertaking, involving order taking,\n  matching, serialization and compression to a feed, dissemination,\n  deserialization, decompression, and interpretation.  This paper will\n  demonstrate how to build such a system using only open-source components,\n  including Liquibook for limit order book matching, QuickFAST for compression\n  and decompression, and Boost ASIO for distribution.\n</p>\n\n<h3>Liquibook Background</h3>\n\n<p>\n  Liquibook is a C++ open source limit order book matching engine.  It is a\n  component library that you can integrate into your project for implementing\n  matching algorithms.  Liquibook includes components for an order book,\n  aggregate depth tracking, BBO tracking, and a trade feed.\n</p>\n\n<h3>QuickFAST Background</h3>\n\n<p>\n  The FAST protocol is a compression and encoding mechanism for streaming data.\n  QuickFAST is an implementation of the FAST protocol in C++ for encoding and \n  decoding message streams using the FAST protocol.\n</p>\n\n<h3>Boost ASIO Background</h3>\n\n<p>\n  Boost ASIO is a cross-platform C++ library for asynchronous network\n  programming.\n</p>\n\n<h2>Example System</h2>\n\n<p>\n  The example project for this paper will take on a more advanced use case:\n  simulating an exchange producing a 5-level depth feed - aggregated by price,\n  and a trade feed.  This example involves a number of steps:\n</p>\n\n<h3>Accept Orders</h3>\n\n<p>\n  The example exchange generates orders, simulating the receipt of orders from\n  traders.  A true exchange takes orders from traders by means of an API - \n  often via the FIX protocol.  For the purposes of this paper, internally\n  generated orders will suffice.\n</p>\n\n<h3>Maintain a Limit Order Book for Each Security</h3>\n\n<p>\n  The example exchange must be ready to match unfilled orders against inbound\n  orders.  This is done by means of a limit order book.  The limit order book\n  keeps these orders sorted so that when multiple existing orders can match a\n  new inbound order, the matching is performed in a sequence determined by\n  established exchange rules.  The example exchange uses Liquibook's \n  DepthOrderBook class to maintain the limit order book.\n</p>\n\n<h3>Match Buy and Sell Orders</h3>\n\n<p>\n  The example exchange must match new inbound orders against those in the \n  limit order book.  The exchange must detect a match, and fill the appropriate\n  orders.  Liquibook's order book classes naturally includes matching\n  capability.\n</p>\n\n<h3>Update Trading Client Order Status</h3>\n\n<p>\n  An exchange must always notify traders of changes in their order status.\n  This includes accepting, filling, and rejecting orders, but also accepting\n  or rejecting order cancellation and replacement requests.  In the example\n  exchange, there are no trading clients (the orders are randomly generated),\n  so this step will be skipped.  Liquibook does, however, provide an interface\n  and make callbacks for changes in order status, which can easily be turned\n  into notifications sent to trading clients.\n</p>\n\n<h3>Aggregate the Top 5 Price Levels into Depth</h3>\n\n<p>\n  While a full order book feed is useful, some exchanges choose to send \n  aggregated forms of data instead, known as depth.  Rather than\n  representing individual orders, depth models price levels as a whole.\n  An exchange will also limit the number of levels distributed - top 5 and \n  top 10 are common limits.  \n</p>\n<p>\n  The example exchange goes through the extra step and complexity of building\n  5-level depth.  Liquibook provides the DepthOrderBook class, which\n  manages the order book and depth, and the DepthListener class for being\n  notified of changes to the top few depth levels.\n</p>\n\n<h3>Determine Changes to Depth in Response to an Event</h3>\n\n<p>\n  It is not enough to maintain the depth.  In order to produce an \n  incremental feed, the example exchange must also be able to determine which\n  levels of the depth have changed.  A change can happen to one or more\n  levels in the depth, on both the buy and sell sides, in response to a\n  single order event.  Liquibook has an interface for interrogating the various\n  levels of depth and finding out if it has changed since the last\n  published change.  This makes it trivial to build an incremental feed -\n  sending only changed levels to feed clients.\n</p>\n\n<h3>Compress and Distributing Market Data in a Feed</h3>\n\n<p>\n  In order to effectively trade, feed clients have a need to understand order\n  flow in the exchange.  Feeds in which clients are notified of all possible\n  order detail are known as \"quote\" feeds or \"full order book\" feeds, while\n  those which aggregate orders by price are called \"depth\" feeds.  A \"BBO\"\n  feed gives only the top-level quote for a security, and a \"trade\" feed \n  reflects all trades, or matched orders.  Liquibook has support for building\n  all of these feeds.\n</p>\n\n<p>\n  The example exchange builds both a trade and depth feed, then compresses the\n  trade and depth messages using QuickFAST and sends them to clients using\n  Boost ASIO.\n</p>\n\n<h3>Handle the Feed in a Client Program</h3>\n\n<p>\n  Finally, the example includes feed clients that connect to the feed, decode\n  the updates to recreate the trade events and reproduce the market depth.\n  The clients use QuickFAST for decoding, Boost ASIO to handle network I/O, and\n  Liquibook to reproduce the depth.\n</p>\n\n<h2>Getting Started</h2>\n\n<p>\n  If you intend to build this project, you will need to download and build:\n</p>\n\n<ol>\n  <li>Boost version 1.53 or later</li>\n  <li>Xerces version 3.1.1 or later</li>\n  <li>QuickFAST version 1.5.0 or later</li>\n  <li>Liquibook version 1.1.0 or later </li>\n</ol>\n\n<p>\n  The project is found in total within the directory\n  <code> examples/depth_feed_publisher</code> of Liquibook.\n</p>\n\n<h2>The Example Exchange</h2>\n\n<p>\n  The example exchange consists of two applications, a publisher and a\n  subscriber.  The figure below illustrates the flow of data in the example\n  exchange.\n</p>\n\n<a name=\"figure2\"><div class=\"figure\">Figure 2: Example Exchange Data Flow</div></a>\n<img src=\"settAug2013_files/ExampleExchange.png\"/>\n\n<h2>Publisher Application</h2>\n\n<p>\n  The publisher implements the exchange in the example project.  The publisher\n  generates orders and adds them to the proper order book, handles the trade\n  and depth events through listeners, encodes these using QuickFAST, and sends\n  them using Boost ASIO.\n</p>\n\n<h3>The Order Book</h3>\n<p>\n  As an exchange, the publisher must implement an order book.  Liquibook comes\n  with an order book class - two actually: <code>book::OrderBook</code> for\n  managing an order book only, and a derived class\n  <code>book::DepthOrderBook</code> for adding depth aggregation to that order\n  book.  Since the publisher builds a depth feed, it uses\n  <code>book::DepthOrderBook</code>.  The relevant parts of the\n  <code>book::OrderBook</code> class are:\n</p>\n\n<div class=\"listing\">book/order_book.h: Selected parts of OrderBook class declaration</div>\n<pre class=\"code\">\nnamespace liquibook { namespace book {\n\ntemplate &lt;class OrderPtr = Order*&gt;\nclass OrderBook {\npublic:\n  typedef OrderBook&lt;OrderPtr &gt; MyClass;\n  typedef TradeListener&lt;MyClass &gt; TypedTradeListener;\n\n  /// @brief set the trade listener\n  void set_trade_listener(TypedTradeListener* listener);\n\n  /// @brief add an order to book\n  /// @param order the order to add\n  /// @param conditions special conditions on the order\n  /// @return true if the add resulted in a fill\n  virtual bool add(const OrderPtr& order, OrderConditions conditions = 0);\n\n  /// @brief perform all callbacks in the queue\n  virtual void perform_callbacks();\n};\n\n} }\n</pre>\n\n<p>\n  Note that the <code>book::OrderBook</code> class is a template class,\n  allowing the user to define not only the order class used in the order book,\n  but the style of pointer used.  This can be a regular pointer or a smart\n  pointer.\n</p>\n\n<p>\n  The first method of interest allows a setting of a listener for trades.  This\n  listener, shown later, gets notified when a trade occurs.  The example\n  exchange needs this notification to build a trade feed, and thus sets the\n  trade listener.  The <code>book::OrderBook</code> class also includes\n  listeners for all order status updates, for providing updates back to the\n  trade clients, and a listener for all changes to the order book, to build a\n  full order book feed.\n</p>\n\n<p>\n  Next is a method to add an order to the order book.  <code>add()</code> \n  accepts an order pointer, and condition flags for special conditions, like\n  an immediate or cancel order.  Note that there are also methods (not used in\n  the example project) to cancel an order and to replace an order.\n</p>\n\n<p>\n  Finally, there is a method to perform the callbacks on the order book.\n  Liquibook gives the client code the responsibility to execute this method,\n  so that it can be done in the calling thread, or a background thread.\n  By default, this method calls <code>perform_callback()</code> for each\n  callback in the queue.  Naturally, <code>perform_callback()</code> can be\n  overridden, but that is not necessary in the publisher.  The default\n  implementation of this method issues callbacks for to the trade listener,\n  order listener, and order book listener, if present.\n</p>\n\n<p>\n  The derived <code>book::DepthOrderBook</code> class is simpler:\n</p>\n\n<div class=\"listing\">book/depth_order_book.h: DepthOrderBook class declaration</div>\n<pre class=\"code\">\nnamespace liquibook { namespace book {\n\n/// @brief Implementation of order book child class, that incorporates\n///        aggregate depth tracking.  Overrides perform_callback() method to \n//         track depth aggregated by price.\ntemplate <class OrderPtr = Order*, int SIZE = 5>\nclass DepthOrderBook : public OrderBook<OrderPtr> {\npublic:\n  typedef Depth<SIZE> DepthTracker;\n  typedef BboListener<DepthOrderBook >TypedBboListener;\n  typedef DepthListener<DepthOrderBook >TypedDepthListener;\n  typedef Callback<OrderPtr> DobCallback;\n\n  /// @brief construct\n  DepthOrderBook();\n\n  /// @brief set the BBO listener\n  void set_bbo_listener(TypedBboListener* bbo_listener);\n\n  /// @brief set the depth listener\n  void set_depth_listener(TypedDepthListener* depth_listener);\n\n  /// @brief handle a single callback\n  virtual void perform_callback(DobCallback& cb);\n\n  // @brief access the depth tracker\n  DepthTracker& depth();\n\n  // @brief access the depth tracker\n  const DepthTracker& depth() const;\n\nprivate:\n  DepthTracker depth_;\n  TypedBboListener* bbo_listener_;\n  TypedDepthListener* depth_listener_;\n};\n</pre>\n\n<p>\n  <code>book::DepthOrderBook</code> overrides <code>perform_callback()</code>\n  to update its depth, which is accessible through the <code>depth()</code>\n  accessor methods.  In addition, <code>book::DepthOrderBook</code> adds two\n  new listeners - a BBO listener, for tracking only changes to the best bid\n  and best offer, and a depth listener, for tracking all depth changes.\n</p>\n\n<p>\n  To build the exchange, the publisher must create a \n  <code>book::DepthOrderBook</code>, and it set the trade listener and depth\n  listener.  While handling these callbacks, the publisher will need to \n  update the feed clients with trade and depth update messages.\n</p>\n\n<p>\n  Note that in some of the callbacks, a pointer to the order book is provided,\n  while a pointer to the order is provided in others.\n  This gives the publisher two opportunities to provide additional fields and \n  logic through inheritance.  The publisher takes advantage of this, providing\n  access to the symbol of the order book's security:\n</p>\n\n<div class=\"listing\">example_order_book.h: ExampleOrderBook class declaration</div>\n<pre class=\"code\">\nnamespace liquibook { namespace examples {\n\ntypedef boost::shared_ptr<Order> OrderPtr;\n\nclass ExampleOrderBook : public book::DepthOrderBook&lt;OrderPtr&gt; {\npublic:\n  ExampleOrderBook(const std::string& symbol);\n  const std::string& symbol() const;\n\nprivate:\n  std::string symbol_;\n};\n\n} } // End namespace\n</pre>\n\n<p>\n  Here the reader will note that the <code>ExampleOrderBook</code>\n  class specializes <code>book::DepthOrderBook</code> and binds a shared\n  pointer of <code>Order</code> to its parent's template argument.\n  The <code>Order</code> class is shown below.  The trivial\n  implementation of the <code>ExampleOrderBook</code> is omitted\n  from this paper.  The class diagram for order books looks like this:\n</p>\n\n<div class=\"figure\">Figure 3: Order Book Class Diagram</div>\n<img src=\"settAug2013_files/OrderBookUML.png\"/>\n\n<h3>The Exchange</h3>\n\n<p>\n  The <code>ExampleOrderBook</code> class manages the order book and\n  depth for a single security.  Since exchanges handle multiple securities, \n  somewhere the publisher needs to create an order book for each security, and\n  maintain a mapping from a symbol to its order book.  The publisher does this\n  in the <code>Exchange</code> class:\n</p>\n\n<div class=\"listing\">exchange.h: Exchange class declaration</div>\n<pre class=\"code\">\nnamespace liquibook { namespace examples {\n\nclass Exchange {\npublic:\n  Exchange(ExampleOrderBook::TypedDepthListener* depth_listener,\n           ExampleOrderBook::TypedTradeListener* trade_listener);\n\n  // Permanently add an order book to the exchange\n  void add_order_book(const std::string&amp; symbol);\n\n  // Handle an incoming order\n  void add_order(const std::string&amp; symbol, OrderPtr&amp; order);\nprivate:\n  typedef std::map&lt;std::string, ExampleOrderBook&gt; OrderBookMap;\n  OrderBookMap order_books_;\n  ExampleOrderBook::TypedDepthListener* depth_listener_;\n  ExampleOrderBook::TypedTradeListener* trade_listener_;\n};\n\n} }\n</pre>\n\n<p> \n  The <code>Exchange</code> class has only three methods: a\n  constructor, a method to add an order book, and a method to handle an order.\n  As expected, it maintains a map of order books.  It also maintains pointers\n  to the depth listener and trade listener.  The constructor does exactly that,\n  in order to add the listeners to future order books:\n</p>\n\n<div class=\"listing\">exchange.cpp: Exchange class implementation</div>\n<pre class=\"code\">\nnamespace liquibook { namespace examples {\n\nExchange::Exchange(ExampleOrderBook::TypedDepthListener* depth_listener,\n                   ExampleOrderBook::TypedTradeListener* trade_listener)\n: depth_listener_(depth_listener),\n  trade_listener_(trade_listener)\n{\n}\n</pre>\n\n<p>\n  The <code>add_order_book()</code> method creates a new order book, sets the\n  listeners on the order book, and adds a mapping from the given symbol to the\n  order book:\n</p>\n\n<div class=\"listing\">exchange.cpp: Exchange class implementation, continued</div>\n<pre class=\"code\">\nvoid\nExchange::add_order_book(const std::string&amp; sym)\n{\n  std::pair<OrderBookMap::iterator, bool> result;\n  result = order_books_.insert(std::make_pair(sym, ExampleOrderBook(sym)));\n  result.first-&gt;second.set_depth_listener(depth_listener_);\n  result.first-&gt;second.set_trade_listener(trade_listener_);\n}\n</pre>\n\n<p>\n  Finally, the <code>add_order()</code> method finds the correct order book,\n  adds the order to the order book, and then triggers callbacks by calling\n  the <code>perform_callbacks()</code> method:\n</p>\n\n<div class=\"listing\">exchange.cpp: Exchange class implementation, continued</div>\n<pre class=\"code\">\nvoid\nExchange::add_order(const std::string&amp; symbol, OrderPtr&amp; order)\n{\n  OrderBookMap::iterator order_book = order_books_.find(symbol);\n  if (order_book != order_books_.end()) {\n    order_book-&gt;second.add(order);\n    order_book-&gt;second.perform_callbacks();\n  }\n}\n\n} } // End namespace\n</pre>\n\n<p>\n  The call to <code>perform_callbacks()</code> will trigger any callbacks to\n  the provided listeners.  This way, a single thread is manipulating the order\n  books.  It is also possible to issue <code>perform_callbacks()</code> calls\n  in a background thread, but the publisher does it this way for simplicity.\n</p>\n\n<h3>Order Class</h3>\n\n<p>\n  Liquibook requires that the application define an order class to represent \n  an order to match.  Liquibook requires that it meet the interface defined\n  in the class <code>src/book/order.h</code>:\n</p>\n\n<div class=\"listing\">book/order.h: Order class (Liquibook) declaration</div>\n<pre class=\"code\">\nnamespace liquibook { namespace book {\n\nclass Order {\npublic:\n  /// @brief is this a limit order?\n  bool is_limit() const;\n\n  /// @brief is this order a buy?\n  virtual bool is_buy() const = 0;\n\n  /// @brief get the price of this order, or 0 if a market order\n  virtual Price price() const = 0;\n\n  /// @brief get the quantity of this order\n  virtual Quantity order_qty() const = 0;\n};\n\n} }\n</pre>\n\n<p>\n  The publisher defines <code>Order</code> to implement the \n  <code>book::Order</code> interface:\n</p>\n\n<div class=\"listing\">order.h: Order class (publisher) declaration</div>\n<pre class=\"code\">\nnamespace liquibook { namespace examples {\n\nclass Order : public book::Order {\npublic:\n  Order(bool buy,\n        const double&amp; price,\n        book::Quantity qty);\n\n  virtual bool is_buy() const;\n  virtual book::Quantity order_qty() const;\n  virtual book::Price price() const;\n\n  static const uint8_t precision_;\nprivate:\n  bool is_buy_;\n  double price_;\n  book::Quantity qty_;\n};\n\n} }\n</pre>\n\n<p>\n  Note that as a template class, Liquibook's <code>book::OrderBook</code> does\n  not strictly require inheriting from the <code>book::Order</code> class,\n  just that the interface be implemented.\n</p>\n<p>\n  The example's <code>Order</code> class implements <code>book::Order</code>,\n  and adds a static field called <code>precision_</code> for price conversion.\n</p>\n\n<p>\n  The <code>Order</code> constructor simply copies the arguments passed to it:\n</p>\n\n<div class=\"listing\">order.h: Order class implementation</div>\n<pre class=\"code\">\nnamespace liquibook { namespace examples {\n\nconst uint8_t Order::precision_(100);\n\nOrder::Order(bool buy, const double&amp; price, book::Quantity qty)\n: is_buy_(buy),\n  price_(price),\n  qty_(qty)\n{\n}\n</pre>\n\n<p>\n  Note the presence of the static initializer of <code>precision_</code>.\n</p>\n\n<p>\n  The <code>is_buy()</code> and <code>order_qty()</code> are simple accessors:\n</p>\n\n<div class=\"listing\">order.h: Order class implementation, continued</div>\n<pre class=\"code\">\nbool\nOrder::is_buy() const\n{\n  return is_buy_;\n}\n\nbook::Quantity\nOrder::order_qty() const\n{\n  return qty_;\n}\n</pre>\n\n<p>\n  The final method is used to provide a price to the order book.  For\n  performance reasons, the Liquibook requires this to be in integer format,\n  so <code>Order</code> converts the price by multiplying by the precision:\n</p>\n\n<div class=\"listing\">order.h: Order class implementation, continued</div>\n<pre class=\"code\">\nbook::Price\nOrder::price() const\n{\n  return price_ * precision_;\n}\n</pre>\n\n<p>\n  There are two implications - first, that the publisher is limited to penny \n  precision.  This is suitable for purposes of the example, but may need to be\n  increased for other use cases.  The second implication is that all securities\n  in the publisher have the same precision - since a static variable is used to\n  set precision.  Again, in other use cases, this may not be sufficient.\n</p>\n\n<h3>QuickFAST Templates</h3>\n\n<p>\n  To transmit messages using the FAST protocol, one must first decide on the \n  messages to transmit on the feed.  This exchange will produce a trade feed\n  and an incremental depth feed.  A simplified view of a trade consists of a\n  symbol, a quantity, and a trade price.  The publisher alters this slightly\n  by providing the trade cost (price times quantity), from which price per\n  share can be derived.\n</p>\n\n<p>\n  QuickFAST uses XML files, called templates to describe the messages in the \n  feed protocol.  The example's templates can be found in the file \n  <code>examples/depth_feed_publisher/depth.xml</code>.  The trade message \n  template looks like this:\n</p>\n\n<pre class=\"code\">\n&lt;template name=\"Trade\" id=\"1\"&gt;\n  &lt;uInt16 name=\"MessageType\" id=\"100\"&gt;\n    &lt;constant value=\"22\"/&gt;\n  &lt;/uInt16&gt;\n  &lt;uInt32 name=\"SequenceNumber\" id=\"200\"&gt;\n    &lt;increment/&gt;\n  &lt;/uInt32&gt;\n  &lt;uInt32 name=\"Timestamp\" id=\"300\"&gt;\n    &lt;copy/&gt;\n  &lt;/uInt32&gt;\n  &lt;string name=\"Symbol\" id=\"400\"&gt;\n    &lt;copy/&gt;\n  &lt;/string&gt;\n  &lt;uInt32 name=\"Quantity\" id=\"604\"&gt;\n    &lt;copy/&gt;\n  &lt;/uInt32&gt;\n  &lt;uInt32 name=\"Cost\" id=\"603\"&gt;\n    &lt;copy/&gt;\n  &lt;/uInt32&gt;\n&lt;/template&gt;\n</pre>\n\n<p>\n  Note that the tag names within the <code>&lt;template&gt;</code> tag\n  indicate the type of the field.  The reader may be surprised to see a\n  currency field (Cost) represented as an integer (uint32).  This, however is\n  consistent with Liquibook's internal storage of prices as as integer.  \n  Liquibook's design decision is thus carried forward to the feed protocol,\n  requiring the clients to convert these prices back to their decimal format.\n</p>\n\n<p>\n  In addition to the expected trade fields, the publisher provides a message\n  type, to indicate to the subscriber that the message is for a trade, a\n  sequence number, so the subscriber can be confident it has received all\n  messages, and processed them in the correct order, and a timestamp, so the\n  subscriber can be confident the message has been received in a timely manner.\n</p>\n\n<p>\n  The depth update template is more complicated:\n</p>\n\n<pre class=\"code\">\n&lt;template name=\"Depth\" id=\"2\"&gt;\n  &lt;uInt16 name=\"MessageType\" id=\"100\"&gt;\n    &lt;constant value=\"11\"/&gt;\n  &lt;/uInt16&gt;\n  &lt;uInt32 name=\"SequenceNumber\" id=\"200\"&gt;\n    &lt;increment/&gt;\n  &lt;/uInt32&gt;\n  &lt;uInt32 name=\"Timestamp\" id=\"300\"&gt;\n    &lt;copy/&gt;\n  &lt;/uInt32&gt;\n  &lt;string name=\"Symbol\" id=\"400\"&gt;\n    &lt;copy/&gt;\n  &lt;/string&gt;\n  &lt;sequence name=\"Bids\" id=\"500\"&gt;\n    &lt;uInt8 name=\"LevelNum\" id=\"501\"&gt;\n      &lt;copy/&gt;\n    &lt;/uInt8&gt;\n    &lt;uInt32 name=\"OrderCount\" id=\"502\"&gt;\n      &lt;copy/&gt;\n    &lt;/uInt32&gt;\n    &lt;uInt32 name=\"Price\" id=\"503\"&gt;\n      &lt;copy/&gt;\n    &lt;/uInt32&gt;\n    &lt;uInt32 name=\"AggregateQty\" id=\"504\"&gt;\n      &lt;copy/&gt;\n    &lt;/uInt32&gt;\n  &lt;/sequence&gt;\n  &lt;sequence name=\"Asks\" id=\"600\"&gt;\n    &lt;uInt8 name=\"LevelNum\" id=\"601\"&gt;\n      &lt;copy/&gt;\n    &lt;/uInt8&gt;\n    &lt;uInt32 name=\"OrderCount\" id=\"602\"&gt;\n      &lt;copy/&gt;\n    &lt;/uInt32&gt;\n    &lt;uInt32 name=\"Price\" id=\"603\"&gt;\n      &lt;copy/&gt;\n    &lt;/uInt32&gt;\n    &lt;uInt32 name=\"AggregateQty\" id=\"604\"&gt;\n      &lt;copy/&gt;\n    &lt;/uInt32&gt;\n  &lt;/sequence&gt;\n&lt;/template&gt;\n</pre>\n\n<p>\n  The depth message begins with the same 4 fields as the trade message: \n  message type, sequence number, timestamp, and symbol.  The depth message also\n  includes two sequences, or  variable-length lists.  These sequences\n  represent the changed bid and ask levels of the depth for the message\n  security.  The sequences themselves contain a set of fields, although in\n  this case both sequences are of the same type.\n</p>\n\n<p>\n  Each changed depth level begins with a level number, indicating which level \n  has changed.  If the exchange were to produce all depth levels on every \n  change, this would not be necessary.  Because in an incremental feed the\n  sequence element could represent any of the 5 levels, it is required.\n</p>\n\n<p>\n  Order count indicates the number of orders which were aggregated at this \n  level.  If the order count is 0, it indicates a deleted level.  Price is the\n  price common to all the aggregated orders at this level.  As in the trade\n  message, it is represented by an integer.  Finally, aggregate quantity shows\n  the sum of all the order quantities at this level.\n</p>\n\n<h3>Using QuickFAST Template</h3>\n\n<p>\n  With the template in place, the publisher (and subscriber) must use\n  QuickFAST to put the templates to use for encoding (and decoding).  The \n  publisher (and subscriber) do this by means of the\n  <code>TemplateConsumer</code> class:\n</p>\n\n<div class=\"listing\">tempate_consumer.h: TemplateConsumer class declaration</div>\n<pre class=\"code\">\nnamespace liquibook { namespace examples {\n\nclass TemplateConsumer {\npublic:\n  static QuickFAST::Codecs::TemplateRegistryPtr \n             parse_templates(const std::string&amp; template_filename);\n\n  // Trade field identities\n  static const QuickFAST::Messages::FieldIdentity id_qty_;\n  static const QuickFAST::Messages::FieldIdentity id_cost_;\n\n  // Common field identities\n  static const QuickFAST::Messages::FieldIdentity id_seq_num_;\n  static const QuickFAST::Messages::FieldIdentity id_msg_type_;\n  static const QuickFAST::Messages::FieldIdentity id_timestamp_;\n  static const QuickFAST::Messages::FieldIdentity id_symbol_;\n\n  // Depth field identities\n  static const QuickFAST::Messages::FieldIdentity id_bids_length_;\n  static const QuickFAST::Messages::FieldIdentity id_bids_;\n  static const QuickFAST::Messages::FieldIdentity id_asks_length_;\n  static const QuickFAST::Messages::FieldIdentity id_asks_;\n\n  static const QuickFAST::Messages::FieldIdentity id_level_num_;\n  static const QuickFAST::Messages::FieldIdentity id_order_count_;\n  static const QuickFAST::Messages::FieldIdentity id_price_;\n  static const QuickFAST::Messages::FieldIdentity id_size_;\n};\n\n} }\n</pre>\n\n<p>\n  The <code>TemplateConsumer</code> class also has a static\n  <code>parse_templates()</code> method for parsing of templates.  It also \n  includes several static members of type\n  <code>const QuickFAST::Messages::FieldIdentityCPtr</code>.  These members\n  are used by QuickFAST to establish identities of fields within the various\n  messages.  The reader will notice that the field identifiers correspond to\n  fields in the template definition, with two exceptions:\n  <code>id_bids_length_</code>, and <code>id_asks_length_</code>.  This is\n  because the FAST protocol specifies that a sequence length is required for\n  each sequence, but can be implicitly declared.\n</p>\n\n<p>\n</p>\n\n<p>\n  These members are initialized in a manner consistent with the template \n  definition:\n</p>\n\n<div class=\"listing\">tempate_consumer.cpp: TemplateConsumer class implementation</div>\n<pre class=\"code\">\nnamespace liquibook { namespace examples {\n\nusing namespace QuickFAST::Messages;\n\nconst FieldIdentity TemplateConsumer::id_seq_num_(\"SequenceNumber\");\n\nconst FieldIdentity TemplateConsumer::id_msg_type_(\"MessageType\");\n\nconst FieldIdentity TemplateConsumer::id_timestamp_(\"Timestamp\");\n\n// more like this...\n</pre>\n\n<p>\n  The remaining members are initialized in a similar manner, and thus are not\n  included in this paper.  Finally, there is the <code>parse_templates()\n  method</code> which parses the QuickFAST templates:\n</p>\n\n<div class=\"listing\">tempate_consumer.cpp: TemplateConsumer class implementation, continued</div>\n<pre class=\"code\">\nQuickFAST::Codecs::TemplateRegistryPtr \nTemplateConsumer::parse_templates(const std::string& template_filename)\n{\n  std::ifstream template_stream(template_filename.c_str());\n  QuickFAST::Codecs::XMLTemplateParser parser;\n  return parser.parse(template_stream);\n}\n\n} } \n</pre>\n\n<p>\n  The <code>parse_templates()</code> method opens an input file stream using\n  the filename passed to it.  Then it creates a\n  <code>QuickFAST::Codecs::XMLTemplateParser</code> and calls the\n  <code>parse()</code> method on it, passing it the input file stream.  This \n  parses the template file, and produces the\n  <code>QuickFAST::Codecs::TemplateRegistryPtr</code> which preserves the\n  parsed form of the template file.\n</p>\n\n<h3>Connecting the Publisher and Subscriber</h3>\n\n<p>\n  The publisher and subscriber communicate over TCP/IP using boost::ASIO.  The\n  communication between publisher and subscriber is one way - the publisher\n  only sends messages, and the subscriber only receives them.  The\n  communication is also one-to-many, as multiple subscribers connect to a \n  single publisher.  Since QuickFAST encodes a stream of data, uniquely\n  compressed for each recipient, the publisher will need to maintain a\n  QuickFAST state for each subscriber's encoder.  This is done through a class\n  called <code>DepthFeedSession</code>.\n</p>\n\n<p>\n  The publisher also uses the <code>DepthFeedConnection</code> to listen for connections from subscribers.  The <code>DepthFeedConnection</code> will establish many <code>DepthFeedSession</code> instances.\n</p>\n\n<div class=\"listing\">depth_feed_connection.h: DepthFeedSession class declaration</div>\n<pre class=\"code\">\nnamespace liquibook { namespace examples {\n  typedef boost::shared_ptr<QuickFAST::WorkingBuffer> WorkingBufferPtr;\n  typedef std::deque<WorkingBufferPtr> WorkingBuffers;\n  typedef boost::array<unsigned char, 128> Buffer;\n  typedef boost::shared_ptr<Buffer> BufferPtr;\n  typedef boost::function<bool (BufferPtr, size_t)> MessageHandler;\n  typedef boost::function<void ()> ResetHandler;\n  typedef boost::function<void (const boost::system::error_code& error,\n                                std::size_t bytes_transferred)> SendHandler;\n  typedef boost::function<void (const boost::system::error_code& error,\n                                std::size_t bytes_transferred)> RecvHandler;\n\n  class DepthFeedConnection;\n\n  // Session between a publisher and one subscriber\n  class DepthFeedSession : boost::noncopyable {\n  public:\n    DepthFeedSession(boost::asio::io_service&amp; ios,\n                     DepthFeedConnection* connection,\n                     QuickFAST::Codecs::TemplateRegistryPtr&amp; templates);\n</pre>\n\n<p>\n  In addition to declaring some typedefs and a forward declaration, this\n  snippet of code declares <code>DepthFeedSession</code>'s  constructor.  This\n  constructor accepts (1) an IO Service object through which it can create a\n  TCP socket, (2) the <code>DepthFeedConnection</code> and (3) the parsed \n  QuickFAST templates, so it can encode outgoing messages.\n</p>\n\n<p>\n  Next are an accessor and setter for the session's connection status, and an\n  accessor for the session's TCP socket:\n</p>\n\n<div class=\"listing\">depth_feed_connection.h: DepthFeedSession class declaration, continued</div>\n<pre class=\"code\">\n    // Is this session connected?\n    bool connected() const { return connected_; }\n\n    // Mark this session as connected\n    void set_connected() { connected_ = true; }\n\n    // Get the socket for this session\n    boost::asio::ip::tcp::socket&amp; socket() { return socket_; }\n</pre>\n\n<p>\n  The real meat of the class is next, where messages are sent to the\n  subscriber, in <code>send_trade()</code> for trades, and both\n  <code>send_incr_update()</code>and <code>send_full_update()</code> for\n  depth updates.\n</p>\n\n<div class=\"listing\">depth_feed_connection.h: DepthFeedSession class declaration, continued</div>\n<pre class=\"code\">\n    // Send a trade messsage to all clients\n    void send_trade(QuickFAST::Messages::FieldSet& message);\n\n    // Send an incremental update - if this client has handled this symbol\n    //   return true if handled\n    bool send_incr_update(const std::string& symbol,\n                          QuickFAST::Messages::FieldSet& message);\n\n    // Send a full update - if the client has not yet received for this symbol\n    void send_full_update(const std::string& symbol,\n                          QuickFAST::Messages::FieldSet& message);\n</pre>\n\n<p>\n  The reader may wonder why there are two methods for sending depth updates.  \n  This is because the publisher produces an incremental feed for depth updates,\n  allowing only the changed depth levels to be published to the subscriber, \n  rather than all 5 levels of depth.  This is particularly effective because of\n  the nature of this data - most changes to depth are at the top one or two\n  levels of the limit order book.\n</p>\n\n<p>\n  Note that the trade feed is not an incremental feed - each trade stands on\n  its own.  This could be different if the trade carried accumulating values,\n  such as volume for the day, or average traded price.  In this case, an\n  incremental feed may be suitable for trades as well.  \n</p>\n\n<p>\n  For the depth feed, two update methods are provided, for sending an \n  incremental update, and for sending a full update.  Even though the depth\n  feed is an incremental feed, it is necessary to send full updates on\n  occasion.  A full update is required, for example, when the subscriber does\n  not yet have the depth state for a security, such as when it first connects\n  to the publisher.\n</p>\n\n<p>\n  The <code>DepthFeedSession</code> class includes a number of private members:\n</p>\n\n<div class=\"listing\">depth_feed_connection.h: DepthFeedSession class declaration, continued</div>\n<pre class=\"code\">\n  private:       \n    bool connected_;\n    uint64_t seq_num_;\n\n    boost::asio::io_service&amp; ios_;\n    boost::asio::ip::tcp::socket socket_;\n</pre>\n\n<p>\n  The first member indicates the connection status of the session.  Next, is a sequence number counter for the session.  This is followed by two low-level ASIO members: a reference to the IO service, and a socket for the session.\n</p>\n\n<p>\n  This is followed by a pointer to the one <code>DepthFeedConnection</code> of\n  the publisher, and the session's QuickFAST encoder:\n</p>\n\n<div class=\"listing\">depth_feed_connection.h: DepthFeedSession class declaration, continued</div>\n<pre class=\"code\">\n    DepthFeedConnection* connection_;\n    QuickFAST::Codecs::Encoder encoder_;\n</pre>\n\n<p>\n  Next, is a <code>set</code> to track which securities have had depth\n  information published, in order to track which securities still need a full\n  update:\n</p>\n\n<div class=\"listing\">depth_feed_connection.h: DepthFeedSession class declaration, continued</div>\n<pre class=\"code\">\n    typedef std::set&lt;std::string&gt; StringSet;\n    StringSet sent_symbols_;\n</pre>\n\n<p>\n  Next are two static members that store the template IDS for the trade and\n  depth messages:\n</p>\n\n<div class=\"listing\">depth_feed_connection.h: DepthFeedSession class declaration, continued</div>\n<pre class=\"code\">\n    static QuickFAST::template_id_t TID_TRADE_MESSAGE;\n    static QuickFAST::template_id_t TID_DEPTH_MESSAGE;\n</pre>\n\n<p>\n  Finally, there are two private methods, to set the sequence number on a \n  message, and to handle a sent message:\n</p>\n\n<div class=\"listing\">depth_feed_connection.h: DepthFeedSession class declaration, continued</div>\n<pre class=\"code\">\n    void set_sequence_num(QuickFAST::Messages::FieldSet&amp; message);\n\n    void on_send(WorkingBufferPtr wb,\n                 const boost::system::error_code&amp; error,\n                 std::size_t bytes_transferred);\n  };\n</pre>\n\n<p>\n  The <code>DepthFeedSession</code> implementation begins with the declarations\n  of its two static members, <code>TID_TRADE_MESSAGE</code> and\n  <code>TID_DEPTH_MESSAGE</code>.\n</p>\n\n<div class=\"listing\">depth_feed_connection.cpp: DepthFeedSession class implementation</div>\n<pre class=\"code\">\nusing namespace boost::asio::ip;\n\nnamespace liquibook { namespace examples {\n\nQuickFAST::template_id_t DepthFeedSession::TID_TRADE_MESSAGE(1);\nQuickFAST::template_id_t DepthFeedSession::TID_DEPTH_MESSAGE(2);\n</pre>\n\n<p>\n  Next is the class constructor, which sets the connected status to false, sets\n  the session sequence number to 0, initializes the socket, saves the IO\n  service and connection, and provides the templates to the QuickFAST encoder:\n</p>\n\n<div class=\"listing\">depth_feed_connection.cpp: DepthFeedSession class implementation, continued</div>\n<pre class=\"code\">\nDepthFeedSession::DepthFeedSession(\n    boost::asio::io_service&amp; ios,\n    DepthFeedConnection* connection,\n    QuickFAST::Codecs::TemplateRegistryPtr&amp; templates)\n: connected_(false),\n  seq_num_(0),\n  ios_(ios),\n  socket_(ios),\n  connection_(connection),\n  encoder_(templates)\n{\n}\n</pre>\n\n<p>\n  The next method sends a trade to the subscriber:\n</p>\n\n<div class=\"listing\">depth_feed_connection.cpp: DepthFeedSession class implementation, continued</div>\n<pre class=\"code\">\nvoid\nDepthFeedSession::send_trade(QuickFAST::Messages::FieldSet&amp; message)\n{\n  // Add or update sequence number in message\n  set_sequence_num(message);\n\n  std::cout &amp;&amp; \"sending trade message with \" &amp;&amp; message.size() &amp;&amp; \" fields\" &amp;&amp; std::endl;\n\n  QuickFAST::Codecs::DataDestination dest;\n  encoder_.encodeMessage(dest, TID_TRADE_MESSAGE, message);\n  WorkingBufferPtr wb = connection_-&gt;reserve_send_buffer();\n  dest.toWorkingBuffer(*wb);\n\n  // Perform the send\n  SendHandler send_handler = boost::bind(&amp;DepthFeedSession::on_send,\n                                         this, wb, _1, _2);\n  boost::asio::const_buffers_1 buffer(\n      boost::asio::buffer(wb-&gt;begin(), wb-&gt;size()));\n  socket_.async_send(buffer, 0, send_handler);\n}\n</pre>\n\n<p>\n  The <code>send_trade()</code> accepts an argument, reference to type \n  <code>QuickFAST::Messages::FieldSet</code>, which contains the method in a\n  protocol-neutral format.  The method starts by setting the sequence number\n  of the message by passing the field set to  <code>set_sequence_num()</code>.\n  The caller is responsible for filling out the other fields of the message, \n  while the session sets the sequence number.\n</p>\n\n<p>\n  Next, the method declares a data destination variable, which holds an\n  encoded message.  This message is then encoded into the destination by the\n  QuickFAST encoder, using the template ID for trade messages.\n</p>\n\n<p>\n  Next a QuickFAST working buffer is reserved for sending the message, and the\n  encoded message is serialized into the buffer.  To send the message, the\n  method first creates a send handler for the buffer, so that\n  <code>DepthFeedSession::on_send</code> is called after the send.  Next, it\n  sets up an ASIO buffer to send the working buffer's contents, and calls the\n  socket's <code>async_send()</code> method.\n</p>\n\n<p>\n  The <code>send_incr_update</code> method is similar, with some key\n  differences:\n</p>\n\n<div class=\"listing\">depth_feed_connection.cpp: DepthFeedSession class implementation, continued</div>\n<pre class=\"code\">\nbool\nDepthFeedSession::send_incr_update(const std::string&amp; symbol,\n                                   QuickFAST::Messages::FieldSet&amp; message)\n{\n  bool sent = false;\n  // If the session has been started for this symbol\n  if (sent_symbols_.find(symbol) != sent_symbols_.end()) {\n    QuickFAST::Codecs::DataDestination dest;\n    // Add or update sequence number in message\n    set_sequence_num(message);\n    encoder_.encodeMessage(dest, TID_DEPTH_MESSAGE, message);\n    WorkingBufferPtr wb = connection_-&gt;reserve_send_buffer();\n    dest.toWorkingBuffer(*wb);\n    SendHandler send_handler = boost::bind(&amp;DepthFeedSession::on_send,\n                                           this, wb, _1, _2);\n    boost::asio::const_buffers_1 buffer(\n        boost::asio::buffer(wb-&gt;begin(), wb-&gt;size()));\n    socket_.async_send(buffer, 0, send_handler);\n    sent = true;\n  }\n  return sent;\n}\n</pre>\n\n<p>\n  First, the reader will notice that <code>send_incr_update()</code> returns a\n  <code>bool</code> value.  This value indicates whether the message was sent\n  or not.  If not, the caller is responsible for calling\n  <code>send_full_update()</code> with the message.\n</p>\n\n<p>\n  The method also checks the <code>sent_symbols_</code> for the symbol of the \n  message (provided as an argument) to ensure the security has been sent to the\n  subscriber previously.  Should this be true, execution is similar to that of\n  <code>send_trade()</code>, where the sequence number is set, the message is\n  encoded to a data destination, a working buffer is reserved, the destination\n  serialized to the working buffer, and the working buffer contents is sent.\n</p>\n\n</p>\n  The <code>send_full_update()</code> method is similar to\n  <code>send_incr_update</code>, without the return value.  In this case, the\n  method updates the <code>sent_symbols_</code> map to be true.  As a form of\n  protection, it does not send the full update if the map already had a value\n  for that security.\n<p>\n\n<div class=\"listing\">depth_feed_connection.cpp: DepthFeedSession class implementation, continued</div>\n<pre class=\"code\">\nvoid\nDepthFeedSession::send_full_update(const std::string&amp; symbol,\n                                   QuickFAST::Messages::FieldSet&amp; message)\n{\n  // Mark this symbols as sent\n  std::pair<StringSet::iterator, bool> result = sent_symbols_.insert(symbol);\n\n  // If this symbol is new for the session\n  if (result.second) {\n    QuickFAST::Codecs::DataDestination dest;\n    // Add or update sequence number in message\n    set_sequence_num(message);\n    encoder_.encodeMessage(dest, TID_DEPTH_MESSAGE, message);\n    WorkingBufferPtr wb = connection_-&gt;reserve_send_buffer();\n    dest.toWorkingBuffer(*wb);\n\n    // Perform the send\n    SendHandler send_handler = boost::bind(&amp;DepthFeedSession::on_send,\n                                           this, wb, _1, _2);\n    boost::asio::const_buffers_1 buffer(\n        boost::asio::buffer(wb-&gt;begin(), wb-&gt;size()));\n    socket_.async_send(buffer, 0, send_handler);\n  }\n}\n</pre>\n\n<p>\n  The first private method, <code>set_sequence_num()</code> is used to set \n  the sequence number field in the outgoing message.  The sequence number is \n  unique to each session, so it must be encoded for each copy of the outbound\n  message:\n</p>\n\n<div class=\"listing\">depth_feed_connection.cpp: DepthFeedSession class implementation, continued</div>\n<pre class=\"code\">\nvoid\nDepthFeedSession::set_sequence_num(QuickFAST::Messages::FieldSet&amp; message)\n{\n  // Create the field\n  QuickFAST::Messages::FieldCPtr value =\n      QuickFAST::Messages::FieldUInt32::create(++seq_num_);\n  // Update the sequence number\n  if (!message.replaceField(TemplateConsumer::id_seq_num_, value)) {\n    // Not found, add the sequence number\n    message.addField(TemplateConsumer::id_seq_num_, value);\n  }\n}\n</pre>\n\n<p>\n  The method begins by creating a QUICKFAST field for the incremented sequence\n  number.  Since this code resides within a session, there is a copy of the\n  member variable <code>seq_num_</code> for each subscriber.  The first message\n  will have a sequence number of 1.\n</p>\n\n<p>\n  The method attempts to update the sequence number field in the message, and \n  if the sequence number is not yet present in the message, the field is added.\n  Using this technique, the message can be built once, and then have the \n  sequence number customized for each subscriber, without having to build the\n  message from scratch for each subscriber.\n</p>\n\n<p>\n  The other private method, <code>on_send()</code> handles a sent message, \n  logging any error code, and calling the <code>DepthFeedConnection</code>\n  version of the method:\n</p>\n\n<div class=\"listing\">depth_feed_connection.cpp: DepthFeedSession class implementation, continued</div>\n<pre class=\"code\">\nvoid\nDepthFeedSession::on_send(WorkingBufferPtr wb,\n                          const boost::system::error_code&amp; error,\n                          std::size_t bytes_transferred)\n{\n  if (error) {\n    std::cout &lt;&lt; \"Error \" &lt;&lt; error &lt;&lt; \" sending message\" &lt;&lt; std::endl;\n    connected_ = false;\n  }\n\n  // Keep buffer for later\n  connection_-&gt;on_send(wb, error, bytes_transferred);\n}\n\n</pre>\n\n<p>\n  The <code>DepthFeedConnection</code> class is used by both the publisher and\n  the subscriber.  It has a constructor that accepts the command line\n  arguments:\n</p>\n\n<div class=\"listing\">depth_feed_connection.h: DepthFeedConnection class declaration</div>\n<pre class=\"code\">\n  typedef boost::shared_ptr<DepthFeedSession> SessionPtr;\n\n  class DepthFeedConnection : boost::noncopyable {\n  public:\n    DepthFeedConnection(int argc, const char* argv[]);\n</pre>\n\n<p>\n  Next are an accessor for the templates parsed by the connection, and two\n  methods for connecting the publisher and subscribers.  The publisher calls\n  <code>accept()</code> and the subscriber calls <code>connect()</code>:\n</p>\n\n<div class=\"listing\">depth_feed_connection.h: DepthFeedConnection class declaration, continued</div>\n<pre class=\"code\">\n    // Get the template registry\n    const QuickFAST::Codecs::TemplateRegistryPtr&amp;\n          get_templates() { return templates_; }\n\n    // Connect to publisher\n    void connect();\n\n    // Accept connection from subscriber\n    void accept();\n</pre>\n\n<p>\n  The next method, <code>run()</code> issues all the ASIO callbacks.  Both the\n  publisher and subscriber must cal <code>run()</code>.\n</p>\n\n<div class=\"listing\">depth_feed_connection.h: DepthFeedConnection class declaration, continued</div>\n<pre class=\"code\">\n    // Let the IO service run\n    void run();\n</pre>\n\n<p>\n  The next two methods set up handlers for events:\n</p>\n\n<div class=\"listing\">depth_feed_connection.h: DepthFeedConnection class declaration, continued</div>\n<pre class=\"code\">\n    // Set a callback to handle a message\n    void set_message_handler(MessageHandler msg_handler);\n\n    // Set a callback to handle a reset connection\n    void set_reset_handler(ResetHandler reset_handler);\n</pre>\n\n<p>\n  The first, <code>set_message_handler()</code>, handles incoming messages in\n  the subscriber.  The second, <code>set_reset_handler()</code> within the\n  publisher handles disconnects within the subscriber to the publisher.\n</p>\n\n<p>\n  The next two methods are for buffer management:\n</p>\n\n<div class=\"listing\">depth_feed_connection.h: DepthFeedConnection class declaration, continued</div>\n<pre class=\"code\">\n    // Reserve a buffer for receiving a message\n    BufferPtr reserve_recv_buffer();\n\n    // Reserve a buffer for sending a message\n    WorkingBufferPtr reserve_send_buffer();\n</pre>\n\n<p>\n  Rather than constantly allocating and deallocating buffers, the publisher\n  and subscriber have a pool of buffers ready to be used again and again.\n  The publisher and subscriber will reserve these buffers from\n  <code>DepthFeedConnection</code>, bind them to an ASIO asynchronous callback,\n  and then restore the buffers back to the <code>DepthFeedConnection</code>. \n</p>\n\n<p>\n  The first, <code>reserve_recv_buffer()</code> is called by the subscriber for\n  a buffer to receive a message.  Likewise, <code>reserve_send_buffer()</code>\n  reserves a buffer to serialize an encoded QuickFAST message, for the\n  publisher to send to the subscriber.\n</p>\n\n<p>\n  Next, are three methods for the publisher to send a message to each\n  subscriber:\n</p>\n\n<div class=\"listing\">depth_feed_connection.h: DepthFeedConnection class declaration, continued</div>\n<pre class=\"code\">\n    // Send a trade messsage to all clients\n    void send_trade(QuickFAST::Messages::FieldSet&amp; message);\n\n    // Send an incremental update\n    //   return true if all sessions could handle an incremental update\n    bool send_incr_update(const std::string&amp; symbol, \n                          QuickFAST::Messages::FieldSet&amp; message);\n\n    // Send a full update to those which have not yet received for this symbol\n    void send_full_update(const std::string&amp; symbol, \n                          QuickFAST::Messages::FieldSet&amp; message);\n</pre>\n\n<p>\n  These three methods call the corresponding method on\n  <code>DepthFeedSession</code> for each subscriber.  The public interface ends\n  with a number of event handlers:\n</p>\n\n<div class=\"listing\">depth_feed_connection.h: DepthFeedConnection class declaration, continued</div>\n<pre class=\"code\">\n    // Handle a connection\n    void on_connect(const boost::system::error_code&amp; error);\n\n    // Handle an accepted connection\n    void on_accept(SessionPtr session,\n                   const boost::system::error_code&amp; error);\n\n    // Handle a received message\n    void on_receive(BufferPtr bp, \n                    const boost::system::error_code&amp; error,\n                    std::size_t bytes_transferred);\n    // Handle a sent message\n    void on_send(WorkingBufferPtr wb,\n                 const boost::system::error_code&amp; error,\n                 std::size_t bytes_transferred);\n</pre>\n\n<p>\n  These methods handle, the result of a subscriber connecting to the publisher,\n  a publisher's accepted connection from a subscriber, a message received from\n  the publisher, and a message sent to the subscriber, respectively.\n</p>\n\n<p>\n  The private members of <code>DepthFeedConnection</code> start with some\n  configuration date: the name of the file containing the FAST templates, the\n  host for the subscriber to connect to, and the connection port.  These are\n  followed by the event handlers, the parsed QuickFAST templates, buffer pools,\n  the <code>DepthFeedSession</code> instances, and some boost ASIO helpers.\n</p>\n\n<p>\n  The private section ends with some methods, to issue a read, and parse the\n  command line arguments:\n</p>\n\n<div class=\"listing\">depth_feed_connection.h: DepthFeedConnection class declaration, continued</div>\n<pre class=\"code\">\n  private:\n    typedef std::deque&lt;BufferPtr&gt; Buffers;\n    typedef std::vector&lt;SessionPtr&gt; Sessions;\n    const char* template_filename_;\n    const char* host_;\n    int port_;\n    MessageHandler msg_handler_;\n    ResetHandler reset_handler_;\n    QuickFAST::Codecs::TemplateRegistryPtr templates_;\n\n    Buffers        unused_recv_buffers_;\n    WorkingBuffers unused_send_buffers_;\n    Sessions sessions_;\n    boost::shared_ptr&lt;boost::asio::ip::tcp::acceptor&gt; acceptor_;\n    boost::asio::io_service ios_;\n    boost::asio::ip::tcp::socket socket_;\n    boost::shared_ptr&lt;boost::asio::io_service::work&gt; work_ptr_;\n\n    void issue_read();\n    static const char* template_file_from_args(int argc, const char* argv[]);\n    static const char* host_from_args(int argc, const char* argv[]);\n    static int port_from_args(int argc, const char* argv[]);\n  };\n} } // End namespace\n</pre>\n\n<p>\n  The <code>DepthFeedConnection</code> constructor derives the configuration\n  variables by passing the command-line arguments to the \n  <code>*_from_args()</code> methods:\n</p>\n\n<div class=\"listing\">depth_feed_connection.cpp: DepthFeedConnection class implementation</div>\n<pre class=\"code\">\nDepthFeedConnection::DepthFeedConnection(int argc, const char* argv[])\n: template_filename_(template_file_from_args(argc, argv)),\n  host_(host_from_args(argc, argv)),\n  port_(port_from_args(argc, argv)),\n  templates_(TemplateConsumer::parse_templates(template_filename_)),\n  socket_(ios_)\n{\n}\n</pre>\n\n<p>\n  It also invokes <code>parse_templates()</code> to parse the QuickFAST\n  templates, and initializes the subscriber socket.  Next, \n  <code>connect()</code> does a standard ASIO asynchronous connection, using\n  <code>on_connect()</code> as its callback:\n</p>\n\n<div class=\"listing\">depth_feed_connection.cpp: DepthFeedConnection class implementation, continued</div>\n<pre class=\"code\">\nvoid\nDepthFeedConnection::connect()\n{\n  std::cout &lt;&lt; \"Connecting to feed\" &lt;&lt; std::endl;\n  tcp::endpoint endpoint(address::from_string(host_), port_);\n  socket_.async_connect(endpoint, boost::bind(&amp;DepthFeedConnection::on_connect,\n                                              this, _1));\n}\n</pre>\n\n<p>\n  The <code>accept()</code> method implements the publisher's side of ASIO\n  connectivity.  The first time <code>accept()</code> id called a TCP acceptor\n  is created and initialized.  For each call, a <code>DepthFeedSession</code>\n  is created, and an asynchronous accept is started, using to\n  <code>on_accept()</code> as its callback:\n</p>\n\n<div class=\"listing\">depth_feed_connection.cpp: DepthFeedConnection class implementation, continued</div>\n<pre class=\"code\">\nvoid\nDepthFeedConnection::accept()\n{\n  if (!acceptor_) {\n    acceptor_.reset(new tcp::acceptor(ios_));\n    tcp::endpoint endpoint(tcp::v4(), port_);\n    acceptor_-&gt;open(endpoint.protocol());\n    boost::system::error_code ec;\n    acceptor_-&gt;set_option(boost::asio::socket_base::reuse_address(true), ec);\n    acceptor_-&gt;bind(endpoint);\n    acceptor_-&gt;listen();\n  }\n  SessionPtr session(new DepthFeedSession(ios_, this, templates_));\n  acceptor_-&gt;async_accept(\n      session-&gt;socket(), \n      boost::bind(&amp;DepthFeedConnection::on_accept, this, session, _1));\n}\n</pre>\n\n<p>\n  The <code>run()</code> method invokes the <code>run()</code> method on the IO\n  service object.  Usually <code>run()</code> will exit when there are no more\n  callbacks to make.  Using the <code>io_service::work</code> object ensures\n  <code>run()</code> does not exit:\n</p>\n\n<div class=\"listing\">depth_feed_connection.cpp: DepthFeedConnection class implementation, continued</div>\n<pre class=\"code\">\nvoid\nDepthFeedConnection::run()\n{\nstd::cout &lt;&lt; \"DepthFeedConnection::run()\" &lt;&lt; std::endl;\n  // Keep on running\n  work_ptr_.reset(new boost::asio::io_service::work(ios_));\n  ios_.run();\n}\n</pre>\n\n<p>\n  The next two methods simply save off the two message handlers:\n</p>\n\n<div class=\"listing\">depth_feed_connection.cpp: DepthFeedConnection class implementation, continued</div>\n<pre class=\"code\">\n\nvoid\nDepthFeedConnection::set_message_handler(MessageHandler handler)\n{\n  msg_handler_ = handler;\n}\n\nvoid\nDepthFeedConnection::set_reset_handler(ResetHandler handler)\n{\n  reset_handler_ = handler;\n}\n</pre>\n\n<p>\n  As stated above, the <code>DepthFeedConnection</code> uses buffer pools to\n  reduce heap allocations and deallocations.  The following two methods \n  provide unused buffers to the caller:\n</p>\n\n<div class=\"listing\">depth_feed_connection.cpp: DepthFeedConnection class implementation</div>\n<pre class=\"code\">\nBufferPtr\nDepthFeedConnection::reserve_recv_buffer()\n{\n  if (unused_recv_buffers_.empty()) {\n    return BufferPtr(new Buffer());\n  } else {\n    BufferPtr bp = unused_recv_buffers_.front();\n    unused_recv_buffers_.pop_front();\n    return bp;\n  }\n}\n\nWorkingBufferPtr\nDepthFeedConnection::reserve_send_buffer()\n{\n  if (unused_send_buffers_.empty()) {\n    return WorkingBufferPtr(new QuickFAST::WorkingBuffer());\n  } else {\n    WorkingBufferPtr wb = unused_send_buffers_.front();\n    unused_send_buffers_.pop_front();\n    return wb;\n  }\n}\n</pre>\n\n<p>\n  In both methods, an unused buffer is returned, and one is created if none are\n  available.\n</p>\n\n<p>\n  The <code>send_trade()</code>, <code>send_incr_update()</code> and\n  <code>send_full_update()</code> methods send a message to all subscribers by\n  iterating through the sessions and invoking the corresponding method on each:\n</p>\n\n<div class=\"listing\">depth_feed_connection.cpp: DepthFeedConnection class implementation, continued</div>\n<pre class=\"code\">\nvoid\nDepthFeedConnection::send_trade(QuickFAST::Messages::FieldSet&amp; message)\n{\n  // For each session\n  Sessions::iterator session;\n  for (session = sessions_.begin(); session != sessions_.end(); ) {\n    // If the session is connected\n    if ((*session)-&gt;connected()) {\n      // conditionally send on that session\n      (*session)-&gt;send_trade(message);\n      ++session;\n    } else {\n      // Remove the session\n      session = sessions_.erase(session);\n    }\n  }\n}\n\nbool\nDepthFeedConnection::send_incr_update(const std::string&amp; symbol,\n                                      QuickFAST::Messages::FieldSet&amp; message)\n{\n  bool none_new = true;\n  // For each session\n  Sessions::iterator session;\n  for (session = sessions_.begin(); session != sessions_.end(); ) {\n    // If the session is connected\n    if ((*session)-&gt;connected()) {\n      // send on that session\n      if (!(*session)-&gt;send_incr_update(symbol, message)) {\n        none_new = false;\n      }\n      ++session;\n    } else {\n      // Remove the session\n      session = sessions_.erase(session);\n    }\n  }\n  return none_new;\n}\n\nvoid\nDepthFeedConnection::send_full_update(const std::string&amp; symbol,\n                                      QuickFAST::Messages::FieldSet&amp; message)\n{\n  // For each session\n  Sessions::iterator session;\n  for (session = sessions_.begin(); session != sessions_.end(); ) {\n    // If the session is connected\n    if ((*session)-&gt;connected()) {\n      // conditionally send on that session\n      (*session)-&gt;send_full_update(symbol, message);\n      ++session;\n    } else {\n      // Remove the session\n      session = sessions_.erase(session);\n    }\n  }\n}\n</pre>\n\n<p>\n  In any of the cases, if the session is no longer connected, the session\n  is removed.  There is one important difference in\n  <code>send_incr_update()</code> - the method's return value indicates if any\n  of the sessions gave back a return value of false.\n</p>\n\n<p>\n  The next method handles a connection within the subscriber:\n</p>\n\n<div class=\"listing\">depth_feed_connection.cpp: DepthFeedConnection class implementation, continued</div>\n<pre class=\"code\">\n\nvoid\nDepthFeedConnection::on_connect(const boost::system::error_code&amp; error)\n{\n  if (!error) {\n    std::cout &lt;&lt; \"connected to feed\" &lt;&lt; std::endl;\n    reset_handler_();\n    issue_read();\n  } else {\n    std::cout &lt;&lt; \"on_connect, error=\" &lt;&lt; error &lt;&lt; std::endl;\n    socket_.close();\n    sleep(3);\n    // Try again\n    connect();\n  }\n}\n</pre>\n\n<p>\n  When <code>on_connect()</code> is called, the method tries again, in case of\n  failure, or calls the reset handler and then begins to read on the socket, in\n  case of success.\n</p>\n<p>\n  The next handler is the counterpart in the publisher:\n</p>\n\n<div class=\"listing\">depth_feed_connection.cpp: DepthFeedConnection class implementation, continued</div>\n<pre class=\"code\">\nvoid\nDepthFeedConnection::on_accept(SessionPtr session,\n                               const boost::system::error_code&amp; error)\n{\n  if (!error) {\n    std::cout &lt;&lt; \"accepted client connection\" &lt;&lt; std::endl;\n    sessions_.push_back(session);\n    session-&gt;set_connected();\n  } else {\n    std::cout &lt;&lt; \"on_accept, error=\" &lt;&lt; error &lt;&lt; std::endl;\n    session.reset();\n    sleep(2);\n  }\n  // accept again\n  accept();\n}\n</pre>\n\n<p>\n  In the case of <code>on_accept()</code>, the publisher always restarts the\n  accept cycle - so that another subscriber may connect.  The subscriber, on\n  the other hand, only wants one connection.\n</p>\n<p>\n  In the case of a successful connection, the publisher saves off the session, \n  and marks it as connected, so that messages may be sent to it.  If there is\n  failure, the session is deleted (by resetting the shared pointer) and the\n  publisher waits momentarily before starting again.\n</p>\n<p>\n  The next event handler handles a message received by the subscriber:\n</p>\n\n<div class=\"listing\">depth_feed_connection.cpp: DepthFeedConnection class implementation, continued</div>\n<pre class=\"code\">\nvoid\nDepthFeedConnection::on_receive(BufferPtr bp,\n                                const boost::system::error_code&amp; error,\n                                std::size_t bytes_transferred)\n{\n  if (!error) {\n    // Next read\n    issue_read();\n\n    // Handle the buffer\n    if (!msg_handler_(bp, bytes_transferred)) {\n      socket_.close();\n    }\n  } else {\n    std::cout &lt;&lt; \"Error \" &lt;&lt; error &lt;&lt; \" receiving message\" &lt;&lt; std::endl;\n    socket_.close();\n    sleep(3);\n    connect();\n  }\n  // Restore buffer\n  unused_recv_buffers_.push_back(bp);\n}\n</pre>\n\n<p>\n  When the receive is handled, if the read was successful, the subscriber\n  first issues a new read, and then calls the receive handler, which parses\n  the message.  Should this parsing fail, the socket will close (and the next\n  read will then fail).\n</p>\n<p>\n  Should the read fail, the socket is closed, and the connection cycle starts\n  anew.  In all cases, the buffer is restored back to the pool.\n</p>\n<p>\n  The next handler is called after a send of a message to the subscriber:\n</p>\n\n<div class=\"listing\">depth_feed_connection.cpp: DepthFeedConnection class implementation, continued</div>\n<pre class=\"code\">\nvoid\nDepthFeedConnection::on_send(WorkingBufferPtr wb,\n                             const boost::system::error_code&amp; error,\n                             std::size_t bytes_transferred)\n{\n  // Keep buffer for later\n  unused_send_buffers_.push_back(wb);\n}\n</pre>\n\n<p>\n  Recall that this method is called from within\n  <code>DepthFeedSession::on_send()</code> which has already examined the\n  error code.  What remains is to restore the buffer back to the pool.\n</p>\n<p>\n  The next method starts an ASIO read on the subscriber's socket:\n</p>\n\n<div class=\"listing\">depth_feed_connection.cpp: DepthFeedConnection class implementation, continued</div>\n<pre class=\"code\">\n\nvoid\nDepthFeedConnection::issue_read()\n{\n  BufferPtr bp = reserve_recv_buffer();\n  RecvHandler recv_handler = boost::bind(&amp;DepthFeedConnection::on_receive, \n                                         this, bp, _1, _2);\n  boost::asio::mutable_buffers_1 buffer(\n      boost::asio::buffer(*bp, bp-&gt;size()));\n  socket_.async_receive(buffer, 0, recv_handler);\n}\n</pre>\n\n<p>\n  <code>issue_read()</code> reserves a buffer, binds the buffer to the \n  <code>on_receive()</code> method, and issues the asynchronous read.\n</p>\n<p>\n  The next three methods look through the command line arguments for\n  configuration variables:\n</p>\n\n<div class=\"listing\">depth_feed_connection.cpp: DepthFeedConnection class implementation, continued</div>\n<pre class=\"code\">\nconst char*\nDepthFeedConnection::template_file_from_args(int argc, const char* argv[])\n{\n  bool next_is_name = false;\n  for (int i = 0; i &lt; argc; ++i) {\n    if (next_is_name) {\n      return argv[i];\n    } else if (strcmp(argv[i], \"-t\") == 0) {\n      next_is_name = true;\n    }\n  }\n  return \"./templates/depth.xml\";\n}\n\nconst char*\nDepthFeedConnection::host_from_args(int argc, const char* argv[])\n{\n  bool next_is_host = false;\n  for (int i = 0; i &lt; argc; ++i) {\n    if (next_is_host) {\n      return argv[i];\n    } else if (strcmp(argv[i], \"-h\") == 0) {\n      next_is_host = true;\n    }\n  }\n  return \"127.0.0.1\";\n}\n\nint\nDepthFeedConnection::port_from_args(int argc, const char* argv[])\n{\n  bool next_is_port = false;\n  for (int i = 0; i &lt; argc; ++i) {\n    if (next_is_port) {\n      return atoi(argv[i]);\n    } else if (strcmp(argv[i], \"-p\") == 0) {\n      next_is_port = true;\n    }\n  }\n  return 10003;\n}\n\n} } // End namespace\n</pre>\n<p>\n  The first method looks for a -t followed by a template file name.  The \n  second looks foe a -h followed by a host name.  The last one looks for a -p\n  followed by a port number.  All three return default values.\n</p>\n\n<h3>Handling Liquibook Events</h3>\n<p>\n  At this point, the publisher is able to accept subscriber connections and\n  route QuickFAST messages to the subscriber.  What is missing is handling\n  Liquibook events, and creating the QuickFAST messages to send.  As shown in \n  <a href=\"#figure2\">figure 2</a>, the publisher needs a properly-typed\n  <code>TradeListener</code> for trade events, and a properly-typed\n  <code>DepthListener</code> for depth events.\n</p>\n\n<p>\n  The <code>TradeListener</code> interface has a single method to implement:\n</p>\n\n<div class=\"listing\">trade_listener.h: TradeListener interface declaration</div>\n<pre class=\"code\">\nnamespace liquibook { namespace book {\n\n/// @brief listener of trade events.   Implement to build a trade feed.\ntemplate &lt;class OrderBook &gt;\nclass TradeListener {\npublic:\n  /// @brief callback for a trade\n  /// @param book the order book of the fill (not defined whether this is before\n  ///      or after fill)\n  /// @param qty the quantity of this fill\n  /// @param cost the cost of this fill (qty * price)\n  virtual void on_trade(const OrderBook* book,\n                        Quantity qty,\n                        Cost cost) = 0;\n};\n\n} }\n</pre>\n\n<p>\n  Likewise, the <code>DepthListener</code> interface has a single method to\n  implement:\n</p>\n\n<div class=\"listing\">trade_listener.h: TradeListener interface declaration</div>\n<pre class=\"code\">\nnamespace liquibook { namespace book {\n\n/// @brief listener of depth events.  Implement to build an aggregate depth \n/// feed.\ntemplate &lt;class OrderBook &gt;\nclass DepthListener {\npublic:\n  /// @brief callback for change in tracked aggregated depth\n  virtual void on_depth_change(\n      const OrderBook* book,\n      const typename OrderBook::DepthTracker* depth) = 0;\n};\n\n} }\n</pre>\n\n<p>\n  The publisher implements these interfaces in the\n  <code>DepthFeedPublisher</code> class:\n</p>\n\n<div class=\"listing\">depth_feed_publisher.h: DepthFeedPublisher class declaration</div>\n<pre class=\"code\">\nnamespace liquibook { namespace examples {\n\nclass DepthFeedPublisher : public ExampleOrderBook::TypedDepthListener,\n                           public ExampleOrderBook::TypedTradeListener,\n                           public TemplateConsumer {\n</pre>\n\n<p>\n  The <code>DepthFeedPublisher</code> class implements both the \n  <code>ExampleOrderBook::TypedDepthListener</code> and the \n  <code>ExampleOrderBook::TypedTradeListener</code> interfaces, which bind the\n  <code>book::DepthListener</code> and the <code>book::TradeListener</code> \n  templates to those used in <code>ExampleOrderBook</code>. \n  <code>DepthFeedPublisher</code> also inherits from\n  <code>TemplateConsumer</code>, but this is simply a convenience (to reduce\n  the need for name qualifiers), as <code>TemplateConsumer</code>'s data and\n  methods are entirely static.\n</p>\n\n<p>\n  The <code>DepthFeedPublisher</code> has a simple constructor, for\n  initializing its pointer.\n</p>\n\n<div class=\"listing\">depth_feed_publisher.h: DepthFeedPublisher class declaration, continued</div>\n<pre class=\"code\">\npublic:\n  DepthFeedPublisher();\n</pre>\n\n<p>\n  The <code>DepthFeedPublisher</code> keeps a pointer to a\n  <code>DepthFeedConnection</code>, and receives that pointer through a setter\n  method:\n</p>\n\n<div class=\"listing\">depth_feed_publisher.h: DepthFeedPublisher class declaration, continued</div>\n<pre class=\"code\">\n  void set_connection(DepthFeedConnection* connection);\n</pre>\n\n<p>\n  Next are the two event handlers to implement the two interfaces:\n</p>\n\n<div class=\"listing\">depth_feed_publisher.h: DepthFeedPublisher class declaration, continued</div>\n<pre class=\"code\">\n  virtual void on_trade(\n      const book::OrderBook&lt;OrderPtr&gt;* order_book,\n      book::Quantity qty,\n      book::Cost cost);\n\n  virtual void on_depth_change(\n      const book::DepthOrderBook&lt;OrderPtr&gt;* order_book,\n      const book::DepthOrderBook&lt;OrderPtr&gt;::DepthTracker* tracker);\n</pre>\n\n<p>\n  The private section has a single member - the\n  <code>DepthFeedConnection</code> pointer:\n</p>\n\n<div class=\"listing\">depth_feed_publisher.h: DepthFeedPublisher class declaration, continued</div>\n<pre class=\"code\">\nprivate:\n  DepthFeedConnection* connection_;\n</pre>\n\n<p>\n  Next are methods to build the feed messages:\n</p>\n\n<div class=\"listing\">depth_feed_publisher.h: DepthFeedPublisher class declaration, continued</div>\n<pre class=\"code\">\n  // Build an trade message\n  void build_trade_message(\n      QuickFAST::Messages::FieldSet&amp; message,\n      const std::string&amp; symbol,\n      book::Quantity qty,\n      book::Cost cost);\n\n  // Build an incremental depth message\n  void build_depth_message(\n      QuickFAST::Messages::FieldSet&amp; message,\n      const std::string&amp; symbol,\n      const book::DepthOrderBook&lt;OrderPtr&gt;::DepthTracker* tracker,\n      bool full_message);\n  void build_depth_level(\n      QuickFAST::Messages::SequencePtr&amp; level_seq,\n      const book::DepthLevel* level,\n      int level_index);\n</pre>\n\n<p>\n  And finally a method to generate a time stamp for the messages:\n</p>\n\n<div class=\"listing\">depth_feed_publisher.h: DepthFeedPublisher class declaration, continued</div>\n<pre class=\"code\">\n  uint32_t time_stamp();\n};\n\n} } // End namespace\n</pre>\n\n<p>\n  The <code>DepthFeedPublisher</code> constructor initializes its connection\n  pointer, which is set by a separate setter method:\n</p>\n\n<div class=\"listing\">depth_feed_publisher.cpp: DepthFeedPublisher class implementation</div>\n<pre class=\"code\">\nnamespace liquibook { namespace examples { \n\nusing namespace QuickFAST::Messages;\n\nDepthFeedPublisher::DepthFeedPublisher()\n: connection_(NULL)\n{\n}\n\nvoid\nDepthFeedPublisher::set_connection(DepthFeedConnection* connection)\n{\n  connection_ = connection;\n}\n</pre>\n\n<p>\n  The <code>DepthFeedPublisher</code>'s primary responsibility is to build \n  feed messages, in response to events.  The first event handler is\n  <code>on_trade()</code>:\n</p>\n\n<div class=\"listing\">depth_feed_publisher.cpp: DepthFeedPublisher class implementation, continued</div>\n<pre class=\"code\">\n\nvoid\nDepthFeedPublisher::on_trade(\n    const book::OrderBook&lt;OrderPtr&gt;* order_book,\n    book::Quantity qty,\n    book::Cost cost)\n{\n  // Publish trade\n  QuickFAST::Messages::FieldSet message(20);\n  const ExampleOrderBook* exob = \n          dynamic_cast&lt;const ExampleOrderBook*&gt;(order_book);\n  std::cout &lt;&lt; \"Got trade for \" &lt;&lt; exob-&gt;symbol() \n            &lt;&lt; \" qty \" &lt;&lt; qty\n            &lt;&lt; \" cost \" &lt;&lt; cost &lt;&lt; std::endl;\n  build_trade_message(message, exob-&gt;symbol(), qty, cost);\n  connection_-&gt;send_trade(message);\n}\n</pre>\n\n<p>\n  <code>on_trade()</code> starts by casting the order book to the derived type.\n  The reader will recall that the derived order book is used to store the\n  symbol of the order book.  The method then builds the trade message,\n  through a call to <code>build_trade_message()</code>, and distributes the\n  message through the <code>DepthFeedConnection</code>.\n</p>\n\n<p>\n  The next event handler handles depth change events:\n</p>\n\n<div class=\"listing\">depth_feed_publisher.cpp: DepthFeedPublisher class implementation, continued</div>\n<pre class=\"code\">\nvoid\nDepthFeedPublisher::on_depth_change(\n    const book::DepthOrderBook&lt;OrderPtr&gt;* order_book,\n    const book::DepthOrderBook&lt;OrderPtr&gt;::DepthTracker* tracker)\n{\n  // Publish changed levels of order book\n  QuickFAST::Messages::FieldSet message(20);\n  const ExampleOrderBook* exob = \n          dynamic_cast&lt;const ExampleOrderBook*&gt;(order_book);\n  build_depth_message(message, exob-&gt;symbol(), tracker, false);\n  if (!connection_-&gt;send_incr_update(exob-&gt;symbol(), message)) {\n    // Publish all levels of order book\n    QuickFAST::Messages::FieldSet full_message(20);\n    build_depth_message(full_message, exob-&gt;symbol(), tracker, true);\n    connection_-&gt;send_full_update(exob-&gt;symbol(), full_message);\n  }\n}\n</pre>\n\n<p>\n  Similar to the trade event handler, the depth change event handler casts the\n  order book to the derived class, builds a feed message, and sends it to the\n  clients through the <code>DepthFeedConnection</code>.  What is different in\n  <code>on_depth_change()</code> is that since the depth feed is incremental,\n  as noted above, the clients must be known to be in a valid state for the\n  security of the update to handle the next message.\n</p>\n\n<p>\n  The reader will recall that the call to\n  <code>DepthFeedConnection::send_incr_update()</code> returns true if and only\n  if all of the clients could handle the message.  If not, false is returned, \n  and <code>on_depth_change()</code> builds and sends a full update instead.\n  In the steady state, only the incremental message need by built.\n</p>\n\n<p>\n  The <code>build_trade_message()</code> method is used by\n  <code>on_trade()</code> to build a trade message:\n</p>\n\n<div class=\"listing\">depth_feed_publisher.cpp: DepthFeedPublisher class implementation, continued</div>\n<pre class=\"code\">\nvoid\nDepthFeedPublisher::build_trade_message(\n    QuickFAST::Messages::FieldSet&amp; message,\n    const std::string&amp; symbol,\n    book::Quantity qty,\n    book::Cost cost)\n{\n  message.addField(id_timestamp_, FieldUInt32::create(time_stamp()));\n  message.addField(id_symbol_, FieldString::create(symbol));\n  message.addField(id_qty_, FieldUInt32::create(qty));\n  message.addField(id_cost_, FieldUInt32::create(cost));\n}\n</pre>\n\n<p>\n  Building a QuickFAST message is relatively simple.  Each field is added to\n  the message through the <code>addField()</code> call.  The sequence number,\n  added later, is particular to a specific client.\n</p>\n\n<p>\n  The next message builder, <code>build_depth_message()</code>, builds\n  repeating sequences of data, and is more complex:\n</p>\n\n<div class=\"listing\">depth_feed_publisher.cpp: DepthFeedPublisher class implementation, continued</div>\n<pre class=\"code\">\nvoid\nDepthFeedPublisher::build_depth_message(\n    QuickFAST::Messages::FieldSet&amp; message,\n    const std::string&amp; symbol,\n    const book::DepthOrderBook&lt;OrderPtr&gt;::DepthTracker* tracker,\n    bool full_message)\n{\n  size_t bid_count(0), ask_count(0);\n\n  message.addField(id_timestamp_, FieldUInt32::create(time_stamp()));\n  message.addField(id_symbol_, FieldString::create(symbol));\n\n  // Build the changed levels\n  book::ChangeId last_published_change = tracker-&gt;last_published_change();\n  \n  // Build changed bids\n  {\n    SequencePtr bids(new Sequence(id_bids_length_, 1));\n    int index = 0;\n    const book::DepthLevel* bid = tracker-&gt;bids();\n    // Create sequence of bids\n    while (true) {\n      if (full_message || bid-&gt;changed_since(last_published_change)) {\n        build_depth_level(bids, bid, index);\n        ++bid_count;\n      }\n      ++index;\n      if (bid == tracker-&gt;last_bid_level()) {\n        break;\n      } else {\n        ++bid;\n      }\n    }\n    message.addField(id_bids_, FieldSequence::create(bids));\n  }\n\n  // Build changed asks\n  {\n    SequencePtr asks(new Sequence(id_asks_length_, 1));\n    int index = 0;\n    const book::DepthLevel* ask = tracker-&gt;asks();\n    // Create sequence of asks\n    while (true) {\n      if (full_message || ask-&gt;changed_since(last_published_change)) {\n        build_depth_level(asks, ask, index);\n        ++ask_count;\n      }\n      ++index;\n      if (ask == tracker-&gt;last_ask_level()) {\n        break;\n      } else {\n        ++ask;\n      }\n    }\n    message.addField(id_asks_, FieldSequence::create(asks));\n  }\n  std::cout &lt;&lt; \"Encoding \" &lt;&lt; (full_message ? \"full\" : \"incr\")\n            &lt;&lt; \" depth message for symbol \" &lt;&lt; symbol \n            &lt;&lt; \" with \" &lt;&lt; bid_count &lt;&lt; \" bids, \"\n            &lt;&lt; ask_count &lt;&lt; \" asks\" &lt;&lt; std::endl;\n}\n</pre>\n\n<p>\n  This method starts like <code>add_trade()</code>, adding the timestamp and \n  symbol fields.  Next, two sequences are built, for the changed bid and ask\n  levels.  To support an incremental feed, Liquibook tracks a change number\n  (called <code>ChangeId</code>) on each depth level, and the ID of the last\n  published change in the depth, which is set after the callback completes.\n  To determine the levels to publish, the publisher needs to compare the last\n  change of each level to the last published change of the depth as a whole.\n</p>\n\n<p>\n  In <code>build_depth_message()</code>, a bid sequence is created, and an\n  associated length is attached.  The changed bid levels are each added to the\n  sequence through calls to <code>build_depth_level()</code>.  The iteration \n  logic here must be careful to not move beyond the last bid level.  Finally,\n  the sequence is added to the message.  The same is done for changed ask\n  levels.\n</p>\n\n<p>\n  By comparison, <code>build_depth_level()</code> is simple:\n</p>\n\n<div class=\"listing\">depth_feed_publisher.cpp: DepthFeedPublisher class implementation, continued</div>\n<pre class=\"code\">\nvoid\nDepthFeedPublisher::build_depth_level(\n    QuickFAST::Messages::SequencePtr&amp; level_seq,\n    const book::DepthLevel* level,\n    int level_index)\n{\n  FieldSetPtr level_fields(new FieldSet(4));\n  level_fields-&gt;addField(id_level_num_, FieldUInt8::create(level_index));\n  level_fields-&gt;addField(id_order_count_, \n                         FieldUInt32::create(level-&gt;order_count()));\n  level_fields-&gt;addField(id_price_,\n                         FieldUInt32::create(level-&gt;price()));\n  level_fields-&gt;addField(id_size_,\n                         FieldUInt32::create(level-&gt;aggregate_qty()));\n  level_seq-&gt;addEntry(level_fields);\n}\n</pre>\n\n<p>\n  This method shows how to add an entry to a QuickFAST sequence - by creating\n  a <code>FieldSet</code>, adding fields to it, and adding the\n  <code>FieldSet</code> to the sequence.\n</p>\n\n<p>\n  The final method is a helper, to create an integer timestamp for a message:\n</p>\n\n<div class=\"listing\">depth_feed_publisher.cpp: DepthFeedPublisher class implementation, continued</div>\n<pre class=\"code\">\nuint32_t\nDepthFeedPublisher::time_stamp()\n{\n  time_t now;\n  time(&amp;now);\n  return now;\n}\n\n} } // End namespace\n</pre>\n\n<h3>Publisher Initialization</h3>\n<p>\n  At this point the publisher has all the necessary parts to publish a trade\n  feed and an incremental depth feed for the exchange.  The only things that\n  remains are to create, initialize, and associate the various parts, and to\n  generate the random orders.\n</p>\n\n<p>\n  The exchange is initialized in the file <code>publisher_main.cpp</code>.\n  The <code>main()</code> function starts by establishing the securities to\n  \"trade\" in the exchange - in this case the NASDAQ 100 - taken from a\n  snapshot in April 2013.  <code>main()</code> records the symbol and a base\n  price in a structure:\n</p>\n\n<div class=\"listing\">publisher_main.cpp: SecurityInfo structure</div>\n<pre class=\"code\">\nstruct SecurityInfo {\n  std::string symbol;\n  double ref_price;\n\n  SecurityInfo(const char* sym, double price)\n  : symbol(sym),\n    ref_price(price)\n  {\n  }\n};\n\ntypedef std::vector<SecurityInfo> SecurityVector;\n</pre>\n\n<p>\n  The base price serves as a basis for generating random prices for the\n  example exchange.  <code>main()</code> keeps this security information in a\n  <code>SecurityVector</code>  and populates it in the \n  <code>create_securities()</code> method, later in <code>main()</code>.\n</p>\n\n<p>\n  The <code>main()</code> function begins by creating the\n  <code>DepthFeedConnection</code>, and uses Boost's thread library to \n  create a background thread to accept connections from subscribers:\n</p>\n\n<div class=\"listing\">publisher_main.cpp: main() function</div>\n<pre class=\"code\">\nint main(int argc, const char* argv[])\n{\n  // Feed connection\n  examples::DepthFeedConnection connection(argc, argv);\n\n  // Open connection in background thread\n  connection.accept();\n  boost::function<void ()> acceptor(\n      boost::bind(&amp;examples::DepthFeedConnection::run, &amp;connection));\n  boost::thread acceptor_thread(acceptor);\n</pre>\n\n<p>\n  Next, the <code>DepthFeedPublisher</code> and the <code>Exchange</code> are\n  created, and the<code>DepthFeedPublisher</code> is made aware of the \n  <code>DepthFeedConnection</code>:\n</p>\n\n<div class=\"listing\">publisher_main.cpp: main() function, continued</div>\n<pre class=\"code\">\n  // Create feed publisher\n  examples::DepthFeedPublisher feed;\n  feed.set_connection(&amp;connection);\n\n  // Create exchange\n  examples::Exchange exchange(&amp;feed, &amp;feed);\n</pre>\n\n<p>\n  Note that the exchange constructor requires a <code>TradeListener</code> and\n  a <code>DepthListener</code>, both of which the\n  <code>DepthFeedPublisher</code> implements.\n</p>\n\n<p>\n  Finally, the securities are created and used to populate the exchange, and\n  orders are generated.\n</p>\n\n<div class=\"listing\">publisher_main.cpp: main() function, continued</div>\n<pre class=\"code\">\n  // Create securities\n  SecurityVector securities;\n  create_securities(securities);\n\n  // Populate exchange with securities\n  populate_exchange(exchange, securities);\n  \n  // Generate random orders\n  generate_orders(exchange, securities);\n\n  return 0;\n}\n</pre>\n\n<p>\n  The final function call, to <code>generate_orders()</code> is an infinite\n  loop, so there is no need to worry about the <code>main()</code> method\n  returning.\n</p>\n\n<p>\n  The helper function <code>create_securities()</code> adds 100 securities to\n  the <code>SecurityVector</code>:\n</p>\n\n<div class=\"listing\">publisher_main.cpp: main() helper functions</div>\n<pre class=\"code\">\nvoid\ncreate_securities(SecurityVector&amp; securities) {\n  securities.push_back(SecurityInfo(\"AAPL\", 436.36));\n  securities.push_back(SecurityInfo(\"ADBE\", 45.06));\n  securities.push_back(SecurityInfo(\"ADI\", 43.93));\n\n  // Repeated for 100 securities...\n}\n</pre>\n\n</p>\n  Due to the mercy of the author, the other 97 securities were omitted from\n  this paper.  The next helper function, <code>populate_exchange()</code> adds\n  these securities to the exchange:\n<p>\n\n<div class=\"listing\">publisher_main.cpp: main() helper functions, continued</div>\n<pre class=\"code\">\nvoid\npopulate_exchange(examples::Exchange&amp; exchange, const SecurityVector&amp; securities) {\n  SecurityVector::const_iterator sec;\n  for (sec = securities.begin(); sec != securities.end(); ++sec) {\n    exchange.add_order_book(sec-&gt;symbol);\n  }\n}\n</pre>\n\n</p>\n  The final helper function, <code>generate_orders()</code> creates random\n  orders and adds them to the exchange:\n<p>\n\n<div class=\"listing\">publisher_main.cpp: main() helper functions, continued</div>\n<pre class=\"code\">\nvoid\ngenerate_orders(examples::Exchange&amp; exchange, const SecurityVector&amp; securities) {\n  time_t now;\n  time(&amp;now);\n  std::srand(now);\n\n  size_t num_securities = securities.size();\n  while (true) {\n    // which security\n    size_t index = std::rand() % num_securities;\n    const SecurityInfo&amp; sec = securities[index];\n    // side\n    bool is_buy = std::rand() % 2;\n    // price\n    uint32_t price_base = sec.ref_price * 100;\n    uint32_t delta_range = price_base / 50;  // +/- 2% of base\n    int32_t delta = std::rand() % delta_range;\n    delta -= (delta_range / 2);\n    double price = double (price_base + delta) / 100;\n\n    // qty\n    book::Quantity qty = (std::rand() % 10 + 1) * 100;\n\n    // order\n    examples::OrderPtr order(new examples::Order(is_buy, price, qty));\n\n    // add order\n    exchange.add_order(sec.symbol, order);\n\n    // Wait for eyes to read\n    sleep(1);\n  }\n}\n</pre>\n\n<p>\n  The implementation of <code>generate_orders()</code> is somewhat complex, but\n  the details are not relevant.  There is a call to <code>sleep()</code>\n  inside the loop, so that the data stream is produced at a somewhat readable\n  pace.  At this point, the publisher is complete.\n</p>\n\n<h2>Subscriber Application</h2>\n\n<p>\n  With the publisher in place, focus turns to the subscriber.  The subscriber\n  must connect to the publisher, decode the FAST feed, recreate the depth \n  state for each security and display the results.  As noted earlier, the\n  connection is handled by the <code>DepthFeedConnection</code> class.  The \n  decoding and display of messages is handled by a the \n  <code>DepthFeedSubscriber</code> class:\n</p>\n\n<div class=\"listing\">depth_feed_subscriber.h: DepthFeedSubscriber class declaration</div>\n<pre class=\"code\">\nnamespace liquibook { namespace examples {\n\n  class DepthFeedSubscriber : public TemplateConsumer {\n  public:\n    DepthFeedSubscriber(\n        const QuickFAST::Codecs::TemplateRegistryPtr&amp; templates);\n\n    // Handle a reset of the connection\n    void handle_reset();\n\n    // Handle a message\n    // return false if failure\n    bool handle_message(BufferPtr&amp; bp, size_t bytes_transferred);\n</pre>\n\n<p>\n  The <code>DepthFeedSubscriber</code> class has a number of private members:\n</p>\n\n<div class=\"listing\">depth_feed_subscriber.h: DepthFeedSubscriber class declaration, continued</div>\n<pre class=\"code\">\n  private:\n    QuickFAST::Codecs::Decoder decoder_;\n    typedef std::map&lt;std::string, book::Depth&lt;5&gt; &gt; DepthMap;\n    DepthMap depth_map_;\n    uint64_t expected_seq_;\n\n    static const uint64_t MSG_TYPE_DEPTH;\n    static const uint64_t MSG_TYPE_TRADE;\n</pre>\n\n<p>\n  These members include a QuickFAST decoder, an order book for each security\n  (kept in a <code>std::map</code>), and the expected sequence number.  The \n  sequence number is tracked to validate the feed, so that the subscriber is\n  sure that every message from the publisher has been handled.\n</p>\n<p>\n  Finally, there are two constants for determining message type.  The reader\n  will note that these message type fields appear in the message, but the\n  publisher nowhere encoded them.  This is because of their field\n  instructions, found in the FAST template, of constant.\n</p>\n\n<p>\n  In addition, there are a few private methods, to process incoming methods:\n</p>\n\n<div class=\"listing\">depth_feed_subscriber.h: DepthFeedSubscriber class declaration, continued</div>\n<pre class=\"code\">\n    void log_depth(book::Depth&lt;5&gt;&amp; depth);\n    bool handle_trade_message(const std::string&amp; symbol,\n                              uint64_t&amp; seq_num,\n                              uint64_t&amp; timestamp,\n                              QuickFAST::Messages::Message&amp; msg);\n    bool handle_depth_message(const std::string&amp; symbol,\n                              uint64_t&amp; seq_num,\n                              uint64_t&amp; timestamp,\n                              QuickFAST::Messages::Message&amp; msg);\n  };\n} }\n</pre>\n\n<p>\n  After initializing the static members comes the class constructor:\n</p>\n\n<div class=\"listing\">depth_feed_subscriber.cpp: DepthFeedSubscriber class implementation</div>\n<pre class=\"code\">\nnamespace liquibook { namespace examples {\n\nconst uint64_t DepthFeedSubscriber::MSG_TYPE_DEPTH(11);\nconst uint64_t DepthFeedSubscriber::MSG_TYPE_TRADE(22);\n\nusing QuickFAST::ValueType;\n\nDepthFeedSubscriber::DepthFeedSubscriber(\n        const QuickFAST::Codecs::TemplateRegistryPtr&amp; templates)\n: decoder_(templates),\n  expected_seq_(1)\n{\n}\n</pre>\n\n<p>\n  The constructor passes the templates to the decoder, and initializes the\n  expected sequence number.  Next is the <code>handle_reset()</code> method, \n  which is called when the connection to the publisher is reset:\n</p>\n\n<div class=\"listing\">depth_feed_subscriber.cpp: DepthFeedSubscriber class implementation, continued</div>\n<pre class=\"code\">\nvoid\nDepthFeedSubscriber::handle_reset()\n{\n  expected_seq_ = 1;\n}\n</pre>\n\n<p>\n  This simple method just resets the expected sequence number to one.  Next, is\n  the meaty method <code>handle_message()</code>:\n</p>\n\n<div class=\"listing\">depth_feed_subscriber.cpp: DepthFeedSubscriber class implementation, continued</div>\n<pre class=\"code\">\n\nbool\nDepthFeedSubscriber::handle_message(BufferPtr&amp; bp, size_t bytes_transferred)\n{\n  // Decode the message\n  QuickFAST::Codecs::DataSourceBuffer source(bp-&gt;c_array(), bytes_transferred);\n  QuickFAST::Codecs::SingleMessageConsumer consumer;\n  QuickFAST::Codecs::GenericMessageBuilder builder(consumer);\n  decoder_.decodeMessage(source, builder);\n  QuickFAST::Messages::Message&amp; msg(consumer.message());\n\n  // Examine message contents\n  uint64_t seq_num, msg_type, timestamp;\n  const QuickFAST::StringBuffer* string_buffer;\n  size_t bids_length, asks_length;\n  std::string symbol;\n  if (!msg.getUnsignedInteger(id_seq_num_, ValueType::UINT32, seq_num)) {\n    std::cout &lt;&lt; \"Could not get seq num from msg\" &lt;&lt; std::endl;\n    return false;\n  }\n  if (seq_num != expected_seq_) {\n    std::cout &lt;&lt; \"ERROR: Got Seq num \" &lt;&lt; seq_num &lt;&lt; \", expected \" \n              &lt;&lt; expected_seq_ &lt;&lt; std::endl;\n    return false;\n  }\n  if (!msg.getUnsignedInteger(id_msg_type_, ValueType::UINT32, msg_type)) {\n    std::cout &lt;&lt; \"Could not get msg type from msg\" &lt;&lt; std::endl;\n    return false;\n  }\n  if (!msg.getString(id_symbol_, ValueType::ASCII, string_buffer)) {\n    std::cout &lt;&lt; \"Could not get symbol from msg\" &lt;&lt; std::endl;\n    return false;\n  }\n  if (!msg.getUnsignedInteger(id_timestamp_, ValueType::UINT32, timestamp)) {\n    std::cout &lt;&lt; \"Could not get timestamp from msg\" &lt;&lt; std::endl;\n    return false;\n  }\n  bool result = false;\n  symbol = (std::string)*string_buffer;\n  switch (msg_type) {\n  case MSG_TYPE_DEPTH:\n    result = handle_depth_message(symbol, seq_num, timestamp, msg);\n    break;\n  case MSG_TYPE_TRADE:\n    result = handle_trade_message(symbol, seq_num, timestamp, msg);\n    break;\n  default:\n    std::cout &lt;&lt; \"ERROR: Unknown message type \" &lt;&lt; msg_type \n              &lt;&lt; \" seq num \" &lt;&lt; seq_num &lt;&lt; std::endl;\n    return false;\n  }\n  ++expected_seq_;\n  return result;\n}\n</pre>\n\n<p>\n  This method first decodes the FAST message.  This is done by stuffing the \n  message contents into a QuickFAST buffer specific for decoding.  Next, a\n  message builder and consumer are created and associated, and the message is\n  decoded into the builder.  After this, the  message is available from the \n  consumer.\n</p>\n\n<p>\n  The common fields are then checked, by using the type-specific extractors on\n  the <code>QuickFAST::Messages::Message</code> class, such as\n  <code>getUnsignedInteger()</code>.  This starts with the sequence number, \n  which is validated against the expected sequence number.  Next the message\n  type, the symbol, and the timestamp are extracted.  If any of these fail, the\n  method exits with an error value.\n</p>\n\n<p>\n  Finally, since the message type is known, the proper message-type-specific\n  handler is called.\n</p>\n\n<p>\n  The first helper method logs the contents of the depth for a security:\n</p>\n<div class=\"listing\">depth_feed_subscriber.cpp: DepthFeedSubscriber class implementation, continued</div>\n<pre class=\"code\">\nvoid\nDepthFeedSubscriber::log_depth(book::Depth&lt;5&gt;&amp; depth)\n{\n  book::DepthLevel* bid = depth.bids();\n  book::DepthLevel* ask = depth.asks();\n  printf(\"----------BID----------    ----------ASK----------\\n\");\n  while (bid || ask) {\n    if (bid &amp;&amp; bid-&gt;order_count()) {\n      printf(\"%8.2f %9d [%2d]\", \n             (double)bid-&gt;price() / Order::precision_,\n             bid-&gt;aggregate_qty(), bid-&gt;order_count());\n      if (bid == depth.last_bid_level()) {\n        bid = NULL;\n      } else {\n        ++bid;\n      }\n    } else {\n      // Blank lines\n      printf(\"                       \");\n      bid = NULL;\n    }\n\n    if (ask &amp;&amp; ask-&gt;order_count()) {\n      printf(\"    %8.2f %9d [%2d]\\n\",\n             (double)ask-&gt;price() / Order::precision_,\n             ask-&gt;aggregate_qty(), ask-&gt;order_count());\n      if (ask == depth.last_ask_level()) {\n        ask = NULL;\n      } else {\n        ++ask;\n      }\n    } else {\n      // Newline\n      printf(\"\\n\");\n      ask = NULL;\n    }\n  }\n}\n</pre>\n\n<p>\n  This method is complex, because it logs both bid and ask on the same line.\n  In its loop, there could be a bid and an ask, only a bid, or only an ask.\n</p>\n\n<p>\n  The next helper handles a depth message:\n</p>\n\n<div class=\"listing\">depth_feed_subscriber.cpp: DepthFeedSubscriber class implementation, continued</div>\n<pre class=\"code\">\nbool\nDepthFeedSubscriber::handle_depth_message(\n  const std::string&amp; symbol,\n  uint64_t&amp; seq_num,\n  uint64_t&amp; timestamp,\n  QuickFAST::Messages::Message&amp; msg)\n{\n  size_t bids_length, asks_length;\n  std::cout &lt;&lt; timestamp\n            &lt;&lt; \" Got depth msg \" &lt;&lt; seq_num \n            &lt;&lt; \" for symbol \" &lt;&lt; symbol &lt;&lt; std::endl;\n\n  // Create or find depth\n  std::pair&lt;DepthMap::iterator, bool&gt; results = depth_map_.insert(\n      std::make_pair(symbol, book::Depth&lt;5&gt;()));\n  book::Depth&lt;5&gt;&amp; depth = results.first-&gt;second;\n\n  if (msg.getSequenceLength(id_bids_, bids_length)) {\n    for (size_t i = 0; i &lt; bids_length; ++i) {\n      const QuickFAST::Messages::MessageAccessor* accessor;\n      if (msg.getSequenceEntry(id_bids_, i, accessor)) {\n        uint64_t level_num, price, order_count, aggregate_qty;\n        if (!accessor-&gt;getUnsignedInteger(id_level_num_, ValueType::UINT8,\n                                         level_num)) {\n          std::cout &lt;&lt; \"Could not get Bid level from depth msg\" &lt;&lt; std::endl;\n          return false;\n        }\n        if (!accessor-&gt;getUnsignedInteger(id_price_, ValueType::UINT32,\n                                         price)) {\n          std::cout &lt;&lt; \"Could not get Bid price from depth msg\" &lt;&lt; std::endl;\n          return false;\n        }\n        if (!accessor-&gt;getUnsignedInteger(id_order_count_, ValueType::UINT32,\n                                         order_count)) {\n          std::cout &lt;&lt; \"Could not get Bid count from depth msg\" &lt;&lt; std::endl;\n          return false;\n        }\n        if (!accessor-&gt;getUnsignedInteger(id_size_, ValueType::UINT32,\n                                         aggregate_qty)) {\n          std::cout &lt;&lt; \"Could not get Bid agg qty  from depth msg\" &lt;&lt; std::endl;\n          return false;\n        }\n\n        book::DepthLevel&amp; level = depth.bids()[level_num];\n        level.set(price, aggregate_qty, order_count);\n\n      } else {\n        std::cout &lt;&lt; \"Failed to get bid \" &lt;&lt; i &lt;&lt; std::endl;\n        return false;\n      }\n      msg.endSequenceEntry(id_bids_, i, accessor);\n    }\n  }\n  if (msg.getSequenceLength(id_asks_, asks_length)) {\n    for (size_t i = 0; i &lt; asks_length; ++i) {\n      const QuickFAST::Messages::MessageAccessor* accessor;\n      if (msg.getSequenceEntry(id_asks_, i, accessor)) {\n        uint64_t level_num, price, order_count, aggregate_qty;\n        if (!accessor-&gt;getUnsignedInteger(id_level_num_, ValueType::UINT8,\n                                         level_num)) {\n          std::cout &lt;&lt; \"Could not get Ask level from depth msg \" &lt;&lt; std::endl;\n          return false;\n        }\n        if (!accessor-&gt;getUnsignedInteger(id_price_, ValueType::UINT32,\n                                         price)) {\n          std::cout &lt;&lt; \"Could not get Ask price  from depth msg\" &lt;&lt; std::endl;\n          return false;\n        }\n        if (!accessor-&gt;getUnsignedInteger(id_order_count_, ValueType::UINT32,\n                                         order_count)) {\n          std::cout &lt;&lt; \"Could not get Ask count from depth msg \" &lt;&lt; std::endl;\n          return false;\n        }\n        if (!accessor-&gt;getUnsignedInteger(id_size_, ValueType::UINT32,\n                                         aggregate_qty)) {\n          std::cout &lt;&lt; \"Could not get Ask agg qty from depth msg \" &lt;&lt; std::endl;\n          return false;\n        }\n\n        book::DepthLevel&amp; level = depth.asks()[level_num];\n        level.set(price, aggregate_qty, order_count);\n\n      } else {\n        std::cout &lt;&lt; \"Failed to get ask \" &lt;&lt; i &lt;&lt; std::endl;\n        return false;\n      }\n      msg.endSequenceEntry(id_asks_, i, accessor);\n    }\n  }\n  log_depth(depth);\n  return true;\n}\n</pre>\n\n<p>\n  This method has the common fields passed to it, and logs the symbol of the \n  message.  It then finds the proper depth object for the security, or creates\n  one if this is the first depth message for the security. \n</p>\n<p>\n  Next the method must iterate through the sequence of changed bids.  To do\n  this, the sequence length is first extracted, and each entry accessed through\n  an accessor.\n</p>\n<p>\n  Each bid field is then accessed using type-specific extractors, including the\n  level number, the price, the number of orders, and the aggregate quantity.\n  These updated values are then used to update the depth level for that\n  security through a call to <code>set()</code>.  Similar logic is performed\n  for changed ask levels, and the resulting depth is logged using\n  <code>log_depth()</code>.\n</p>\n\n<p>\n  The final helper method handles a trade message:\n</p>\n\n<div class=\"listing\">depth_feed_subscriber.cpp: DepthFeedSubscriber class implementation, continued</div>\n<pre class=\"code\">\nbool\nDepthFeedSubscriber::handle_trade_message(\n  const std::string&amp; symbol,\n  uint64_t&amp; seq_num,\n  uint64_t&amp; timestamp,\n  QuickFAST::Messages::Message&amp; msg)\n{\n  uint64_t qty, cost;\n  // Get trade fields\n  if (!msg.getUnsignedInteger(id_qty_, ValueType::UINT32, qty)) {\n    std::cout &lt;&lt; \"Could not qty from trade msg\" &lt;&lt; std::endl;\n    return false;\n  }\n  if (!msg.getUnsignedInteger(id_cost_, ValueType::UINT32, cost)) {\n    std::cout &lt;&lt; \"Could not get cost from trade msg\" &lt;&lt; std::endl;\n    return false;\n  }\n\n  double price = (double) cost / (qty * Order::precision_);\n  std::cout &lt;&lt; timestamp\n            &lt;&lt; \" Got trade msg \" &lt;&lt; seq_num \n            &lt;&lt; \" for symbol \" &lt;&lt; symbol \n            &lt;&lt; \": \" &lt;&lt; qty &lt;&lt; \"@\" &lt;&lt; price\n            &lt;&lt; std::endl;\n\n  return true;\n}\n\n} }\n</pre>\n\n<p>\n  Like <code>handle_depth_message()</code>, <code>handle_trade_message()</code>\n  is passed the common fields.  It extracts the trade quantity and cost, from\n  which it calculates the price of the trade (after adjusting for the \n  precision).  The result is then logged.\n</p>\n\n<h3>Subscriber Initialization</h3>\n\n<p>\n  Finally, the subscriber can create, initialize, and associate its components.\n  The <code>main()</code> function of subscriber starts by creating the\n  <code>DepthFeedConnection</code> and the <code>DepthFeedSubscriber</code>:\n</p>\n\n<div class=\"listing\">subscriber_main.cpp: main() function</div>\n<pre class=\"code\">\nint main(int argc, const char* argv[])\n{\n  // Create the connection\n  liquibook::examples::DepthFeedConnection connection(argc, argv);\n\n  // Create feed subscriber\n  liquibook::examples::DepthFeedSubscriber feed(connection.get_templates());\n\n  // Set up handlers\n  liquibook::examples::MessageHandler msg_handler =\n      boost::bind(&amp;liquibook::examples::DepthFeedSubscriber::handle_message,\n                  &amp;feed, _1, _2);\n  liquibook::examples::ResetHandler reset_handler =\n      boost::bind(&amp;liquibook::examples::DepthFeedSubscriber::handle_reset,\n                  &amp;feed);\n  connection.set_message_handler(msg_handler);\n  connection.set_reset_handler(reset_handler);\n\n  // Connect to server\n  connection.connect();\n  connection.run();\n\n  return 0;\n}\n</pre>\n\n<p>\n  Next, the handlers for messages and connection resets are set up, and \n  finally, the subscriber connects to the publisher.  This completes the \n  subscriber application.\n</p>\n\n<h2>Running the Example</h2>\n\n<p>\n  By default the publisher and subscriber connect on port 10003 on localhost.\n  To run on a different port, add the -p &lt;port&gt; to each command line.\n  The subscriber may also specify a remote host with the -h &lt;host&gt;\n  option.  To specify a different template file, or template file location, use\n  the -t &lt;filename&gt; option.\n</p>\n<p>\n  For example:\n</p>\n\n<pre>\n  $ ./depth_feed_publisher -p 9999\n  $ ./depth_feed_subscriber -p 9999\n</pre>\n\n<p>\n  The subscriber produces output like this:\n</p>\n\n<pre>\n1369167639 Got depth msg 8182 for symbol GILD\n----------BID----------    ----------ASK----------\n   49.93       400 [ 1]       50.12       500 [ 1]\n   49.66       300 [ 1]       50.13       500 [ 1]\n   49.59      1000 [ 3]       50.14       500 [ 1]\n   49.58       700 [ 1]       50.19       500 [ 1]\n                              50.26       800 [ 1]\n1369167640 Got depth msg 8183 for symbol XLNX\n----------BID----------    ----------ASK----------\n   37.40       400 [ 1]       37.60      1000 [ 2]\n   37.36       400 [ 1]       37.61      1900 [ 3]\n   37.35      1000 [ 1]       37.65       900 [ 3]\n   37.28       500 [ 2]       37.70       600 [ 1]\n   37.25      1700 [ 2]       37.71      1000 [ 2]\n1369167641 Got depth msg 8184 for symbol GOLD\n----------BID----------    ----------ASK----------\n   78.30       300 [ 1]       78.43       300 [ 1]\n   78.18       300 [ 1]       78.48       700 [ 1]\n   78.17       900 [ 1]       78.64       600 [ 1]\n   78.09       200 [ 1]       78.70       600 [ 1]\n   78.06       900 [ 1]       79.12       500 [ 1]\n1369167642 Got trade msg 8185 for symbol HSIC: 600@89.47\n1369167642 Got trade msg 8186 for symbol HSIC: 200@89.49\n1369167642 Got depth msg 8187 for symbol HSIC\n----------BID----------    ----------ASK----------\n   89.32       700 [ 1]       89.49       500 [ 1]\n   89.09       500 [ 1]       89.52       200 [ 1]\n   88.96       600 [ 1]       89.68       500 [ 1]\n   88.82       200 [ 1]       89.76       900 [ 1]\n   88.59       100 [ 1]       89.91       100 [ 1]\n</pre>\n\n<p>\n  These updates show the full depth for each security updated, and not just \n  the changed levels.  The first three updates shows the depth for various\n  securities, followed by some trades and a depth update for a fourth security.\n  The trades go hand-in-hand with a depth update.  Some depth updates cause\n  trades, and some do not.\n</p>\n<p>\n  Note that a very good test of the incremental feed is to start two\n  subscribers at different times, so that the first subscriber has handled a\n  good number of messages before the second subscriber is started.  The two\n  should still be perfectly in sync, and produce identical output.\n</p>\n\n<h2>Summary</h2>\n\n<p>\n  Although much code has been walked through in this example, very little\n  custom code was related to the order book.  Most of the code was either \n  general networking code using ASIO, or QuickFAST code.  In addition, the\n  complexities of order book maintenance and depth-building are contained -\n  most of the code shown was simple, or even trivial.\n</p>\n\n<p>\n  Liquibook makes it very simple to implement a limit order book matching \n  engine, whether you are building an exchange, or are a trader simulating an\n  exchange's matching capability.\n</p>\n\n<h2>References</h2>\n\n<ul>\n    <li>Liquibook -\n        <a href=\"https://github.com/objectcomputing/liquibook\" shape=\"rect\">https://github.com/objectcomputing/liquibook</a>\n    </li>\n    <li>QuickFAST -\n        <a href=\"http://quickfast.org\" shape=\"rect\">http://quickfast.org</a>\n    </li>\n    <li>Boost -\n        <a href=\"http://www.boost.org/\" shape=\"rect\">http://www.boost.org/</a>\n    </li>\n    <li>Xerces C -\n        <a href=\"http://xerces.apache.org/xerces-c/\" shape=\"rect\">http://xerces.apache.org/xerces-c/</a>\n    </li>\n    <li>FIX protocol -\n        <a href=\"http://www.fixprotocol.org\" shape=\"rect\">http://www.fixprotocol.org</a>\n    </li>\n    <li>FAST protocol -\n        <a href=\"http://www.fixprotocol.org/fast\" shape=\"rect\">http://www.fixprotocol.org/fast</a>\n    </li>\n    <li>NASDAQ 100 -\n        <a href=\"http://www.nasdaq.com/markets/indices/nasdaq-100.aspx\" shape=\"rect\">http://www.nasdaq.com/markets/indices/nasdaq-100.aspx</a>\n    </li>\n</ul>\n\n<p class=\"footer\">\n    Inquiries regarding\n    <a class=\"career\" href=\"http://www.ociweb.com/careers/index.html\">Career Opportunities</a>\n    can be directed to: <a href=\"mailto:hr@ociweb.com\">hr@ociweb.com</a>.\n</p>\n<p class=\"footer\">\n    The <em><strong>Software Engineering Tech Trends</strong></em>\n    is a monthly newsletter. The purpose and intent of this publication is to\n    partner with clients in developing solutions for their most demanding mission critical\n    systems, by leveraging our deep experience in software and systems engineering. We promote\n    non-proprietary, standards-based solutions that afford our clients greater control and\n    broader choice. Knowledge transfer is a fundamental aspect of services we offer our customers.\n    We tailor our engagements to meet customer needs. We foster the professional growth of our\n    employees and reward excellence.\n\n    To\n    <a href=\"mailto:sett-join@ociweb.com\">subscribe</a>\n    or\n    <a href=\"mailto:sett-leave@ociweb.com\">unsubscribe</a>\n</p>\n<p class=\"footer\">\n    Copyright\n    &copy;2008-2013.\n    Object Computing, Inc. All rights reserved.<br/>\n    <br/>Java and all\n    Java-based marks are trademarks or registered trademarks of Oracle Corporation.<br/>\n    <br/>\n    .NET, C#, and .NET-based marks are trademarks or registered trademarks of Microsoft\n    Corporation.\n</p>\n<div style=\"margin-top: 25px\">\n    <div style=\"float:left\">\n        <a href=\"http://validator.w3.org/check?uri=referer\"><img src=\"http://www.w3.org/Icons/valid-xhtml10\"\n                                                                 alt=\"Valid XHTML 1.0 Strict\" height=\"31\" width=\"88\"/></a>\n        <a href=\"http://feed2.w3.org/check.cgi?url=http%3A//ociweb.com/sett/rss.xml\"><img src=\"images/valid-rss-rogers.png\" alt=\"[Valid RSS]\" title=\"Validate my RSS feed\" /></a>\n    </div>\n    <div>\n        <a href=\"http://ociweb.com/sett/rss.xml\"><span class=\"rssRow\">RSS</span></a>\n    </div>\n    <div style=\"float:right\">\n        <a href=\"#top\">Top</a>\n    </div>\n\n</div>\n<script type=\"text/javascript\">\n    (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){\n        (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),\n            m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)\n    })(window,document,'script','//www.google-analytics.com/analytics.js','ga');\n\n    ga('create', 'UA-40828801-1', 'ociweb.com');\n    ga('send', 'pageview');\n\n</script>\n\n<script src=\"http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js\" type=\"text/javascript\"></script>\n<script src=\"http://alexgorbatchev.com/pub/sh/current/scripts/shAutoloader.js\" type=\"text/javascript\"></script>\n\n<script src=\"http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJava.js\" type=\"text/javascript\"></script>\n<script src=\"http://alexgorbatchev.com/pub/sh/current/scripts/shBrushXml.js\" type=\"text/javascript\"></script>\n<script src=\"http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPhp.js\" type=\"text/javascript\"></script>\n\n<script type=\"text/javascript\">SyntaxHighlighter.all()</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "doc/settAug2013/settAug2013_files/paper.css",
    "content": ".listing, .figure {\n  font-weight: bold;\n  font-size: .9em;\n}\n.listing {\n  margin-bottom: -16px;\n}\n"
  },
  {
    "path": "doc/settAug2013/styles/SETT.css",
    "content": "body {\n    color: rgb(0, 0, 0);\n    background-color: rgb(255, 255, 255);\n    font-family: Verdana, sans-serif;\n    margin-left: 0.25in;\n    margin-right: 0.25in;\n    min-width: 800px;\n}\n\n.header {\n    float: left;\n    width: 100%;\n}\n\n.left {\n    float: left;\n}\n\n.right {\n    float: right;\n}\n\n.lower_header {\n    height: 34px;\n    float: left;\n    width: 100%;\n    border-top: 1px solid lightgrey;\n    border-bottom: 1px solid lightgrey;\n    margin-bottom: 25px;\n}\n\n.social {\n    margin-top: 6px;\n}\n\nspan.rssRow  {\n    margin: 33px;\n    background:transparent url(../images/rss_icon_12x12.gif) no-repeat scroll 0;\n    padding-left:18px;\n}\n\n.headimage_container {\n    position: relative;\n    float: left;\n    width: 100%;\n    background: url('../images/Middle.png') repeat-x 35px;\n    height: 123px;\n}\n\n.headerimage_leftlogo {\n    position: absolute;\n    left: 0;\n    top: 0;\n    background-color: white;\n    width: 180px;\n    height: 123px;\n}\n\n.headimage_left {\n    position: absolute;\n    background-color: white;\n    top: 33px;\n    left: 180px;\n    width: 10px;\n}\n\n.headimage_right {\n    position: absolute;\n    background-color: white;\n    width: 278px;\n    right: 0;\n    margin-top: 33px;\n}\n\na.career {\n    font-weight: bold;\n}\n\ncode {\n    font-family: \"Courier New\", monospace;\n}\n\ndiv.center {\n    text-align: center;\n}\n\nh1 {\n    text-align: center;\n}\n\nh2 {\n    text-align: left;\n}\n\nh3 {\n    text-align: left;\n}\n\nh4 {\n    text-align: left;\n}\n\nh5 {\n    text-align: left;\n}\n\nhr {\n    height: 1px;\n    color: rgb(17, 59, 86);\n    background-color: transparent;\n}\n\nkbd {\n    font-family: \"Courier New\", monospace;\n}\n\np {\n    text-align: justify;\n}\n\np.author {\n    text-align: center;\n}\n\np.footer {\n    text-align: justify;\n}\n\npre {\n    font-family: \"Courier New\", monospace;\n}\n\n.quicklinks {\n    text-align: right;\n}\n\n.red {\n    color: rgb(255, 0, 0);\n    background-color: rgb(255, 255, 255);\n}\n\n.green {\n    color: rgb(0, 128, 0);\n    background-color: rgb(255, 255, 255);\n}\n\n.blue {\n    color: rgb(0, 0, 192);\n    background-color: rgb(255, 255, 255);\n}\n\n.code {\n    background-color: #FFFFF0;\n    border: dashed black 1px;\n    padding-left: 10px;\n}\n\n.comment {\n    color: rgb(128, 128, 128);\n    font-weight: normal;\n    font-style: italic;\n}\n\n"
  },
  {
    "path": "env.sh",
    "content": "SOURCE=\"${BASH_SOURCE[0]}\"\nSOURCE_DIR=`dirname $SOURCE`\n\nif test \"$LIQUIBOOK_ROOT\" = \"\"; then\n    READLINK='readlink'\n    $READLINK --version >/dev/null 2>/dev/null\n    if (( $? != 0 )); then\n      echo \"readlink does not exist or it does not support --version\"\n      echo \"maybe it is not GNU readlink but BSD\"\n      echo \"trying with greadlink...\"\n      READLINK='greadlink'\n    fi\n    $READLINK --version >/dev/null 2>/dev/null\n    if (( $? != 0 )); then\n      echo \"greadlink does not exist or an error occurred\"\n      UNAME=`uname`\n      if [[ $UNAME == \"Darwin\" ]]; then\n            echo \"You are running on a Mac OSX system.\"\n            echo \"Consider installing homebrew.\"\n            echo \"Then install coreutils.\"\n            echo \"# brew install coreutils\"\n      fi\n    else\n      echo \"$READLINK found at `which $READLINK`.\"\n    fi\n    $READLINK -f $SOURCE_DIR\n    if (( $? != 0 )); then\n      echo \"trying exporting LIQUIBOOK_ROOT by pwd.\"\n      export LIQUIBOOK_ROOT=`pwd`\n      echo \"LIQUIBOOK_ROOT = $LIQUIBOOK_ROOT\"\n    else\n      export LIQUIBOOK_ROOT=`$READLINK -f $SOURCE_DIR`\n    fi\nfi\n\nif test \"$QUICKFAST_ROOT\" == \"\";  then\n  export QUICKFAST_ROOT=`pwd`/noQuickFAST\n  echo QuickFAST support disabled\nfi\n\nif test \"$BOOST_VERSION\" = \"\"; then\n  echo Please export BOOST_VERSION, and BOOST_CFG\n  echo you can also set BOOST_ROOT if it is not /usr/boost/BOOST_VERSION\nelse\n  if test \"$BOOST_ROOT\" = \"\"; then\n    export BOOST_ROOT=/usr/boost/$BOOST_VERSION\n  fi\n  if test \"$BOOST_ROOT_LIB\" = \"\"; then\n    export BOOST_ROOT_LIB=$BOOST_ROOT/lib\n  fi\n  if test \"$BOOST_CFG\" = \"\"; then  \n    export BOOST_CFG=-gcc62-mt-1_63\n  fi\n  if test \"$BOOST_STATIC_LIB_PREFIX\" = \"\"; then\n    export BOOST_STATIC_LIB_PREFIX=\n  fi\nfi\n\nLD_LIBRARY_PATH=$LD_LIBRARY_PATH:$LIQUIBOOK_ROOT/lib\n# CIAO is not used, set so MPC does not give warning\nexport CIAO_ROOT=/dev/null\n"
  },
  {
    "path": "examples/.gitignore",
    "content": "\n"
  },
  {
    "path": "examples/mt_order_entry/Market.cpp",
    "content": "// Copyright (c) 2017 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#include \"Market.h\"\n#include \"Util.h\"\n\n#include <functional> \n#include <cctype>\n#include <locale>\n\nnamespace {\n    ///////////////////////\n    // depth display helper\n    void displayDepthLevel(std::ostream & out, const liquibook::book::DepthLevel & level)\n    {\n        out << \"\\tPrice \"  <<  level.price();\n        out << \" Count: \" << level.order_count();\n        out << \" Quantity: \" << level.aggregate_qty();\n        if(level.is_excess())\n        {\n            out << \" EXCESS\";\n        }\n        out << \" Change id#: \" << level.last_change();\n        out << std::endl;\n    }\n\n    void publishDepth(std::ostream & out, const orderentry::BookDepth & depth)\n    {\n        liquibook::book::ChangeId published = depth.last_published_change();\n        bool needTitle = true;\n        // Iterate awkwardly\n        auto pos = depth.bids();\n        auto back = depth.last_bid_level();\n        bool more = true;\n        while(more)\n        {\n            if(pos->aggregate_qty() !=0 && pos->last_change() > published)\n            {\n                if(needTitle)\n                {\n                    out << \"\\n\\tBIDS:\\n\";\n                    needTitle = false;\n                }\n                displayDepthLevel(out, *pos);\n            }\n            ++pos;\n            more = pos != back;\n        }\n\n        needTitle = true;\n        pos = depth.asks();\n        back = depth.last_ask_level();\n        more = true;\n        while(more)\n        {\n            if(pos->aggregate_qty() !=0 && pos->last_change() > published)\n            {\n                if(needTitle)\n                {\n                    out << \"\\n\\tASKS:\\n\";\n                    needTitle = false;\n                }\n                displayDepthLevel(out, *pos);\n            }\n            ++pos;\n            more = pos != back;\n        }\n    }\n}\n\nnamespace orderentry\n{\n\nuint32_t Market::orderIdSeed_ = 0;\n\nMarket::Market(std::ostream * out)\n: logFile_(out)\n{\n}\n\nMarket::~Market()\n{\n}\n\nconst char * \nMarket::prompt()\n{\n    return \"\\t(B)uy\\n\\t(S)ell\\n\\t(M)odify\\n\\t(C)ancel\\n\\t(D)isplay\\n\";\n}\n\nvoid \nMarket::help(std::ostream & out)\n{\n    out << \"Buy: Create a new Buy order and add it to the book\\n\"\n        << \"Sell: Create a new Sell order and add it to the book\\n\"\n        << \"  Arguments for BUY or SELL\\n\"\n        << \"     <Quantity>\\n\"\n        << \"     <Symbol>\\n\"\n        << \"     <Price> or MARKET\\n\"\n        << \"     AON            (optional)\\n\"\n        << \"     IOC            (optional)\\n\"\n        << \"     STOP <Price>   (optional)\\n\"\n        << \"     ;              end of order\\n\"\n        << std::endl;\n\n    out << \"Modify: Request Modify an existing order\\n\"\n        << \"  Arguments:\\n\"\n        << \"     <order#>\\n\"\n        << \"     PRICE <new price>\\n\"\n        << \"     QUANTITY <new initial quantity>\\n\"\n        << \"     ;              end of modify requet\\n\"\n        << std::endl;\n\n    out << \"Cancel: Request cancel an existing order\\n\"\n        << \"  Arguments:\\n\"\n        << \"     <order#>\\n\"\n        << \"     ;              end of cancel request (optional)\\n\"\n        << std::endl;\n\n    out << \"Display: Display status of an existing order\\n\"\n        << \"  Arguments:\\n\"\n        << \"     +       (enable verbose display)\\n\"\n        << \"     <order#> or <symbol> or \\\"all\\\"\\n\"\n        << std::endl;\n\n}\n\nbool \nMarket::apply(const std::vector<std::string> & tokens)\n{\n    const std::string & command = tokens[0];\n    if(command == \"BUY\" || command == \"B\")\n    {\n        return doAdd(\"BUY\", tokens, 1);\n    }\n    if(command == \"SELL\" || command == \"S\")\n    {\n        return doAdd(\"SELL\", tokens, 1);\n    }\n    else if (command == \"CANCEL\" || command == \"C\")\n    {\n        return doCancel(tokens, 1);\n    }\n    else if(command == \"MODIFY\" || command == \"M\")\n    {\n        return doModify(tokens, 1);\n    }\n    else if(command == \"DISPLAY\" || command == \"D\")\n    {\n        return doDisplay(tokens, 1);\n    }\n    return false;\n}\n\n\n////////\n// ADD\nbool \nMarket::doAdd(const  std::string & side, const std::vector<std::string> & tokens, size_t pos)\n{\n    //////////////\n    // Quantity\n    liquibook::book::Quantity quantity;\n    std::string qtyStr = nextToken(tokens, pos);\n    if(!qtyStr.empty())\n    {\n        quantity = toUint32(qtyStr);\n    }\n    else\n    {\n        quantity = promptForUint32(\"Quantity\");\n    }\n    // sanity check\n    if(quantity == 0 || quantity > 1000000000)\n    {\n        out() << \"--Expecting quantity\" << std::endl;\n        return false;\n    }\n\n    //////////////\n    // SYMBOL\n    std::string symbol = nextToken(tokens, pos);\n    if(symbol.empty())\n    {\n        symbol = promptForString(\"Symbol\");\n    }\n    if(!symbolIsDefined(symbol))\n    {\n        if(symbol[0] == '+' || symbol[0] == '!')\n        {\n            bool useDepth = symbol[0] == '!';\n            symbol = symbol.substr(1);\n            if(!symbolIsDefined(symbol))\n            {\n                addBook(symbol, useDepth);\n            }\n        }\n        else\n        {\n            std::string bookType;\n            while(bookType != \"S\" \n              && bookType != \"D\" \n              && bookType != \"N\")\n            {\n              bookType = promptForString(\n              \"New Symbol \" + symbol +  \n              \". \\nAdd [S]imple book, or [D]epth book, or 'N' to cancel request.\\n[SDN}\");\n            }\n            if(bookType == \"N\")\n            {\n                out() << \"Request ignored\" << std::endl;\n                return false;\n            }\n            bool useDepth = bookType == \"D\";\n            addBook(symbol, useDepth);\n        }\n    }\n\n    ///////////////\n    // PRICE\n    uint32_t price = 0;\n    std::string priceStr = nextToken(tokens, pos);\n    if(!priceStr.empty())\n    {\n        price = stringToPrice(priceStr);\n    }\n    else\n    {\n        price = promptForPrice(\"Limit Price or MKT\");\n    }\n    if(price > 10000000)\n    {\n        out() << \"--Expecting price or MARKET\" << std::endl;\n        return false;\n    }\n\n    //////////////////////////\n    // OPTIONS: AON, IOC STOP\n    bool aon = false;\n    bool ioc = false;\n    liquibook::book::Price stopPrice = 0;\n    bool go = false;\n    while(!go)\n    {\n        bool prompted = false;\n        bool optionOk = false;\n        std::string option = nextToken(tokens, pos);\n        if(option.empty())\n        {\n            prompted = true;\n            option = promptForString(\"AON, or IOC, or STOP, or END\");\n        }\n        if(option == \";\" || option == \"E\" || option == \"END\")\n        {\n            go = true;\n            optionOk = true;\n        }\n        else if(option == \"A\" || option == \"AON\")\n        {\n            aon = true;\n            optionOk = true;\n        }\n        else if(option == \"I\" || option == \"IOC\")\n        {\n            ioc = true;\n            optionOk = true;\n        }\n        else if(option == \"S\" || option == \"STOP\")\n        {\n            std::string stopstr = nextToken(tokens, pos);\n\n            if(!stopstr.empty())\n            {\n                stopPrice = stringToPrice(stopstr);\n            } \n            else\n            {\n                stopPrice = promptForUint32(\"Stop Price\");\n                prompted = true;\n            }\n            optionOk = stopPrice <= 10000000;\n        }\n        if(!optionOk)\n        {\n            out() << \"Unknown option \" << option << std::endl;\n            if(!prompted)\n            {\n                out() << \"--Expecting AON IOC STOP or END\" << std::endl;\n                return false;\n            }\n        }\n    }\n\n    std::string orderId = std::to_string(++orderIdSeed_);\n\n    OrderPtr order = std::make_shared<Order>(orderId, side == \"BUY\", quantity, symbol, price, stopPrice, aon, ioc);\n\n    const liquibook::book::OrderConditions AON(liquibook::book::oc_all_or_none);\n    const liquibook::book::OrderConditions IOC(liquibook::book::oc_immediate_or_cancel);\n    const liquibook::book::OrderConditions NOC(liquibook::book::oc_no_conditions);\n\n    const liquibook::book::OrderConditions conditions = \n        (aon ? AON : NOC) | (ioc ? IOC : NOC);\n\n\n    auto book = findBook(symbol);\n    if(!book)\n    {\n        out() << \"--No order book for symbol\" << symbol << std::endl;\n        return false;\n    }\n\n    order->onSubmitted();\n    out() << \"ADDING order:  \" << *order << std::endl;\n\n    orders_[orderId] = order;\n    book->add(order, conditions);\n    return true;\n}\n\n///////////\n// CANCEL\nbool\nMarket::doCancel(const std::vector<std::string> & tokens, size_t position)\n{\n    OrderPtr order;\n    OrderBookPtr book;\n    if(!findExistingOrder(tokens, position, order, book))\n    {\n        return false;\n    }\n    out() << \"Requesting Cancel: \" << *order << std::endl;\n    book->cancel(order);\n    return true;\n}\n\n///////////\n// MODIFY\nbool\nMarket::doModify(const std::vector<std::string> & tokens, size_t position)\n{\n    OrderPtr order;\n    OrderBookPtr book;\n    if(!findExistingOrder(tokens, position, order, book))\n    {\n        return false;\n    }\n\n    //////////////\n    // options\n    //////////////////////////\n    // OPTIONS: PRICE (price) ; QUANTITY (delta)\n\n    int64_t quantityChange = liquibook::book::SIZE_UNCHANGED;\n    liquibook::book::Price price = liquibook::book::PRICE_UNCHANGED;\n\n    bool go = false;\n    while(!go)\n    {\n        bool prompted = false;\n        bool optionOk = false;\n        std::string option = nextToken(tokens, position);\n        if(option.empty())\n        {\n            prompted = true;\n            option = promptForString(\"PRICE, or QUANTITY, or END\");\n        }\n        if(option == \";\" || option == \"E\" || option == \"END\")\n        {\n            go = true;\n            optionOk = true;\n        }\n        else if(option == \"P\" || option == \"PRICE\")\n        {\n            uint32_t newPrice = INVALID_UINT32;\n            std::string priceStr = nextToken(tokens, position);\n            if(priceStr.empty())\n            {\n                newPrice = promptForUint32(\"New Price\");\n            }\n            else\n            {\n                newPrice = toUint32(priceStr);\n            }\n\n            if(newPrice > 0 && newPrice != INVALID_UINT32)\n            {\n                price = newPrice;\n                optionOk = true;\n            }\n            else\n            {\n                out() << \"Invalid price\" << std::endl;\n            }\n        }\n        else if(option == \"Q\" || option == \"QUANTITY\")\n        {\n            int32_t qty = INVALID_INT32;\n            std::string qtyStr = nextToken(tokens, position);\n            if(qtyStr.empty())\n            {\n                qty = promptForInt32(\"Change in quantity\");\n            }\n            else\n            {\n                qty = toInt32(qtyStr);\n            }\n            if(qty != INVALID_INT32)\n            {\n                quantityChange = qty;\n                optionOk = true;\n            }\n            else\n            {\n                out() << \"Invalid quantity change.\" << std::endl;\n            }\n        }\n\n        if(!optionOk)\n        {\n            out() << \"Unknown or invalid option \" << option << std::endl;\n            if(!prompted)\n            {\n                out() << \"--Expecting PRICE <price>, or QUANTITY <change>, or  END\" << std::endl;\n                return false;\n            }\n        }\n    }\n\n    book->replace(order, quantityChange, price);\n    out() << \"Requested Modify\" ;\n    if(quantityChange != liquibook::book::SIZE_UNCHANGED)\n    {\n        out() << \" QUANTITY  += \" << quantityChange;\n    }\n    if(price != liquibook::book::PRICE_UNCHANGED)\n    {\n        out() << \" PRICE \" << price;\n    }\n    out() << std::endl;\n    return true;\n}\n\n///////////\n// DISPLAY\nbool\nMarket::doDisplay(const std::vector<std::string> & tokens, size_t pos)\n{\n    bool verbose = false;\n    // see if first token could be an order id.\n    // todo: handle prompted imput!\n    std::string parameter = nextToken(tokens, pos);\n    if(parameter.empty())\n    {\n        parameter = promptForString(\"+ or #OrderId or -orderOffset or symbol or \\\"ALL\\\"\");\n    }\n    else\n    {\n        --pos; // Don't consume this parameter yet.\n    }\n    if(parameter[0] == '+')\n    {\n        verbose = true;\n        if(parameter.length() > 1)\n        {\n            parameter = parameter.substr(1);\n        }\n        else\n        {\n            ++pos; // now we can consume the first parameter (whether or not it's there!)\n            parameter = nextToken(tokens, pos);\n            if(parameter.empty())\n            {\n                parameter = promptForString(\"#OrderId or -orderOffset or symbol or \\\"ALL\\\"\");\n            }\n            else\n            {\n                --pos; // Don't consume this parameter yet.\n            }\n        }\n    }\n    if(parameter[0] == '#' || parameter[0] == '-' || isdigit(parameter[0]))\n    {\n        OrderPtr order;\n        OrderBookPtr book;\n        if(findExistingOrder(parameter, order, book))\n        {\n            out() << *order << std::endl;\n            return true;\n        }\n    }\n\n    // Not an order id.  Try for a symbol:\n    std::string symbol = parameter;\n    if(symbolIsDefined(symbol))\n    {\n        for(auto pOrder = orders_.begin(); pOrder != orders_.end(); ++pOrder)\n        {\n            const OrderPtr & order = pOrder->second;\n            if(order->symbol() == symbol)\n            {\n                out() << order->verbose(verbose) << std::endl;\n                order->verbose(false);\n            }\n        }\n        auto book = findBook(symbol);\n        if(!book)\n        {\n            out() << \"--No order book for symbol\" << symbol << std::endl;\n        }\n        else\n        {\n            book->log(out());\n        }\n        return true;\n    }\n    else if( symbol == \"ALL\")\n    {\n        for(auto pOrder = orders_.begin(); pOrder != orders_.end(); ++pOrder)\n        {\n            const OrderPtr & order = pOrder->second;\n            out() << order->verbose(verbose) << std::endl;\n            order->verbose(false);\n        }\n\n        for(auto pBook = books_.begin(); pBook != books_.end(); ++pBook)\n        {\n            out() << \"Order book for \" << pBook->first << std::endl;\n            pBook->second->log(out());\n        }\n        return true;\n    }\n    else\n    {\n        out() << \"--Unknown symbol: \" << symbol << std::endl;\n    }\n    return false;\n}\n\n/////////////////////////////\n// Order book interactions\n\nbool\nMarket::symbolIsDefined(const std::string & symbol)\n{\n    auto book = books_.find(symbol);\n    return book != books_.end();\n}\n\nOrderBookPtr\nMarket::addBook(const std::string & symbol, bool useDepthBook)\n{\n    OrderBookPtr result;\n    if(useDepthBook)\n    {\n        out() << \"Create new depth order book for \" << symbol << std::endl;\n        DepthOrderBookPtr depthBook = std::make_shared<DepthOrderBook>(symbol);\n        depthBook->set_bbo_listener(this);\n        depthBook->set_depth_listener(this);\n        result = depthBook;\n    }\n    else\n    {\n        out() << \"Create new order book for \" << symbol << std::endl;\n        result = std::make_shared<OrderBook>(symbol);\n    }\n    result->set_order_listener(this);\n    result->set_trade_listener(this);\n    result->set_order_book_listener(this);\n    books_[symbol] = result;\n    return result;\n}\n\nOrderBookPtr\nMarket::findBook(const std::string & symbol)\n{\n    OrderBookPtr result;\n    auto entry = books_.find(symbol);\n    if(entry != books_.end())\n    {\n        result = entry->second;\n    }\n    return result;\n}\n\nbool Market::findExistingOrder(const std::vector<std::string> & tokens, size_t & position, OrderPtr & order, OrderBookPtr & book)\n{\n    ////////////////\n    // Order ID\n    std::string orderId = nextToken(tokens, position);\n    trim(orderId);\n    if(orderId.empty())\n    {\n        orderId = promptForString(\"Order Id#\");\n        trim(orderId);\n    }\n    // discard leading # if any\n    if(orderId[0] == '#')\n    {\n        orderId = orderId.substr(1);\n        trim(orderId);\n        if(orderId.empty())\n        {\n            out() << \"--Expecting #orderID\" << std::endl;\n            return false;\n        }\n    }\n\n    if(orderId[0] == '-') // relative addressing\n    {\n        int32_t orderOffset = toInt32(orderId);\n        if(orderOffset == INVALID_INT32)\n        {\n            out() << \"--Expecting orderID or offset\" << std::endl;\n            return false;\n        }\n        uint32_t orderNumber = orderIdSeed_  + 1 + orderOffset;\n        orderId = std::to_string(orderNumber);\n    }\n    return findExistingOrder(orderId, order, book);\n}\n\nbool Market::findExistingOrder(const std::string & orderId, OrderPtr & order, OrderBookPtr & book)\n{\n    auto orderPosition = orders_.find(orderId);\n    if(orderPosition == orders_.end())\n    {\n        out() << \"--Can't find OrderID #\" << orderId << std::endl;\n        return false;\n    }\n\n    order = orderPosition->second;\n    std::string symbol = order->symbol();\n    book = findBook(symbol);\n    if(!book)\n    {\n        out() << \"--No order book for symbol\" << symbol << std::endl;\n        return false;\n    }\n    return true;\n}\n\n/////////////////////////////////////\n// Implement OrderListener interface\n\nvoid \nMarket::on_accept(const OrderPtr& order)\n{\n    order->onAccepted();\n    out() << \"\\tAccepted: \" <<*order<< std::endl;\n}\n\nvoid \nMarket::on_reject(const OrderPtr& order, const char* reason)\n{\n    order->onRejected(reason);\n    out() << \"\\tRejected: \" <<*order<< ' ' << reason << std::endl;\n\n}\n\nvoid \nMarket::on_fill(const OrderPtr& order, \n    const OrderPtr& matched_order, \n    liquibook::book::Quantity fill_qty, \n    liquibook::book::Cost fill_cost)\n{\n    order->onFilled(fill_qty, fill_cost);\n    matched_order->onFilled(fill_qty, fill_cost);\n    out() << (order->is_buy() ? \"\\tBought: \" : \"\\tSold: \") \n        << fill_qty << \" Shares for \" << fill_cost << ' ' <<*order<< std::endl;\n    out() << (matched_order->is_buy() ? \"\\tBought: \" : \"\\tSold: \") \n        << fill_qty << \" Shares for \" << fill_cost << ' ' << *matched_order << std::endl;\n}\n\nvoid \nMarket::on_cancel(const OrderPtr& order)\n{\n    order->onCancelled();\n    out() << \"\\tCanceled: \" << *order<< std::endl;\n}\n\nvoid Market::on_cancel_reject(const OrderPtr& order, const char* reason)\n{\n    order->onCancelRejected(reason);\n    out() << \"\\tCancel Reject: \" <<*order<< ' ' << reason << std::endl;\n}\n\nvoid Market::on_replace(const OrderPtr& order, \n    const int64_t& size_delta, \n    liquibook::book::Price new_price)\n{\n    order->onReplaced(size_delta, new_price);\n    out() << \"\\tModify \" ;\n    if(size_delta != liquibook::book::SIZE_UNCHANGED)\n    {\n        out() << \" QUANTITY  += \" << size_delta;\n    }\n    if(new_price != liquibook::book::PRICE_UNCHANGED)\n    {\n        out() << \" PRICE \" << new_price;\n    }\n    out() <<*order<< std::endl;\n}\n\nvoid \nMarket::on_replace_reject(const OrderPtr& order, const char* reason)\n{\n    order->onReplaceRejected(reason);\n    out() << \"\\tReplace Reject: \" <<*order<< ' ' << reason << std::endl;\n}\n\n////////////////////////////////////\n// Implement TradeListener interface\n\nvoid \nMarket::on_trade(const OrderBook* book, \n    liquibook::book::Quantity qty, \n    liquibook::book::Cost cost)\n{\n    out() << \"\\tTrade: \" << qty <<  ' ' << book->symbol() << \" Cost \"  << cost  << std::endl;\n}\n\n/////////////////////////////////////////\n// Implement OrderBookListener interface\n\nvoid \nMarket::on_order_book_change(const OrderBook* book)\n{\n    out() << \"\\tBook Change: \" << ' ' << book->symbol() << std::endl;\n}\n\n\n\n/////////////////////////////////////////\n// Implement BboListener interface\nvoid \nMarket::on_bbo_change(const DepthOrderBook * book, const BookDepth * depth)\n{\n    out() << \"\\tBBO Change: \" << ' ' << book->symbol() \n        << (depth->changed() ? \" Changed\" : \" Unchanged\")\n        << \" Change Id: \" << depth->last_change()\n        << \" Published: \" << depth->last_published_change()\n        << std::endl;\n\n}\n\n/////////////////////////////////////////\n// Implement DepthListener interface\nvoid \nMarket::on_depth_change(const DepthOrderBook * book, const BookDepth * depth)\n{\n    out() << \"\\tDepth Change: \" << ' ' << book->symbol();\n    out() << (depth->changed() ? \" Changed\" : \" Unchanged\")\n        << \" Change Id: \" << depth->last_change()\n        << \" Published: \" << depth->last_published_change();\n    publishDepth(out(), *depth);\n    out() << std::endl;\n}\n\n}  // namespace orderentry\n"
  },
  {
    "path": "examples/mt_order_entry/Market.h",
    "content": "// Copyright (c) 2017 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#pragma once\n\n#include <book/depth_order_book.h>\n\n#include \"Order.h\"\n\n#include <string>\n#include <vector>\n#include <iostream>\n#include <algorithm>\n#include <map>\n#include <memory>\n\nnamespace orderentry\n{\ntypedef liquibook::book::OrderBook<OrderPtr> OrderBook;\ntypedef std::shared_ptr<OrderBook> OrderBookPtr;\ntypedef liquibook::book::DepthOrderBook<OrderPtr> DepthOrderBook;\ntypedef std::shared_ptr<DepthOrderBook> DepthOrderBookPtr;\ntypedef liquibook::book::Depth<> BookDepth;\n\nclass Market \n    : public liquibook::book::OrderListener<OrderPtr>\n    , public liquibook::book::TradeListener<OrderBook>\n    , public liquibook::book::OrderBookListener<OrderBook>\n    , public liquibook::book::BboListener<DepthOrderBook>\n    , public liquibook::book::DepthListener<DepthOrderBook>\n{\n    typedef std::map<std::string, OrderPtr> OrderMap;\n    typedef std::map<std::string, OrderBookPtr> SymbolToBookMap;\npublic:\n    Market(std::ostream * logFile = &std::cout);\n    ~Market();\n\n    /// @brief What to display to user when requesting input\n    static const char * prompt();\n\n    /// @brief Help for user's input\n    static void help(std::ostream & out = std::cout);\n\n    /// @brief Apply a user command that has been parsed into tokens.\n    bool apply(const std::vector<std::string> & tokens);\n\npublic:\n    /////////////////////////////////////\n    // Implement OrderListener interface\n\n    /// @brief callback for an order accept\n    virtual void on_accept(const OrderPtr& order);\n\n    /// @brief callback for an order reject\n    virtual void on_reject(const OrderPtr& order, const char* reason);\n\n    /// @brief callback for an order fill\n    /// @param order the inbound order\n    /// @param matched_order the matched order\n    /// @param fill_qty the quantity of this fill\n    /// @param fill_cost the cost of this fill (qty * price)\n    virtual void on_fill(const OrderPtr& order, \n        const OrderPtr& matched_order, \n        liquibook::book::Quantity fill_qty, \n        liquibook::book::Cost fill_cost);\n\n    /// @brief callback for an order cancellation\n    virtual void on_cancel(const OrderPtr& order);\n\n    /// @brief callback for an order cancel rejection\n    virtual void on_cancel_reject(const OrderPtr& order, const char* reason);\n\n    /// @brief callback for an order replace\n    /// @param order the replaced order\n    /// @param size_delta the change to order quantity\n    /// @param new_price the updated order price\n    virtual void on_replace(const OrderPtr& order, \n        const int64_t& size_delta, \n        liquibook::book::Price new_price);\n\n    /// @brief callback for an order replace rejection\n    virtual void on_replace_reject(const OrderPtr& order, const char* reason);\n\n    ////////////////////////////////////\n    // Implement TradeListener interface\n\n    /// @brief callback for a trade\n    /// @param book the order book of the fill (not defined whether this is before\n    ///      or after fill)\n    /// @param qty the quantity of this fill\n    /// @param cost the cost of this fill (qty * price)\n    virtual void on_trade(const OrderBook* book, \n        liquibook::book::Quantity qty, \n        liquibook::book::Cost cost);\n\n    /////////////////////////////////////////\n    // Implement OrderBookListener interface\n\n    /// @brief callback for change anywhere in order book\n    virtual void on_order_book_change(const OrderBook* book);\n\n    /////////////////////////////////////////\n    // Implement BboListener interface\n    void on_bbo_change(const DepthOrderBook * book, const BookDepth * depth);\n\n    /////////////////////////////////////////\n    // Implement DepthListener interface\n    void on_depth_change(const DepthOrderBook * book, const BookDepth * depth);\n\nprivate:\n    ////////////////////////////////////\n    // Command implementatiokns\n    bool doAdd(const std::string & side, const std::vector<std::string> & tokens, size_t pos);\n    bool doCancel(const std::vector<std::string> & tokens, size_t position);\n    bool doModify(const std::vector<std::string> & tokens, size_t position);\n    bool doDisplay(const std::vector<std::string> & tokens, size_t position);\n\n    ////////////////////////\n    // Order book interactions\n    bool symbolIsDefined(const std::string & symbol);\n    OrderBookPtr findBook(const std::string & symbol);\n    OrderBookPtr addBook(const std::string & symbol, bool useDepthBook);\n    bool findExistingOrder(const std::vector<std::string> & tokens, size_t & position, OrderPtr & order, OrderBookPtr & book);\n    bool findExistingOrder(const std::string & orderId, OrderPtr & order, OrderBookPtr & book);\n\n    std::ostream & out() \n    {\n        return *logFile_;\n    }\nprivate:\n    static uint32_t orderIdSeed_;\n\n    std::ostream * logFile_;\n\n    OrderMap orders_;\n    SymbolToBookMap books_;\n\n};\n\n} // namespace orderentry\n"
  },
  {
    "path": "examples/mt_order_entry/Order.cpp",
    "content": "// Copyright (c) 2017 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#include \"Order.h\"\n#include <sstream>\n\nnamespace orderentry\n{\n\nOrder::Order(const std::string & id,\n    bool buy_side,\n    liquibook::book::Quantity quantity,\n    std::string symbol,\n    liquibook::book::Price price,\n    liquibook::book::Price stopPrice,\n    bool aon,\n    bool ioc)\n    : id_(id)\n    , buy_side_(buy_side)\n    , symbol_(symbol)\n    , quantity_(quantity)\n    , price_(price)\n    , stopPrice_(stopPrice)\n    , ioc_(ioc)\n    , aon_(aon)\n    , quantityFilled_(0)\n    , quantityOnMarket_(0)\n    , fillCost_(0)\n    , verbose_(false)\n\n{\n}\n\nstd::string \nOrder::order_id() const\n{\n    return id_;\n}\n\nbool \nOrder::is_limit() const\n{\n    return price() != 0;\n}\n\nbool \nOrder::is_buy() const\n{\n    return buy_side_;\n}\n\nbool \nOrder::all_or_none() const\n{\n    return aon_;\n}\n\nbool \nOrder::immediate_or_cancel() const\n{\n    return ioc_;\n}\n\nstd::string \nOrder::symbol() const\n{\n   return symbol_;\n}\n\nliquibook::book::Price \nOrder::price() const\n{\n    return price_;\n}\n\nliquibook::book::Quantity \nOrder::order_qty() const\n{\n    return quantity_;\n}\n\n\nliquibook::book::Price \nOrder::stop_price() const\n{\n    return stopPrice_;\n}\n\nuint32_t \nOrder::quantityOnMarket() const\n{\n    return quantityOnMarket_;\n}\n\nuint32_t \nOrder::quantityFilled() const\n{\n    return quantityFilled_;\n}\n\nuint32_t \nOrder::fillCost() const\n{\n    return fillCost_;\n}\n\n\nconst Order::History & \nOrder::history() const\n{\n    return history_;\n}\n\nconst Order::StateChange & \nOrder::currentState() const\n{\n    return history_.back();\n}\n\n\nOrder & \nOrder::verbose(bool verbose)\n{\n    verbose_ = verbose;\n    return *this;\n}\n\nbool\nOrder::isVerbose() const\n{\n    return verbose_;\n}\n\nvoid \nOrder::onSubmitted()\n{\n    std::stringstream msg;\n    msg << (is_buy() ? \"BUY \" : \"SELL \") << quantity_ << ' ' << symbol_ << \" @\";\n    if( price_ == 0)\n    {\n        msg << \"MKT\";\n    }\n    else\n    {\n        msg << price_;\n    }\n    history_.emplace_back(Submitted, msg.str());\n}\n\nvoid \nOrder::onAccepted()\n{\n    quantityOnMarket_ = quantity_;\n    history_.emplace_back(Accepted);\n}\n\nvoid \nOrder::onRejected(const char * reason)\n{\n    history_.emplace_back(Rejected, reason);\n}\n\nvoid \nOrder::onFilled(\n    liquibook::book::Quantity fill_qty, \n    liquibook::book::Cost fill_cost)\n{\n    quantityOnMarket_ -= fill_qty;\n    fillCost_ += fill_cost;\n\n    std::stringstream msg;\n    msg << fill_qty << \" for \" << fill_cost;\n    history_.emplace_back(Filled, msg.str());\n}\n\nvoid \nOrder::onCancelRequested()\n{\n    history_.emplace_back(CancelRequested);\n}\n\nvoid \nOrder::onCancelled()\n{\n    quantityOnMarket_ = 0;\n    history_.emplace_back(Cancelled);\n}\n\nvoid \nOrder::onCancelRejected(const char * reason)\n{\n    history_.emplace_back(CancelRejected, reason);\n}\n\nvoid \nOrder::onReplaceRequested(\n    const int32_t& size_delta, \n    liquibook::book::Price new_price)\n{\n    std::stringstream msg;\n    if(size_delta != liquibook::book::SIZE_UNCHANGED)\n    {\n        msg << \"Quantity change: \" << size_delta << ' ';\n    }\n    if(new_price != liquibook::book::PRICE_UNCHANGED)\n    {\n        msg << \"New Price \" << new_price;\n    }\n    history_.emplace_back(ModifyRequested, msg.str());\n}\n\nvoid \nOrder::onReplaced(const int32_t& size_delta, \n    liquibook::book::Price new_price)\n{\n    std::stringstream msg;\n    if(size_delta != liquibook::book::SIZE_UNCHANGED)\n    {\n        quantity_ += size_delta;\n        quantityOnMarket_ += size_delta;\n        msg << \"Quantity change: \" << size_delta << ' ';\n    }\n    if(new_price != liquibook::book::PRICE_UNCHANGED)\n    {\n        price_ = new_price;\n        msg << \"New Price \" << new_price;\n    }\n    history_.emplace_back(Modified, msg.str());\n}\n\nvoid \nOrder::onReplaceRejected(const char * reason)\n{\n    history_.emplace_back(ModifyRejected, reason);\n}\n\nstd::ostream & operator << (std::ostream & out, const Order::StateChange & event)\n{\n    out << \"{\";\n    switch(event.state_)\n    {\n    case Order::Submitted:\n        out << \"Submitted \";\n        break;\n    case Order::Rejected: \n        out << \"Rejected \"; \n        break;\n    case Order::Accepted:\n        out << \"Accepted \";\n        break;\n    case Order::ModifyRequested:\n        out << \"ModifyRequested \";\n        break;\n    case Order::ModifyRejected:\n        out << \"ModifyRejected \";\n        break;\n    case Order::Modified:\n        out << \"Modified \";\n        break;\n    case Order::PartialFilled:\n        out << \"PartialFilled \";\n        break;\n    case Order::Filled: \n        out << \"Filled \"; \n        break;\n    case Order::CancelRequested:\n        out << \"CancelRequested \";\n        break;\n    case Order::CancelRejected:\n        out << \"CancelRejected \";\n        break;\n    case Order::Cancelled: \n        out << \"Cancelled \"; \n        break;\n    case Order::Unknown:\n        out << \"Unknown \";\n        break;\n    }\n    out << event.description_;\n    out << \"}\";\n    return out;\n}\n\nstd::ostream & operator << (std::ostream & out, const Order & order)\n{\n    out << \"[#\" << order.order_id(); \n    out << ' ' << (order.is_buy() ? \"BUY\" : \"SELL\");\n    out << ' ' << order.order_qty();\n    out << ' ' << order.symbol();\n    if(order.price() == 0)\n    {\n        out << \" MKT\";\n    }\n    else\n    {\n        out << \" $\" << order.price();\n    }\n\n    if(order.stop_price() != 0)\n    {\n       out << \" STOP \" << order.stop_price();\n    }\n\n    out  << (order.all_or_none() ? \" AON\" : \"\")\n        << (order.immediate_or_cancel() ? \" IOC\" : \"\");\n\n    auto onMarket = order.quantityOnMarket();\n    if(onMarket != 0)\n    {\n        out << \" Open: \" << onMarket;\n    }\n\n    auto filled = order.quantityFilled();\n    if(filled != 0)\n    {\n        out << \" Filled: \" << filled;\n    }\n\n    auto cost = order.fillCost();\n    if(cost != 0)\n    {\n        out << \" Cost: \" << cost;\n    }\n\n    if(order.isVerbose())\n    {\n        const Order::History & history = order.history();\n        for(auto event = history.begin(); event != history.end(); ++event)\n        {\n            out << \"\\n\\t\" << *event;\n        } \n    }\n    else\n    {\n        out << \" Last Event:\" << order.currentState();\n    }\n\n   out << ']';\n   \n   return out;\n}\n\n\n}\n"
  },
  {
    "path": "examples/mt_order_entry/Order.h",
    "content": "// Copyright (c) 2017 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#pragma once\n\n#include \"OrderFwd.h\"\n#include <book/types.h>\n\n#include <string>\n#include <vector>\n\nnamespace orderentry\n{\n\nclass Order\n{\npublic:\n    enum State{\n        Submitted,\n        Rejected, // Terminal state\n        Accepted,\n        ModifyRequested,\n        ModifyRejected,\n        Modified,\n        PartialFilled,\n        Filled, // Terminal State\n        CancelRequested,\n        CancelRejected,\n        Cancelled, // Terminal state\n        Unknown\n    };\n\n    struct StateChange\n    {\n        State state_;\n        std::string description_;\n        StateChange()\n          : state_(Unknown)\n          {}\n\n        StateChange(State state, const std::string & description = \"\")\n            : state_(state)\n            , description_(description)\n        {}\n    };    \n    typedef std::vector<StateChange> History;\npublic:\n    Order(const std::string & id,\n        bool buy_side,\n        liquibook::book::Quantity quantity,\n        std::string symbol,\n        liquibook::book::Price price,\n        liquibook::book::Price stopPrice,\n        bool aon,\n        bool ioc);\n\n    //////////////////////////\n    // Implement the \n    // liquibook::book::order\n    // concept.\n\n    /// @brief is this a limit order?\n    bool is_limit() const;\n\n    /// @brief is this order a buy?\n    bool is_buy() const;\n\n    /// @brief get the price of this order, or 0 if a market order\n    liquibook::book::Price price() const;\n\n    /// @brief get the stop price (if any) for this order.\n    /// @returns the stop price or zero if not a stop order\n    liquibook::book::Price stop_price() const;\n\n    /// @brief get the quantity of this order\n    liquibook::book::Quantity order_qty() const;\n\n    /// @brief if no trades should happen until the order\n    /// can be filled completely.\n    /// Note: one or more trades may be used to fill the order.\n    virtual bool all_or_none() const;\n\n    /// @brief After generating as many trades as possible against\n    /// orders already on the market, cancel any remaining quantity.\n    virtual bool immediate_or_cancel() const;\n\n    std::string symbol() const;\n\n    std::string order_id() const;\n\n    uint32_t quantityFilled() const;\n\n    uint32_t quantityOnMarket() const;\n\n    uint32_t fillCost() const;\n\n    Order & verbose(bool verbose = true);\n    bool isVerbose()const;\n    const History & history() const;\n    const StateChange & currentState() const;\n\n    ///////////////////////////\n    // Order life cycle events\n    void onSubmitted();\n    void onAccepted();\n    void onRejected(const char * reason);\n\n    void onFilled(\n        liquibook::book::Quantity fill_qty, \n        liquibook::book::Cost fill_cost);\n\n    void onCancelRequested();\n    void onCancelled();\n    void onCancelRejected(const char * reason);\n\n    void onReplaceRequested(\n        const int32_t& size_delta, \n        liquibook::book::Price new_price);\n\n    void onReplaced(const int32_t& size_delta, \n        liquibook::book::Price new_price);\n\n    void onReplaceRejected(const char * reaseon);\n\nprivate:\n    std::string id_;\n    bool buy_side_;\n    std::string symbol_;\n    liquibook::book::Quantity quantity_;\n    liquibook::book::Price price_;\n    liquibook::book::Price stopPrice_;\n\n    bool aon_;\n    bool ioc_;\n\n    liquibook::book::Quantity quantityFilled_;\n    int32_t quantityOnMarket_;\n    uint32_t fillCost_;\n    \n    std::vector<StateChange> history_;\n    bool verbose_;\n};\n\nstd::ostream & operator << (std::ostream & out, const Order & order);\nstd::ostream & operator << (std::ostream & out, const Order::StateChange & event);\n\n}\n"
  },
  {
    "path": "examples/mt_order_entry/OrderFwd.h",
    "content": "// Copyright (c) 2017 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#pragma once\n#include <memory>\nnamespace orderentry\n{\n    class Order;\n    typedef std::shared_ptr<Order> OrderPtr;\n}\n"
  },
  {
    "path": "examples/mt_order_entry/TestOneAonBidTwoAsk.script",
    "content": "## Copyright (c) 2017 Object Computing, Inc.\n## All rights reserved.\n## See the file license.txt for licensing information.\n\n# Run the One AON bid, two AON ask test\nBUY 300 +IBM 1251 AON;\nSELL 100 IBM 1251;\nSELL 200 IBM 1251;\n#expect execution, but currently the test fails\nD + ALL\n"
  },
  {
    "path": "examples/mt_order_entry/Util.cpp",
    "content": "// Copyright (c) 2017 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#include \"Util.h\"\n#include <iostream>\n#include <algorithm>\n#include <functional>\n#include <cctype>\n\nnamespace orderentry\n{\nstd::string nextToken(const std::vector<std::string> & tokens, size_t & pos)\n{\n    if(pos < tokens.size())\n    {\n        return tokens[pos++];\n    }\n    return \"\";\n}\n\nuint32_t toUint32(const std::string & input)\n{\n    char * end;\n    uint32_t value = strtoul(input.c_str(), &end, 10);\n    if(*end != '\\0')\n    {\n        value = INVALID_UINT32;\n    }\n    return value;\n}\n\nuint32_t toInt32(const std::string & input)\n{\n    char * end;\n    uint32_t value = strtol(input.c_str(), &end, 10);\n    if(*end != '\\0')\n    {\n        value = INVALID_INT32;\n    }\n    return value;\n}\n\n\nliquibook::book::Price stringToPrice(const std::string & str)\n{\n    if(str == \"MARKET\" || str == \"MKT\")\n    {\n        return 0;\n    } else\n    {\n        return toUint32(str);\n    }\n}\n\nstd::string promptForString(const std::string & prompt, bool uppercase)\n{\n    std::cout << \"\\n\" << prompt << \": \" << std::flush;\n    std::string input;\n    std::getline(std::cin, input);\n    if(uppercase)\n    {\n      std::transform(input.begin(), input.end(), input.begin(), toupper);\n    }\n    return input;\n}\n\nliquibook::book::Price promptForPrice(const std::string & prompt)\n{\n    std::string str = promptForString(prompt);\n    return stringToPrice(str);\n}\n\nuint32_t promptForUint32(const std::string & prompt)\n{\n    std::cout << \"\\n\" << prompt << \": \" << std::flush;\n    std::string input;\n    std::getline(std::cin, input);\n    return toUint32(input);\n}\n\nint32_t promptForInt32(const std::string & prompt)\n{\n    std::cout << \"\\n\" << prompt << \": \" << std::flush;\n    std::string input;\n    std::getline(std::cin, input);\n    return toInt32(input);\n}\n\nbool promptForYesNo(const std::string & prompt)\n{\n    while(true)\n    {\n        std::string input = promptForString(prompt);\n        if(input == \"Y\" || input == \"YES\" || input == \"T\" || input == \"TRUE\")\n        {\n            return true;\n        }\n        if(input == \"N\" || input == \"NO\" || input == \"F\" || input == \"FALSE\")\n        {\n            return false;\n        }\n    }\n}\n\n// trim from start (in place)\nstd::string &  ltrim(std::string &s) {\n    s.erase(s.begin(), std::find_if(s.begin(), s.end(), \n        std::not1(std::ptr_fun<int, int>(std::isspace))));\n    return s;\n}\n\n// trim from end (in place)\nstd::string &  rtrim(std::string &s) {\n    s.erase(std::find_if(s.rbegin(), s.rend(), \n        std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());\n    return s;\n}\n\n// trim from both ends (in place)\nstd::string &  trim(std::string &s) \n{\n    return ltrim(rtrim(s));\n}\n\n// trim from start (copying)\nstd::string ltrimmed(std::string s) \n{\n    ltrim(s);\n    return s;\n}\n\n// trim from end (copying)\nstd::string rtrimmed(std::string s) \n{\n    rtrim(s);\n    return s;\n}\n\n// trim from both ends (copying)\nstd::string trimmed(std::string s) \n{\n    trim(s);\n    return s;\n}\n\n}\n\n"
  },
  {
    "path": "examples/mt_order_entry/Util.h",
    "content": "// Copyright (c) 2017 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n\n/// @brief Command parsing helpers\n#pragma once\n#include <book/types.h>\n#include <string>\n#include <vector>\n\nnamespace orderentry\n{\nstatic const uint32_t INVALID_UINT32 = UINT32_MAX;\nstatic const int32_t INVALID_INT32 = INT32_MAX;\n\n/// @brief Parse a string into tokens breaking on delimiters.\n/// @param input The string to parse.\n/// @param delimiter A set of delimiter characters.\n/// @param[out] tokens  the tokens parsed from the string.\ntemplate<typename INPUT_STRING,typename DELIMITER_STRING,typename STRING_CONTAINER>\nvoid split(const INPUT_STRING & input, const DELIMITER_STRING & delimiter, STRING_CONTAINER & tokens)\n{\n    size_t pos = 0;\n    size_t end = input.length();\n    while(pos < end)\n    {\n        auto last = input.find_first_of(delimiter, pos);\n        if(last == std::string::npos)\n        {\n            last = end;\n        }\n        tokens.push_back(input.substr(pos, last - pos));\n        pos = ++last;\n    }\n}\n\n/// @brief Get the next token from a vector of tokens.\n/// @param tokens The vector of tokens\n/// @param[inout] pos the current position in the vector. Will be updated if a token is found.\n/// @return the next token or an empty string if no more tokens.\nstd::string nextToken(const std::vector<std::string> & tokens, size_t & pos);\n\n/// @brief Convert a string to uint32\n/// @param input the input string.\n/// @return the converted number or INVALID_UINT32 if the string ill-formed.\nuint32_t toUint32(const std::string & input);\n\n/// @brief Convert a string to int32\n/// @param input the input string.\n/// @return the converted number or INVALID_INT32 if the string ill-formed.\nuint32_t toInt32(const std::string & input);\n\n/// @brief Convert a string to Price\n/// @param input the input string which may be a number or \"MARKET\", \"MKT\", etc.\n/// @return the converted price (MARKET is 0) or INVALID_UINT32 if the string ill-formed.\nliquibook::book::Price stringToPrice(const std::string & input);\n\n/// @brief Display a prompt and ask the console user for a string.\n/// @param prompt What to display\n/// @returns what the user typed.\nstd::string promptForString(const std::string & prompt, bool uppercase = true);\n\n/// @brief Display a prompt and ask the console user for a price.\n/// @param prompt What to display\n/// @returns what the user typed converted to a price.\nliquibook::book::Price promptForPrice(const std::string & prompt);\n\n/// @brief Display a prompt and ask the console user for a uint32.\n/// @param prompt What to display\n/// @returns what the user typed converted to a uint32.\nuint32_t promptForUint32(const std::string & prompt);\n\n/// @brief Display a prompt and ask the console user for a int32.\n/// @param prompt What to display\n/// @returns what the user typed converted to a int32.\nint32_t promptForInt32(const std::string & prompt);\n\n/// @brief Display a prompt and ask the console user for \"yes\" or \"no\"\n/// @param prompt What to display\n/// @returns what the user typed converted to a bool.\nbool promptForYesNo(const std::string & prompt);\n\n/// @brief Remove whitespace from the start of a string (in place)\n/// @param[inout] s is the string to be trimmed in place.\n/// @returns a reference to the string.\nstd::string & ltrim(std::string &s);\n\n/// @brief Remove whitespace from the end of a string (in place)\n/// @param[inout] s is the string to be trimmed in place.\n/// @returns a reference to the string.\nstd::string & rtrim(std::string &s);\n\n/// @brief Remove whitespace from both ends of a string (in place)\n/// @param[inout] s is the string to be trimmed in place.\n/// @returns a reference to the string.\nstd::string & trim(std::string &s);\n\n/// @brief Remove whitespace from the start of a constant string\n/// @param s is the string to be trimmed.\n/// @return the string after trimming.\nstd::string ltrimmed(std::string s);\n\n/// @brief Remove whitespace from the end of a constant string\n/// @param s is the string to be trimmed\n/// @return the string after trimming.\nstd::string rtrimmed(std::string s);\n\n/// @brief Remove whitespace from both ends of a constant string\n/// @param s is the string to be trimmed.\n/// @return the string after trimming.\nstd::string trimmed(std::string s);\n\n}\n\n"
  },
  {
    "path": "examples/mt_order_entry/mt_order_entry.mpc",
    "content": "// Copyright (c) 2017 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\nproject(*) : liquibook_book, liquibook_simple, liquibook_exe {\n  requires += example_manual\n  exename = *\n}\n"
  },
  {
    "path": "examples/mt_order_entry/mt_order_entry_main.cpp",
    "content": "// Copyright (c) 2017 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#include \"Market.h\"\n#include \"Util.h\"\n#include <fstream>\n#include <iomanip>\n#include <string>\n#include <locale>\n#include <cstring>\n#include <algorithm> \n#include <vector>\n#include <iterator>\n\nusing namespace orderentry;\n\nint main(int argc, const char * argv[])\n{\n    bool done = false;\n    bool prompt = true;\n    bool interactive = true;\n    bool fileActive = false;\n    std::ostream * log = &std::cout;\n    std::ifstream commandFile;\n    std::ofstream logFile;\n\n    if(argc > 1)\n    {\n        std::string filename = argv[1];\n        if(filename != \"-\")\n        {\n            commandFile.open(filename);\n            if(!commandFile.good())\n            {\n                std::cerr << \"Can't open command file \" << filename << \". Exiting.\" << std::endl;\n                return -1;\n            }\n            interactive = false;\n            fileActive = true;\n        }\n    }\n    if(argc > 2)\n    {\n        const char * filename = argv[2];\n        logFile.open(filename);\n        if(!logFile.good())\n        {\n            std::cerr << \"Can't open log file \" << filename << \". Exiting.\" << std::endl;\n            return -1;\n        }\n        log = & logFile;\n    }\n\n    Market market(log);\n    while( !done)\n    {\n        std::string input;\n        if(fileActive) \n        {\n            std::getline(commandFile, input);\n            if(!commandFile.good())\n            {\n                if(interactive)\n                {\n                    input = \"# Switching to console input.\";               \n                    fileActive = false;\n                }\n                else\n                {\n                    input = \"# end of command file.\";\n                    done = true;\n                }\n            }\n            // if it came from a file, echo it to the log\n            if(input.substr(0,2) != \"##\") // don't log ## comments.\n            {\n                *log << input << std::endl;\n            }\n        }\n        else\n        {\n            if(prompt)\n            {\n                std::cout << \"Action[\" << Market::prompt() \n                << \"\\t(?)    help for more options and detail.\\n\"\n                << \"\\t(Quit) ]\\n\";\n                prompt = false;\n            }\n            std::cout << \"> \" << std::flush;\n            std::getline(std::cin, input);\n        }\n        std::transform(input.begin(), input.end(), input.begin(), toupper);\n        if(log != &std::cout && !fileActive)\n        {\n            if(input.substr(0,2) != \"##\") // don't log ## comments.\n            {\n                *log << input << std::endl;\n            }\n        }\n\n        // if input ends in a ';' be sure there's a space before it to simplify parsing.\n        if(input.length() > 1)\n        {\n            if(input.back() == ';')\n            {\n                input.pop_back();\n                if(input.back() == ' ')\n                {\n                    input.pop_back();\n                }\n                input.append(\" ;\");\n            }\n        }\n\n        std::vector< std::string> words;\n        split(input,\" \\t\\v\\n\\r\", words);\n        if(!words.empty())\n        {        \n            const std::string command = words[0];\n            if(command == \"QUIT\")\n            {\n                done = true;\n            }\n            else if(command[0] == '#')\n            {\n                // nothing\n            }\n            else if(command == \"F\" || command == \"FILE\")\n            {\n                if(fileActive)\n                {\n                    std::cout << \"Only one input file at a time can be open.\" << std::endl;\n                }\n                else\n                {\n                    std::cout << \"Command file name: \" << std::flush;\n                    std::string filename;\n                    std::getline(std::cin, filename);\n                    commandFile.open(filename);\n                    if(commandFile.good())\n                    {\n                        fileActive = true;\n                    }\n                    else\n                    {\n                        std::cout << \"Cannot open \" << filename << std::endl;\n                    }\n                }\n            }\n            else if(command == \"?\" || command == \"HELP\")\n            {\n                market.help();\n                *log << \"(F)ile  Open or Close a command input file\\n\"\n                    << \"\\tArguments\\n\"\n                    << \"\\t\\t<FileName>  Required if no file is open. Must not appear if file is open.\\n\";\n                *log << \"QUIT  Exit from this program.\\n\";\n                bool prompt = true;\n            }\n            else if(!market.apply(words))\n            {\n                std::cerr << \"Cannot process command\";\n                for(auto word = words.begin(); word != words.end(); ++ word)\n                {\n                    std::cerr << ' ' << *word;\n                }\n                std::cerr << std::endl;\n                bool prompt = true;\n            }\n        }\n    }\n    return 0;\n}\n"
  },
  {
    "path": "examples/mt_order_entry/order_entry.script",
    "content": "# Copyright (c) 2017 Object Computing, Inc.\n# All rights reserved.\n# See the file license.txt for licensing information.\n## A simple test script to use with mt_order_entry.\n## To use it: make this file's name the first argument on the command line, or\n## type \"FILE filename\" at the interactive prompt.\nBUY 100 !IBM 50;\nSELL 100 IBM 50;\nD + ALL\n"
  },
  {
    "path": "examples/mt_order_entry/teststoporders.script",
    "content": "# Script to test stop orders\n\n# set market price to 56\nbuy 100 +ibm mkt;\nsell 100 ibm 56;\n\n# enter seed orders that won't trade with each other\nbuy 100 ibm 53;\nsell 100 ibm 58;\n\n# add stop orders off market\nbuy 100 ibm mkt stop 57;\nsell 100 ibm mkt stop 54;\n\n# use large AOC orders to set a new market price to 57\n# without trading with existing orders\n# This will trigger the buy stop market order (#5)\n# which will match (and trade with) the sell 58 limit order #4\nbuy 1000 ibm 57 aon;\nsell 1000 ibm 57 aon;\n\n# do the same thing on the other side to \n# hit the stop price of 54 for order #6\nsell 1000 ibm 54 aon;\nbuy 1000 ibm 54 aon;\n\n# and display the orders, all of which should be filled.\nd ibm\nquit\n"
  },
  {
    "path": "license.txt",
    "content": "Copyright (c) 2012, 2013 Object Computing, Inc. All rights reserved.\n\nLiquibook is a licensed product, is protected by copyright, and is distributed under the following terms:\n\nLiquibook is an open source implementation of a limit order book matching engine, developed and copyrighted by Object Computing Incorporated (OCI). \n\nSince Liquibook is open source and free of licensing fees, you are free to use, modify, and distribute the source code, as long as you include this copyright statement.\n\nIn particular, you can use Liquibook to build proprietary software and are under no obligation to redistribute any of your source code that is built using Liquibook. Note however, that you may not do anything to the Liquibook code, such as copyrighting it yourself or claiming authorship of the Liquibook code, that will prevent Liquibook from being distributed freely using an open source development model.\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n* Neither the name of Object Computing, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n\nIN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "liquibook.features",
    "content": "// Copyright (c) 2013-2017 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n// This file defines MPC features for the liquibook project\n\nexample_pubsub=1\nexample_manual=1\n\n// BOOST IS NEEDED BY THE  unit tests\nboost=1\n// QUICKFAST IS NEEDED BY THE PUBLISH/SUBSUBSCRIBE example\nQuickFAST=1\n\n"
  },
  {
    "path": "liquibook.mwc",
    "content": "workspace(liquibook) {\n  cmdline += -include mpc \n  cmdline += -include $QUICKFAST_ROOT\n  cmdline += -feature_file liquibook.features\n  cmdline += -expand_vars\n  cmdline += -use_env\n  \n  specific(make) {\n    cmdline += -value_template \"configurations=Release Debug\"\n  }  \n}\n\n"
  },
  {
    "path": "mpc/liquibook.mpb",
    "content": "project {\n  includes += $(LIQUIBOOK_ROOT)/src\n  libpaths += $(LIQUIBOOK_ROOT)/lib\n\n  // Force use of Visual C++ DLL runtime libraries\n  specific(vc71,vc8,vc9) {\n    Debug::runtime_library = 3\n    Release::runtime_library = 2\n  }\n  specific(vc10,vc11,vc12,vc13,vc14,vc15) {\n    Debug::runtime_library = MultiThreadedDebugDLL\n    Release::runtime_library = MultiThreadedDLL\n  }\n}\n\n"
  },
  {
    "path": "mpc/liquibook_book.mpb",
    "content": "project : liquibook {\n    // obsolete\n}\n\n"
  },
  {
    "path": "mpc/liquibook_exe.mpb",
    "content": "project {\n  specific(prop:microsoft) {\n    Release::exeout = $(LIQUIBOOK_ROOT)/Output/Release\n    Debug::exeout = $(LIQUIBOOK_ROOT)/Output/Debug\n  } else {\n    exeout = $(LIQUIBOOK_ROOT)/bin\n  }\n}\n"
  },
  {
    "path": "mpc/liquibook_lib.mpb",
    "content": "project : liquibook {\n  libout = $(LIQUIBOOK_ROOT)/lib\n  macros += LIQUIBOOK_BUILD_DLL  \n}\n\n"
  },
  {
    "path": "mpc/liquibook_simple.mpb",
    "content": "project : liquibook {\n  libs += liquibook_simple\n  after += liquibook_simple\n}\n\n"
  },
  {
    "path": "mpc/liquibook_test.mpb",
    "content": "project : liquibook, liquibook_exe, liquibook_book, liquibook_simple{\n  exeout = $(LIQUIBOOK_ROOT)/bin/test\n}\n"
  },
  {
    "path": "mpc.bat",
    "content": "@REM Copyright (c) 2009, 2010 Object Computing, Inc.\n@REM All rights reserved.\n@REM See the file license.txt for licensing information.\n@REM\n@REM This batch file runs MWC which is part of the MPC package to create\n@REM Visual Studio solution and project files.\n@REM\n@REM Note: -expand_vars -use_env options force MPC to expand $(BOOST_ROOT) into the absolute path.  This avoids\n@REM        a problem that happened when people were starting Visual Studio from the Start menu rather than\n@REM        from the command line where the BOOST_ROOT environment had been defined.\n\"%MPC_ROOT%\\mwc.pl\" -type vc%VCVER% liquibook.mwc\n"
  },
  {
    "path": "noQuickFAST/QuickFASTApplication.mpb",
    "content": "project{\n  requires += QuickFAST\n}\n"
  },
  {
    "path": "pt_run.bat",
    "content": "bin\\test\\pt_order_book.exe\n"
  },
  {
    "path": "src/book/bbo_listener.h",
    "content": "// Copyright (c) 2012, 2013 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#pragma once\n\nnamespace liquibook { namespace book {\n\n/// @brief generic listener of top-of-book events\ntemplate <class OrderBook>\nclass BboListener {\npublic:\n  /// @brief callback for top of book change\n  virtual void on_bbo_change(\n      const OrderBook* book, \n      const typename OrderBook::DepthTracker* depth) = 0;\n};\n\n} }\n"
  },
  {
    "path": "src/book/callback.h",
    "content": "// Copyright (c) 2012, 2013 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#pragma once\n\n#include \"types.h\"\n\nnamespace liquibook { namespace book {\n\ntemplate <class OrderPtr>\nclass OrderBook;\n\n// Callback events\n//   New order accept\n//     - order accept\n//     - fill (2) and/or quote (if not complete)\n//     - depth/bbo ?\n//   New order reject\n//     - order reject\n//   Order fill\n//     - fill (2)\n//     - trade\n//     - quote (2)\n//     - depth/bbo ?\n//   Order cancel\n//     - order cancel\n//     - quote\n//     - depth/bbo ?\n//   Order cancel reject\n//     - order cancel reject\n//   Order replace\n//     - order replace\n//     - fill (2) and/or quote (if not complete)\n//     - depth/bbo ?\n//   Order replace reject\n//     - order replace reject\n\n/// @brief notification from OrderBook of an event\ntemplate <typename OrderPtr>\nclass Callback {\npublic:\n  typedef OrderBook<OrderPtr > TypedOrderBook;\n\n  enum CbType {\n    cb_unknown,\n    cb_order_accept,\n    cb_order_accept_stop,\n    cb_order_trigger_stop,\n    cb_order_reject,\n    cb_order_fill,\n    cb_order_cancel,\n    cb_order_cancel_stop,\n    cb_order_cancel_reject,\n    cb_order_replace,\n    cb_order_replace_reject,\n    cb_book_update\n  };\n\n  enum FillFlags {\n    ff_neither_filled = 0,\n    ff_inbound_filled = 1,\n    ff_matched_filled = 2,\n    ff_both_filled    = 4\n  };\n\n  Callback();\n\n  /// @brief create a new accept callback\n  static Callback<OrderPtr> accept(const OrderPtr& order);\n  /// @brief create a new accept callback\n  static Callback<OrderPtr> accept_stop(const OrderPtr& order);\n  /// @brief create a new accept callback\n  static Callback<OrderPtr> trigger_stop(const OrderPtr& order);\n  /// @brief create a new reject callback\n  static Callback<OrderPtr> reject(const OrderPtr& order,\n                                   const char* reason);\n  /// @brief create a new fill callback\n  static Callback<OrderPtr> fill(const OrderPtr& inbound_order,\n                                 const OrderPtr& matched_order,\n                                 const Quantity& fill_qty,\n                                 const Price& fill_price,\n                                 FillFlags fill_flags);\n  /// @brief create a new cancel callback\n  static Callback<OrderPtr> cancel(const OrderPtr& order,\n                                   const Quantity& open_qty);\n  /// @brief create a new cancel callback\n  static Callback<OrderPtr> cancel_stop(const OrderPtr& order);\n  /// @brief create a new cancel reject callback\n  static Callback<OrderPtr> cancel_reject(const OrderPtr& order,\n                                          const char* reason);\n  /// @brief create a new replace callback\n  static Callback<OrderPtr> replace(const OrderPtr& order,\n                                    const Quantity& curr_open_qty,\n                                    const int64_t& size_delta,\n                                    const Price& new_price);\n  /// @brief create a new replace reject callback\n  static Callback<OrderPtr> replace_reject(const OrderPtr& order,\n                                           const char* reason);\n\n  static Callback<OrderPtr> book_update(const TypedOrderBook* book = nullptr);\n  CbType type;\n  OrderPtr order;\n  OrderPtr matched_order;\n  Quantity quantity;\n  Price price;\n  uint8_t flags;\n  int64_t delta;\n  const char* reject_reason;\n};\n\ntemplate <class OrderPtr>\nCallback<OrderPtr>::Callback()\n: type(cb_unknown),\n  order(nullptr),\n  matched_order(nullptr),\n  quantity(0),\n  price(0),\n  flags(0),\n  delta(0),\n  reject_reason(nullptr)\n{\n}\n\ntemplate <class OrderPtr>\nCallback<OrderPtr> Callback<OrderPtr>::accept(\n  const OrderPtr& order)\n{\n  Callback<OrderPtr> result;\n  result.type = cb_order_accept;\n  result.order = order;\n  return result;\n}\n\ntemplate <class OrderPtr>\nCallback<OrderPtr> Callback<OrderPtr>::accept_stop(\n  const OrderPtr& order)\n{\n  Callback<OrderPtr> result;\n  result.type = cb_order_accept_stop;\n  result.order = order;\n  return result;\n}\n\ntemplate <class OrderPtr>\nCallback<OrderPtr> Callback<OrderPtr>::trigger_stop(\n  const OrderPtr& order)\n{\n  Callback<OrderPtr> result;\n  result.type = cb_order_trigger_stop;\n  result.order = order;\n  return result;\n}\n\ntemplate <class OrderPtr>\nCallback<OrderPtr> Callback<OrderPtr>::reject(\n  const OrderPtr& order,\n  const char* reason)\n{\n  Callback<OrderPtr> result;\n  result.type = cb_order_reject;\n  result.order = order;\n  result.reject_reason = reason;\n  return result;\n}\n\ntemplate <class OrderPtr>\nCallback<OrderPtr> Callback<OrderPtr>::fill(\n  const OrderPtr& inbound_order,\n  const OrderPtr& matched_order,\n  const Quantity& fill_qty,\n  const Price& fill_price,\n  FillFlags fill_flags)\n{\n  Callback<OrderPtr> result;\n  result.type = cb_order_fill;\n  result.order = inbound_order;\n  result.matched_order = matched_order;\n  result.quantity = fill_qty;\n  result.price = fill_price;\n  result.flags = fill_flags;\n  return result;\n}\n\ntemplate <class OrderPtr>\nCallback<OrderPtr> Callback<OrderPtr>::cancel(\n  const OrderPtr& order,\n  const Quantity& open_qty)\n{\n  // TODO save the open qty\n  Callback<OrderPtr> result;\n  result.type = cb_order_cancel;\n  result.order = order;\n  result.quantity = open_qty;\n  return result;\n}\n\ntemplate <class OrderPtr>\nCallback<OrderPtr> Callback<OrderPtr>::cancel_stop(\n  const OrderPtr& order)\n{\n  Callback<OrderPtr> result;\n  result.type = cb_order_cancel_stop;\n  result.order = order;\n  return result;\n}\n\ntemplate <class OrderPtr>\nCallback<OrderPtr> Callback<OrderPtr>::cancel_reject(\n  const OrderPtr& order,\n  const char* reason)\n{\n  Callback<OrderPtr> result;\n  result.type = cb_order_cancel_reject;\n  result.order = order;\n  result.reject_reason = reason;\n  return result;\n}\n\ntemplate <class OrderPtr>\nCallback<OrderPtr> Callback<OrderPtr>::replace(\n  const OrderPtr& order,\n  const Quantity& curr_open_qty,\n  const int64_t& size_delta,\n  const Price& new_price)\n{\n  // TODO save the order open qty\n  Callback<OrderPtr> result;\n  result.type = cb_order_replace;\n  result.order = order;\n  result.quantity = curr_open_qty;\n  result.delta = size_delta;\n  result.price = new_price;\n  return result;\n}\n\ntemplate <class OrderPtr>\nCallback<OrderPtr> Callback<OrderPtr>::replace_reject(\n  const OrderPtr& order,\n  const char* reason)\n{\n  Callback<OrderPtr> result;\n  result.type = cb_order_replace_reject;\n  result.order = order;\n  result.reject_reason = reason;\n  return result;\n}\n\ntemplate <class OrderPtr>\nCallback<OrderPtr>\nCallback<OrderPtr>::book_update(const OrderBook<OrderPtr>* book)\n{\n  Callback<OrderPtr> result;\n  result.type = cb_book_update;\n  return result;\n}\n\n} }\n"
  },
  {
    "path": "src/book/comparable_price.h",
    "content": "// Copyright (c) 2017 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#pragma once\n\n#include \"types.h\"\n#include <iostream>\n\nnamespace liquibook { namespace book {\n\n/// @brief A price that knows which side of the market it is on\n/// Designed to be compared to other prices on the same side using\n/// standard comparison operators (< > <= >= == !=) and to\n/// compared to prices on the other side using the match() method.\n///\n/// Using the  '<' operation to sort a set of prices will result in the\n/// prices being partially ordered from most liquid to least liquid.\n/// i.e:\n///   Market prices always sort first since they will match any counter price.\n///   Sell side low prices sort before high prices because they match more buys.\n///   Buy side high prices sort before low prices because they match more asks.\n///   \nclass ComparablePrice\n{\n  Price price_;\n  bool buySide_;\n\npublic:\n  /// @brief construct given side and price\n  /// @param buySide controls whether price comparison is normal or reversed\n  /// @param price is the price for this key, or 0 (MARKET_ORDER_PRICE) for market\n  ComparablePrice(bool buySide, Price price)\n    : price_(price)\n    , buySide_(buySide)\n  {\n  }\n\n  /// @brief Check possible trade\n  /// Assumes rhs is on the opposite side\n  bool matches(Price rhs) const\n  {\n    if(price_ == rhs)\n    {\n      return true;\n    }\n    if(buySide_)\n    {\n      return rhs < price_  || price_ == MARKET_ORDER_PRICE ;\n    }\n    return price_ < rhs || rhs == MARKET_ORDER_PRICE;\n  }\n\n  /// @brief less than compare key to a price\n  /// Assumes both prices are on the same side.\n  /// Uses side to determine the sense of the comparison.\n  bool operator <(Price rhs) const\n  {\n    // Compare difficulty finding a match.  (easy is less than hard)\n    if(price_ == MARKET_ORDER_PRICE)\n    {\n      return rhs != MARKET_ORDER_PRICE;\n    }\n    else if(rhs == MARKET_ORDER_PRICE)\n    {\n      return false;\n    }\n    else if(buySide_)\n    {\n      // Buying: Highest prices first. \n      return rhs < price_ ;\n    }\n    else\n    {\n      // Selling: lowest prices first\n      return price_ < rhs;\n    }\n  }\n\n  /// @brief equality compare key to a price\n  bool operator ==(Price rhs) const\n  {\n    // compares equal without regard to side\n    return price_ == rhs;\n  }\n\n  /// @brief inequality compare key to a price\n  bool operator !=(Price rhs) const\n  {\n    return !( price_ == rhs );\n  }\n\n  /// @brief greater than compare key to a price\n  /// Assumes both prices are on the same side.\n  bool operator > (Price rhs) const\n  {\n    return price_!= MARKET_ORDER_PRICE && ((rhs == MARKET_ORDER_PRICE) || (buySide_ ? (rhs > price_) : (price_ > rhs)));\n  }\n\n  /// @brief less than or equal to compare key to a price\n  /// Assumes both prices are on the same side.\n  bool operator <=(Price rhs) const\n  {\n    return *this < rhs || *this == rhs;\n  }\n\n  /// @brief greater than or equal to compare key to a price\n  /// Assumes both prices are on the same side.\n  bool operator >=(Price rhs) const\n  {\n    return *this > rhs || *this == rhs;\n  }\n\n  /// @brief less than compare order map keys\n  /// compares the prices assuming they are on the same side\n  bool operator <(const ComparablePrice & rhs) const\n  {\n    return *this < rhs.price_;\n  }\n\n  /// @brief equality compare order map keys\n  bool operator ==(const ComparablePrice & rhs) const\n  {\n    return *this == rhs.price_;\n  }\n\n  /// @brief inequality compare order map keys\n  bool operator !=(const ComparablePrice & rhs) const\n  {\n    return *this != rhs.price_;\n  }\n\n  /// @brief greater than compare order map keys\n  /// Assumes both prices are on the same side.\n  bool operator >(const ComparablePrice & rhs) const\n  {\n    return *this > rhs.price_;\n  }\n\n  /// @brief access price.\n  Price price() const\n  {\n    return price_;\n  }\n\n  /// @brief access side.\n  bool isBuy() const\n  {\n    return buySide_;\n  }\n\n  /// @brief check to see if this is market price\n  bool isMarket() const\n  {\n    return price_ == MARKET_ORDER_PRICE;\n  }\n};\n\n/// @brief less than compare price to key\ninline\nbool operator < (Price price, const ComparablePrice & key)\n{\n  return key > price;\n}\n\n/// @brief greater than compare price to key\ninline\nbool operator > (Price price, const ComparablePrice & key)\n{\n  return key < price;\n}\n\n/// @brief equality compare price to key\ninline\nbool operator == (Price price, const ComparablePrice & key)\n{\n  return key == price;\n}\n\n/// @brief inequality compare price to key\ninline\nbool operator != (Price price, const ComparablePrice & key)\n{\n  return key != price;\n}\n\n/// @brief less than or equal to compare price to key\ninline\nbool operator <= (Price price, const ComparablePrice & key)\n{\n  return key >= price;\n}\n\n/// @brief greater or equal to than compare price to key\ninline\nbool operator >= (Price price, const ComparablePrice & key)\n{\n  return key <= price;\n}\n\ninline\nstd::ostream & operator << (std::ostream & out, const ComparablePrice & key)\n{\n  out << (key.isBuy() ? \"Buy at \" : \"Sell at \");\n  if(key.isMarket())\n  {\n    out << \"Market\";\n  }\n  else\n  {\n    out << key.price();\n  }\n  return out;\n}\n\n}}\n"
  },
  {
    "path": "src/book/depth.h",
    "content": "// Copyright (c) 2012 - 2017 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#pragma once\n\n#include \"depth_constants.h\"\n#include \"depth_level.h\"\n#include <stdexcept>\n#include <map>\n#include <cmath>\n#include <string.h>\n#include <functional>\n\nnamespace liquibook { namespace book {\n/// @brief container of limit order data aggregated by price.  Designed so that\n///    the depth levels themselves are easily copyable with a single memcpy\n///    when used with a separate callback thread.\n///\n/// TODO: Fix the bid and ask methods to behave like a normal iterator (i.e. begin(), back(), and end()\n\ntemplate <int SIZE=5> \nclass Depth {\npublic:\n  /// @brief construct\n  Depth();\n\n  /// @brief get the first bid level (const)\n  const DepthLevel* bids() const;\n  /// @brief get the last bid level (const)\n  const DepthLevel* last_bid_level() const;\n  /// @brief get the first ask level (const)\n  const DepthLevel* asks() const;\n  /// @brief get the last ask level (const)\n  const DepthLevel* last_ask_level() const;\n  /// @brief get one past the last ask level (const)\n  const DepthLevel* end() const;\n\n  /// @brief get the first bid level (mutable)\n  DepthLevel* bids();\n  /// @brief get the last bid level (mutable)\n  DepthLevel* last_bid_level();\n  /// @brief get the first ask level (mutable)\n  DepthLevel* asks();\n  /// @brief get the last ask level (mutable)\n  DepthLevel* last_ask_level();\n\n  /// @brief add an order\n  /// @param price the price level of the order\n  /// @param qty the open quantity of the order\n  /// @param is_bid indicator of bid or ask\n  void add_order(Price price, Quantity qty, bool is_bid);\n\n  /// @brief ignore future fill quantity on a side, due to a match at \n  ///        accept time for an order\n  /// @param qty the open quantity to ignore\n  /// @param is_bid indicator of bid or ask\n  void ignore_fill_qty(Quantity qty, bool is_bid);\n\n  /// @brief handle an order fill\n  /// @param price the price level of the order\n  /// @param fill_qty the quantity of this fill\n  /// @param filled was this order completely filled?\n  /// @param is_bid indicator of bid or ask\n  void fill_order(Price price, \n                  Quantity fill_qty, \n                  bool filled,\n                  bool is_bid);\n  /// @brief cancel or fill an order\n  /// @param price the price level of the order\n  /// @param open_qty the open quantity of the order\n  /// @param is_bid indicator of bid or ask\n  /// @return true if the close erased a visible level\n  bool close_order(Price price, Quantity open_qty, bool is_bid);\n\n  /// @brief change quantity of an order\n  /// @param price the price level of the order\n  /// @param qty_delta the change in open quantity of the order (+ or -)\n  /// @param is_bid indicator of bid or ask\n  void change_qty_order(Price price, int64_t qty_delta, bool is_bid);\n\n  /// @brief replace a order\n  /// @param current_price the current price level of the order\n  /// @param new_price the new price level of the order\n  /// @param current_qty the current open quantity of the order\n  /// @param new_qty the new open quantity of the order\n  /// @param is_bid indicator of bid or ask\n  /// @return true if the close erased a visible level\n  bool replace_order(Price current_price,\n                     Price new_price,\n                     Quantity current_qty,\n                     Quantity new_qty,\n                     bool is_bid);\n\n  /// @brief does this depth need bid restoration after level erasure\n  /// @param restoration_price the price to restore after (out)\n  /// @return true if restoration is needed (previously was full)\n  bool needs_bid_restoration(Price& restoration_price);\n\n  /// @brief does this depth need ask restoration after level erasure\n  /// @param restoration_price the price to restore after (out)\n  /// @return true if restoration is needed (previously was full)\n  bool needs_ask_restoration(Price& restoration_price);\n\n  /// @brief has the depth changed since the last publish\n  bool changed() const;\n\n  /// @brief what was the ID of the last change?\n  ChangeId last_change() const;\n\n  /// @brief what was the ID of the last published change?\n  ChangeId last_published_change() const;\n\n  /// @brief note the ID of last published change\n  void published();\n\nprivate:\n  DepthLevel levels_[SIZE*2];\n  ChangeId last_change_;\n  ChangeId last_published_change_;\n  Quantity ignore_bid_fill_qty_;\n  Quantity ignore_ask_fill_qty_;\n\n  typedef std::map<Price, DepthLevel, std::greater<Price> > BidLevelMap;\n  typedef std::map<Price, DepthLevel, std::less<Price> > AskLevelMap;\n  BidLevelMap excess_bid_levels_;\n  AskLevelMap excess_ask_levels_;\n\n  /// @brief find the level associated with the price\n  /// @param price the price to find\n  /// @param is_bid indicator of bid or ask\n  /// @param should_create should a level for the price be created, if necessary\n  /// @return the level, or nullptr if not found and full\n  DepthLevel* find_level(Price price, bool is_bid, bool should_create = true);\n\n  /// @brief insert a new level before this level and shift down\n  /// @param level the level to insert before\n  /// @param is_bid indicator of bid or ask\n  /// @param price the price to initialize the level at\n  void insert_level_before(DepthLevel* level,\n                           bool is_bid,\n                           Price price);\n\n  /// @brief erase a level and shift up\n  /// @param level the level to erase\n  /// @param is_bid indicator of bid or ask\n  void erase_level(DepthLevel* level, bool is_bid);\n};\n\ntemplate <int SIZE> \nDepth<SIZE>::Depth()\n: last_change_(0),\n  last_published_change_(0),\n  ignore_bid_fill_qty_(0),\n  ignore_ask_fill_qty_(0)\n{\n  memset(levels_, 0, sizeof(DepthLevel) * SIZE * 2);\n}\n\ntemplate <int SIZE> \ninline const DepthLevel* \nDepth<SIZE>::bids() const\n{\n  return levels_;\n}\n\ntemplate <int SIZE> \ninline const DepthLevel* \nDepth<SIZE>::asks() const\n{\n  return levels_ + SIZE;\n}\n\ntemplate <int SIZE> \ninline const DepthLevel*\nDepth<SIZE>::last_bid_level() const\n{\n  return levels_ + (SIZE - 1);\n}\n\ntemplate <int SIZE> \ninline const DepthLevel*\nDepth<SIZE>::last_ask_level() const\n{\n  return levels_ + (SIZE * 2 - 1);\n}\n\ntemplate <int SIZE> \ninline const DepthLevel* \nDepth<SIZE>::end() const\n{\n  return levels_ + (SIZE * 2);\n}\n\ntemplate <int SIZE> \ninline DepthLevel* \nDepth<SIZE>::bids()\n{\n  return levels_;\n}\n\ntemplate <int SIZE> \ninline DepthLevel* \nDepth<SIZE>::asks()\n{\n  return levels_ + SIZE;\n}\n\ntemplate <int SIZE> \ninline DepthLevel*\nDepth<SIZE>::last_bid_level()\n{\n  return levels_ + (SIZE - 1);\n}\n\ntemplate <int SIZE> \ninline DepthLevel*\nDepth<SIZE>::last_ask_level()\n{\n  return levels_ + (SIZE * 2 - 1);\n}\n\ntemplate <int SIZE> \ninline void\nDepth<SIZE>::add_order(Price price, Quantity qty, bool is_bid)\n{\n  ChangeId last_change_copy = last_change_;\n  DepthLevel* level = find_level(price, is_bid);\n  if (level) {\n    level->add_order(qty);\n    // If this is a visible level\n    if (!level->is_excess()) {\n      // The depth changed\n      last_change_ = last_change_copy + 1; // Ensure incremented\n      level->last_change(last_change_copy + 1);\n    }\n    // The level is not marked as changed if it is not visible\n  }\n}\n\ntemplate <int SIZE> \ninline void\nDepth<SIZE>::ignore_fill_qty(Quantity qty, bool is_bid)\n{\n  if (is_bid) {\n    if (ignore_bid_fill_qty_) {\n      throw std::runtime_error(\"Unexpected ignore_bid_fill_qty_\");\n    }\n    ignore_bid_fill_qty_ = qty;\n  } else {\n    if (ignore_ask_fill_qty_) {\n      throw std::runtime_error(\"Unexpected ignore_ask_fill_qty_\");\n    }\n    ignore_ask_fill_qty_ = qty;\n  }  \n}\n\ntemplate <int SIZE> \ninline void\nDepth<SIZE>::fill_order(\n  Price price, \n  Quantity fill_qty, \n  bool filled,\n  bool is_bid)\n{\n  if (is_bid && ignore_bid_fill_qty_) {\n    ignore_bid_fill_qty_ -= fill_qty;\n  } else if ((!is_bid) && ignore_ask_fill_qty_) {\n    ignore_ask_fill_qty_ -= fill_qty;\n  } else if (filled) {\n    close_order(price, fill_qty, is_bid);\n  } else {\n    change_qty_order(price, -(int64_t)fill_qty, is_bid);\n  }\n}\n\ntemplate <int SIZE> \ninline bool\nDepth<SIZE>::close_order(Price price, Quantity open_qty, bool is_bid)\n{\n  DepthLevel* level = find_level(price, is_bid, false);\n  if (level) {\n    // If this is the last order on the level\n    if (level->close_order(open_qty)) {\n      erase_level(level, is_bid);\n      return true;\n    // Else, mark the level as changed\n    } else {\n      level->last_change(++last_change_);\n    }\n  }\n  return false;\n}\n\ntemplate <int SIZE> \ninline void\nDepth<SIZE>::change_qty_order(Price price, int64_t qty_delta, bool is_bid)\n{\n  DepthLevel* level = find_level(price, is_bid, false);\n  if (level && qty_delta) {\n    if (qty_delta > 0) {\n      level->increase_qty(Quantity(qty_delta));\n    } else {\n      level->decrease_qty(Quantity(std::abs(qty_delta)));\n    }\n    level->last_change(++last_change_);\n  }\n  // Ignore if not found - may be beyond our depth size\n}\n \ntemplate <int SIZE> \ninline bool\nDepth<SIZE>::replace_order(\n  Price current_price,\n  Price new_price,\n  Quantity current_qty,\n  Quantity new_qty,\n  bool is_bid)\n{\n  bool erased = false;\n  // If the price is unchanged, modify this level only\n  if (current_price == new_price) {\n    int64_t qty_delta = ((int64_t)new_qty) - current_qty;\n    // Only change order qty.  If this closes order, a cancel callback will\n    // also be fired\n    change_qty_order(current_price, qty_delta, is_bid);\n  // Else this is a price change\n  } else {\n    // Add the new order quantity first, and possibly insert a new level\n    add_order(new_price, new_qty, is_bid);\n    // Remove the old order quantity, and possibly erase a level\n    erased = close_order(current_price, current_qty, is_bid);\n  }\n  return erased;\n}\n\ntemplate <int SIZE> \ninline bool\nDepth<SIZE>::needs_bid_restoration(Price& restoration_price)\n{\n  // If this depth has multiple levels\n  if (SIZE > 1) {\n    // Restore using the price before the last level\n    restoration_price = (last_bid_level() - 1)->price();\n    // Restore if that level was valid\n    return restoration_price != INVALID_LEVEL_PRICE;\n  // Else this depth is BBO only\n  } else if (SIZE == 1) {\n    // There is no earlier level to look at, restore using the first non-market\n    // bid price\n    restoration_price = MARKET_ORDER_BID_SORT_PRICE;\n    // Always restore on BBO only\n    return true;\n  }\n  throw std::runtime_error(\"Depth size less than one not allowed\");\n}\n\ntemplate <int SIZE> \ninline bool\nDepth<SIZE>::needs_ask_restoration(Price& restoration_price)\n{\n  // If this depth has multiple levels\n  if (SIZE > 1) {\n    // Restore using the price before the last level\n    restoration_price = (last_ask_level() - 1)->price();\n    // Restore if that level was valid\n    return restoration_price != INVALID_LEVEL_PRICE;\n  // Else this depth is BBO only\n  } else if (SIZE == 1) {\n    // There is no earlier level to look at, restore the first non-market\n    // ask price\n    restoration_price =  MARKET_ORDER_ASK_SORT_PRICE;\n    // Always restore on BBO only\n    return true;\n  }\n  throw std::runtime_error(\"Depth size less than one not allowed\");\n}\n\ntemplate <int SIZE> \nDepthLevel*\nDepth<SIZE>::find_level(Price price, bool is_bid, bool should_create)\n{\n  // Find starting and ending point\n  DepthLevel* level = is_bid ? bids() : asks();\n  const DepthLevel* past_end = is_bid ? asks() : end();\n  // Linear search each level\n  for ( ; level != past_end; ++level) {\n    if (level->price() == price) {\n      break;\n    // Else if the level is blank\n    } else if (should_create && level->price() == INVALID_LEVEL_PRICE) {\n      level->init(price, false);  // Change ID will be assigned by caller\n      break;  // Blank slot\n    // Else if the bid level price is too low\n    } else if (is_bid && should_create && level->price() < price) {\n      // Insert a slot\n      insert_level_before(level, is_bid, price);\n      break;\n    // Else if the ask level price is too high\n    } else if ((!is_bid) && should_create && level->price() > price) {\n      // Insert a slot\n      insert_level_before(level, is_bid, price);\n      break;\n    }\n  }\n  // If level was not found\n  if (level == past_end) {\n    if (is_bid) {\n      // Search in excess bid levels\n      BidLevelMap::iterator find_result = excess_bid_levels_.find(price);\n      // If found in excess levels, return location\n      if (find_result != excess_bid_levels_.end()) {\n        level = &find_result->second;\n      // Else not found, insert if one should be created\n      } else if (should_create) {\n        DepthLevel new_level;\n        new_level.init(price, true);\n        std::pair<BidLevelMap::iterator, bool> insert_result;\n        insert_result = excess_bid_levels_.insert(\n            std::make_pair(price, new_level));\n        level = &insert_result.first->second;\n      }\n    } else {\n      // Search in excess ask levels\n      AskLevelMap::iterator find_result = excess_ask_levels_.find(price);\n      // If found in excess levels, return location\n      if (find_result != excess_ask_levels_.end()) {\n        level = &find_result->second;\n      // Else not found, insert if one should be created\n      } else if (should_create) {\n        DepthLevel new_level;\n        new_level.init(price, true);\n        std::pair<AskLevelMap::iterator, bool> insert_result;\n        insert_result = excess_ask_levels_.insert(\n            std::make_pair(price, new_level));\n        level = &insert_result.first->second;\n      }\n    }\n  }\n  return level;\n}\n\ntemplate <int SIZE> \nvoid\nDepth<SIZE>::insert_level_before(DepthLevel* level, \n                                 bool is_bid,\n                                 Price price)\n{\n  DepthLevel* last_side_level = is_bid ? last_bid_level() : last_ask_level();\n\n  // If the last level has valid data\n  if (last_side_level->price() != INVALID_LEVEL_PRICE) {\n    DepthLevel excess_level;\n    excess_level.init(0, true);  // Will assign over price\n    excess_level = *last_side_level;\n    // Save it in excess levels\n    if (is_bid) {\n      excess_bid_levels_.insert(\n      std::make_pair(last_side_level->price(), excess_level));\n    } else {\n      excess_ask_levels_.insert(\n      std::make_pair(last_side_level->price(), excess_level));\n    }\n  }\n  // Back from end\n  DepthLevel* current_level = last_side_level - 1;\n  // Increment only once\n  ++last_change_;\n  // Last level to process is one passed in\n  while (current_level >= level) {\n    // Copy level to level one lower\n    *(current_level + 1) = *current_level;\n    // If the level being copied is valid\n    if (current_level->price() != INVALID_LEVEL_PRICE) {\n      // Update change Id\n      (current_level + 1)->last_change(last_change_);\n    }\n    // Move back one\n    --current_level;\n   }\n   level->init(price, false);\n}\n\ntemplate <int SIZE> \nvoid\nDepth<SIZE>::erase_level(DepthLevel* level, bool is_bid)\n{\n  // If ther level being erased is from the excess, remove excess from map\n  if (level->is_excess()) {\n    if (is_bid) {\n      excess_bid_levels_.erase(level->price());\n    } else {\n      excess_ask_levels_.erase(level->price());\n    }\n  // Else the level being erased is not excess, copy over from those worse\n  } else {\n    DepthLevel* last_side_level = is_bid ? last_bid_level() : last_ask_level();\n    // Increment once\n    ++last_change_;\n    DepthLevel* current_level = level;\n    // Level to end\n    while (current_level < last_side_level) {\n      // If this is the first level, or the level to be overwritten is valid\n      // (must force first level, when called already should be invalidated)\n      if ((current_level->price() != INVALID_LEVEL_PRICE) ||\n          (current_level == level)) {\n        // Copy to current level from one lower\n        *current_level = *(current_level + 1);\n        // Mark the current level as updated\n        current_level->last_change(last_change_);\n      }\n      // Move forward one\n      ++current_level;\n    }\n\n    // If I erased the last level, or the last level was valid\n    if ((level == last_side_level) ||\n        (last_side_level->price() != INVALID_LEVEL_PRICE)) {\n      // Attempt to restore last level from excess\n      if (is_bid) {\n        BidLevelMap::iterator best_bid = excess_bid_levels_.begin();\n        if (best_bid != excess_bid_levels_.end()) {\n          *last_side_level = best_bid->second;\n          excess_bid_levels_.erase(best_bid);\n        } else {\n          // Nothing to restore, last level is blank\n          last_side_level->init(INVALID_LEVEL_PRICE, false);\n          last_side_level->last_change(last_change_);\n        }\n      } else {\n        AskLevelMap::iterator best_ask = excess_ask_levels_.begin();\n        if (best_ask != excess_ask_levels_.end()) {\n          *last_side_level = best_ask->second;\n          excess_ask_levels_.erase(best_ask);\n        } else {\n          // Nothing to restore, last level is blank\n          last_side_level->init(INVALID_LEVEL_PRICE, false);\n          last_side_level->last_change(last_change_);\n        }\n      }\n      last_side_level->last_change(last_change_);\n    }\n  }\n}\n\ntemplate <int SIZE> \nbool\nDepth<SIZE>::changed() const\n{\n  return last_change_ > last_published_change_;\n}\n\n\ntemplate <int SIZE> \nChangeId\nDepth<SIZE>::last_change() const\n{\n  return last_change_;\n}\n\ntemplate <int SIZE> \nChangeId\nDepth<SIZE>::last_published_change() const\n{\n  return last_published_change_;\n}\n\n\ntemplate <int SIZE> \nvoid\nDepth<SIZE>::published()\n{\n  last_published_change_ = last_change_;\n}\n\n} }\n"
  },
  {
    "path": "src/book/depth_constants.h",
    "content": "// Copyright (c) 2012 - 2017 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#pragma once\n\n#include \"types.h\"\n\nnamespace liquibook { namespace book {\n\nnamespace {\n// Constants used in liquibook\nconst Price INVALID_LEVEL_PRICE(0);\nconst Price MARKET_ORDER_BID_SORT_PRICE(QUANTITY_MAX);\nconst Price MARKET_ORDER_ASK_SORT_PRICE(0);\n}\n\n}}\n"
  },
  {
    "path": "src/book/depth_level.h",
    "content": "// Copyright (c) 2012, 2013 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#pragma once\n\n#include \"depth_constants.h\"\n\nnamespace liquibook { namespace book {\n\n/// @brief a single level of the limit order book aggregated by price\nclass DepthLevel {\npublic:\n  /// @brief construct\n  DepthLevel();\n\n  /// @brief assign\n  DepthLevel& operator=(const DepthLevel& rhs);\n\n  /// @brief get price\n  const Price& price() const;\n  /// @brief get count\n  uint32_t order_count() const;\n  /// @brief get aggregate quantity\n  Quantity aggregate_qty() const;\n  /// @brief is this level part of the excess\n  bool is_excess() const { return is_excess_; }\n\n  void init(Price price, bool is_excess);\n\n  /// @brief add an order to the level\n  /// @param qty open quantity of the order\n  void add_order(Quantity qty);\n\n  /// @brief increase the quantity of existing orders\n  /// @param qty amount to increase the quantity by\n  void increase_qty(Quantity qty);\n\n  /// @brief decrease the quantity of existing orders\n  /// @param qty amount to decrease the quantity by\n  void decrease_qty(Quantity qty);\n\n  /// @brief overwrite all values of the level\n  /// @param price the level price\n  /// @param qty the aggegate quantity\n  /// @param order_count the number of orders\n  /// @param last_change the last change ID (optional)\n  void set(Price price, \n           Quantity qty,\n           uint32_t order_count,\n           ChangeId last_change = 0);\n\n  /// @brief cancel or fill an order, decrease count and quantity\n  /// @param qty the closed quantity\n  /// @return true if the level is now empty\n  bool close_order(Quantity qty);\n\n  /// @brief set last changed stamp on this level\n  void last_change(ChangeId last_change) { last_change_ = last_change; }\n\n  /// @brief get last change stamp for this level\n  ChangeId last_change() const { return last_change_; }\n\n  /// @brief has the level changed since the given stamp?\n  /// @param last_published_change the stamp to compare to\n  bool changed_since(ChangeId last_published_change) const;\n\nprivate:\n  Price price_;\n  uint32_t order_count_;\n  Quantity aggregate_qty_;\n  bool is_excess_;\npublic:\n  ChangeId last_change_;\n};\n\ninline bool\nDepthLevel::changed_since(ChangeId last_published_change) const\n{\n  return last_change_ > last_published_change;\n}\n\ninline\nDepthLevel::DepthLevel()\n  : price_(INVALID_LEVEL_PRICE),\n  order_count_(0),\n  aggregate_qty_(0)\n{\n}\n\ninline\nDepthLevel&\nDepthLevel::operator=(const DepthLevel& rhs)\n{\n  price_ = rhs.price_;\n  order_count_ = rhs.order_count_;\n  aggregate_qty_ = rhs.aggregate_qty_;\n  if (rhs.price_ != INVALID_LEVEL_PRICE) {\n    last_change_ = rhs.last_change_;\n  }\n\n  // Do not copy is_excess_\n\n  return *this;\n}\n\ninline\nconst Price&\nDepthLevel::price() const\n{\n  return price_;\n}\n\ninline\nvoid\nDepthLevel::init(Price price, bool is_excess)\n{\n  price_ = price;\n  order_count_ = 0;\n  aggregate_qty_ = 0;\n  is_excess_ = is_excess;\n}\n\ninline\nuint32_t\nDepthLevel::order_count() const\n{\n  return order_count_;\n}\n\ninline\nQuantity\nDepthLevel::aggregate_qty() const\n{\n  return aggregate_qty_;\n}\n\ninline\nvoid\nDepthLevel::add_order(Quantity qty)\n{\n  // Increment/increase\n  ++order_count_;\n  aggregate_qty_ += qty;\n}\n\ninline\nbool\nDepthLevel::close_order(Quantity qty)\n{\n  bool empty = false;\n  // If this is the last order, reset the level\n  if (order_count_ == 0) {\n    throw std::runtime_error(\"DepthLevel::close_order \"\n      \"order count too low\");\n  } else if (order_count_ == 1) {\n    order_count_ = 0;\n    aggregate_qty_ = 0;\n    empty = true;\n    // Else, decrement/decrease\n  } else {\n    --order_count_;\n    if (aggregate_qty_ >= qty) {\n      aggregate_qty_ -= qty;\n    } else {\n      throw std::runtime_error(\"DepthLevel::close_order \"\n        \"level quantity too low\");\n    }\n  }\n  return empty;\n}\n\ninline\nvoid\nDepthLevel::set(Price price, \n  Quantity qty,\n  uint32_t order_count,\n  ChangeId last_change)\n{\n  price_ = price;\n  aggregate_qty_ = qty;\n  order_count_ = order_count;\n  last_change_ = last_change;\n}\n\ninline\nvoid\nDepthLevel::increase_qty(Quantity qty)\n{\n  aggregate_qty_ += qty;\n}\n\ninline\nvoid\nDepthLevel::decrease_qty(Quantity qty)\n{\n  aggregate_qty_ -= qty;\n}\n\n} }\n\n"
  },
  {
    "path": "src/book/depth_listener.h",
    "content": "// Copyright (c) 2012, 2013 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#pragma once\n\n#include \"order_book.h\"\n\nnamespace liquibook { namespace book {\n\n/// @brief listener of depth events.  Implement to build an aggregate depth \n/// feed.\ntemplate <class OrderBook >\nclass DepthListener {\npublic:\n  /// @brief callback for change in tracked aggregated depth\n  virtual void on_depth_change(\n      const OrderBook* book,\n      const typename OrderBook::DepthTracker* depth) = 0;\n};\n\n} }\n\n"
  },
  {
    "path": "src/book/depth_order_book.h",
    "content": "// Copyright (c) 2012, 2013 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#pragma once\n\n#include \"order_book.h\"\n#include \"depth.h\"\n#include \"bbo_listener.h\"\n#include \"depth_listener.h\"\n\nnamespace liquibook { namespace book {\n\n/// @brief Implementation of order book child class, that incorporates\n///        aggregate depth tracking.  \ntemplate <typename OrderPtr, int SIZE = 5>\nclass DepthOrderBook : public OrderBook<OrderPtr> {\npublic:\n  typedef Depth<SIZE> DepthTracker;\n  typedef BboListener<DepthOrderBook >TypedBboListener;\n  typedef DepthListener<DepthOrderBook >TypedDepthListener;\n\n  /// @brief construct\n  DepthOrderBook(const std::string & symbol = \"unknown\");\n\n  /// @brief set the BBO listener\n  void set_bbo_listener(TypedBboListener* bbo_listener);\n\n  /// @brief set the depth listener\n  void set_depth_listener(TypedDepthListener* depth_listener);\n\n  // @brief access the depth tracker\n  DepthTracker& depth();\n\n  // @brief access the depth tracker\n  const DepthTracker& depth() const;\n\n  protected:\n  //////////////////////////////////\n  // Implement virtual callback methods\n  // needed to maintain depth book.\n  virtual void on_accept(const OrderPtr& order, Quantity quantity);\n  virtual void on_accept_stop(const OrderPtr& order);\n  virtual void on_trigger_stop(const OrderPtr& order);\n\n  virtual void on_fill(const OrderPtr& order, \n    const OrderPtr& matched_order, \n    Quantity fill_qty, \n    Price fill_price,\n    bool inbound_order_filled,\n    bool matched_order_filled);\n\n  virtual void on_cancel(const OrderPtr& order, Quantity quantity);\n  virtual void on_cancel_stop(const OrderPtr& order);\n\n  virtual void on_replace(const OrderPtr& order,\n    Quantity current_qty, \n    Quantity new_qty,\n    Price new_price);\n\n  virtual void on_order_book_change();\n\nprivate:\n  DepthTracker depth_;\n  TypedBboListener* bbo_listener_;\n  TypedDepthListener* depth_listener_;\n};\n\ntemplate <class OrderPtr, int SIZE>\nDepthOrderBook<OrderPtr, SIZE>::DepthOrderBook(const std::string & symbol)\n: OrderBook<OrderPtr>(symbol),\n  bbo_listener_(nullptr),\n  depth_listener_(nullptr)\n{\n}\n\ntemplate <class OrderPtr, int SIZE>\nvoid\nDepthOrderBook<OrderPtr, SIZE>::set_bbo_listener(TypedBboListener* listener)\n{\n  bbo_listener_ = listener;\n}\n\ntemplate <class OrderPtr, int SIZE>\nvoid\nDepthOrderBook<OrderPtr, SIZE>::set_depth_listener(TypedDepthListener* listener)\n{\n  depth_listener_ = listener;\n}\n\ntemplate <class OrderPtr, int SIZE> \nvoid \nDepthOrderBook<OrderPtr, SIZE>::on_accept(const OrderPtr& order, Quantity quantity)\n{\n  // If the order is a limit order\n  if (order->is_limit())\n  {\n    // If the order is completely filled on acceptance, do not modify \n    // depth unnecessarily\n    if (quantity == order->order_qty()) \n    {\n      // Don't tell depth about this order - it's going away immediately.\n      // Instead tell Depth about future fills to ignore\n      depth_.ignore_fill_qty(quantity, order->is_buy());\n    } \n    else \n    {\n      // Add to bid or ask depth\n      depth_.add_order(order->price(), \n        order->order_qty(), \n        order->is_buy());\n    }\n  }\n}\n\ntemplate <class OrderPtr, int SIZE> \nvoid \nDepthOrderBook<OrderPtr, SIZE>::on_accept_stop(const OrderPtr& order)\n{\n}\n\ntemplate <class OrderPtr, int SIZE> \nvoid \nDepthOrderBook<OrderPtr, SIZE>::on_trigger_stop(const OrderPtr& order)\n{\n  // Add to depth\n  depth_.add_order(order->price(), order->order_qty(), order->is_buy());\n}\n\ntemplate <class OrderPtr, int SIZE> \nvoid \nDepthOrderBook<OrderPtr, SIZE>::on_fill(const OrderPtr& order, \n  const OrderPtr& matched_order, \n  Quantity quantity, \n  Price fill_price,\n  bool inbound_order_filled,\n  bool matched_order_filled)\n{\n  // If the matched order is a limit order\n  if (matched_order->is_limit()) {\n    // Inform the depth\n    depth_.fill_order(matched_order->price(), \n      quantity,\n      matched_order_filled,\n      matched_order->is_buy());\n  }\n  // If the inbound order is a limit order\n  if (order->is_limit()) {\n    // Inform the depth\n    depth_.fill_order(order->price(), \n      quantity,\n      inbound_order_filled,\n      order->is_buy());\n  }\n}\n\ntemplate <class OrderPtr, int SIZE> \nvoid \nDepthOrderBook<OrderPtr, SIZE>::on_cancel(const OrderPtr& order, Quantity quantity)\n{\n  // If the order is a limit order\n  if (order->is_limit()) {\n    // If the close erases a level\n    depth_.close_order(order->price(), \n      quantity, \n      order->is_buy());\n  }\n}\n\ntemplate <class OrderPtr, int SIZE> \nvoid \nDepthOrderBook<OrderPtr, SIZE>::on_cancel_stop(const OrderPtr& order)\n{\n  // nothing to do for STOP until triggered/submitted\n}\n\ntemplate <class OrderPtr, int SIZE> \nvoid \nDepthOrderBook<OrderPtr, SIZE>::on_replace(const OrderPtr& order,\n  Quantity current_qty, \n  Quantity new_qty,\n  Price new_price)\n{\n  // Notify the depth\n  depth_.replace_order(order->price(), new_price, \n    current_qty, new_qty, order->is_buy());\n}\n\ntemplate <class OrderPtr, int SIZE> \nvoid \nDepthOrderBook<OrderPtr, SIZE>::on_order_book_change()\n{\n  // Book was updated, see if the depth we track was effected\n  if (depth_.changed()) {\n    if (depth_listener_) {\n      depth_listener_->on_depth_change(this, &depth_);\n    }\n    if (bbo_listener_) {\n      ChangeId last_change = depth_.last_published_change();\n      // May have been the first level which changed\n      if ((depth_.bids()->changed_since(last_change)) ||\n        (depth_.asks()->changed_since(last_change))) {\n        bbo_listener_->on_bbo_change(this, &depth_);\n      }\n    }\n    // Start tracking changes again...\n    depth_.published();\n  }\n}\n\ntemplate <class OrderPtr, int SIZE>\ninline typename DepthOrderBook<OrderPtr, SIZE>::DepthTracker&\nDepthOrderBook<OrderPtr, SIZE>::depth()\n{\n  return depth_;\n}\n\ntemplate <class OrderPtr, int SIZE>\ninline const typename DepthOrderBook<OrderPtr, SIZE>::DepthTracker&\nDepthOrderBook<OrderPtr, SIZE>::depth() const\n{\n  return depth_;\n}\n\n} }\n"
  },
  {
    "path": "src/book/liquibook.mpc",
    "content": "project (liquibook): liquibook_exe {\n  exename = *\n  Header_files {\n    *.h\n  }\n  Source_Files {\n    *.cpp\n  }\n}\n\n"
  },
  {
    "path": "src/book/logger.h",
    "content": "// Copyright (c) 2012, 2013 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#pragma once\n\n#include <exception>\n#include <string>\nnamespace liquibook { namespace book {\n/// @brief Interface to allow application to control error logging\nclass Logger\n{\npublic:\n  virtual void log_exception(const std::string & context, const std::exception& ex) = 0;\n  virtual void log_message(const std::string & message) = 0;\n};\n\n}}\n"
  },
  {
    "path": "src/book/main.cpp",
    "content": "#include <iostream>\n#include \"version.h\"\n\n#include \"depth_order_book.h\"\n#include \"order.h\"\n\nusing namespace liquibook;\nusing namespace book;\nnamespace\n{\n  // depth order book pulls in all the other header files.\n  // except order.h which is actually a concept.\n  DepthOrderBook<Order *, 5> unusedDepthOrderBook_;\n}\n\nint main(int, const char**)\n{\n    std::cout << \"Liquibook version \" << Version::MAJOR << '.' << Version::MINOR << '.' << Version::PATCH \n      << \" (\" << Version::RELEASE_DATE << \")\\n\";\n    std::cout << \"Liquibook is a header-only library.\\n\\n\";\n    std::cout << \"This executable is a placeholder to make the book header files visible in\\n\";\n    std::cout << \"Visual Studio.  It also lets the compiler to do syntax checking of the header\\n\";\n    std::cout << \"files at build time.\" << std::endl;\n    return 0;\n}\n\n"
  },
  {
    "path": "src/book/order.h",
    "content": "// Copyright (c) 2012, 2013 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#pragma once\n\n#include \"types.h\"\n\nnamespace liquibook { namespace book {\n\n/// @brief interface an order must implement in order to be used by OrderBook.\n/// Note: structly speaking, inheriting from Order should not be required, \n///       due to the template implementation of OrderBook.\nclass Order {\npublic:\n  /// @brief is this a limit order?\n  bool is_limit() const;\n\n  /// @brief is this order a buy?\n  virtual bool is_buy() const = 0;\n\n  /// @brief get the price of this order, or 0 if a market order\n  virtual Price price() const = 0;\n\n  /// @brief get the stop price (if any) for this order.\n  /// @returns the stop price or zero if not a stop order\n  virtual Price stop_price() const;\n\n  /// @brief get the quantity of this order\n  virtual Quantity order_qty() const = 0;\n\n  /// @brief if no trades should happen until the order\n  /// can be filled completely.\n  /// Note: one or more trades may be used to fill the order.\n  virtual bool all_or_none() const;\n\n  /// @brief After generating as many trades as possible against\n  /// orders already on the market, cancel any remaining quantity.\n  virtual bool immediate_or_cancel() const;\n};\n\ninline\nbool\nOrder::is_limit() const \n{\n  return (price() > 0);\n}\n\ninline\nPrice\nOrder::stop_price() const\n{\n  // default to not a stop order\n  return 0;\n}\n\ninline\nbool\nOrder::all_or_none() const\n{\n  // default to normal\n  return false;\n}\n\ninline\nbool\nOrder::immediate_or_cancel() const\n{\n  // default to normal\n  return false;\n}\n\n} }\n"
  },
  {
    "path": "src/book/order_book.h",
    "content": "// Copyright (c) 2012 - 2017 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#pragma once\n\n#include \"version.h\"\n#include \"order_tracker.h\"\n#include \"callback.h\"\n#include \"order_listener.h\"\n#include \"order_book_listener.h\"\n#include \"trade_listener.h\"\n#include \"comparable_price.h\"\n#include \"logger.h\"\n\n#include <sstream>\n#include <map>\n#include <vector>\n#include <stdexcept>\n#include <cmath>\n#include <list>\n#include <functional>\n#include <algorithm>\n\n#ifdef LIQUIBOOK_IGNORES_DEPRECATED_CALLS\n#define COMPLAIN_ONCE(message)\n#else // LIQUIBOOK_IGNORES_DEPRECATED_CALLS\n#define COMPLAIN_ONCE(message) \\\ndo{ \\\n  static bool once = true; \\\n  if(once) \\\n  { \\\n    once = false; \\\n    std::cerr << \"One-time Warning: \" << message << std::endl; \\\n  } \\\n} while(false)\n#endif // LIQUIBOOK_IGNORES_DEPRECATED_CALLS\n\nnamespace liquibook { namespace book {\n\ntemplate<class OrderPtr>\nclass OrderListener;\n\ntemplate<class OrderBook>\nclass OrderBookListener;\n\n/// @brief The limit order book of a security.  Template implementation allows\n///        user to supply common or smart pointers, and to provide a different\n///        Order class completely (as long as interface is obeyed).\ntemplate <typename OrderPtr>\nclass OrderBook {\npublic:\n  typedef OrderTracker<OrderPtr > Tracker;\n  typedef Callback<OrderPtr > TypedCallback;\n  typedef OrderListener<OrderPtr > TypedOrderListener;\n  typedef OrderBook<OrderPtr > MyClass;\n  typedef TradeListener<MyClass > TypedTradeListener;\n  typedef OrderBookListener<MyClass > TypedOrderBookListener;\n  typedef std::vector<TypedCallback > Callbacks;\n  typedef std::multimap<ComparablePrice, Tracker> TrackerMap;\n  typedef std::vector<Tracker> TrackerVec;\n  // Keep this around briefly for compatibility.\n  typedef TrackerMap Bids;\n  typedef TrackerMap Asks;\n\n  typedef std::list<typename TrackerMap::iterator> DeferredMatches;\n\n  /// @brief construct\n  OrderBook(const std::string & symbol = \"unknown\");\n\n  /// @brief Set symbol for orders in this book.\n  void set_symbol(const std::string & symbol);\n\n  /// @ Get the symbol for orders in this book\n  /// @return the symbol.\n  const std::string & symbol() const;\n\n  /// @brief set the order listener\n  void set_order_listener(TypedOrderListener* listener);\n\n  /// @brief set the trade listener\n  void set_trade_listener(TypedTradeListener* listener);\n\n  /// @brief set the order book listener\n  void set_order_book_listener(TypedOrderBookListener* listener);\n\n  /// @brief let the application handle reporting errors.\n  void set_logger(Logger * logger);\n\n  /// @brief add an order to book\n  /// @param order the order to add\n  /// @param conditions special conditions on the order\n  /// @return true if the add resulted in a fill\n  virtual bool add(const OrderPtr& order, OrderConditions conditions = 0);\n\n  /// @brief cancel an order in the book\n  virtual void cancel(const OrderPtr& order);\n\n  /// @brief replace an order in the book\n  /// @param order the order to replace\n  /// @param size_delta the change in size for the order (positive or negative)\n  /// @param new_price the new order price, or PRICE_UNCHANGED\n  /// @return true if the replace resulted in a fill\n  virtual bool replace(const OrderPtr& order, \n                       int64_t size_delta = SIZE_UNCHANGED,\n                       Price new_price = PRICE_UNCHANGED);\n\n  /// @brief Set the current market price\n  /// Intended to be used during initialization to establish the market\n  /// price before this order book has generated any exceptions.\n  ///\n  /// If price is zero (or never set) no market-to-market trades can happen.\n  /// @param price is the current market price for this security.\n  void set_market_price(Price price);\n\n  /// @brief Get current market price.\n  /// The market price is normally the price at which the last trade happened.\n  Price market_price()const;\n\n  /// @brief access the bids container\n  const TrackerMap& bids() const { return bids_; };\n\n  /// @brief access the asks container\n  const TrackerMap& asks() const { return asks_; };\n\n  /// @brief access stop bid orders\n  const TrackerMap & stopBids() const { return stopBids_;}\n\n  /// @brief access stop ask orders\n  const TrackerMap & stopAsks() const { return stopAsks_;}\n\n  /// @brief move callbacks to another thread's container\n  /// @deprecated  This doesn't do anything now\n  /// so don't bother to call it in new code.\n  void move_callbacks(Callbacks& target);\n\n  /// @brief perform all callbacks in the queue\n  /// @deprecated  This doesn't do anything now\n  /// so don't bother to call it in new code.\n  virtual void perform_callbacks();\n\n  /// @brief log the orders in the book.\n  std::ostream & log(std::ostream & out) const;\n\nprotected:\n  /// @brief Internal method to process callbacks.\n  /// Protected against recursive calls in case callbacks\n  /// issue new requests. \n  void callback_now();\n\n  /// @brief perform an individual callback\n  virtual void perform_callback(TypedCallback& cb);\n\n  /// @brief match a new order to current orders\n  /// @param inbound_order the inbound order\n  /// @param inbound_price price of the inbound order\n  /// @param current_orders open orders\n  /// @param[OUT] deferred_aons AON orders from current_orders \n  ///             that matched the inbound price, \n  ///             but were not filled due to quantity\n  /// @return true if a match occurred \n  virtual bool match_order(Tracker& inbound_order, \n    Price inbound_price, \n    TrackerMap& current_orders,\n    DeferredMatches & deferred_aons);\n\n  bool match_aon_order(Tracker& inbound, \n    Price inbound_price, \n    TrackerMap& current_orders,\n    DeferredMatches & deferred_aons);\n\n  bool match_regular_order(Tracker& inbound, \n    Price inbound_price, \n    TrackerMap& current_orders,\n    DeferredMatches & deferred_aons);\n\n  Quantity try_create_deferred_trades(\n    Tracker& inbound,\n    DeferredMatches & deferred_matches, \n    Quantity maxQty, // do not exceed\n    Quantity minQty, // must be at least\n    TrackerMap& current_orders);\n\n  /// @brief see if any deferred All Or None orders can now execute.\n  /// @param aons iterators to the orders that might now match\n  /// @param deferredTrackers the container of the aons\n  /// @param marketTrackers the orders to check for matches\n  bool check_deferred_aons(DeferredMatches & aons, \n    TrackerMap & deferredTrackers, \n    TrackerMap & marketTrackers);\n\n  /// @brief perform fill on two orders\n  /// @param inbound_tracker the new (or changed) order tracker\n  /// @param current_tracker the current order tracker\n  /// @param max_quantity maximum quantity to trade.\n  /// @return the number of units traded (zero if unsuccessful).\n  Quantity create_trade(Tracker& inbound_tracker, \n                    Tracker& current_tracker,\n                    Quantity max_quantity = QUANTITY_MAX);\n\n  /// @brief find an order in a container\n  /// @param order is the the order we are looking for\n  /// @param[OUT] result will point to the entry in the container if we find a match\n  /// @returns true: match, false: no match\n  bool find_on_market(\n    const OrderPtr& order,\n    typename TrackerMap::iterator& result);\n\n  /// @brief find stop order in a container.\n  /// @param order is the the stop order we are looking for\n  /// @param[OUT] result will point to the entry in the container if we find a match\n  /// @returns true: match, false: no match\n  bool find_in_stop_orders(\n    const OrderPtr& order,\n    typename TrackerMap::iterator& result);\n\n  /// @brief add incoming stop order to stops colletion unless it's already\n  /// on the market.\n  /// @return true if added to stops, false if it should go directly to the order book.\n  bool add_stop_order(Tracker & tracker);\n\n  /// @brief See if any stop orders should go on the market.\n  void check_stop_orders(bool side, Price price, TrackerMap & stops);\n\n  /// @brief accept pending (formerly stop) orders.\n  void submit_pending_orders();\n\n  ///////////////////////////////\n  // Callback interfaces as\n  // virtual methods to simplify\n  // derived classes.\n  ///////////////////////////////\n  // Order Listener interface\n  /// @brief callback for an order accept\n  virtual void on_accept(const OrderPtr& order, Quantity quantity){}\n  virtual void on_accept_stop(const OrderPtr& order){}\n  virtual void on_trigger_stop(const OrderPtr& order){}\n\n  /// @brief callback for an order reject\n  virtual void on_reject(const OrderPtr& order, const char* reason){}\n\n  /// @brief callback for an order fill\n  /// @param order the inbound order\n  /// @param matched_order the matched order\n  /// @param fill_qty the quantity of this fill\n  /// @param fill_price the price of this fill\n  virtual void on_fill(const OrderPtr& order, \n    const OrderPtr& matched_order, \n    Quantity fill_qty, \n    Price fill_price,\n    bool inbound_order_filled,\n    bool matched_order_filled){}\n\n  /// @brief callback for an order cancellation\n  virtual void on_cancel(const OrderPtr& order, Quantity quantity){}\n\n  /// @brief callback for a STOP cancellation\n  virtual void on_cancel_stop(const OrderPtr& order){}\n\n  /// @brief callback for an order cancel rejection\n  virtual void on_cancel_reject(const OrderPtr& order, const char* reason){}\n\n  /// @brief callback for an order replace\n  /// @param order the replaced order\n  /// @param size_delta the change to order quantity\n  /// @param new_price the updated order price\n  virtual void on_replace(const OrderPtr& order,\n    Quantity current_qty, \n    Quantity new_qty,\n    Price new_price){}\n\n  /// @brief callback for an order replace rejection\n  virtual void on_replace_reject(const OrderPtr& order, const char* reason){}\n\n  // End of OrderListener Interface\n  ///////////////////////////////\n  // TradeListener Interface\n  /// @brief callback for a trade\n  /// @param book the order book of the fill (not defined whether this is before\n  ///      or after fill)\n  /// @param qty the quantity of this fill\n  /// @param price the price of this fill\n  virtual void on_trade(const OrderBook* book,\n    Quantity qty,\n    Price price){}\n  // End of TradeListener Interface\n  ///////////////////////////////\n  // BookListener Interface\n  /// @brief callback for change anywhere in order book\n  virtual void on_order_book_change(){}\n  // End of BookListener Interface\n  ///////////////////////////////\n\n\nprivate:\n    bool submit_order(Tracker & inbound);\n    bool add_order(Tracker& order_tracker, Price order_price);\nprivate:\n\n  std::string symbol_;\n  TrackerMap bids_;\n  TrackerMap asks_;\n\n  TrackerMap stopBids_;\n  TrackerMap stopAsks_;\n  TrackerVec pendingOrders_;\n\n  Callbacks callbacks_;\n  Callbacks workingCallbacks_;\n  bool handling_callbacks_;\n  TypedOrderListener* order_listener_;\n  TypedTradeListener* trade_listener_;\n  TypedOrderBookListener* order_book_listener_;\n  Logger * logger_;\n  Price marketPrice_;\n};\n\ntemplate <class OrderPtr>\nOrderBook<OrderPtr>::OrderBook(const std::string & symbol)\n: symbol_(symbol),\n  handling_callbacks_(false),\n  order_listener_(nullptr),\n  trade_listener_(nullptr),\n  order_book_listener_(nullptr),\n  logger_(nullptr),\n  marketPrice_(MARKET_ORDER_PRICE)\n{\n  callbacks_.reserve(16);  // Why 16?  Why not?  \n  workingCallbacks_.reserve(callbacks_.capacity());\n}\n\ntemplate <class OrderPtr>\nvoid\nOrderBook<OrderPtr>::set_logger(Logger * logger)\n{\n  logger_ = logger;\n}\n\n\ntemplate <class OrderPtr>\nvoid \nOrderBook<OrderPtr>::set_symbol(const std::string & symbol)\n{\n    symbol_ = symbol;\n}\n\ntemplate <class OrderPtr>\nconst std::string &\nOrderBook<OrderPtr>::symbol() const\n{\n    return symbol_;\n}\n\ntemplate <class OrderPtr>\nvoid\nOrderBook<OrderPtr>:: set_market_price(Price price)\n{\n  Price oldMarketPrice = marketPrice_;\n  marketPrice_ = price;\n  if(price > oldMarketPrice || oldMarketPrice == MARKET_ORDER_PRICE)\n  {\n    // price has gone up: check stop bids\n    bool buySide = true;\n    check_stop_orders(buySide, price, stopBids_);\n  }\n  else if(price < oldMarketPrice || oldMarketPrice == MARKET_ORDER_PRICE)\n  {\n    // price has gone down: check stop asks\n    bool buySide = false;\n    check_stop_orders(buySide, price, stopAsks_);\n  }\n}\n\n/// @brief Get current market price.\n/// The market price is normally the price at which the last trade happened.\ntemplate <class OrderPtr>\nPrice\nOrderBook<OrderPtr>::market_price() const\n{\n  return marketPrice_;\n}\n\ntemplate <class OrderPtr>\nvoid\nOrderBook<OrderPtr>::set_order_listener(TypedOrderListener* listener)\n{\n  order_listener_ = listener;\n}\n\ntemplate <class OrderPtr>\nvoid\nOrderBook<OrderPtr>::set_trade_listener(TypedTradeListener* listener)\n{\n  trade_listener_ = listener;\n}\n\ntemplate <class OrderPtr>\nvoid\nOrderBook<OrderPtr>::set_order_book_listener(TypedOrderBookListener* listener)\n{\n  order_book_listener_ = listener;\n}\n\ntemplate <class OrderPtr>\nbool\nOrderBook<OrderPtr>::add(const OrderPtr& order, OrderConditions conditions)\n{\n  bool matched = false;\n\n  // If the order is invalid, ignore it\n  if (order->order_qty() == 0) {\n    callbacks_.push_back(TypedCallback::reject(order, \"size must be positive\"));\n  }\n  else \n  {\n    Tracker inbound(order, conditions);\n    if(inbound.ptr()->stop_price() != 0 && add_stop_order(inbound))\n    {\n      // The order has been added to stops\n      callbacks_.push_back(TypedCallback::accept_stop(order));\n    }\n    else\n    {\n      size_t accept_cb_index = callbacks_.size();\n      callbacks_.push_back(TypedCallback::accept(order));\n      matched = submit_order(inbound);\n      // Note the filled qty in the accept callback\n      callbacks_[accept_cb_index].quantity = inbound.filled_qty();\n\n      // Cancel any unfilled IOC order\n      if (inbound.immediate_or_cancel() && !inbound.filled()) \n      {\n        // NOTE - this may need he actual open qty???\n        callbacks_.push_back(TypedCallback::cancel(order, 0));\n      }\n    }\n    // If adding this order triggered any stops\n    // handle those stops now\n    while(!pendingOrders_.empty())\n    {\n      submit_pending_orders();\n    }\n    callbacks_.push_back(TypedCallback::book_update(this));\n  }\n  callback_now();\n  return matched;\n}\n\ntemplate <class OrderPtr>\nvoid\nOrderBook<OrderPtr>::cancel(const OrderPtr& order)\n{\n  bool found = false;\n  bool foundStop = false;\n  Quantity open_qty;\n  // If the cancel is a buy order\n  if (order->is_buy()) {\n    typename TrackerMap::iterator bid;\n    find_on_market(order, bid);\n    if (bid != bids_.end()) {\n      open_qty = bid->second.open_qty();\n      // Remove from container for cancel\n      bids_.erase(bid);\n      found = true;\n    }\n    else if (order->stop_price()) {\n      find_in_stop_orders(order, bid);\n      if (bid != stopBids_.end()) {\n        stopBids_.erase(bid);\n        foundStop = true;\n      }\n    }\n  // Else the cancel is a sell order\n  } else {\n    typename TrackerMap::iterator ask;\n    find_on_market(order, ask);\n    if (ask != asks_.end()) {\n      open_qty = ask->second.open_qty();\n      // Remove from container for cancel\n      asks_.erase(ask);\n      found = true;\n    }\n    else if (order->stop_price()) {\n      find_in_stop_orders(order, ask);\n      if (ask != stopAsks_.end()) {\n        stopAsks_.erase(ask);\n        foundStop = true;\n      }\n    }\n  } \n  // If the cancel was found, issue callback\n  if (found) {\n    callbacks_.push_back(TypedCallback::cancel(order, open_qty));\n    callbacks_.push_back(TypedCallback::book_update(this));\n  }\n  else if (foundStop) {\n    callbacks_.push_back(TypedCallback::cancel_stop(order));\n    callbacks_.push_back(TypedCallback::book_update(this));\n  }\n  else {\n    callbacks_.push_back(TypedCallback::cancel_reject(order, \"not found\"));\n  }\n  callback_now();\n}\n\ntemplate <class OrderPtr>\nbool\nOrderBook<OrderPtr>::replace(\n  const OrderPtr& order, \n  int64_t size_delta,\n  Price new_price)\n{\n  bool matched = false;\n  bool price_change = new_price && (new_price != order->price());\n\n  Price price = (new_price == PRICE_UNCHANGED) ? order->price() : new_price;\n\n  // If the order to replace is a buy order\n  TrackerMap & market = order->is_buy() ? bids_ : asks_;\n  typename TrackerMap::iterator pos;\n  if(find_on_market(order, pos))\n  {\n    // If this is a valid replace\n    const Tracker& tracker = pos->second;\n    // If there is not enough open quantity for the size reduction\n    if (size_delta < 0 && ((int)tracker.open_qty() < -size_delta)) \n    {\n      // get rid of as much as we can\n      size_delta = -int(tracker.open_qty());\n      if(size_delta == 0)\n      {\n        // if there is nothing to get rid of\n        // Reject the replace\n        callbacks_.push_back(TypedCallback::replace_reject(tracker.ptr(), \n          \"order is already filled\"));\n        return false;\n      }\n    }\n\n    // Accept the replace\n    callbacks_.push_back(\n        TypedCallback::replace(order, pos->second.open_qty(), size_delta, \n                                price));\n    Quantity new_open_qty = pos->second.open_qty() + size_delta;\n    pos->second.change_qty(size_delta);  // Update my copy\n    // If the size change will close the order\n    if (!new_open_qty) \n    {\n      // Cancel with NO open qty (should be zero after replace)\n      callbacks_.push_back(TypedCallback::cancel(order, 0));\n      market.erase(pos); // Remove order\n    } \n    else \n    {\n      // Else rematch the new order - there could be a price change\n      // or size change - that could cause all or none match\n      auto order = pos->second;\n      market.erase(pos); // Remove old order order\n      matched = add_order(order, price); // Add order\n    }\n    // If replace any order this order triggered any trades\n    // which triggered any stops\n    // handle those stops now\n    while(!pendingOrders_.empty())\n    {\n      submit_pending_orders();\n    }\n    callbacks_.push_back(TypedCallback::book_update(this));\n  }\n  else\n  {\n    // not found\n    callbacks_.push_back(\n          TypedCallback::replace_reject(order, \"not found\"));\n  }\n  callback_now();\n  return matched;\n}\n\ntemplate <class OrderPtr>\nbool\nOrderBook<OrderPtr>::add_stop_order(Tracker & tracker)\n{\n  bool isBuy = tracker.ptr()->is_buy();\n  ComparablePrice key(isBuy, tracker.ptr()->stop_price());\n  // if the market price is a better deal then the stop price, it's not time to panic\n  bool isStopped = key < marketPrice_;\n  if(isStopped)\n  {\n    if(isBuy)\n    {\n      stopBids_.emplace(key, std::move(tracker));\n    }\n    else\n    {\n      stopAsks_.emplace(key, std::move(tracker));\n    }\n  }\n  return isStopped;\n}\n\ntemplate <class OrderPtr>\nvoid\nOrderBook<OrderPtr>::check_stop_orders(bool side, Price price, TrackerMap & stops)\n{\n  ComparablePrice until(side, price);\n  auto pos = stops.begin(); \n  while(pos != stops.end())\n  {\n    auto here = pos++;\n    if(until > here->first)\n    {\n      break;\n    }\n    pendingOrders_.push_back(std::move(here->second));\n    stops.erase(here);\n  }\n}\n\ntemplate <class OrderPtr>\nvoid\nOrderBook<OrderPtr>::submit_pending_orders()\n{\n  TrackerVec pending;\n  pending.swap(pendingOrders_);\n  for(auto pos = pending.begin(); pos != pending.end(); ++pos)\n  {\n    Tracker & tracker = *pos;\n    submit_order(tracker);\n    callbacks_.push_back(TypedCallback::trigger_stop(tracker.ptr()));\n  }\n}\n\ntemplate <class OrderPtr>\nbool\nOrderBook<OrderPtr>::submit_order(Tracker & inbound)\n{\n  Price order_price = inbound.ptr()->price();\n  return add_order(inbound, order_price);\n}\n\ntemplate <class OrderPtr>\nbool\nOrderBook<OrderPtr>::find_on_market(\n  const OrderPtr& order,\n  typename TrackerMap::iterator& result)\n{\n  const ComparablePrice key(order->is_buy(), order->price());\n  TrackerMap & sideMap = order->is_buy() ? bids_ : asks_;\n\n  for (result = sideMap.find(key); result != sideMap.end(); ++result) {\n    // If this is the correct bid\n    if (result->second.ptr() == order) \n    {\n      return true;\n    } \n    else if (key < result->first) \n    {\n      // exit early if result is beyond the matching prices\n      result = sideMap.end();\n      return false;\n    }\n  }\n  return false;\n}\n\ntemplate <class OrderPtr>\nbool\nOrderBook<OrderPtr>::find_in_stop_orders(\n  const OrderPtr& order,\n  typename TrackerMap::iterator& result)\n{\n  const ComparablePrice key(order->is_buy(), order->stop_price());\n  TrackerMap & sideMap = order->is_buy() ? stopBids_ : stopAsks_;\n\n  for (result = sideMap.find(key); result != sideMap.end(); ++result) {\n    // If this is the correct bid\n    if (result->second.ptr() == order)\n    {\n      return true;\n    }\n    else if (key < result->first)\n    {\n      // exit early if result is beyond the matching prices\n      result = sideMap.end();\n      return false;\n    }\n  }\n  return false;\n}\n\n// Try to match order.  Generate trades.\n// If not completely filled and not IOC,\n// add the order to the order book\ntemplate <class OrderPtr>\nbool\nOrderBook<OrderPtr>::add_order(Tracker& inbound, Price order_price)\n{\n  bool matched = false;\n  OrderPtr& order = inbound.ptr();\n  DeferredMatches deferred_aons;\n  // Try to match with current orders\n  if (order->is_buy()) {\n    matched = match_order(inbound, order_price, asks_, deferred_aons);\n  } else {\n    matched = match_order(inbound, order_price, bids_, deferred_aons);\n  }\n\n  // If order has remaining open quantity and is not immediate or cancel\n  if (inbound.open_qty() && !inbound.immediate_or_cancel()) {\n    // If this is a buy order\n    if (order->is_buy()) \n    {\n      // Insert into bids\n      bids_.insert(std::make_pair(ComparablePrice(true, order_price), inbound));\n      // and see if that satisfies any ask orders\n      if(check_deferred_aons(deferred_aons, asks_, bids_))\n      {\n        matched = true;\n      }\n    } \n    else \n    {\n      // Else this is a sell order\n      // Insert into asks\n      asks_.insert(std::make_pair(ComparablePrice(false, order_price), inbound));\n      if(check_deferred_aons(deferred_aons, bids_, asks_))\n      {\n        matched = true;\n      }\n    }\n  }\n  return matched;\n}\n\ntemplate <class OrderPtr>\nbool\nOrderBook<OrderPtr>::check_deferred_aons(DeferredMatches & aons, \n  TrackerMap & deferredTrackers, \n  TrackerMap & marketTrackers)\n{\n  bool result = false;\n  DeferredMatches ignoredAons;\n\n  for(auto pos = aons.begin(); pos != aons.end(); ++pos)\n  {\n    auto entry = *pos;\n    ComparablePrice current_price = entry->first;\n    Tracker & tracker = entry->second;\n    bool matched = match_order(tracker, current_price.price(), \n      marketTrackers, ignoredAons);\n    result |= matched;\n    if(tracker.filled())\n    {\n      deferredTrackers.erase(entry);\n    }\n  }\n  return result;\n}\n\n///  Try to match order at 'price' against 'current' orders\n///  If successful\n///    generate trade(s)\n///    if any current order is complete, remove from 'current' orders\ntemplate <class OrderPtr>\nbool\nOrderBook<OrderPtr>::match_order(Tracker& inbound, \n  Price inbound_price, \n  TrackerMap& current_orders,\n  DeferredMatches & deferred_aons)\n{\n  if(inbound.all_or_none())\n  {\n    return match_aon_order(inbound, inbound_price, current_orders, deferred_aons);\n  }\n  return match_regular_order(inbound, inbound_price, current_orders, deferred_aons);\n}\n\ntemplate <class OrderPtr>\nbool\nOrderBook<OrderPtr>::match_regular_order(Tracker& inbound, \n  Price inbound_price, \n  TrackerMap& current_orders,\n  DeferredMatches & deferred_aons)\n{\n  // while incoming ! satisfied\n  //   current is reg->trade\n  //   current is AON:\n  //    incoming satisfies AON ->TRADE\n  //    add AON to deferred\n  // loop\n  bool matched = false;\n  Quantity inbound_qty = inbound.open_qty();\n  typename TrackerMap::iterator pos = current_orders.begin(); \n  while(pos != current_orders.end() && !inbound.filled()) \n  {\n    auto entry = pos++;\n    const ComparablePrice & current_price = entry->first;\n    if(!current_price.matches(inbound_price))\n    {\n      // no more trades against current orders are possible\n      break;\n    }\n\n    //////////////////////////////////////\n    // Current price matches inbound price\n    Tracker & current_order = entry->second;\n    Quantity current_quantity = current_order.open_qty();\n\n    if(current_order.all_or_none())\n    {\n      // if the inbound order can satisfy the current order's AON condition\n      if(current_quantity <= inbound_qty)\n      {\n        // current is AON, inbound is not AON.\n        // inbound can satisfy current's AON\n        Quantity traded = create_trade(inbound, current_order);\n        if(traded > 0)\n        {\n          matched = true;\n          // assert traded == current_quantity\n          current_orders.erase(entry);\n          inbound_qty -= traded;\n        }\n      }\n      else\n      {\n        // current is AON, inbound is not AON.\n        // inbound is not enough to satisfy current order's AON\n        deferred_aons.push_back(entry);\n      }\n    }\n    else \n    {\n      // neither are AON\n      Quantity traded = create_trade(inbound, current_order);\n      if(traded > 0)\n      {\n        matched = true;\n        if(current_order.filled())\n        {\n          current_orders.erase(entry);\n        }\n        inbound_qty -= traded;\n      }\n    }\n  }\n  return matched;\n}\n\ntemplate <class OrderPtr>\nbool\nOrderBook<OrderPtr>::match_aon_order(Tracker& inbound, \n  Price inbound_price, \n  TrackerMap& current_orders,\n  DeferredMatches & deferred_aons)\n{\n  bool matched = false;\n  Quantity inbound_qty = inbound.open_qty();\n  Quantity deferred_qty = 0;\n\n  DeferredMatches deferred_matches;\n\n  typename TrackerMap::iterator pos = current_orders.begin(); \n  while(pos != current_orders.end() && !inbound.filled()) \n  {\n    auto entry = pos++;\n    const ComparablePrice current_price = entry->first;\n    if(!current_price.matches(inbound_price))\n    {\n      // no more trades against current orders are possible\n      break;\n    }\n\n    //////////////////////////////////////\n    // Current price matches inbound price\n    Tracker & current_order = entry->second;\n    Quantity current_quantity = current_order.open_qty();\n\n    if(current_order.all_or_none())\n    {\n      // AON::AON\n      // if the inbound order can satisfy the current order's AON condition\n      if(current_quantity <= inbound_qty)\n      {\n        // if the the matched quantity can satisfy\n        // the inbound order's AON condition\n        if(inbound_qty <= current_quantity + deferred_qty)\n        {\n          // Try to create the deferred trades (if any) before creating\n          // the trade with the current order.\n          // What quantity will we need from the deferred orders?\n          Quantity maxQty = inbound_qty - current_quantity;\n          if(maxQty == try_create_deferred_trades(\n            inbound, \n            deferred_matches, \n            maxQty, \n            maxQty, \n            current_orders))\n          {\n            inbound_qty -= maxQty;\n            // finally execute this trade\n            Quantity traded = create_trade(inbound, current_order);\n            if(traded > 0)\n            {\n              // assert traded == current_quantity\n              inbound_qty -= traded;\n              matched = true;\n              current_orders.erase(entry);\n            }\n          }\n        }\n        else\n        {\n          // AON::AON -- inbound could satisfy current, but\n          // current cannot satisfy inbound;\n          deferred_qty += current_quantity;\n          deferred_matches.push_back(entry);\n        }\n      }\n      else\n      {\n        // AON::AON -- inbound cannot satisfy current's AON\n        deferred_aons.push_back(entry);\n      }\n    }\n    else \n    {\n      // AON::REG\n\n      // if we have enough to satisfy inbound\n      if(inbound_qty <= current_quantity + deferred_qty)\n      {        \n        Quantity traded = try_create_deferred_trades(\n          inbound, \n          deferred_matches, \n          inbound_qty, // create as many as possible\n          (inbound_qty > current_quantity) ? (inbound_qty - current_quantity) : 0, // but we need at least this many\n          current_orders);\n        if(inbound_qty <= current_quantity + traded)\n        {\n          traded += create_trade(inbound, current_order);\n          if(traded > 0)\n          {\n            inbound_qty -= traded;\n            matched = true;\n          }\n          if(current_order.filled())\n          {\n            current_orders.erase(entry);\n          }\n        }\n      }\n      else\n      {\n        // not enough to satisfy inbound, yet.\n        // remember the current order for later use\n        deferred_qty += current_quantity;\n        deferred_matches.push_back(entry);\n      }\n    }\n  }\n  return matched;\n}\nnamespace {\n  const size_t AON_LIMIT = 5;\n}\n\ntemplate <class OrderPtr>\nQuantity\nOrderBook<OrderPtr>::try_create_deferred_trades(\n  Tracker& inbound,\n  DeferredMatches & deferred_matches, \n  Quantity maxQty, // do not exceed\n  Quantity minQty, // must be at least\n  TrackerMap& current_orders)\n{\n  Quantity traded = 0;\n  // create a vector of proposed trade quantities:\n  std::vector<int> fills(deferred_matches.size());\n  std::fill(fills.begin(), fills.end(), 0);\n  Quantity foundQty = 0;\n  auto pos = deferred_matches.begin(); \n  for(size_t index = 0;\n    foundQty < maxQty && pos != deferred_matches.end();\n    ++index)\n  {\n    auto entry = *pos++;\n    Tracker & tracker = entry->second;\n    Quantity qty = tracker.open_qty();\n    // if this would put us over the limit\n    if(foundQty + qty > maxQty)\n    {\n      if(tracker.all_or_none())\n      {\n        qty = 0;\n      }\n      else\n      {\n        qty = maxQty - foundQty;\n        // assert qty <= tracker.open_qty();\n      }\n    }\n    foundQty += qty;\n    fills[index] = qty;\n  }\n\n  if(foundQty >= minQty && foundQty <= maxQty)\n  {\n    // pass through deferred matches again, doing the trades.\n    auto pos = deferred_matches.begin(); \n    for(size_t index = 0;\n      traded < foundQty && pos != deferred_matches.end();\n      ++index)\n    {\n      auto entry = *pos++;\n      Tracker & tracker = entry->second;\n      traded += create_trade(inbound, tracker, fills[index]);\n      if(tracker.filled())\n      {\n        current_orders.erase(entry);\n      }\n    }\n  }\n  return traded;\n}\n\ntemplate <class OrderPtr>\nQuantity\nOrderBook<OrderPtr>::create_trade(Tracker& inbound_tracker, \n                                  Tracker& current_tracker,\n                                  Quantity maxQuantity)\n{\n  Price cross_price = current_tracker.ptr()->price();\n  // If current order is a market order, cross at inbound price\n  if (MARKET_ORDER_PRICE == cross_price) {\n    cross_price = inbound_tracker.ptr()->price();\n  }\n  if(MARKET_ORDER_PRICE == cross_price)\n  {\n    cross_price = marketPrice_;\n  }\n  if(MARKET_ORDER_PRICE == cross_price)\n  {\n    // No price available for this order\n    return 0;\n  }\n  Quantity fill_qty = \n    (std::min)(maxQuantity,\n    (std::min)(inbound_tracker.open_qty(), \n               current_tracker.open_qty()));\n  if(fill_qty > 0)\n  {\n    inbound_tracker.fill(fill_qty);\n    current_tracker.fill(fill_qty);\n    set_market_price(cross_price);\n\n    typename TypedCallback::FillFlags fill_flags = \n                                TypedCallback::ff_neither_filled;\n    if (!inbound_tracker.open_qty()) {\n      fill_flags = (typename TypedCallback::FillFlags)(\n                       fill_flags | TypedCallback::ff_inbound_filled);\n    }\n    if (!current_tracker.open_qty()) {\n      fill_flags = (typename TypedCallback::FillFlags)(\n                       fill_flags | TypedCallback::ff_matched_filled);\n    }\n\n    callbacks_.push_back(TypedCallback::fill(inbound_tracker.ptr(),\n                                             current_tracker.ptr(),\n                                             fill_qty,\n                                             cross_price,\n                                             fill_flags));\n  }\n  return fill_qty;\n}\n\ntemplate <class OrderPtr>\nvoid\nOrderBook<OrderPtr>::move_callbacks(Callbacks& target)\n{\n  COMPLAIN_ONCE(\"Ignoring call to deprecated method: move_callbacks\");\n  // We get to decide when callbacks happen.\n  // And it *certainly* doesn't happen on another thread!\n}\n\ntemplate <class OrderPtr>\nvoid\nOrderBook<OrderPtr>::perform_callbacks()\n{\n  COMPLAIN_ONCE(\"Ignoring call to deprecated method: perform_callbacks\");\n  // We get to decide when callbacks happen.\n}\n\ntemplate <class OrderPtr>\nvoid\nOrderBook<OrderPtr>::callback_now()\n{\n  // protect against recursive calls\n  // callbacks generated in response to previous callbacks\n  // will be handled before this method returns.\n  if(!handling_callbacks_)\n  {\n    handling_callbacks_ = true;\n    // remove all accumulated callbacks in case\n    // new callbacks are generated by the application code.\n    while(!callbacks_.empty())\n    {\n      // if we needed more entries, be sure that both containers have them.\n      workingCallbacks_.reserve(callbacks_.capacity());\n      workingCallbacks_.swap(callbacks_);\n      for (auto cb = workingCallbacks_.begin(); cb != workingCallbacks_.end(); ++cb) {\n        try\n        {\n          perform_callback(*cb);\n        }\n        catch(const std::exception & ex)\n        {\n          if(logger_)\n          {\n            logger_->log_exception(\"Caught exception during callback: \", ex);\n          }\n          else\n          {\n            std::cerr << \"Caught exception during callback: \" << ex.what() << std::endl;\n          }\n        }\n        catch(...)\n        {\n          if(logger_)\n          {\n            logger_->log_message(\"Caught unknown exception during callback\");\n          }\n          else\n          {\n            std::cerr << \"Caught unknown exception during callback\" << std::endl;\n          }\n        }\n      }\n      workingCallbacks_.clear();\n    }\n    handling_callbacks_ = false;\n  }\n}\n\ntemplate <class OrderPtr>\nvoid\nOrderBook<OrderPtr>::perform_callback(TypedCallback& cb)\n{\n  switch (cb.type) \n  {\n    case TypedCallback::cb_order_fill: \n    {\n      bool inbound_filled = (cb.flags & (TypedCallback::ff_inbound_filled | TypedCallback::ff_both_filled)) != 0;\n      bool matched_filled = (cb.flags & (TypedCallback::ff_matched_filled | TypedCallback::ff_both_filled)) != 0;\n      on_fill(cb.order, cb.matched_order, \n        cb.quantity, cb.price,\n        inbound_filled,\n        matched_filled);\n      if(order_listener_)\n      {\n        order_listener_->on_fill(cb.order, cb.matched_order, \n                                cb.quantity, cb.price);\n      }\n      on_trade(this, cb.quantity, cb.price);\n      if(trade_listener_)\n      {\n        trade_listener_->on_trade(this, cb.quantity, cb.price);\n      }\n      break;\n    }\n    case TypedCallback::cb_order_accept:\n      on_accept(cb.order, cb.quantity);\n      if(order_listener_)\n      {\n        order_listener_->on_accept(cb.order);\n      }\n      break;\n    case TypedCallback::cb_order_accept_stop:\n      on_accept_stop(cb.order);\n      if(order_listener_)\n      {\n        order_listener_->on_accept(cb.order);\n      }\n      break;\n    case TypedCallback::cb_order_trigger_stop:\n      on_trigger_stop(cb.order);\n      if(order_listener_)\n      {\n        order_listener_->on_trigger_stop(cb.order);\n      }\n      break;\n    case TypedCallback::cb_order_reject:\n      on_reject(cb.order, cb.reject_reason);\n      if(order_listener_)\n      {\n        order_listener_->on_reject(cb.order, cb.reject_reason);\n      }\n      break;\n    case TypedCallback::cb_order_cancel:\n      on_cancel(cb.order, cb.quantity);\n      if(order_listener_)\n      {\n        order_listener_->on_cancel(cb.order);\n      }\n      break;\n    case TypedCallback::cb_order_cancel_stop:\n      on_cancel_stop(cb.order);\n      if(order_listener_)\n      {\n        order_listener_->on_cancel(cb.order);\n      }\n      break;\n    case TypedCallback::cb_order_cancel_reject:\n      on_cancel_reject(cb.order, cb.reject_reason);\n      if(order_listener_)\n      {\n        order_listener_->on_cancel_reject(cb.order, cb.reject_reason);\n      }\n      break;\n    case TypedCallback::cb_order_replace:\n      on_replace(cb.order, \n        cb.order->order_qty(), \n        cb.order->order_qty() + cb.delta,\n        cb.price);\n      if(order_listener_)\n      {\n        order_listener_->on_replace(cb.order,\n        cb.delta,\n        cb.price);\n      }\n      break;\n    case TypedCallback::cb_order_replace_reject:\n      on_replace_reject(cb.order, cb.reject_reason);\n      if(order_listener_)\n      {\n        order_listener_->on_replace_reject(cb.order, cb.reject_reason);\n      }\n      break;\n    case TypedCallback::cb_book_update:\n      on_order_book_change();\n      if(order_book_listener_)\n      {\n        order_book_listener_->on_order_book_change(this);\n      }\n      break;\n    default:\n    {\n      std::stringstream msg;\n      msg << \"Unexpected callback type \" << cb.type;\n      std::runtime_error(msg.str());\n      break;\n    }\n  }\n}\n\ntemplate <class OrderPtr>\nstd::ostream &\nOrderBook<OrderPtr>::log(std::ostream & out) const\n{\n  for(auto ask = asks_.rbegin(); ask != asks_.rend(); ++ask) {\n    out << \"  Ask \" << ask->second.open_qty() << \" @ \" << ask->first\n                          << std::endl;\n  }\n\n  for(auto bid = bids_.begin(); bid != bids_.end(); ++bid) {\n    out << \"  Bid \" << bid->second.open_qty() << \" @ \" << bid->first\n                          << std::endl;\n  }\n  return out;\n}\n\n} }\n\n"
  },
  {
    "path": "src/book/order_book_listener.h",
    "content": "// Copyright (c) 2012, 2013 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#pragma once\n\n#include \"order_book.h\"\n\nnamespace liquibook { namespace book {\n\n/// @brief generic listener of order book events\ntemplate <class OrderBook >\nclass OrderBookListener {\npublic:\n  /// @brief callback for change anywhere in order book\n  virtual void on_order_book_change(const OrderBook* book) = 0;\n};\n\n} }\n"
  },
  {
    "path": "src/book/order_listener.h",
    "content": "// Copyright (c) 2012, 2013 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#pragma once\n\nnamespace liquibook { namespace book {\n\n/// @brief generic listener of order events.  Implement to build a full order book feed.\n//    Used by common version of OrderBook::process_callback().\ntemplate <typename OrderPtr>\nclass OrderListener {\npublic:\n  /// @brief callback for an order accept\n  virtual void on_accept(const OrderPtr& order) = 0;\n\n  /// @brief callback for triggered STOP order\n  virtual void on_trigger_stop(const OrderPtr& order) {}\n\n  /// @brief callback for an order reject\n  virtual void on_reject(const OrderPtr& order, const char* reason) = 0;\n\n  /// @brief callback for an order fill\n  /// @param order the inbound order\n  /// @param matched_order the matched order\n  /// @param fill_qty the quantity of this fill\n  /// @param fill_price the price of this fill\n  virtual void on_fill(const OrderPtr& order, \n                       const OrderPtr& matched_order, \n                       Quantity fill_qty, \n                       Price fill_price) = 0;\n\n  /// @brief callback for an order cancellation\n  virtual void on_cancel(const OrderPtr& order) = 0;\n\n  /// @brief callback for an order cancel rejection\n  virtual void on_cancel_reject(const OrderPtr& order, const char* reason) = 0;\n\n  /// @brief callback for an order replace\n  /// @param order the replaced order\n  /// @param size_delta the change to order quantity\n  /// @param new_price the updated order price\n  virtual void on_replace(const OrderPtr& order,\n                          const int64_t& size_delta,\n                          Price new_price) = 0;\n\n  /// @brief callback for an order replace rejection\n  virtual void on_replace_reject(const OrderPtr& order, const char* reason) = 0;\n};\n\n} }\n"
  },
  {
    "path": "src/book/order_tracker.h",
    "content": "// Copyright (c) 2012 - 2017 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#pragma once\n\n#include \"types.h\"\n\nnamespace liquibook { namespace book {\n\n/// @brief Tracker of an order's state, to keep inside the OrderBook.  \n///   Kept separate from the order itself.\ntemplate <typename OrderPtr>\nclass OrderTracker {\npublic:\n  /// @brief construct\n  OrderTracker(const OrderPtr& order, OrderConditions conditions = 0);\n\n  /// @brief modify the order quantity\n  void change_qty(int64_t delta);\n\n  /// @brief fill an order\n  /// @param qty the number of shares filled in this fill\n  void fill(Quantity qty); \n\n  /// @brief is there no remaining open quantity in this order?\n  bool filled() const;\n\n  /// @brief get the total filled quantity of this order\n  Quantity filled_qty() const;\n\n  /// @brief get the open quantity of this order\n  Quantity open_qty() const;\n\n  /// @brief get the order pointer\n  const OrderPtr& ptr() const;\n\n  /// @brief get the order pointer\n  OrderPtr& ptr();\n\n  /// @ brief is this order marked all or none?\n  bool all_or_none() const;\n\n  /// @ brief is this order marked immediate or cancel?\n  bool immediate_or_cancel() const;\n\n  Quantity reserve(int64_t reserved);\n\nprivate:\n  OrderPtr order_;\n  Quantity open_qty_;\n  int64_t reserved_;\n  OrderConditions conditions_;\n};\n\ntemplate <class OrderPtr>\nOrderTracker<OrderPtr>::OrderTracker(\n  const OrderPtr& order,\n  OrderConditions conditions)\n: order_(order),\n  open_qty_(order->order_qty()),\n  reserved_(0),\n  conditions_(conditions)\n{\n#if defined(LIQUIBOOK_ORDER_KNOWS_CONDITIONS)\n  if(order->all_or_none())\n  {\n    conditions |= oc_all_or_none;\n  }\n  if(order->immediate_or_cancel())\n  {\n    conditions |= oc_immediate_or_cancel;\n  }\n#endif\n}\n\ntemplate <class OrderPtr>\nQuantity\nOrderTracker<OrderPtr>::reserve(int64_t reserved)\n{\n  reserved_ += reserved;\n  return open_qty_  - reserved_;\n}\n\ntemplate <class OrderPtr>\nvoid\nOrderTracker<OrderPtr>::change_qty(int64_t delta)\n{\n  if ((delta < 0 && \n      (int)open_qty_ < std::abs(delta))) {\n    throw \n        std::runtime_error(\"Replace size reduction larger than open quantity\");\n  }\n  open_qty_ += delta;\n}\n\ntemplate <class OrderPtr>\nvoid\nOrderTracker<OrderPtr>::fill(Quantity qty) \n{\n  if (qty > open_qty_) {\n    throw std::runtime_error(\"Fill size larger than open quantity\");\n  }\n  open_qty_ -= qty;\n}\n\ntemplate <class OrderPtr>\nbool\nOrderTracker<OrderPtr>::filled() const\n{\n  return open_qty_ == 0;\n}\n\ntemplate <class OrderPtr>\nQuantity\nOrderTracker<OrderPtr>::filled_qty() const\n{\n  return order_->order_qty() - open_qty();\n}\n\n// TODO: Rename this to be available and change the rest of the\n// system to use that, then provide a method to get to the open\n// quantity without considering reserved\ntemplate <class OrderPtr>\nQuantity\nOrderTracker<OrderPtr>::open_qty() const\n{\n  return open_qty_ - reserved_;\n}\n\ntemplate <class OrderPtr>\nconst OrderPtr&\nOrderTracker<OrderPtr>::ptr() const\n{\n  return order_;\n}\n\ntemplate <class OrderPtr>\nOrderPtr&\nOrderTracker<OrderPtr>::ptr()\n{\n  return order_;\n}\n\ntemplate <class OrderPtr>\nbool\nOrderTracker<OrderPtr>::all_or_none() const\n{\n  return bool(conditions_ & oc_all_or_none);\n}\n\ntemplate <class OrderPtr>\nbool\nOrderTracker<OrderPtr>::immediate_or_cancel() const\n{\n    return bool((conditions_ & oc_immediate_or_cancel) != 0);\n}\n\n} }\n"
  },
  {
    "path": "src/book/trade_listener.h",
    "content": "// Copyright (c) 2012, 2013 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#pragma once\n\nnamespace liquibook { namespace book {\n\n/// @brief listener of trade events.   Implement to build a trade feed.\ntemplate <class OrderBook >\nclass TradeListener {\npublic:\n  /// @brief callback for a trade\n  /// @param book the order book of the fill (not defined whether this is before\n  ///      or after fill)\n  /// @param qty the quantity of this fill\n  /// @param price the price of this fill\n  virtual void on_trade(const OrderBook* book,\n                        Quantity qty,\n                        Price price) = 0;\n};\n\n} }\n"
  },
  {
    "path": "src/book/types.h",
    "content": "// Copyright (c) 2012, 2013 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#pragma once\n\n#include <cstdlib>\n#include <cstdint>\n#include <stdexcept>\n\nnamespace liquibook { namespace book {\n  // Types used in Liquibook\n  typedef uint64_t Price;\n  typedef uint64_t Quantity;\n  typedef uint64_t Cost;\n  typedef uint32_t FillId;\n  typedef uint32_t ChangeId;\n  typedef uint32_t OrderConditions;\n\n  enum OrderCondition {\n    oc_no_conditions = 0,\n    oc_all_or_none = 1,\n    oc_immediate_or_cancel = oc_all_or_none << 1,\n    oc_fill_or_kill = oc_all_or_none | oc_immediate_or_cancel,\n    oc_stop = oc_immediate_or_cancel << 1\n  };\n\n  namespace {\n  // Constants used in liquibook API\n  const Price MARKET_ORDER_PRICE(0);\n  const Price PRICE_UNCHANGED(0);\n  const Quantity QUANTITY_MAX(UINT64_MAX);\n  const int64_t SIZE_UNCHANGED(0);\n  }\n\n} } // namespace\n"
  },
  {
    "path": "src/book/version.h",
    "content": "// Copyright (c) 2012 - 2017 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#pragma once\n\nnamespace liquibook {\n\nstruct Version\n{\n  static const int MAJOR = 2;\n  static const int MINOR = 0;\n  static const int PATCH = 0;\n  static const int RELEASE_DATE = 20170222;\n};\n\n}"
  },
  {
    "path": "src/liquibook_export.h",
    "content": "// Copyright (c) 2013 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#ifdef _MSC_VER\n# pragma once\n#endif\n#ifndef liquibook_export_H\n#define liquibook_export_H\n\n// Compile time controls for library generation.  Define with /D or #define\n// To produce or use a static library: #define LIQUIBOOK_HAS_DLL=0\n//   Default is to produce/use a DLL\n// While building the LIQUIBOOK_ library: #define LIQUIBOOK_BUILD_DLL\n//   Default is to export symbols from a pre-built LIQUIBOOK DLL\n//\n// Within LIQUIBOOK use the Liquibook_Export macro where a __declspec is needed.\n\n#if defined (_WIN32)\n\n#  if !defined (LIQUIBOOK_HAS_DLL)\n#    define LIQUIBOOK_HAS_DLL 1\n#  endif /* ! LIQUIBOOK_HAS_DLL */\n\n#  if defined (LIQUIBOOK_HAS_DLL) && (LIQUIBOOK_HAS_DLL == 1)\n#    if defined (LIQUIBOOK_BUILD_DLL)\n#      define Liquibook_Export __declspec(dllexport)\n#    else /* LIQUIBOOK_BUILD_DLL */\n#      define Liquibook_Export __declspec(dllimport)\n#    endif /* LIQUIBOOK_BUILD_DLL */\n#  else /* LIQUIBOOK_HAS_DLL == 1 */\n#    define Liquibook_Export\n#  endif /* LIQUIBOOK_HAS_DLL == 1 */\n\n#  else /* !_WIN32 */\n\n#    define Liquibook_Export __attribute__ ((visibility(\"default\")))\n#  endif /* _WIN32 */\n#endif /* LIQUIBOOK_EXPORT_H */\n\n"
  },
  {
    "path": "src/simple/liquibook_simple.mpc",
    "content": "project : liquibook_lib, liquibook_book {\n  sharedname =\n  staticname = *\n}\n\n"
  },
  {
    "path": "src/simple/simple_order.cpp",
    "content": "// Copyright (c) 2012, 2013 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#include \"simple_order.h\"\n\n#include <iostream>\n\nnamespace liquibook { namespace simple {\n\nuint32_t SimpleOrder::last_order_id_(0);\n\nSimpleOrder::SimpleOrder(\n  bool is_buy,\n  book::Price price,\n  book::Quantity qty,\n  book::Price stop_price,\n  book::OrderConditions conditions)\n: state_(os_new),\n  is_buy_(is_buy),\n  order_qty_(qty),\n  price_(price),\n  stop_price_(stop_price),\n  conditions_(conditions),\n  filled_qty_(0),\n  filled_cost_(0),\n  order_id_(++last_order_id_)\n{\n}\n\nconst OrderState&\nSimpleOrder::state() const\n{\n  return state_;\n}\n\nbool \nSimpleOrder::is_buy() const\n{\n  return is_buy_;\n}\n\nbook::Price\nSimpleOrder::price() const\n{\n  return price_;\n}\n\nbook::Price\nSimpleOrder::stop_price() const\n{\n  return stop_price_;\n}\n\nbook::OrderConditions\nSimpleOrder::conditions() const\n{\n  return conditions_;\n}\n\nbool\nSimpleOrder::all_or_none() const\n{\n  return (conditions_ & book::OrderCondition::oc_all_or_none) != 0;\n}\n\nbool\nSimpleOrder::immediate_or_cancel() const\n{\n  return (conditions_ & book::OrderCondition::oc_immediate_or_cancel) != 0;\n}\nbook::Quantity\nSimpleOrder::order_qty() const\n{\n  return order_qty_;\n}\n\nbook::Quantity\nSimpleOrder::open_qty() const\n{\n  // If not completely filled, calculate\n  if (filled_qty_ < order_qty_) {\n    return order_qty_ - filled_qty_;\n  // Else prevent accidental overflow\n  } else {\n    return 0;\n  }\n}\n\nconst book::Quantity&\nSimpleOrder::filled_qty() const\n{\n  return filled_qty_;\n}\n\nconst book::Cost&\nSimpleOrder::filled_cost() const\n{\n  return filled_cost_;\n}\n\nvoid\nSimpleOrder::fill(book::Quantity fill_qty,\n                  book::Cost fill_cost,\n                  book::FillId /*fill_id*/)\n{\n  filled_qty_ += fill_qty;\n  filled_cost_ += fill_cost;\n  if (!open_qty()) {\n    state_ = os_complete;\n  }\n}\n\nvoid\nSimpleOrder::accept()\n{\n  if (os_new == state_) {\n    state_ = os_accepted;\n  }\n}\n\nvoid\nSimpleOrder::cancel()\n{\n  if (os_complete != state_) {\n    state_ = os_cancelled;\n  }\n}\n\nvoid\nSimpleOrder::replace(book::Quantity size_delta, book::Price new_price)\n{\n  if (os_accepted == state_) {\n    order_qty_ += size_delta;\n    price_ = new_price;\n  }\n}\n\n} }\n\n"
  },
  {
    "path": "src/simple/simple_order.h",
    "content": "// Copyright (c) 2012, 2013 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#pragma once\n\n#define LIQUIBOOK_ORDER_KNOWS_CONDITIONS\n#include <book/order.h>\n#include <book/types.h>\n\nnamespace liquibook { namespace simple {\n\nenum OrderState {\n  os_new,\n  os_accepted,\n  os_complete,\n  os_cancelled,\n  os_rejected\n};\n\n/// @brief impelementation of the Order interface for testing purposes.\nclass SimpleOrder : public book::Order {\npublic:\n  SimpleOrder(bool is_buy,\n              book::Price price,\n              book::Quantity qty,\n              book::Price stop_price = 0,\n              book::OrderConditions conditions = book::OrderCondition::oc_no_conditions);\n\n  /// @brief get the order's state\n  const OrderState& state() const;\n\n  /// @brief is this order a buy?\n  virtual bool is_buy() const;\n\n  /// @brief get the limit price of this order\n  virtual book::Price price() const;\n\n  virtual book::Price stop_price()const;\n\n  /// @brief get the quantity of this order\n  virtual book::Quantity order_qty() const;\n\n  /// @brief get the open quantity of this order\n  virtual book::Quantity open_qty() const;\n\n  /// @brief get the filled quantity of this order\n  virtual const book::Quantity& filled_qty() const;\n\n  /// @brief get the total filled cost of this order\n  const book::Cost& filled_cost() const;\n\n  /// @brief notify of a fill of this order\n  /// @param fill_qty the number of shares in this fill\n  /// @param fill_cost the total amount of this fill\n  /// @fill_id the unique identifier of this fill\n  virtual void fill(book::Quantity fill_qty, \n                    book::Cost fill_cost,\n                    book::FillId fill_id);\n\n  /// @brief get order conditions as a bit mask\n  virtual book::OrderConditions conditions() const;\n\n  /// @brief if no trades should happen until the order\n  /// can be filled completely.\n  /// Note: one or more trades may be used to fill the order.\n  virtual bool all_or_none() const;\n\n  /// @brief After generating as many trades as possible against\n  /// orders already on the market, cancel any remaining quantity.\n  virtual bool immediate_or_cancel() const;\n\n  /// @brief exchange accepted this order\n  void accept();\n  /// @brief exchange cancelled this order\n  void cancel();\n\n  /// @brief exchange replaced this order\n  /// @param size_delta change to the order quantity\n  /// @param new_price the new price\n  void replace(book::Quantity size_delta, book::Price new_price);\n\nprivate:\n  OrderState state_;\n  bool is_buy_;\n  book::Quantity order_qty_;\n  book::Price price_;\n  book::Price stop_price_;\n  book::OrderConditions conditions_;\n  book::Quantity filled_qty_;\n  book::Cost filled_cost_;\n  static uint32_t last_order_id_;\n\npublic:\n  const uint32_t order_id_;\n};\n\n} }\n"
  },
  {
    "path": "src/simple/simple_order_book.h",
    "content": "// Copyright (c) 2012, 2013 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#pragma once\n\n#include \"simple_order.h\"\n#include <book/depth_order_book.h>\n#include <iostream>\n\nnamespace liquibook { namespace simple {\n\n// @brief binding of DepthOrderBook template with SimpleOrder* order pointer.\ntemplate <int SIZE = 5>\nclass SimpleOrderBook : public book::DepthOrderBook<SimpleOrder*, SIZE> {\npublic:\n  typedef book::Callback<SimpleOrder*> SimpleCallback;\n  typedef uint32_t FillId;\n\n  SimpleOrderBook();\n\n  // Override callback handling to update SimpleOrder state\n  virtual void perform_callback(SimpleCallback& cb);\nprivate:\n  FillId fill_id_;\n};\n\ntemplate <int SIZE>\nSimpleOrderBook<SIZE>::SimpleOrderBook() \n: fill_id_(0)\n{\n}\n\ntemplate <int SIZE>\ninline void\nSimpleOrderBook<SIZE>::perform_callback(SimpleCallback& cb)\n{\n  book::DepthOrderBook<SimpleOrder*, SIZE>::perform_callback(cb);\n  switch(cb.type) {\n    case SimpleCallback::cb_order_accept:\n      cb.order->accept();\n      break;\n    case SimpleCallback::cb_order_fill: {\n      // Increment fill ID once\n      ++fill_id_;\n      // Update the orders\n      book::Cost fill_cost = cb.quantity * cb.price;\n      cb.matched_order->fill(cb.quantity, fill_cost, fill_id_);\n      cb.order->fill(cb.quantity, fill_cost, fill_id_);\n      break;\n    }\n    case SimpleCallback::cb_order_cancel:\n      cb.order->cancel();\n      break;\n    case SimpleCallback::cb_order_replace:\n      // Modify the order itself\n      cb.order->replace(cb.delta, cb.price);\n      break;\n    default:\n      // Nothing\n      break;\n  }\n}\n} }\n"
  },
  {
    "path": "test/.gitignore",
    "content": "pt_order_book\nut_all_or_none\nut_bbo_order_book\nut_depth\nut_immediate_or_cancel\nut_listeners\nut_order_book\nut_order_book_shared_ptr\n"
  },
  {
    "path": "test/latency/clock_gettime.h",
    "content": "#pragma once\n// clock_gettime is not defined on Windows / msvc\n// Let's fix that.\n#include <time.h>\n#ifdef _MSC_VER \n// Windows.h should already be included, but Just In Case\n#include <Windows.h>\n\nstatic const int CLOCK_REALTIME = 0;\n\n// The following code was painstakingly programmed (i.e. copy/pasted from stack overflow)\n//  http://stackoverflow.com/questions/5404277/porting-clock-gettime-to-windows\n// Thanks, StackOverflow\nLARGE_INTEGER\ngetFILETIMEoffset()\n{\n    SYSTEMTIME s;\n    FILETIME f;\n    LARGE_INTEGER t;\n\n    s.wYear = 1970;\n    s.wMonth = 1;\n    s.wDay = 1;\n    s.wHour = 0;\n    s.wMinute = 0;\n    s.wSecond = 0;\n    s.wMilliseconds = 0;\n    SystemTimeToFileTime(&s,&f);\n    t.QuadPart = f.dwHighDateTime;\n    t.QuadPart <<= 32;\n    t.QuadPart |= f.dwLowDateTime;\n    return (t);\n}\n\nint\nclock_gettime(int X,struct timespec *tv)\n{\n    LARGE_INTEGER           t;\n    FILETIME            f;\n    double                  microseconds;\n    static LARGE_INTEGER    offset;\n    static double           frequencyToMicroseconds;\n    static int              initialized = 0;\n    static BOOL             usePerformanceCounter = 0;\n\n    if(!initialized) {\n        LARGE_INTEGER performanceFrequency;\n        initialized = 1;\n        usePerformanceCounter = QueryPerformanceFrequency(&performanceFrequency);\n        if(usePerformanceCounter) {\n            QueryPerformanceCounter(&offset);\n            frequencyToMicroseconds = (double)performanceFrequency.QuadPart / 1000000.;\n        } else {\n            offset = getFILETIMEoffset();\n            frequencyToMicroseconds = 10.;\n        }\n    }\n    if(usePerformanceCounter) QueryPerformanceCounter(&t);\n    else {\n        GetSystemTimeAsFileTime(&f);\n        t.QuadPart = f.dwHighDateTime;\n        t.QuadPart <<= 32;\n        t.QuadPart |= f.dwLowDateTime;\n    }\n\n    t.QuadPart -= offset.QuadPart;\n    microseconds = (double)t.QuadPart / frequencyToMicroseconds;\n    t.QuadPart = (LONGLONG)microseconds;\n    tv->tv_sec = (time_t)( t.QuadPart / 1000000);\n    unsigned int uSec = t.QuadPart % 1000000;\n    tv->tv_nsec = uSec * 1000;\n    return 0;\n}\n\n#endif\n"
  },
  {
    "path": "test/latency/liquibook_latency.mpc",
    "content": "project (lt_order_book) : liquibook_book, liquibook_simple, liquibook_test {\n  exename = *\n}\n"
  },
  {
    "path": "test/latency/lt_order_book.cpp",
    "content": "// Copyright (c) 2012, 2013 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#include <simple/simple_order_book.h>\n#include <book/types.h>\n#include \"clock_gettime.h\"\n\n#include <iostream>\n#include <stdexcept>\n#include <stdlib.h>\n\nusing namespace liquibook;\nusing namespace liquibook::book;\n\ntypedef simple::SimpleOrderBook<5> FullDepthOrderBook;\ntypedef simple::SimpleOrderBook<1> BboOrderBook;\ntypedef book::OrderBook<simple::SimpleOrder*> NoDepthOrderBook;\n\nvoid build_histogram(timespec* timestamps, int count) {\n  timespec* prev = nullptr;\n  std::cout << \"Latency (ns) \" << std::endl;\n\n  for (timespec* timestamp = timestamps;\n       (timestamp - timestamps) <= count;\n       ++timestamp)\n  {\n    if (prev) {\n      timespec elapsed;\n      if (timestamp->tv_sec == prev->tv_sec) {\n        elapsed.tv_sec = 0;\n        elapsed.tv_nsec = timestamp->tv_nsec - prev->tv_nsec;\n      } else {\n        // Second changed\n        elapsed.tv_sec = timestamp->tv_sec - prev->tv_sec;\n        // Borrow from sec if necessary\n        if (prev->tv_nsec > timestamp->tv_nsec) {\n          --elapsed.tv_sec;\n          elapsed.tv_nsec = 1000000000 + timestamp->tv_nsec - prev->tv_nsec;\n        } else {\n          elapsed.tv_nsec = timestamp->tv_nsec - prev->tv_nsec;\n        }\n      }\n      if (elapsed.tv_sec) {\n        std::cout << elapsed.tv_sec * 1000000000 + elapsed.tv_nsec << std::endl;\n      } else {\n        std::cout << elapsed.tv_nsec << std::endl;\n      }\n    }\n    prev = timestamp;\n  }\n}\n\ntemplate <class TypedOrderBook, class TypedOrder>\nint run_test(TypedOrderBook& order_book, TypedOrder** orders,\n             timespec* timestamps) {\n  int count = 0;\n  TypedOrder** pp_order = orders;\n  timespec* timestamp = timestamps;\n  do {\n    // Take timestamp at start of each order\n    int status = clock_gettime(CLOCK_REALTIME, timestamp);\n    if (status) {\n      throw std::runtime_error(\"clock_gettime() failed\");\n    }\n    order_book.add(*pp_order);\n    ++pp_order;\n    ++timestamp;\n    if (*pp_order == nullptr) {\n      break;\n    }\n    ++count;\n  } while (true);\n  // Take timestamp at end\n  int status = clock_gettime(CLOCK_REALTIME, timestamp);\n  if (status) {\n    throw std::runtime_error(\"clock_gettime() failed\");\n  }\n  return int(pp_order - orders);\n}\n\ntemplate <class TypedOrderBook>\nbool build_and_run_test(uint32_t num_to_try, bool dry_run = false) {\n  TypedOrderBook order_book;\n  simple::SimpleOrder** orders = new simple::SimpleOrder*[num_to_try + 1];\n  timespec* timestamps = new timespec[num_to_try + 1];\n  \n  for (uint32_t i = 0; i < num_to_try; ++i) {\n    bool is_buy((i % 2) == 0);\n    uint32_t delta = is_buy ? 1880 : 1884;\n    // AsSK 1893\n    // ASK 1892\n    // ASK 1891\n    // ASK 1890\n    // ASK 1889 crossable\n    // ASK 1888 crossable\n    // ASK 1887 crossable\n    // ASK 1886 crossable\n    // ASK 1885 crossable\n    // ASK 1884 crossable\n\n    // BID 1889 crossable\n    // BID 1888 crossable\n    // BID 1887 crossable\n    // BID 1886 crossable\n    // BID 1885 crossable\n    // BID 1884 crossable\n    // BID 1883\n    // BID 1882\n    // BID 1881\n    // BID 1880\n\n    Price price = (rand() % 10) + delta;\n    \n    Quantity qty = ((rand() % 10) + 1) * 100;\n    orders[i] = new simple::SimpleOrder(is_buy, price, qty);\n  }\n  orders[num_to_try] = nullptr; // Final null\n  \n  run_test(order_book, orders, timestamps);\n  for (uint32_t i = 0; i <= num_to_try; ++i) {\n    delete orders[i];\n  }\n  delete [] orders;\n  std::cout << \" - complete!\" << std::endl;\n  uint32_t remain = uint32_t(order_book.bids().size() + order_book.asks().size());\n  if (!dry_run) {\n    std::cout << \"Building histogram\" << std::endl;\n    build_histogram(timestamps, num_to_try);\n  }\n  delete [] timestamps;\n\n  return true;\n}\n\nint main(int argc, const char* argv[])\n{\n  uint32_t num_to_try = 10000;\n  if (argc > 1) {\n    num_to_try = atoi(argv[1]);\n    if (!num_to_try) { \n      num_to_try = 10000;\n    }\n  }\n  std::cout << num_to_try << \" order latency test of order book\" << std::endl;\n  srand(num_to_try);\n\n  {\n    std::cout << \"starting dry run\" << std::endl;\n    build_and_run_test<FullDepthOrderBook>(num_to_try, true);\n  }\n\n  {\n    std::cout << \"testing order book with depth\" << std::endl;\n    build_and_run_test<FullDepthOrderBook>(num_to_try);\n  }\n\n  {\n    std::cout << \"testing order book with bbo\" << std::endl;\n    build_and_run_test<BboOrderBook>(num_to_try);\n  }\n\n  {\n    std::cout << \"testing order book without depth\" << std::endl;\n    build_and_run_test<NoDepthOrderBook>(num_to_try);\n  }\n}\n\n"
  },
  {
    "path": "test/perf/liquibook_perf.mpc",
    "content": "project (pt_order_book) : liquibook_book, liquibook_simple, liquibook_test {\n  exename = *\n}\n"
  },
  {
    "path": "test/perf/pt_order_book.cpp",
    "content": "// Copyright (c) 2012, 2013 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#include <simple/simple_order_book.h>\n#include <book/types.h>\n\n#include <iostream>\n#include <stdexcept>\n#include <stdlib.h>\n#include <time.h>\n\nusing namespace liquibook;\nusing namespace liquibook::book;\n\ntypedef simple::SimpleOrderBook<5> FullDepthOrderBook;\ntypedef simple::SimpleOrderBook<1> BboOrderBook;\ntypedef book::OrderBook<simple::SimpleOrder*> NoDepthOrderBook;\n\ntemplate <class TypedOrderBook, class TypedOrder>\nint run_test(TypedOrderBook& order_book, TypedOrder** orders, clock_t end) {\n  int count = 0;\n  TypedOrder** pp_order = orders;\n  do {\n    order_book.add(*pp_order);\n    ++pp_order;\n    if (*pp_order == nullptr) {\n      return -1;\n    }\n    ++count;\n  } while (clock() < end);\n  return int(pp_order - orders);\n}\n\ntemplate <class TypedOrderBook>\nbool build_and_run_test(uint32_t dur_sec, uint32_t num_to_try) {\n  std::cout << \"trying run of \" << num_to_try << \" orders\";\n  TypedOrderBook order_book;\n  simple::SimpleOrder** orders = new simple::SimpleOrder*[num_to_try + 1];\n  \n  for (uint32_t i = 0; i <= num_to_try; ++i) {\n    bool is_buy((i % 2) == 0);\n    uint32_t delta = is_buy ? 1880 : 1884;\n    // ASK 1893\n    // ASK 1892\n    // ASK 1891\n    // ASK 1890\n    // ASK 1889 crossable\n    // ASK 1888 crossable\n    // ASK 1887 crossable\n    // ASK 1886 crossable\n    // ASK 1885 crossable\n    // ASK 1884 crossable\n\n    // BID 1889 crossable\n    // BID 1888 crossable\n    // BID 1887 crossable\n    // BID 1886 crossable\n    // BID 1885 crossable\n    // BID 1884 crossable\n    // BID 1883\n    // BID 1882\n    // BID 1881\n    // BID 1880\n\n    Price price = (rand() % 10) + delta;\n    \n    Quantity qty = ((rand() % 10) + 1) * 100;\n    orders[i] = new simple::SimpleOrder(is_buy, price, qty);\n  }\n  orders[num_to_try] = nullptr; // Final null\n  \n  clock_t start = clock();\n  clock_t stop = start + (dur_sec * CLOCKS_PER_SEC);\n\n  int count = run_test(order_book, orders, stop);\n  for (uint32_t i = 0; i <= num_to_try; ++i) {\n    delete orders[i];\n  }\n  delete [] orders;\n  if (count > 0) {\n    std::cout << \" - complete!\" << std::endl;\n    std::cout << \"Inserted \" << count << \" orders in \" << dur_sec << \" seconds\"\n              << \", or \" << count / dur_sec << \" insertions per sec\"\n              << std::endl;\n    uint32_t remain = uint32_t(order_book.bids().size() + order_book.asks().size());\n    std::cout << \"Run matched \" << count - remain << \" orders\" << std::endl;\n    return true;\n  } else {\n    std::cout << \" - not enough orders\" << std::endl;\n    return false;\n  }\n\n  return count > 0;\n}\n\nint main(int argc, const char* argv[])\n{\n  uint32_t dur_sec = 3;\n  if (argc > 1) {\n    dur_sec = atoi(argv[1]);\n    if (!dur_sec) { \n      dur_sec = 3;\n    }\n  }\n  std::cout << dur_sec << \" sec performance test of order book\" << std::endl;\n  \n  srand(dur_sec);\n\n  {\n    std::cout << \"testing order book with depth\" << std::endl;\n    uint32_t num_to_try = dur_sec * 125000;\n    while (true) {\n      if (build_and_run_test<FullDepthOrderBook>(dur_sec, num_to_try)) {\n        break;\n      } else {\n        num_to_try *= 2;\n      }\n    }\n  }\n\n  {\n    std::cout << \"testing order book with bbo\" << std::endl;\n    uint32_t num_to_try = dur_sec * 125000;\n    while (true) {\n      if (build_and_run_test<BboOrderBook>(dur_sec, num_to_try)) {\n        break;\n      } else {\n        num_to_try *= 2;\n      }\n    }\n  }\n\n  {\n    std::cout << \"testing order book without depth\" << std::endl;\n    uint32_t num_to_try = dur_sec * 125000;\n    while (true) {\n      if (build_and_run_test<NoDepthOrderBook>(dur_sec, num_to_try)) {\n        break;\n      } else {\n        num_to_try *= 2;\n      }\n    }\n  }\n\n}\n\n"
  },
  {
    "path": "test/unit/changed_checker.h",
    "content": "// Copyright (c) 2012, 2013 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#include <book/depth.h>\n#include <iostream>\n\nnamespace liquibook {\n\nusing book::Depth;\nusing book::DepthLevel;\nusing book::ChangeId;\n\nnamespace test {\n\ntemplate <int SIZE = 5>\nclass ChangedChecker {\npublic:\n  typedef Depth<SIZE> SizedDepth;\n  ChangedChecker(SizedDepth& depth)\n  : depth_(depth)\n  {\n    reset();\n  }\n\n  void reset() {\n    last_change_ = depth_.last_change();\n  }\n\n  bool verify_bid_changed(bool l0, bool l1, bool l2, bool l3, bool l4)\n  {\n    return verify_side_changed(depth_.bids(), l0, l1, l2, l3, l4);\n  }\n  bool verify_ask_changed(bool l0, bool l1, bool l2, bool l3, bool l4)\n  {\n    return verify_side_changed(depth_.asks(), l0, l1, l2, l3, l4);\n  }\n\n  bool verify_bid_stamps(ChangeId l0, ChangeId l1, ChangeId l2, \n                  ChangeId l3, ChangeId l4)\n  {\n    return verify_side_stamps(depth_.bids(), l0, l1, l2, l3, l4);\n  }\n\n  bool verify_ask_stamps(ChangeId l0, ChangeId l1, ChangeId l2, \n                  ChangeId l3, ChangeId l4)\n  {\n    return verify_side_stamps(depth_.asks(), l0, l1, l2, l3, l4);\n  }\n\n  bool verify_bbo_changed(bool bid_changed, bool ask_changed)\n  {\n    bool matched = true;\n    \n    if (depth_.bids()->changed_since(last_change_))\n    {\n      if(! bid_changed) {\n        std::cout << \"best bid unexpected change\" << std::endl;\n        matched = false;\n      }\n    }\n    else if(bid_changed){\n      std::cout << \"best bid expected change\" << std::endl;\n      matched = false;\n    }\n    if (depth_.asks()->changed_since(last_change_)){\n      if(!ask_changed) {\n        std::cout << \"best ask unexpected change\" << std::endl;\n        matched = false;\n      }\n    }\n    else if(ask_changed){\n      std::cout << \"best ask expected change\" << std::endl;\n      matched = false;\n    }\n    return matched;\n  }\n\n  bool verify_bbo_stamps(ChangeId bid_stamp, ChangeId ask_stamp)\n  {\n    bool matched = true;\n    if (depth_.bids()->last_change() != bid_stamp) {\n      std::cout << \"best bid change \" \n                << depth_.bids()->last_change() << std::endl;\n      matched = false;\n    }\n    if (depth_.asks()->last_change() != ask_stamp) {\n      std::cout << \"best ask change \" \n                << depth_.asks()->last_change() << std::endl;\n      matched = false;\n    }\n    return matched;\n  }\n  private:\n  ChangeId last_change_;\n  bool verify_side_stamps(const DepthLevel* start, \n                   ChangeId l0, ChangeId l1, ChangeId l2, \n                   ChangeId l3, ChangeId l4)\n  {\n    bool matched = true;\n    if (start[0].last_change() != l0) {\n      std::cout << \"change id[0] \" << start[0].last_change() << std::endl;\n      matched = false;\n    }\n    if (start[1].last_change() != l1) {\n      std::cout << \"change id[1] \" << start[1].last_change() << std::endl;\n      matched = false;\n    }\n    if (start[2].last_change() != l2) {\n      std::cout << \"change id[2] \" << start[2].last_change() << std::endl;\n      matched = false;\n    }\n    if (start[3].last_change() != l3) {\n      std::cout << \"change id[3] \" << start[3].last_change() << std::endl;\n      matched = false;\n    }\n    if (start[4].last_change() != l4) {\n      std::cout << \"change id[4] \" << start[4].last_change() << std::endl;\n      matched = false;\n    }\n    return matched;\n  }\n\n  bool verify_level(const DepthLevel* levels, size_t index, bool expected)\n  {\n    bool matched = true;\n    if (levels[index].changed_since(last_change_) != expected) \n    {\n      matched = false;\n      if(expected)\n      {\n        std::cout << \"expected change level[\" << index << \"] \" << levels[index].price() << std::endl;\n      }\n      else\n      {\n        std::cout << \"unexpected change level[\" << index << \"] \" << levels[index].price() << std::endl;\n      }\n    }\n    return matched;\n  } \n\n  bool verify_side_changed(const DepthLevel* start,\n                           bool l0, bool l1, bool l2, bool l3, bool l4)\n  {\n    bool matched = true;\n    matched = verify_level(start, 0, l0) && matched;\n    matched = verify_level(start, 1, l1) && matched;\n    matched = verify_level(start, 2, l2) && matched;\n    matched = verify_level(start, 3, l3) && matched;\n    matched = verify_level(start, 4, l4) && matched;\n    return matched;\n  }\n\n  private:\n  SizedDepth& depth_;\n};\n\n} } // namespace\n"
  },
  {
    "path": "test/unit/depth_check.h",
    "content": "// Copyright (c) 2012=2017 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#pragma once\n\n#include <book/order_book.h>\n#include <simple/simple_order_book.h>\n#include <simple/simple_order.h>\n\nusing namespace liquibook::book;\n\nnamespace liquibook {\n\ntemplate<typename SimpleOrderBook>\nclass DepthCheck {\n  typedef typename SimpleOrderBook::DepthTracker SimpleDepth;\n\npublic:\n  DepthCheck(const SimpleDepth& depth) \n  : depth_(depth)\n  {\n    reset();\n  }\n\n  static bool verify_depth(const DepthLevel& level,\n    const Price& price,\n    uint32_t count,\n    const Quantity& qty)\n  {\n    bool matched = true;\n    if (level.price() != price) {\n      std::cout << \"Price \" << level.price() << \" expecting \" << price << std::endl;\n      matched = false;\n    }\n    if (level.order_count() != count) {\n      std::cout << \"Level: \" << level.price() << \" Count \" << level.order_count() << \" expecting \" << count << std::endl;\n      matched = false;\n    }\n    if (level.aggregate_qty() != qty) {\n      std::cout << \"Level: \" << level.price() << \" Quantity \" << level.aggregate_qty() << \" expecting \" << qty << std::endl;\n      matched = false;\n    }\n    if (level.is_excess()) {\n      std::cout << \"Marked as excess\" << std::endl;\n      matched = false;\n    }\n    return matched;\n  }\n\n  bool verify_bid(const Price& price, int count, const Quantity& qty)\n  {\n    return verify_depth(*next_bid_++, price, count, qty);\n  }\n\n  bool verify_ask(const Price& price, int count, const Quantity& qty)\n  {\n    return verify_depth(*next_ask_++, price, count, qty);\n  }\n\n  bool verify_bids_done()\n  {\n    while(next_bid_ != depth_.last_bid_level() + 1)\n    {\n      auto level = *next_bid_;\n      if(level.order_count() != 0)\n      {\n        return false;\n        }\n      ++next_bid_;\n    }\n    return true;\n  }\n\n  bool verify_adds_done()\n  {\n    while(next_ask_ != depth_.last_ask_level() + 1)\n    {\n      auto level = *next_ask_;\n      if(level.order_count() != 0)\n      {\n        return false;\n      }\n      ++next_bid_;\n    }\n    return true;\n  }\n\n  void reset()\n  {\n    next_bid_ = depth_.bids();\n    next_ask_ = depth_.asks();\n  }\n\nprivate:\n  const SimpleDepth& depth_;\n  const DepthLevel* next_bid_;\n  const DepthLevel* next_ask_;\n};\n\n} // namespace\n"
  },
  {
    "path": "test/unit/liquibook_unit.mpc",
    "content": "project (liquibook_unit_test) : liquibook_test, boost_unit_test_framework, boost_base{\n   exename = *\n   \n   specific(make) {\n      macros += BOOST_TEST_DYN_LINK\n   }\n}\n"
  },
  {
    "path": "test/unit/ut_all_or_none.cpp",
    "content": "// Copyright (c) 2012 - 2017 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n\n#define BOOST_TEST_NO_MAIN LiquibookTest\n#include <boost/test/unit_test.hpp>\n\n#include \"ut_utils.h\"\n\nnamespace liquibook {\n\nusing simple::SimpleOrder;\ntypedef FillCheck<SimpleOrder*> SimpleFillCheck;\n\nnamespace {\nconst OrderConditions AON(oc_all_or_none);\nconst OrderConditions noConditions(0);\n\nconst Quantity qty1 = 100;\nconst Quantity qty2 = qty1 + qty1;\nconst Quantity qty3 = qty2 + qty1;\nconst Quantity qty4 = qty2 + qty2;\nconst Quantity qty6 = qty2 + qty4;\nconst Quantity qty7 = 700; // derive this?\nconst Quantity qtyNone = 0;\n\nconst Price prc0 = 1250;\nconst Price prc1 = 1251;\nconst Price prc2 = 1252;\nconst Price prc3 = 1253;\nconst Price prcNone = 0;\nconst Price MARKET_ORDER_PRICE = MARKET_ORDER_PRICE;\n\nconst bool buySide = true;\nconst bool sellSide = false;\nconst bool expectMatch = true;\nconst bool expectNoMatch = false;\nconst bool expectComplete = true;\nconst bool expectNoComplete = false;\n\n}\n\n\nBOOST_AUTO_TEST_CASE(TestRegBidMatchAon)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask2(sellSide, prc2, qty1);\n  SimpleOrder ask1(sellSide, prc1, qty1); // AON\n  SimpleOrder ask0(sellSide, prc1, qty2); // AON, but skipped\n  SimpleOrder bid1(buySide, prc1, qty1);\n  SimpleOrder bid0(buySide, prc0, qty1);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, expectNoMatch, expectNoComplete, AON));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, expectNoMatch, expectNoComplete, AON));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, expectNoMatch));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1UL, order_book.bids().size());\n  BOOST_CHECK_EQUAL(3UL, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(prc0, 1, qty1));\n  BOOST_CHECK(dc.verify_ask(prc1, 2, qty1 + qty2));\n  BOOST_CHECK(dc.verify_ask(prc2, 1, qty1));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc1(&bid1, qty1, prc1 * qty1);\n    SimpleFillCheck fc2(&ask1, qty1, prc1 * qty1);\n    BOOST_CHECK(add_and_verify(order_book, &bid1, expectMatch, expectComplete));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(prc0, 1, qty1));\n  BOOST_CHECK(dc.verify_ask(prc1, 1, qty2));\n  BOOST_CHECK(dc.verify_ask(prc2, 1, qty1));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n}\n\nBOOST_AUTO_TEST_CASE(TestRegBidMatchMulti)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask2(sellSide, prc1, qty7);\n  SimpleOrder ask1(sellSide, prc1, qty1); // AON\n  SimpleOrder ask0(sellSide, prc1, qty1); // AON\n  SimpleOrder bid1(buySide, prc1, qty4);\n  SimpleOrder bid0(buySide, prc0, qty1);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, expectNoMatch, expectNoComplete, AON));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, expectNoMatch, expectNoComplete, AON));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, expectNoMatch, expectNoComplete));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(3, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(prc0, 1, qty1));\n  BOOST_CHECK(dc.verify_ask(prc1, 3, qty7 + qty1 + qty1));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc0(&bid1, qty4, prc1 * qty4);\n    SimpleFillCheck fc1(&ask0, qty1, prc1 * qty1);\n    SimpleFillCheck fc2(&ask1, qty1, prc1 * qty1);\n    SimpleFillCheck fc3(&ask2, qty2, prc1 * qty2);\n    BOOST_CHECK(add_and_verify(order_book, &bid1, expectMatch, expectComplete));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(prc0, 1, qty1));\n  BOOST_CHECK(dc.verify_ask(prc1, 1, qty4 + qty1));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n}\n\nBOOST_AUTO_TEST_CASE(TestAonBidNoMatch)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask1(sellSide, prc2, qty1); // no match, price\n  SimpleOrder ask0(sellSide, prc1, qty1); \n  SimpleOrder bid1(buySide, prc1, qty3); // no match, AON\n  SimpleOrder bid0(buySide, prc0, qty1); // no match, price\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, expectNoMatch));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(prc0, 1, qty1));\n  BOOST_CHECK(dc.verify_ask(prc1, 1, qty1));\n  BOOST_CHECK(dc.verify_ask(prc2, 1, qty1));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc1(&bid1, qtyNone, prcNone);\n    SimpleFillCheck fc2(&ask0, qtyNone, prcNone);\n    BOOST_CHECK(add_and_verify(order_book, &bid1, expectNoMatch, expectNoComplete, AON));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(prc1, 1, qty3));\n  BOOST_CHECK(dc.verify_bid(prc0, 1, qty1));\n  BOOST_CHECK(dc.verify_ask(prc1, 1, qty1));\n  BOOST_CHECK(dc.verify_ask(prc2, 1, qty1));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n}\n\nBOOST_AUTO_TEST_CASE(TestAonBidMatchReg)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask1(sellSide, prc2, qty1);\n  SimpleOrder ask0(sellSide, prc1, qty4);\n  SimpleOrder bid1(buySide, prc1, qty3); // AON\n  SimpleOrder bid0(buySide, prc0, qty1);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, expectNoMatch));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(prc0, 1, qty1));\n  BOOST_CHECK(dc.verify_ask(prc1, 1, qty4));\n  BOOST_CHECK(dc.verify_ask(prc2, 1, qty1));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc1(&bid1, qty3, prc1 * qty3);\n    SimpleFillCheck fc2(&ask0, qty3, prc1 * qty3);\n    BOOST_CHECK(add_and_verify(order_book, &bid1, expectMatch, expectComplete, AON));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(prc0, 1, qty1));\n  BOOST_CHECK(dc.verify_ask(prc1, 1, qty1));\n  BOOST_CHECK(dc.verify_ask(prc2, 1, qty1));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n}\n\nBOOST_AUTO_TEST_CASE(TestAonBidMatchMulti)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask3(sellSide, prc2, qty1);\n  SimpleOrder ask2(sellSide, prc2, qty1);\n  SimpleOrder ask1(sellSide, prc1, qty4); // AON no match\n  SimpleOrder ask0(sellSide, prc1, qty4);\n  SimpleOrder bid1(buySide, MARKET_ORDER_PRICE, qty6); // AON\n  SimpleOrder bid0(buySide, prc0, qty1);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, expectNoMatch, expectNoComplete, AON));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &ask3, expectNoMatch));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(4, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(prc0, 1, qty1));\n  BOOST_CHECK(dc.verify_ask(prc1, 2, qty4 + qty4));\n  BOOST_CHECK(dc.verify_ask(prc2, 2, qty1 + qty1));\n\n  // Match - complete\n  { \n  //ASSERT_NO_THROW(\n    SimpleFillCheck fc1(&bid1, qty6, prc1 * qty2 + prc1 * qty4);\n    SimpleFillCheck fc2(&ask0, qty2, prc1 * qty2);\n    SimpleFillCheck fc3(&ask1, qty4, prc1 * qty4);\n    SimpleFillCheck fc4(&ask2, 0, prc2 * 0);\n    SimpleFillCheck fc5(&ask3, 0, prc2 * 0);\n    BOOST_CHECK(add_and_verify(order_book, &bid1, expectMatch, expectComplete, AON));\n  //); \n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(prc0, 1, qty1));\n  BOOST_CHECK(dc.verify_ask(prc1, 1, qty2));\n  BOOST_CHECK(dc.verify_ask(prc2, 2, qty1 + qty1));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(3, order_book.asks().size());\n}\n\nBOOST_AUTO_TEST_CASE(TestAonBidNoMatchMulti)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask2(sellSide, prc2, qty4); // AON no match\n  SimpleOrder ask1(sellSide, prc2, qty1);\n  SimpleOrder ask0(sellSide, prc1, qty4);\n  SimpleOrder bid1(buySide, MARKET_ORDER_PRICE, qty6); // AON\n  SimpleOrder bid0(buySide, prc0, qty1);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, expectNoMatch, expectNoComplete, AON));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(3, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(prc0, 1, qty1));\n  BOOST_CHECK(dc.verify_ask(prc1, 1, qty4));\n  BOOST_CHECK(dc.verify_ask(prc2, 2, qty4 + qty1));\n\n  // Match - complete\n  { \n  //ASSERT_NO_THROW(\n    SimpleFillCheck fc0(&bid0, qtyNone, prcNone);\n    SimpleFillCheck fc1(&bid1, qty6, qty2 * prc1 + qty4 * prc2); // filled 600 @ 751000\n    SimpleFillCheck fc2(&ask0, qty2, qty2 * prc1); // filled 200 @ 250200\n    SimpleFillCheck fc3(&ask1, qtyNone, prcNone); // 0\n    SimpleFillCheck fc4(&ask2, qty4, qty4 * prc2); // filled 400 @ 500800\n    BOOST_CHECK(add_and_verify(order_book, &bid1, expectMatch, expectComplete, AON));\n  //); \n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(prc0, 1, qty1));\n  BOOST_CHECK(dc.verify_ask(prc1, 1, qty2));\n}\n\nBOOST_AUTO_TEST_CASE(TestAonBidMatchAon)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask1(sellSide, prc2, qty1);\n  SimpleOrder ask0(sellSide, prc1, qty3); // AON\n  SimpleOrder bid1(buySide, prc1, qty3); // AON\n  SimpleOrder bid0(buySide, prc0, qty1);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, expectNoMatch, expectNoComplete, AON));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, expectNoMatch));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(prc0, 1, qty1));\n  BOOST_CHECK(dc.verify_ask(prc1, 1, qty3));\n  BOOST_CHECK(dc.verify_ask(prc2, 1, qty1));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc1(&bid1, qty3, prc1 * qty3);\n    SimpleFillCheck fc2(&ask0, qty3, prc1 * qty3);\n    BOOST_CHECK(add_and_verify(order_book, &bid1, expectMatch, expectComplete, AON));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(prc0, 1, qty1));\n  BOOST_CHECK(dc.verify_ask(prc2, 1, qty1));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n}\n\nBOOST_AUTO_TEST_CASE(TestRegAskMatchAon)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(sellSide, prc2, qty1);\n  SimpleOrder ask1(sellSide, prc1, qty1);\n  SimpleOrder bid1(buySide, prc1, qty2); // AON, but skipped\n  SimpleOrder bid2(buySide, prc1, qty1); // AON\n  SimpleOrder bid0(buySide, prc0, qty1);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, expectNoMatch, expectNoComplete, AON));\n  BOOST_CHECK(add_and_verify(order_book, &bid2, expectNoMatch, expectNoComplete, AON));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, expectNoMatch));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(3, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(prc1, 2, qty3));\n  BOOST_CHECK(dc.verify_bid(prc0, 1, qty1));\n  BOOST_CHECK(dc.verify_ask(prc2, 1, qty1));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc1(&bid2, qty1, prc1 * qty1);\n    SimpleFillCheck fc2(&ask1, qty1, prc1 * qty1);\n    BOOST_CHECK(add_and_verify(order_book, &ask1, expectMatch, expectComplete));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(prc1, 1, qty2));\n  BOOST_CHECK(dc.verify_bid(prc0, 1, qty1));\n  BOOST_CHECK(dc.verify_ask(prc2, 1, qty1));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n}\n\nBOOST_AUTO_TEST_CASE(TestRegAskMatchMulti)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(sellSide, prc2, qty1);\n  SimpleOrder ask1(sellSide, prc0, qty4);\n  SimpleOrder bid1(buySide, prc1, qty1); // AON\n  SimpleOrder bid2(buySide, prc1, qty1); // AON\n  SimpleOrder bid0(buySide, prc0, qty7);\n\n  // Calculate some expected results\n  // ask1(400) matches bid 1(100), bid2(100), and part(200) of bid0 \n  // leaving 500 shares of bid 0)\n  Quantity bid0FillQty = qty4 - qty1 - qty1;\n  Quantity bid0RemainQty = qty7 - bid0FillQty;\n  uint32_t bid0FillAmount = bid0FillQty * prc0;\n  uint32_t bid1FillAmount = prc1 * qty1;\n  uint32_t bid2FillAmount = prc1 * qty1;\n  uint32_t ask1FillAmount = bid1FillAmount + bid2FillAmount + bid0FillAmount;\n  \n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &bid0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, expectNoMatch, expectNoComplete, AON));\n  BOOST_CHECK(add_and_verify(order_book, &bid2, expectNoMatch, expectNoComplete, AON));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(3, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(prc1, 2, qty2));\n  BOOST_CHECK(dc.verify_bid(prc0, 1, qty7));\n  BOOST_CHECK(dc.verify_ask(prc2, 1, qty1));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc0(&bid1, qty1, prc1 * qty1);\n    SimpleFillCheck fc1(&bid2, qty1, prc1 * qty1);\n    SimpleFillCheck fc2(&bid0, qty2, prc0 * qty2);\n    SimpleFillCheck fc3(&ask1, qty4, ask1FillAmount);\n    BOOST_CHECK(add_and_verify(order_book, &ask1, expectMatch, expectComplete));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(prc0, 1, bid0RemainQty));\n  BOOST_CHECK(dc.verify_ask(prc2, 1, qty1));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n}\n\nBOOST_AUTO_TEST_CASE(TestAonAskNoMatch)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(sellSide, prc2, qty1);\n  SimpleOrder ask1(sellSide, prc1, qty4); // AON\n  SimpleOrder bid1(buySide, prc1, qty1);\n  SimpleOrder bid2(buySide, prc1, qty1);\n  SimpleOrder bid0(buySide, prc0, qty7);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &bid0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &bid2, expectNoMatch));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(3, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(prc1, 2, qty2));\n  BOOST_CHECK(dc.verify_bid(prc0, 1, qty7));\n  BOOST_CHECK(dc.verify_ask(prc2, 1, qty1));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc0(&bid1, qtyNone, prcNone);\n    SimpleFillCheck fc1(&bid2, qtyNone, prcNone);\n    SimpleFillCheck fc2(&bid0, qtyNone, prcNone);\n    SimpleFillCheck fc3(&ask1, qtyNone, prcNone);\n    BOOST_CHECK(add_and_verify(order_book, &ask1, expectNoMatch, expectNoComplete, AON));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(prc1, 2, qty2));\n  BOOST_CHECK(dc.verify_bid(prc0, 1, qty7));\n  BOOST_CHECK(dc.verify_ask(prc1, 1, qty4));\n  BOOST_CHECK(dc.verify_ask(prc2, 1, qty1));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(3, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n}\n\nBOOST_AUTO_TEST_CASE(TestAonAskMatchReg)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(sellSide, prc2, qty1);\n  SimpleOrder ask1(sellSide, prc1, qty1); // AON\n  SimpleOrder bid1(buySide, prc1, qty1);\n  SimpleOrder bid0(buySide, prc0, qty7);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &bid0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, expectNoMatch));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(prc1, 1, qty1));\n  BOOST_CHECK(dc.verify_bid(prc0, 1, qty7));\n  BOOST_CHECK(dc.verify_ask(prc2, 1, qty1));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc0(&bid1, qty1, prc1 * qty1);\n    SimpleFillCheck fc3(&ask1, qty1, prc1 * qty1);\n    BOOST_CHECK(add_and_verify(order_book, &ask1, expectMatch, expectComplete, AON));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(prc0, 1, qty7));\n  BOOST_CHECK(dc.verify_ask(prc2, 1, qty1));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n}\n\nBOOST_AUTO_TEST_CASE(TestAonAskMatchMulti)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(sellSide, prc2, qty1); // no match due to price\n  SimpleOrder ask1(sellSide, prc0, qty6); // AON\n  SimpleOrder bid1(buySide, prc1, qty1); // AON\n  SimpleOrder bid2(buySide, prc1, qty1);\n  SimpleOrder bid3(buySide, prc1, qty1);\n  SimpleOrder bid0(buySide, prc0, qty7);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &bid0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, expectNoMatch, expectNoComplete, AON));\n  BOOST_CHECK(add_and_verify(order_book, &bid2, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &bid3, expectNoMatch));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(4, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(prc1, 3, qty3));\n  BOOST_CHECK(dc.verify_bid(prc0, 1, qty7));\n  BOOST_CHECK(dc.verify_ask(prc2, 1, qty1));\n\n  // Match - complete\n  { \n  // ASSERT_NO_THROW(\n    \n    uint32_t b1Cost = prc1 * qty1;\n    SimpleFillCheck fc0(&bid1, qty1, b1Cost);\n    uint32_t b2Cost = prc1 * qty1;\n    SimpleFillCheck fc1(&bid2, qty1, b2Cost);\n    uint32_t b3Cost = prc1 * qty1;\n    SimpleFillCheck fc2(&bid3, qty1, b3Cost);\n    Quantity b0Fill = qty6 - qty1 - qty1 - qty1;\n    uint32_t b0Cost = b0Fill * prc0;\n    SimpleFillCheck fc3(&bid0, b0Fill, b0Cost);\n    uint32_t a1Cost = b0Cost + b1Cost +b2Cost + b3Cost;\n    SimpleFillCheck fc4(&ask1, qty6, a1Cost);\n    BOOST_CHECK(add_and_verify(order_book, &ask1, expectMatch, expectComplete, AON));\n  // ); \n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(prc0, 1, qty4));\n  BOOST_CHECK(dc.verify_ask(prc2, 1, qty1));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n}\n///////////////////\n\nBOOST_AUTO_TEST_CASE(TestOneAonBidOneAonAsk)\n{\n    SimpleOrderBook order_book;\n    SimpleOrder bid1(buySide,prc1,qty1); // AON\n    SimpleOrder ask1(sellSide,prc1,qty1); // AON\n\n    // Prime the order book: No Matches\n    BOOST_CHECK(add_and_verify(order_book,&bid1,expectNoMatch,expectNoComplete,AON));\n\n    // Verify sizes\n    BOOST_CHECK_EQUAL(1u,order_book.bids().size());\n    BOOST_CHECK_EQUAL(0u,order_book.asks().size());\n\n    // Verify depth\n    DepthCheck<SimpleOrderBook> dc(order_book.depth());\n    BOOST_CHECK(dc.verify_bid(prc1 , 1, qty1));\n\n    // Add matching order\n    {\n        SimpleFillCheck fc1(&bid1,qty1, qty1 * prc1);\n        SimpleFillCheck fc3(&ask1,qty1, qty1 * prc1);\n        BOOST_CHECK(add_and_verify(order_book, &ask1, expectMatch, expectComplete, AON));\n    }\n\n    // Verify sizes\n    BOOST_CHECK_EQUAL(0,order_book.bids().size());\n    BOOST_CHECK_EQUAL(0,order_book.asks().size());\n}\n\nBOOST_AUTO_TEST_CASE(TestTwoAonBidOneAonAsk)\n{\n    SimpleOrderBook order_book;\n    SimpleOrder bid1(buySide,prc1,qty1); // AON\n    SimpleOrder bid2(buySide,prc1,qty2); // AON\n    SimpleOrder ask1(sellSide,prc1,qty3); // AON\n\n    // Prime the order book: No Matches\n    BOOST_CHECK(add_and_verify(order_book, &bid1, expectNoMatch, expectNoComplete,AON));//AON)); //noConditions\n    BOOST_CHECK(add_and_verify(order_book, &bid2,expectNoMatch,expectNoComplete,AON));\n\n    // Verify sizes\n    BOOST_CHECK_EQUAL(2u,order_book.bids().size());\n    BOOST_CHECK_EQUAL(0u,order_book.asks().size());\n\n    // Verify depth\n    DepthCheck<SimpleOrderBook> dc(order_book.depth());\n    BOOST_CHECK(dc.verify_bid(prc1, 2, qty1 + qty2));\n\n    // Add matching order\n    {\n        SimpleFillCheck fc1(&bid1, qty1, qty1 * prc1);\n        SimpleFillCheck fc2(&bid2, qty2, qty2 * prc1);\n        SimpleFillCheck fc3(&ask1, qty3, qty3 * prc1);\n        BOOST_CHECK(add_and_verify(order_book, &ask1, expectMatch, expectComplete, AON));\n    }\n\n    // Verify sizes\n    BOOST_CHECK_EQUAL(0,order_book.bids().size());\n    BOOST_CHECK_EQUAL(0,order_book.asks().size());\n\n}\n\nBOOST_AUTO_TEST_CASE(TestOneAonBidTwoAsk)\n{\n    SimpleOrderBook order_book;\n\n    SimpleOrder bid1(buySide,prc1,qty3); // AON\n    SimpleOrder ask1(sellSide,prc1,qty1); // No Conditions\n    SimpleOrder ask2(sellSide,prc1,qty2); // No Conditions\n\n    // Prime the order book: No Matches\n    BOOST_CHECK(add_and_verify(order_book,&bid1,expectNoMatch,expectNoComplete,AON));//AON)); //noConditions\n\n    // Add an order that does NOT meet the AON condition\n    BOOST_CHECK(add_and_verify(order_book,&ask1,expectNoMatch,expectNoComplete,noConditions));\n    // Verify sizes\n    BOOST_CHECK_EQUAL(1u,order_book.bids().size());\n    BOOST_CHECK_EQUAL(1u,order_book.asks().size());\n\n    // Verify depth\n    DepthCheck<SimpleOrderBook> dc(order_book.depth());\n    BOOST_CHECK(dc.verify_bid(prc1,1,qty3));\n    BOOST_CHECK(dc.verify_ask(prc1,1,qty1));\n\n    // Add matching order\n    {\n        SimpleFillCheck fc1(&bid1,qty3,qty3 * prc1);\n    SimpleFillCheck fc2(&ask1,qty1,qty1 * prc1);\n    SimpleFillCheck fc3(&ask2,qty2,qty2 * prc1);\n    BOOST_CHECK(add_and_verify(order_book,&ask2,expectMatch,expectComplete,noConditions));\n    }\n\n    // Verify sizes\n    BOOST_CHECK_EQUAL(0,order_book.bids().size());\n    BOOST_CHECK_EQUAL(0,order_book.asks().size());\n}\n\nBOOST_AUTO_TEST_CASE(TestOneBidTwoAonAsk)\n{\n    SimpleOrderBook order_book;\n\n    SimpleOrder bid1(buySide,prc1,qty3); // noConditions\n    SimpleOrder ask1(sellSide,prc1,qty1); // AON \n    SimpleOrder ask2(sellSide,prc1,qty2); // AON\n\n    // Prime the order book: No Matches\n    BOOST_CHECK(add_and_verify(order_book,&bid1,expectNoMatch,expectNoComplete,AON));\n\n    // Verify sizes\n    BOOST_CHECK_EQUAL(1u,order_book.bids().size());\n    BOOST_CHECK_EQUAL(0u,order_book.asks().size());\n\n    // Verify depth\n    DepthCheck<SimpleOrderBook> dc(order_book.depth());\n    BOOST_CHECK(dc.verify_bid(prc1,1,qty3));\n\n    // Add matching order\n    {\n        SimpleFillCheck fc1(&bid1,qty3,qty3 * prc1);\n        SimpleFillCheck fc2(&ask1,qty1,qty1 * prc1);\n        SimpleFillCheck fc3(&ask2,qty2,qty2 * prc1);\n        BOOST_CHECK(add_and_verify(order_book,&ask1,expectNoMatch,expectNoComplete,noConditions));\n        BOOST_CHECK(add_and_verify(order_book,&ask2,expectMatch,expectComplete,noConditions));\n    }\n\n    // Verify sizes\n    BOOST_CHECK_EQUAL(0,order_book.bids().size());\n    BOOST_CHECK_EQUAL(0,order_book.asks().size());\n}\n\nBOOST_AUTO_TEST_CASE(TestTwoAonBidTwoAonAsk)\n{\n#if 1\n    int todo_FixTestAonsTwoBidTwoAsk;\n    std::cout << \"***** WARNING TEST \" << \"TestAonsTwoBidTwoAsk\" << \" is disabled\" << std::endl;\n#else\n  // The current match algorithm tries to match one order from one side of the market to \"N\" orders\n  // from the other side.   This test won't pass because it requires two orders from each side.\n  // I'm leaving the test here as a challenge to future developers who want to improve the matching\n  // algorithm (good luck)\n\n  SimpleOrderBook order_book;\n\n  SimpleOrder ask1(sellSide,prc1,qty3); // AON\n  SimpleOrder ask2(sellSide,prc1,qty2); // AON\n\n  SimpleOrder bid1(buySide,prc1,qty1); // AON\n  SimpleOrder bid2(buySide,prc1,qty4); // AON\n\n                                        // Prime the order book: No Matches\n  BOOST_CHECK(add_and_verify(order_book,&bid1,expectNoMatch,expectNoComplete,AON));\n  BOOST_CHECK(add_and_verify(order_book,&bid2,expectNoMatch,expectNoComplete,AON));\n  BOOST_CHECK(add_and_verify(order_book,&ask1,expectNoMatch,expectNoComplete,AON));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2u,order_book.bids().size());\n  BOOST_CHECK_EQUAL(1u,order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(prc1,2,qty1 + qty4));\n  BOOST_CHECK(dc.verify_ask(prc1,1,qty3));\n\n  // Add matching order\n  {\n      SimpleFillCheck fc1(&bid1,qty1,qty3 * prc1);\n  SimpleFillCheck fc2(&bid2,qty4,qty3 * prc1);\n  SimpleFillCheck fc3(&ask1,qty3,qty1 * prc1);\n  SimpleFillCheck fc4(&ask2,qty2,qty2 * prc1);\n  BOOST_CHECK(add_and_verify(order_book,&ask2,expectMatch,expectComplete,AON));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(0,order_book.bids().size());\n  BOOST_CHECK_EQUAL(0,order_book.asks().size());\n#endif\n}\n\nBOOST_AUTO_TEST_CASE(TestAonAskNoMatchMulti)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(sellSide, prc2, qty1); // no match (price)\n  SimpleOrder ask1(sellSide, prc0, qty6); // AON\n\n  SimpleOrder bid0(buySide, prc0, qty4); // AON no match\n  SimpleOrder bid1(buySide, prc1, qty1); // AON\n  SimpleOrder bid2(buySide, prc1, qty4);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &bid0, expectNoMatch, expectNoComplete,AON));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, expectNoMatch, expectNoComplete,AON));//AON)); //noConditions\n  BOOST_CHECK(add_and_verify(order_book, &bid2, expectNoMatch));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(3, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(prc1, 2, qty1 + qty4));\n  BOOST_CHECK(dc.verify_bid(prc0, 1, qty4));\n  BOOST_CHECK(dc.verify_ask(prc2, 1, qty1));\n\n  // This test was bogus -- testing a bug in the matching algorithm\n  // I fixed the bug and the test started to fail.\n  // So fixed the test to expect:\n  // Ask1 (600 AON) should match bid0 (400 AON) + bid1(100) + bid 2(100 of 400)\n  //\n  // Now we need a new test of an AON that should NOT match!\n\n  // No match\n  { \n//  ASSERT_NO_THROW(\n    SimpleFillCheck fc0(&bid0, qty4, prc0 * qty4);\n    SimpleFillCheck fc1(&bid1, qty1, qty1 * prc1);\n    SimpleFillCheck fc2(&bid2, qty1, prc1 * qty1);\n    SimpleFillCheck fc3(&ask1, qty6, prc0 * qty4 + qty1 * prc1 + prc1 * qty1);\n    BOOST_CHECK(add_and_verify(order_book, &ask1, expectMatch, expectComplete, AON));\n  //); \n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(prc1, 1, qty4 - qty1));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n}\n\nBOOST_AUTO_TEST_CASE(TestAonAskMatchAon)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(sellSide, prc2, qty1);\n  SimpleOrder ask1(sellSide, prc1, qty2); // AON\n  SimpleOrder bid1(buySide, prc1, qty2); // AON\n  SimpleOrder bid0(buySide, prc0, qty4);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &bid0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, expectNoMatch, expectNoComplete, AON));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_ask(prc2, 1, qty1));\n  BOOST_CHECK(dc.verify_bid(prc1, 1, qty2));\n  BOOST_CHECK(dc.verify_bid(prc0, 1, qty4));\n\n  // Match complete\n  {\n    SimpleFillCheck fc1(&bid1, qty2, prc1 * qty2);\n    SimpleFillCheck fc3(&ask1, qty2, prc1 * qty2);\n    BOOST_CHECK(add_and_verify(order_book, &ask1, expectMatch, expectComplete, AON));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_ask(prc2, 1, qty1));\n  BOOST_CHECK(dc.verify_bid(prc0, 1, qty4));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n}\n\nBOOST_AUTO_TEST_CASE(TestReplaceAonBidSmallerMatch)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask2(sellSide, prc3, qty1);\n  SimpleOrder ask1(sellSide, prc2, qty1);\n  SimpleOrder ask0(sellSide, prc1, qty1);\n  SimpleOrder bid1(buySide, prc1, qty2); // AON\n  SimpleOrder bid0(buySide, prc0, qty1);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, expectNoMatch, expectNoComplete, AON));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, expectNoMatch));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(3, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(prc1, 1, qty2));\n  BOOST_CHECK(dc.verify_bid(prc0, 1, qty1));\n  BOOST_CHECK(dc.verify_ask(prc1, 1, qty1));\n  BOOST_CHECK(dc.verify_ask(prc2, 1, qty1));\n  BOOST_CHECK(dc.verify_ask(prc3, 1, qty1));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc2(&ask0, qty1, prc1 * qty1);\n    BOOST_CHECK(replace_and_verify(\n        order_book, &bid1, -(int32_t)qty1, PRICE_UNCHANGED, simple::os_complete, qty1));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(prc0, 1, qty1));\n  BOOST_CHECK(dc.verify_ask(prc2, 1, qty1));\n  BOOST_CHECK(dc.verify_ask(prc3, 1, qty1));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n}\n\nBOOST_AUTO_TEST_CASE(TestReplaceAonBidPriceMatch)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask2(sellSide, prc3, qty1);\n  SimpleOrder ask1(sellSide, prc2, qty1);\n  SimpleOrder ask0(sellSide, prc1, qty1);\n  SimpleOrder bid1(buySide, prc1, qty2); // AON\n  SimpleOrder bid0(buySide, prc0, qty1);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, expectNoMatch, expectNoComplete, AON));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, expectNoMatch));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(3, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(prc1, 1, qty2));\n  BOOST_CHECK(dc.verify_bid(prc0, 1, qty1));\n  BOOST_CHECK(dc.verify_ask(prc1, 1, qty1));\n  BOOST_CHECK(dc.verify_ask(prc2, 1, qty1));\n  BOOST_CHECK(dc.verify_ask(prc3, 1, qty1));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc1(&ask0, qty1, prc1 * qty1);\n    SimpleFillCheck fc2(&ask1, qty1, prc2 * qty1);\n    BOOST_CHECK(replace_and_verify(\n        order_book, &bid1, qtyNone, prc2, simple::os_complete, qty2));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(prc0, 1, qty1));\n  BOOST_CHECK(dc.verify_ask(prc3, 1, qty1));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n}\n\nBOOST_AUTO_TEST_CASE(TestReplaceBidLargerMatchAon)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask2(sellSide, prc3, qty1);\n  SimpleOrder ask1(sellSide, prc2, qty1);\n  SimpleOrder ask0(sellSide, prc1, qty2); // AON\n  SimpleOrder bid1(buySide, prc1, qty1);\n  SimpleOrder bid0(buySide, prc0, qty1);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, expectNoMatch, expectNoComplete, AON));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, expectNoMatch));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(3, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(prc1, 1, qty1));\n  BOOST_CHECK(dc.verify_bid(prc0, 1, qty1));\n  BOOST_CHECK(dc.verify_ask(prc1, 1, qty2));\n  BOOST_CHECK(dc.verify_ask(prc2, 1, qty1));\n  BOOST_CHECK(dc.verify_ask(prc3, 1, qty1));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc2(&ask0, qty2, qty2 * prc1);\n    BOOST_CHECK(replace_and_verify(\n        order_book, &bid1, qty1, PRICE_UNCHANGED, simple::os_complete, qty2));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(prc0, 1, qty1));\n  BOOST_CHECK(dc.verify_ask(prc2, 1, qty1));\n  BOOST_CHECK(dc.verify_ask(prc3, 1, qty1));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n}\n\n} // Namespace\n"
  },
  {
    "path": "test/unit/ut_bbo_order_book.cpp",
    "content": "// Copyright (c) 2012 - 2017 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n\n#define BOOST_TEST_NO_MAIN LiquibookTest\n#include <boost/test/unit_test.hpp>\n\n#include <book/depth_constants.h>\n#include <book/order_book.h>\n#include <simple/simple_order.h>\n#include <simple/simple_order_book.h>\n#include \"changed_checker.h\"\n#include \"depth_check.h\"\n#include \"ut_utils.h\"\n\nusing namespace liquibook::book;\n\nnamespace liquibook {\n\nusing book::DepthLevel;\nusing book::OrderBook;\nusing book::OrderTracker;\nusing simple::SimpleOrder;\n\ntypedef OrderTracker<SimpleOrder*> SimpleTracker;\ntypedef test::ChangedChecker<5> ChangedChecker;\ntypedef SimpleOrderBook::DepthTracker SimpleDepth;\n\ntypedef FillCheck<SimpleOrder*> SimpleFillCheck;\n\nBOOST_AUTO_TEST_CASE(TestBboBidsMultimapSortCorrect)\n{\n  SimpleOrderBook::Bids bids;\n  SimpleOrder order0(true, 1250, 100);\n  SimpleOrder order1(true, 1255, 100);\n  SimpleOrder order2(true, 1240, 100);\n  SimpleOrder order3(true,    0, 100);\n  SimpleOrder order4(true, 1245, 100);\n\n  // Insert out of price order\n  bids.insert(std::make_pair(ComparablePrice(true, order0.price()), SimpleTracker(&order0)));\n  bids.insert(std::make_pair(ComparablePrice(true, order1.price()), SimpleTracker(&order1)));\n  bids.insert(std::make_pair(ComparablePrice(true, order2.price()), SimpleTracker(&order2)));\n  bids.insert(std::make_pair(ComparablePrice(true, 0), \n                             SimpleTracker(&order3)));\n  bids.insert(std::make_pair(ComparablePrice(true, order4.price()), SimpleTracker(&order4)));\n  \n  // Should access in price order\n  SimpleOrder* expected_order[] = {\n    &order3, &order1, &order0, &order4, &order2\n  };\n\n  SimpleOrderBook::Bids::iterator bid;\n  int index = 0;\n\n  for (bid = bids.begin(); bid != bids.end(); ++bid, ++index) {\n    if (expected_order[index]->price() == MARKET_ORDER_PRICE) {\n      BOOST_CHECK_EQUAL(MARKET_ORDER_PRICE, bid->first);\n    } else {\n      BOOST_CHECK_EQUAL(expected_order[index]->price(), bid->first);\n    }\n    BOOST_CHECK_EQUAL(expected_order[index], bid->second.ptr());\n  }\n\n  // Should be able to search and find\n  BOOST_CHECK((bids.upper_bound(book::ComparablePrice(true, 1245)))->second.ptr()->price() == 1240);\n  BOOST_CHECK((bids.lower_bound(book::ComparablePrice(true, 1245)))->second.ptr()->price() == 1245);\n}\n\nBOOST_AUTO_TEST_CASE(TestBboAsksMultimapSortCorrect)\n{\n  SimpleOrderBook::Asks asks;\n  SimpleOrder order0(false, 3250, 100);\n  SimpleOrder order1(false, 3235, 800);\n  SimpleOrder order2(false, 3230, 200);\n  SimpleOrder order3(false,    0, 200);\n  SimpleOrder order4(false, 3245, 100);\n  SimpleOrder order5(false, 3265, 200);\n\n  // Insert out of price order\n  asks.insert(std::make_pair(book::ComparablePrice(false, order0.price()), SimpleTracker(&order0)));\n  asks.insert(std::make_pair(book::ComparablePrice(false, order1.price()), SimpleTracker(&order1)));\n  asks.insert(std::make_pair(book::ComparablePrice(false, order2.price()), SimpleTracker(&order2)));\n  asks.insert(std::make_pair(book::ComparablePrice(false, MARKET_ORDER_PRICE), \n                             SimpleTracker(&order3)));\n  asks.insert(std::make_pair(book::ComparablePrice(false, order4.price()), SimpleTracker(&order4)));\n  asks.insert(std::make_pair(book::ComparablePrice(false, order5.price()), SimpleTracker(&order5)));\n  \n  // Should access in price order\n  SimpleOrder* expected_order[] = {\n    &order3, &order2, &order1, &order4, &order0, &order5\n  };\n\n  SimpleOrderBook::Asks::iterator ask;\n  int index = 0;\n\n  for (ask = asks.begin(); ask != asks.end(); ++ask, ++index) {\n    if (expected_order[index]->price() == MARKET_ORDER_PRICE) {\n      BOOST_CHECK_EQUAL(MARKET_ORDER_ASK_SORT_PRICE, ask->first);\n    } else {\n      BOOST_CHECK_EQUAL(expected_order[index]->price(), ask->first);\n    }\n    BOOST_CHECK_EQUAL(expected_order[index], ask->second.ptr());\n  }\n\n  BOOST_CHECK((asks.upper_bound(book::ComparablePrice(false, 3235)))->second.ptr()->price() == 3245);\n  BOOST_CHECK((asks.lower_bound(book::ComparablePrice(false, 3235)))->second.ptr()->price() == 3235);\n}\n\nBOOST_AUTO_TEST_CASE(TestBboAddCompleteBid)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask1(false, 1252, 100);\n  SimpleOrder ask0(false, 1251, 100);\n  SimpleOrder bid1(true,  1251, 100);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc1(&bid1, 100, 125100);\n    SimpleFillCheck fc2(&ask0, 100, 125100);\n    BOOST_CHECK(add_and_verify(order_book, &bid1, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n}\n\nBOOST_AUTO_TEST_CASE(TestBboAddCompleteAsk)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(false, 1251, 100);\n  SimpleOrder ask1(false, 1250, 100);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc1(&ask1, 100, 125000);\n    SimpleFillCheck fc2(&bid0, 100, 125000);\n    BOOST_CHECK(add_and_verify(order_book, &ask1, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(   0, 0,   0));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(0, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n}\n\nBOOST_AUTO_TEST_CASE(TestBboAddMultiMatchBid)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask1(false, 1252, 100);\n  SimpleOrder ask0(false, 1251, 300);\n  SimpleOrder ask2(false, 1251, 200);\n  SimpleOrder bid1(true,  1251, 500);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, false));\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 2, 500));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(3, order_book.asks().size());\n\n  // Match - complete\n  {\n    SimpleFillCheck fc1(&bid1, 500, 1251 * 500);\n    SimpleFillCheck fc2(&ask2, 200, 1251 * 200);\n    SimpleFillCheck fc3(&ask0, 300, 1251 * 300);\n    BOOST_CHECK(add_and_verify(order_book, &bid1, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify remaining\n  BOOST_CHECK_EQUAL(&ask1, order_book.asks().begin()->second.ptr());\n}\n\nBOOST_AUTO_TEST_CASE(TestBboAddMultiMatchAsk)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask1(false, 9252, 100);\n  SimpleOrder ask0(false, 9251, 300);\n  SimpleOrder ask2(false, 9251, 200);\n  SimpleOrder ask3(false, 9250, 600);\n  SimpleOrder bid0(true,  9250, 100);\n  SimpleOrder bid1(true,  9250, 500);\n  SimpleOrder bid2(true,  9248, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(3, order_book.bids().size());\n  BOOST_CHECK_EQUAL(3, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(9250, 2, 600));\n  BOOST_CHECK(dc.verify_ask(9251, 2, 500));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc1(&ask3, 600, 9250 * 600);\n    SimpleFillCheck fc2(&bid0, 100, 9250 * 100);\n    SimpleFillCheck fc3(&bid1, 500, 9250 * 500);\n    BOOST_CHECK(add_and_verify(order_book, &ask3, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(9248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(9251, 2, 500));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(3, order_book.asks().size());\n\n  // Verify remaining\n  BOOST_CHECK_EQUAL(&bid2, order_book.bids().begin()->second.ptr());\n}\n\nBOOST_AUTO_TEST_CASE(TestBboAddPartialMatchBid)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(false, 7253, 300);\n  SimpleOrder ask1(false, 7252, 100);\n  SimpleOrder ask2(false, 7251, 200);\n  SimpleOrder bid1(true,  7251, 350);\n  SimpleOrder bid0(true,  7250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(3, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(7250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(7251, 1, 200));\n\n  // Match - partial\n  {\n    SimpleFillCheck fc1(&bid1, 200, 7251 * 200);\n    SimpleFillCheck fc2(&ask2, 200, 7251 * 200);\n    BOOST_CHECK(add_and_verify(order_book, &bid1, true, false));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(7251, 1, 150));\n  BOOST_CHECK(dc.verify_ask(7252, 1, 100));\n\n  // Verify remaining\n  BOOST_CHECK_EQUAL(&ask1, order_book.asks().begin()->second.ptr());\n  BOOST_CHECK_EQUAL(&bid1, order_book.bids().begin()->second.ptr());\n}\n\nBOOST_AUTO_TEST_CASE(TestBboAddPartialMatchAsk)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(false, 1253, 300);\n  SimpleOrder ask1(false, 1251, 400);\n  SimpleOrder bid1(true,  1251, 350);\n  SimpleOrder bid0(true,  1250, 100);\n  SimpleOrder bid2(true,  1250, 200);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(3, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1251, 1, 350));\n  BOOST_CHECK(dc.verify_ask(1253, 1, 300));\n\n  // Match - partial\n  {\n    SimpleFillCheck fc1(&ask1, 350, 1251 * 350);\n    SimpleFillCheck fc2(&bid1, 350, 1251 * 350);\n    BOOST_CHECK(add_and_verify(order_book, &ask1,  true, false));\n  }\n\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 2, 300));\n  BOOST_CHECK(dc.verify_ask(1251, 1,  50));\n\n  // Verify remaining\n  BOOST_CHECK_EQUAL(&bid0, order_book.bids().begin()->second.ptr());\n  BOOST_CHECK_EQUAL(&ask1, order_book.asks().begin()->second.ptr());\n}\n\nBOOST_AUTO_TEST_CASE(TestBboAddMultiPartialMatchBid)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask1(false, 1252, 100);\n  SimpleOrder ask2(false, 1251, 200);\n  SimpleOrder ask0(false, 1251, 300);\n  SimpleOrder bid1(true,  1251, 750);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(3, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 2, 500));\n\n  // Match - partial\n  {\n    SimpleFillCheck fc1(&bid1, 500, 1251 * 500);\n    SimpleFillCheck fc2(&ask0, 300, 1251 * 300);\n    SimpleFillCheck fc3(&ask2, 200, 1251 * 200);\n    BOOST_CHECK(add_and_verify(order_book, &bid1, true, false));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 1, 250));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // Verify remaining\n  BOOST_CHECK_EQUAL(&ask1, order_book.asks().begin()->second.ptr());\n  BOOST_CHECK_EQUAL(&bid1, order_book.bids().begin()->second.ptr());\n}\n\nBOOST_AUTO_TEST_CASE(TestBboAddMultiPartialMatchAsk)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(false, 1253, 300);\n  SimpleOrder ask1(false, 1251, 700);\n  SimpleOrder bid1(true,  1251, 370);\n  SimpleOrder bid2(true,  1251, 200);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(3, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1251, 2, 570));\n  BOOST_CHECK(dc.verify_ask(1253, 1, 300));\n\n  // Match - partial\n  {\n    SimpleFillCheck fc1(&ask1, 570, 1251 * 570);\n    SimpleFillCheck fc2(&bid1, 370, 1251 * 370);\n    SimpleFillCheck fc3(&bid2, 200, 1251 * 200);\n    BOOST_CHECK(add_and_verify(order_book, &ask1,  true, false));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 130));\n\n  // Verify remaining\n  BOOST_CHECK_EQUAL(&bid0, order_book.bids().begin()->second.ptr());\n  BOOST_CHECK_EQUAL(100, order_book.bids().begin()->second.open_qty());\n  BOOST_CHECK_EQUAL(&ask1, order_book.asks().begin()->second.ptr());\n  BOOST_CHECK_EQUAL(130, order_book.asks().begin()->second.open_qty());\n}\n\nBOOST_AUTO_TEST_CASE(TestBboRepeatMatchBid)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask3(false, 1251, 400);\n  SimpleOrder ask2(false, 1251, 200);\n  SimpleOrder ask1(false, 1251, 300);\n  SimpleOrder ask0(false, 1251, 100);\n  SimpleOrder bid1(true,  1251, 900);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1251, 1, 900));\n\n  // Match - repeated\n  {\n    SimpleFillCheck fc1(&bid1, 100, 125100);\n    SimpleFillCheck fc2(&ask0, 100, 125100);\n    BOOST_CHECK(add_and_verify(order_book, &ask0, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 1, 800));\n\n  {\n    SimpleFillCheck fc1(&bid1, 300, 1251 * 300);\n    SimpleFillCheck fc2(&ask1, 300, 1251 * 300);\n    BOOST_CHECK(add_and_verify(order_book, &ask1, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 1, 500));\n\n  {\n    SimpleFillCheck fc1(&bid1, 200, 1251 * 200);\n    SimpleFillCheck fc2(&ask2, 200, 1251 * 200);\n    BOOST_CHECK(add_and_verify(order_book, &ask2, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 1, 300));\n\n  {\n    SimpleFillCheck fc1(&bid1, 300, 1251 * 300);\n    SimpleFillCheck fc2(&ask3, 300, 1251 * 300);\n    BOOST_CHECK(add_and_verify(order_book, &ask3, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n}\n\nBOOST_AUTO_TEST_CASE(TestBboRepeatMatchAsk)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(false,  1252, 100);\n  SimpleOrder ask1(false,  1251, 900);\n  SimpleOrder bid0(true, 1251, 100);\n  SimpleOrder bid1(true, 1251, 300);\n  SimpleOrder bid2(true, 1251, 200);\n  SimpleOrder bid3(true, 1251, 400);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_ask(1251, 1, 900));\n\n  BOOST_CHECK_EQUAL(&ask1, order_book.asks().begin()->second.ptr());\n\n  // Match - repeated\n  {\n    SimpleFillCheck fc1(&ask1, 100, 125100);\n    SimpleFillCheck fc2(&bid0, 100, 125100);\n    BOOST_CHECK(add_and_verify(order_book, &bid0, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_ask(1251, 1, 800));\n\n  {\n    SimpleFillCheck fc1(&ask1, 300, 1251 * 300);\n    SimpleFillCheck fc2(&bid1, 300, 1251 * 300);\n    BOOST_CHECK(add_and_verify(order_book, &bid1, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_ask(1251, 1, 500));\n\n  {\n    SimpleFillCheck fc1(&ask1, 200, 1251 * 200);\n    SimpleFillCheck fc2(&bid2, 200, 1251 * 200);\n    BOOST_CHECK(add_and_verify(order_book, &bid2, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_ask(1251, 1, 300));\n\n  {\n    SimpleFillCheck fc1(&ask1, 300, 1251 * 300);\n    SimpleFillCheck fc2(&bid3, 300, 1251 * 300);\n    BOOST_CHECK(add_and_verify(order_book, &bid3, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n}\n\nBOOST_AUTO_TEST_CASE(TestBboAddMarketOrderBid)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask1(false, 1252, 100);\n  SimpleOrder ask0(false, 1251, 100);\n  SimpleOrder bid1(true,     0, 100);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc1(&bid1, 100, 125100);\n    SimpleFillCheck fc2(&ask0, 100, 125100);\n    BOOST_CHECK(add_and_verify(order_book, &bid1, true, true));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n}\n\nBOOST_AUTO_TEST_CASE(TestBboAddMarketOrderAsk)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(false, 1252, 100);\n  SimpleOrder ask1(false,    0, 100);\n  SimpleOrder bid1(true,  1251, 100);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc1(&bid1, 100, 125100);\n    SimpleFillCheck fc2(&ask1, 100, 125100);\n    BOOST_CHECK(add_and_verify(order_book, &ask1, true, true));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n}\n\nBOOST_AUTO_TEST_CASE(TestBboAddMarketOrderBidMultipleMatch)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask1(false, 12520, 300);\n  SimpleOrder ask0(false, 12510, 200);\n  SimpleOrder bid1(true,      0, 500);\n  SimpleOrder bid0(true,  12500, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(12500, 1, 100));\n  BOOST_CHECK(dc.verify_ask(12510, 1, 200));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc1(&bid1, 500, 12510 * 200 + 12520 * 300);\n    SimpleFillCheck fc2(&ask0, 200, 12510 * 200);\n    SimpleFillCheck fc3(&ask1, 300, 12520 * 300);\n    BOOST_CHECK(add_and_verify(order_book, &bid1, true, true));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(0, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(12500, 1, 100));\n  BOOST_CHECK(dc.verify_ask(    0, 0,   0));\n}\n\nBOOST_AUTO_TEST_CASE(TestBboAddMarketOrderAskMultipleMatch)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(false, 12520, 100);\n  SimpleOrder ask1(false,     0, 600);\n  SimpleOrder bid1(true,  12510, 200);\n  SimpleOrder bid0(true,  12500, 400);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(12510, 1, 200));\n  BOOST_CHECK(dc.verify_ask(12520, 1, 100));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc1(&bid0, 400, 12500 * 400);\n    SimpleFillCheck fc2(&bid1, 200, 12510 * 200);\n    SimpleFillCheck fc3(&ask1, 600, 12500 * 400 + 12510 * 200);\n    BOOST_CHECK(add_and_verify(order_book, &ask1, true, true));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(0, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(    0, 0,   0));\n  BOOST_CHECK(dc.verify_ask(12520, 1, 100));\n}\n\nBOOST_AUTO_TEST_CASE(TestBboMatchMarketOrderBid)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(false, 1253, 100);\n  SimpleOrder bid1(true,     0, 100);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(0, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(   0, 0,   0));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc1(&bid1, 100, 125300);\n    SimpleFillCheck fc2(&ask0, 100, 125300);\n    BOOST_CHECK(add_and_verify(order_book, &ask0, true, true));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(0, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(   0, 0,   0));\n}\n\nBOOST_AUTO_TEST_CASE(TestBboMatchMarketOrderAsk)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(false, 1252, 100);\n  SimpleOrder ask1(false,    0, 100);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(0, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n  BOOST_CHECK(dc.verify_bid(   0, 0,   0));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc1(&bid0, 100, 125000);\n    SimpleFillCheck fc2(&ask1, 100, 125000);\n    BOOST_CHECK(add_and_verify(order_book, &bid0, true, true));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(0, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n}\n\nBOOST_AUTO_TEST_CASE(TestBboMatchMultipleMarketOrderBid)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(false, 1253, 400);\n  SimpleOrder bid1(true,     0, 100);\n  SimpleOrder bid2(true,     0, 200);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(3, order_book.bids().size());\n  BOOST_CHECK_EQUAL(0, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_ask(   0, 0,   0));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc1(&bid1, 100, 1253 * 100);\n    SimpleFillCheck fc2(&bid2, 200, 1253 * 200);\n    SimpleFillCheck fc3(&ask0, 300, 1253 * 300);\n    BOOST_CHECK(add_and_verify(order_book, &ask0, true, false));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_ask(1253, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n}\n\n\nBOOST_AUTO_TEST_CASE(TestBboMatchMultipleMarketOrderAsk)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(false, 1252, 100);\n  SimpleOrder ask2(false,    0, 400);\n  SimpleOrder ask1(false,    0, 100);\n  SimpleOrder bid0(true,  1250, 300);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(0, order_book.bids().size());\n  BOOST_CHECK_EQUAL(3, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n  BOOST_CHECK(dc.verify_bid(   0, 0,   0));\n\n  // Match - partiaL\n  {\n    SimpleFillCheck fc1(&bid0, 300, 1250 * 300);\n    SimpleFillCheck fc2(&ask1, 100, 1250 * 100);\n    SimpleFillCheck fc3(&ask2, 200, 1250 * 200);\n    BOOST_CHECK(add_and_verify(order_book, &bid0, true, true));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(0, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n  BOOST_CHECK(dc.verify_bid(   0, 0,   0));\n}\n\nBOOST_AUTO_TEST_CASE(TestBboCancelBid)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask1(false, 1252, 100);\n  SimpleOrder ask0(false, 1251, 100);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n\n  // Cancel bid\n  BOOST_CHECK(cancel_and_verify(order_book, &bid0, simple::os_cancelled));\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(0,    0,   0));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(0, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n}\n\nBOOST_AUTO_TEST_CASE(TestBboCancelAskAndMatch)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask1(false, 1252, 100);\n  SimpleOrder ask0(false, 1251, 100);\n  SimpleOrder bid2(true,  1252, 100);\n  SimpleOrder bid0(true,  1250, 100);\n  SimpleOrder bid1(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1250, 2, 200));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n\n  // Cancel bid\n  BOOST_CHECK(cancel_and_verify(order_book, &ask0, simple::os_cancelled));\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 2, 200));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // Match - partiaL\n  {\n    SimpleFillCheck fc1(&bid2, 100, 1252 * 100);\n    SimpleFillCheck fc2(&ask1, 100, 1252 * 100);\n    BOOST_CHECK(add_and_verify(order_book, &bid2, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 2, 200));\n  BOOST_CHECK(dc.verify_ask(   0, 0,   0));\n\n  // Cancel bid\n  BOOST_CHECK(cancel_and_verify(order_book, &bid0, simple::os_cancelled));\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(   0, 0,   0));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(0, order_book.asks().size());\n}\n\nBOOST_AUTO_TEST_CASE(TestBboCancelBidFail)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(false, 1251, 100);\n  SimpleOrder ask1(false, 1250, 100);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc1(&ask1, 100, 125000);\n    SimpleFillCheck fc2(&bid0, 100, 125000);\n    BOOST_CHECK(add_and_verify(order_book, &ask1, true, true));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(0, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_bid(   0, 0,   0));\n\n  // Cancel a filled order\n  BOOST_CHECK(cancel_and_verify(order_book, &bid0, simple::os_complete));\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_bid(   0, 0,   0));\n}\n\nBOOST_AUTO_TEST_CASE(TestBboCancelAskFail)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask1(false, 1252, 100);\n  SimpleOrder ask0(false, 1251, 100);\n  SimpleOrder bid1(true,  1251, 100);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc1(&bid1, 100, 125100);\n    SimpleFillCheck fc2(&ask0, 100, 125100);\n    BOOST_CHECK(add_and_verify(order_book, &bid1, true, true));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n\n  // Cancel a filled order\n  BOOST_CHECK(cancel_and_verify(order_book, &ask0, simple::os_complete));\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n}\n\nBOOST_AUTO_TEST_CASE(TestBboCancelBidRestore)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask10(false, 1258, 600);\n  SimpleOrder ask9(false,  1257, 700);\n  SimpleOrder ask8(false,  1256, 100);\n  SimpleOrder ask7(false,  1256, 100);\n  SimpleOrder ask6(false,  1255, 500);\n  SimpleOrder ask5(false,  1255, 200);\n  SimpleOrder ask4(false,  1254, 300);\n  SimpleOrder ask3(false,  1252, 200);\n  SimpleOrder ask2(false,  1252, 100);\n  SimpleOrder ask1(false,  1251, 400);\n  SimpleOrder ask0(false,  1250, 500);\n\n  SimpleOrder bid0(true,   1249, 100);\n  SimpleOrder bid1(true,   1249, 200);\n  SimpleOrder bid2(true,   1249, 200);\n  SimpleOrder bid3(true,   1248, 400);\n  SimpleOrder bid4(true,   1246, 600);\n  SimpleOrder bid5(true,   1246, 500);\n  SimpleOrder bid6(true,   1245, 200);\n  SimpleOrder bid7(true,   1245, 100);\n  SimpleOrder bid8(true,   1245, 200);\n  SimpleOrder bid9(true,   1244, 700);\n  SimpleOrder bid10(true,  1244, 300);\n  SimpleOrder bid11(true,  1242, 300);\n  SimpleOrder bid12(true,  1241, 400);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask0,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask3,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask4,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask5,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask6,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask7,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask8,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask9,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask10, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid0,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid3,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid4,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid5,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid6,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid7,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid8,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid9,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid10, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid11, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid12, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(13, order_book.bids().size());\n  BOOST_CHECK_EQUAL(11, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1249, 3,  500));\n  BOOST_CHECK(dc.verify_ask(1250, 1,  500));\n\n  // Cancel a bid level (erase)\n  BOOST_CHECK(cancel_and_verify(order_book, &bid3, simple::os_cancelled));\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1249, 3,  500));\n  BOOST_CHECK(dc.verify_ask(1250, 1,  500));\n  \n  // Cancel common bid levels (not erased)\n  BOOST_CHECK(cancel_and_verify(order_book, &bid7, simple::os_cancelled));\n  BOOST_CHECK(cancel_and_verify(order_book, &bid4, simple::os_cancelled));\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1249, 3,  500));\n  BOOST_CHECK(dc.verify_ask(1250, 1,  500));\n\n  // Cancel the best bid level (erased)\n  BOOST_CHECK(cancel_and_verify(order_book, &bid1, simple::os_cancelled));\n  BOOST_CHECK(cancel_and_verify(order_book, &bid0, simple::os_cancelled));\n  BOOST_CHECK(cancel_and_verify(order_book, &bid2, simple::os_cancelled));\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1246, 1,  500));\n  BOOST_CHECK(dc.verify_ask(1250, 1,  500));\n}\n\nBOOST_AUTO_TEST_CASE(TestBboCancelAskRestore)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask10(false, 1258, 600);\n  SimpleOrder ask9(false,  1257, 700);\n  SimpleOrder ask8(false,  1256, 100);\n  SimpleOrder ask7(false,  1256, 100);\n  SimpleOrder ask6(false,  1255, 500);\n  SimpleOrder ask5(false,  1255, 200);\n  SimpleOrder ask4(false,  1254, 300);\n  SimpleOrder ask3(false,  1252, 200);\n  SimpleOrder ask2(false,  1252, 100);\n  SimpleOrder ask1(false,  1251, 400);\n  SimpleOrder ask0(false,  1250, 500);\n\n  SimpleOrder bid0(true,   1249, 100);\n  SimpleOrder bid1(true,   1249, 200);\n  SimpleOrder bid2(true,   1249, 200);\n  SimpleOrder bid3(true,   1248, 400);\n  SimpleOrder bid4(true,   1246, 600);\n  SimpleOrder bid5(true,   1246, 500);\n  SimpleOrder bid6(true,   1245, 200);\n  SimpleOrder bid7(true,   1245, 100);\n  SimpleOrder bid8(true,   1245, 200);\n  SimpleOrder bid9(true,   1244, 700);\n  SimpleOrder bid10(true,  1244, 300);\n  SimpleOrder bid11(true,  1242, 300);\n  SimpleOrder bid12(true,  1241, 400);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask0,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask3,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask4,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask5,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask6,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask7,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask8,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask9,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask10, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid0,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid3,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid4,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid5,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid6,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid7,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid8,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid9,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid10, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid11, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid12, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(13, order_book.bids().size());\n  BOOST_CHECK_EQUAL(11, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1249, 3,  500));\n  BOOST_CHECK(dc.verify_ask(1250, 1,  500));\n\n  // Cancel an ask level (erase)\n  BOOST_CHECK(cancel_and_verify(order_book, &ask1, simple::os_cancelled));\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1249, 3,  500));\n  BOOST_CHECK(dc.verify_ask(1250, 1,  500));\n\n  // Cancel common ask levels (not erased)\n  BOOST_CHECK(cancel_and_verify(order_book, &ask2, simple::os_cancelled));\n  BOOST_CHECK(cancel_and_verify(order_book, &ask6, simple::os_cancelled));\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1249, 3,  500));\n  BOOST_CHECK(dc.verify_ask(1250, 1,  500));\n\n  // Cancel the best ask level (erased)\n  BOOST_CHECK(cancel_and_verify(order_book, &ask0, simple::os_cancelled));\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1249, 3,  500));\n  BOOST_CHECK(dc.verify_ask(1252, 1,  200));\n}\n\nBOOST_AUTO_TEST_CASE(TestBboFillCompleteBidRestoreDepth)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask10(false, 1258, 600);\n  SimpleOrder ask9(false,  1257, 700);\n  SimpleOrder ask8(false,  1256, 100);\n  SimpleOrder ask7(false,  1256, 100);\n  SimpleOrder ask6(false,  1255, 500);\n  SimpleOrder ask5(false,  1255, 200);\n  SimpleOrder ask4(false,  1254, 300);\n  SimpleOrder ask3(false,  1252, 200);\n  SimpleOrder ask2(false,  1252, 100);\n  SimpleOrder ask1(false,  1251, 400);\n  SimpleOrder ask0(false,  1250, 500);\n\n  SimpleOrder bid0(true,   1249, 100);\n  SimpleOrder bid1(true,   1249, 200);\n  SimpleOrder bid2(true,   1249, 200);\n  SimpleOrder bid3(true,   1248, 400);\n  SimpleOrder bid4(true,   1246, 600);\n  SimpleOrder bid5(true,   1246, 500);\n  SimpleOrder bid6(true,   1245, 200);\n  SimpleOrder bid7(true,   1245, 100);\n  SimpleOrder bid8(true,   1245, 200);\n  SimpleOrder bid9(true,   1244, 700);\n  SimpleOrder bid10(true,  1244, 300);\n  SimpleOrder bid11(true,  1242, 300);\n  SimpleOrder bid12(true,  1241, 400);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask0,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask3,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask4,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask5,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask6,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask7,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask8,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask9,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask10, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid0,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid3,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid4,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid5,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid6,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid7,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid8,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid9,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid10, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid11, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid12, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(13, order_book.bids().size());\n  BOOST_CHECK_EQUAL(11, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1249, 3,  500));\n  BOOST_CHECK(dc.verify_ask(1250, 1,  500));\n\n  // Fill the top bid level (erase) and add an ask level (insert)\n  SimpleOrder cross_ask(false,  1249, 800);\n  {\n    SimpleFillCheck fc1(&bid0,      100, 1249 * 100);\n    SimpleFillCheck fc2(&bid1,      200, 1249 * 200);\n    SimpleFillCheck fc3(&bid2,      200, 1249 * 200);\n    SimpleFillCheck fc4(&cross_ask, 500, 1249 * 500);\n    BOOST_CHECK(add_and_verify(order_book, &cross_ask, true, false));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1248, 1,  400));\n  BOOST_CHECK(dc.verify_ask(1249, 1,  300)); // Inserted\n  \n  // Fill the top bid level (erase) but do not add an ask level (no insert)\n  SimpleOrder cross_ask2(false,  1248, 400);\n  {\n    SimpleFillCheck fc1(&bid3,       400, 1248 * 400);\n    SimpleFillCheck fc4(&cross_ask2, 400, 1248 * 400);\n    BOOST_CHECK(add_and_verify(order_book, &cross_ask2, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1246, 2, 1100));\n  BOOST_CHECK(dc.verify_ask(1249, 1,  300));\n\n  // Fill the top bid level (erase) and add ask level (insert),\n  //    but nothing to restore\n  SimpleOrder cross_ask3(false,  1246, 2400);\n  {\n    SimpleFillCheck fc1(&bid4,        600, 1246 * 600);\n    SimpleFillCheck fc2(&bid5,        500, 1246 * 500);\n    SimpleFillCheck fc3(&cross_ask3, 1100, 1246 * 1100);\n    BOOST_CHECK(add_and_verify(order_book, &cross_ask3, true, false));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1245, 3,  500));\n  BOOST_CHECK(dc.verify_ask(1246, 1, 1300));\n\n  // Partial fill the top bid level (reduce) \n  SimpleOrder cross_ask4(false,  1245, 250);\n  {\n    SimpleFillCheck fc1(&bid6,        200, 1245 * 200);\n    SimpleFillCheck fc2(&bid7,         50, 1245 *  50);\n    SimpleFillCheck fc3(&cross_ask4,  250, 1245 * 250);\n    BOOST_CHECK(add_and_verify(order_book, &cross_ask4, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1245, 2,  250)); // 1 filled, 1 reduced\n  BOOST_CHECK(dc.verify_ask(1246, 1, 1300));\n}\n\nBOOST_AUTO_TEST_CASE(TestBboFillCompleteAskRestoreDepth)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask10(false, 1258, 600);\n  SimpleOrder ask9(false,  1257, 700);\n  SimpleOrder ask8(false,  1256, 100);\n  SimpleOrder ask7(false,  1256, 100);\n  SimpleOrder ask6(false,  1255, 500);\n  SimpleOrder ask5(false,  1255, 200);\n  SimpleOrder ask4(false,  1254, 300);\n  SimpleOrder ask3(false,  1252, 200);\n  SimpleOrder ask2(false,  1252, 100);\n  SimpleOrder ask1(false,  1251, 400);\n  SimpleOrder ask0(false,  1250, 500);\n\n  SimpleOrder bid0(true,   1249, 100);\n  SimpleOrder bid1(true,   1249, 200);\n  SimpleOrder bid2(true,   1249, 200);\n  SimpleOrder bid3(true,   1248, 400);\n  SimpleOrder bid4(true,   1246, 600);\n  SimpleOrder bid5(true,   1246, 500);\n  SimpleOrder bid6(true,   1245, 200);\n  SimpleOrder bid7(true,   1245, 100);\n  SimpleOrder bid8(true,   1245, 200);\n  SimpleOrder bid9(true,   1244, 700);\n  SimpleOrder bid10(true,  1244, 300);\n  SimpleOrder bid11(true,  1242, 300);\n  SimpleOrder bid12(true,  1241, 400);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask0,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask3,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask4,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask5,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask6,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask7,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask8,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask9,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask10, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid0,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid3,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid4,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid5,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid6,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid7,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid8,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid9,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid10, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid11, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid12, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(13, order_book.bids().size());\n  BOOST_CHECK_EQUAL(11, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1249, 3,  500));\n  BOOST_CHECK(dc.verify_ask(1250, 1,  500));\n\n  // Fill the top ask level (erase) and add a bid level (insert)\n  SimpleOrder cross_bid(true,  1250, 800);\n  {\n    SimpleFillCheck fc1(&ask0,      500, 1250 * 500);\n    SimpleFillCheck fc4(&cross_bid, 500, 1250 * 500);\n    BOOST_CHECK(add_and_verify(order_book, &cross_bid, true, false));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 1,  300));\n  BOOST_CHECK(dc.verify_ask(1251, 1,  400));\n\n  // Fill the top ask level (erase) but do not add an bid level (no insert)\n  SimpleOrder cross_bid2(true,  1251, 400);\n  {\n    SimpleFillCheck fc1(&ask1,       400, 1251 * 400);\n    SimpleFillCheck fc4(&cross_bid2, 400, 1251 * 400);\n    BOOST_CHECK(add_and_verify(order_book, &cross_bid2, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 1,  300));\n  BOOST_CHECK(dc.verify_ask(1252, 2,  300));\n\n  // Fill the top ask level (erase) and add bid level (insert),\n  //    but nothing to restore\n  SimpleOrder cross_bid3(true,  1252, 2400);\n  {\n    SimpleFillCheck fc1(&ask2,        100, 1252 * 100);\n    SimpleFillCheck fc2(&ask3,        200, 1252 * 200);\n    SimpleFillCheck fc3(&cross_bid3,  300, 1252 * 300);\n    BOOST_CHECK(add_and_verify(order_book, &cross_bid3, true, false));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1252, 1, 2100)); // Insert\n  BOOST_CHECK(dc.verify_ask(1254, 1,  300));\n\n  // Fill the top ask level (erase) but nothing to restore\n  SimpleOrder cross_bid4(true,  1254, 300);\n  {\n    SimpleFillCheck fc2(&ask4,        300, 1254 * 300);\n    SimpleFillCheck fc3(&cross_bid4,  300, 1254 * 300);\n    BOOST_CHECK(add_and_verify(order_book, &cross_bid4, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1252, 1, 2100));\n  BOOST_CHECK(dc.verify_ask(1255, 2,  700));\n\n  // Partial fill the top ask level (reduce) \n  SimpleOrder cross_bid5(true,  1255, 550);\n  {\n    SimpleFillCheck fc1(&ask5,        200, 1255 * 200);\n    SimpleFillCheck fc2(&ask6,        350, 1255 * 350);\n    SimpleFillCheck fc3(&cross_bid5,  550, 1255 * 550);\n    BOOST_CHECK(add_and_verify(order_book, &cross_bid5, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1252, 1, 2100));\n  BOOST_CHECK(dc.verify_ask(1255, 1,  150)); // 1 filled, 1 reduced\n}\n\nBOOST_AUTO_TEST_CASE(TestBboReplaceSizeDecrease)\n{\n  SimpleOrderBook order_book;\n  ChangedChecker cc(order_book.depth());\n  SimpleOrder ask1(false, 1252, 200);\n  SimpleOrder ask0(false, 1252, 300);\n  SimpleOrder bid1(true,  1251, 100);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 2, 500));\n\n  // Verify changed stamps\n  BOOST_CHECK(cc.verify_bbo_changed(true, true));\n  cc.reset();\n\n  // Replace size\n  BOOST_CHECK(replace_and_verify(order_book, &bid0, -60));\n  BOOST_CHECK(replace_and_verify(order_book, &ask0, -150));\n\n  // Verify orders\n  BOOST_CHECK_EQUAL(40, bid0.order_qty());\n  BOOST_CHECK_EQUAL(150, ask0.order_qty());\n  \n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 2, 350));\n\n  // Verify changed stamps\n  BOOST_CHECK(cc.verify_bbo_changed(false, true));\n}\n\nBOOST_AUTO_TEST_CASE(TestBboReplaceSizeDecreaseCancel)\n{\n  SimpleOrderBook order_book;\n  ChangedChecker cc(order_book.depth());\n  SimpleOrder ask1(false, 1252, 200);\n  SimpleOrder ask0(false, 1252, 300);\n  SimpleOrder bid1(true,  1251, 400);\n  SimpleOrder bid0(true,  1250, 100);\n  SimpleOrder bid2(true,  1249, 700);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1251, 1, 400));\n  BOOST_CHECK(dc.verify_ask(1252, 2, 500));\n\n  // Partial Fill existing book\n  SimpleOrder cross_bid(true,  1252, 125);\n  SimpleOrder cross_ask(false, 1251, 100);\n  \n  {\n    SimpleFillCheck fc1(&cross_bid, 125, 1252 * 125);\n    SimpleFillCheck fc2(&ask0,      125, 1252 * 125);\n    BOOST_CHECK(add_and_verify(order_book, &cross_bid, true, true));\n  }\n  {\n    SimpleFillCheck fc1(&cross_ask, 100, 1251 * 100);\n    SimpleFillCheck fc2(&bid1,      100, 1251 * 100);\n    BOOST_CHECK(add_and_verify(order_book, &cross_ask, true, true));\n  }\n\n  // Verify quantity\n  BOOST_CHECK_EQUAL(175, ask0.open_qty());\n  BOOST_CHECK_EQUAL(300, bid1.open_qty());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 1, 300));\n  BOOST_CHECK(dc.verify_ask(1252, 2, 375));\n\n  // Replace size - cancel\n  BOOST_CHECK(replace_and_verify(\n      order_book, &ask0, -175, PRICE_UNCHANGED, simple::os_cancelled)); \n\n  // Verify orders\n  BOOST_CHECK_EQUAL(125, ask0.order_qty());\n  BOOST_CHECK_EQUAL(0, ask0.open_qty());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 1, 300));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 200));\n\n  // Replace size - reduce level\n  BOOST_CHECK(replace_and_verify(\n      order_book, &bid1, -100, PRICE_UNCHANGED, simple::os_accepted)); \n\n  // Verify orders\n  BOOST_CHECK_EQUAL(300, bid1.order_qty());\n  BOOST_CHECK_EQUAL(200, bid1.open_qty());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 1, 200));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 200));\n\n  // Replace size - cancel and erase level\n  BOOST_CHECK(replace_and_verify(\n      order_book, &bid1, -200, PRICE_UNCHANGED, simple::os_cancelled)); \n\n  // Verify orders\n  BOOST_CHECK_EQUAL(100, bid1.order_qty());\n  BOOST_CHECK_EQUAL(0, bid1.open_qty());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 200));\n}\n\nBOOST_AUTO_TEST_CASE(TestBboReplaceSizeDecreaseTooMuch)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask1(false, 1252, 200);\n  SimpleOrder ask0(false, 1252, 300);\n  SimpleOrder bid1(true,  1251, 100);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 2, 500));\n\n  SimpleOrder cross_bid(true,  1252, 200);\n  // Partial fill existing order\n  {\n    SimpleFillCheck fc1(&cross_bid, 200, 1252 * 200);\n    SimpleFillCheck fc2(&ask0,      200, 1252 * 200);\n    BOOST_CHECK(add_and_verify(order_book, &cross_bid, true, true));\n  }\n\n  // Verify open quantity\n  BOOST_CHECK_EQUAL(100, ask0.open_qty());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 2, 300));\n\n  // Replace size - not enough left\n  order_book.replace(&ask0, -150, PRICE_UNCHANGED);\n\n  // Verify ask0 state\n  BOOST_CHECK_EQUAL(0, ask0.open_qty());\n  BOOST_CHECK_EQUAL(200, ask0.order_qty());\n  BOOST_CHECK_EQUAL(simple::os_cancelled, ask0.state());\n\n  // Verify depth unchanged\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 200));\n}\n\nBOOST_AUTO_TEST_CASE(TestBboReplaceSizeIncreaseDecrease)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask1(false, 1252, 200);\n  SimpleOrder ask0(false, 1251, 300);\n  SimpleOrder bid1(true,  1251, 100);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 300));\n\n  // Replace size\n  BOOST_CHECK(replace_and_verify(order_book, &ask0, 50));\n  BOOST_CHECK(replace_and_verify(order_book, &bid0, 25));\n\n  BOOST_CHECK(replace_and_verify(order_book, &ask0, -100));\n  BOOST_CHECK(replace_and_verify(order_book, &bid0, 25));\n\n  BOOST_CHECK(replace_and_verify(order_book, &ask0, 300));\n  BOOST_CHECK(replace_and_verify(order_book, &bid0, -75));\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 1, 75));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 550));\n}\n\nBOOST_AUTO_TEST_CASE(TestBboReplaceBidPriceChange)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(false, 1253, 300);\n  SimpleOrder ask1(false, 1252, 200);\n  SimpleOrder bid1(true,  1251, 140);\n  SimpleOrder bid0(true,  1250, 120);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1251, 1, 140));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 200));\n\n  // Replace price increase\n  BOOST_CHECK(replace_and_verify(order_book, &bid0, SIZE_UNCHANGED, 1251));\n\n  // Verify price change in book\n  SimpleOrderBook::Bids::const_iterator bid = order_book.bids().begin();\n  BOOST_CHECK_EQUAL(1251, bid->first);\n  BOOST_CHECK_EQUAL(&bid1, bid->second.ptr());\n  BOOST_CHECK_EQUAL(1251, (++bid)->first);\n  BOOST_CHECK_EQUAL(&bid0, bid->second.ptr());\n  BOOST_CHECK(order_book.bids().end() == ++bid);\n\n  // Verify order\n  BOOST_CHECK_EQUAL(1251, bid0.price());\n  BOOST_CHECK_EQUAL(120, bid0.order_qty());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 2, 260));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 200));\n\n  // Replace price decrease\n  BOOST_CHECK(replace_and_verify(order_book, &bid1, SIZE_UNCHANGED, 1250));\n\n  // Verify price change in book\n  bid = order_book.bids().begin();\n  BOOST_CHECK_EQUAL(1251, bid->first);\n  BOOST_CHECK_EQUAL(&bid0, bid->second.ptr());\n  BOOST_CHECK_EQUAL(1250, (++bid)->first);\n  BOOST_CHECK_EQUAL(&bid1, bid->second.ptr());\n  BOOST_CHECK(order_book.bids().end() == ++bid);\n\n  // Verify order\n  BOOST_CHECK_EQUAL(1250, bid1.price());\n  BOOST_CHECK_EQUAL(140, bid1.order_qty());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 1, 120));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 200));\n}\n\nBOOST_AUTO_TEST_CASE(TestBboReplaceAskPriceChange)\n{\n  SimpleOrderBook order_book;\n  ChangedChecker cc(order_book.depth());\n\n  SimpleOrder ask0(false, 1253, 300);\n  SimpleOrder ask1(false, 1252, 200);\n  SimpleOrder bid1(true,  1251, 140);\n  SimpleOrder bid0(true,  1250, 120);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1251, 1, 140));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 200));\n\n  // Replace price increase 1252 -> 1253\n  BOOST_CHECK(replace_and_verify(order_book, &ask1, SIZE_UNCHANGED, 1253));\n\n  // Verify price change in book\n  SimpleOrderBook::Asks::const_iterator ask = order_book.asks().begin();\n  BOOST_CHECK_EQUAL(1253, ask->first);\n  BOOST_CHECK_EQUAL(&ask0, ask->second.ptr());\n  BOOST_CHECK_EQUAL(1253, (++ask)->first);\n  BOOST_CHECK_EQUAL(&ask1, ask->second.ptr());\n  BOOST_CHECK(order_book.asks().end() == ++ask);\n\n  // Verify order\n  BOOST_CHECK_EQUAL(1253, ask1.price());\n  BOOST_CHECK_EQUAL(200, ask1.order_qty());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 1, 140));\n  BOOST_CHECK(dc.verify_ask(1253, 2, 500));\n\n  // Replace price decrease 1253 -> 1252\n  BOOST_CHECK(replace_and_verify(order_book, &ask0, SIZE_UNCHANGED, 1252));\n\n  // Verify price change in book\n  ask = order_book.asks().begin();\n  BOOST_CHECK_EQUAL(1252, ask->first);\n  BOOST_CHECK_EQUAL(&ask0, ask->second.ptr());\n  BOOST_CHECK_EQUAL(1253, (++ask)->first);\n  BOOST_CHECK_EQUAL(&ask1, ask->second.ptr());\n  BOOST_CHECK(order_book.asks().end() == ++ask);\n\n  // Verify order\n  BOOST_CHECK_EQUAL(1252, ask0.price());\n  BOOST_CHECK_EQUAL(300, ask0.order_qty());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 1, 140));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 300));\n}\n} // namespace\n"
  },
  {
    "path": "test/unit/ut_depth.cpp",
    "content": "// Copyright (c) 2012 - 2017 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n\n#define BOOST_TEST_NO_MAIN LiquibookTest\n#include <boost/test/unit_test.hpp>\n\n#include <book/depth.h>\n#include \"changed_checker.h\"\n#include <iostream>\n\nnamespace liquibook {\n\nusing book::Depth;\nusing book::DepthLevel;\ntypedef Depth<5> SizedDepth;\ntypedef test::ChangedChecker<5> ChangedChecker;\n\nbool verify_level(const DepthLevel*& level, \n                  book::Price price, \n                  uint32_t order_count, \n                  book::Quantity aggregate_qty)\n{\n  bool matched = true;\n  if (price != level->price()) {\n    std::cout << \"Level price \" << level->price() << std::endl;\n    matched = false;\n  }\n  if (order_count != level->order_count()) {\n    std::cout << \"Level order count \" << level->order_count() << std::endl;\n    matched = false;\n  }\n  if (aggregate_qty != level->aggregate_qty()) {\n    std::cout << \"Level aggregate qty \" << level->aggregate_qty() << std::endl;\n    matched = false;\n  }\n  ++level;\n  return matched;\n}\n\nBOOST_AUTO_TEST_CASE(TestAddBid)\n{\n  SizedDepth depth;\n  ChangedChecker cc(depth);\n  depth.add_order(1234, 100, true);\n  const DepthLevel* first_bid = depth.bids();\n  BOOST_CHECK(verify_level(first_bid, 1234, 1, 100));\n  BOOST_CHECK(cc.verify_bid_changed(true, false, false, false, false));\n}\n\nBOOST_AUTO_TEST_CASE(TestAddBids)\n{\n  SizedDepth depth;\n  ChangedChecker cc(depth);\n  depth.add_order(1234, 100, true);\n  depth.add_order(1234, 200, true);\n  depth.add_order(1234, 300, true);\n  const DepthLevel* first_bid = depth.bids();\n  BOOST_CHECK(verify_level(first_bid, 1234, 3, 600));\n  BOOST_CHECK(cc.verify_bid_changed(true,false, false, false, false));\n}\n\nBOOST_AUTO_TEST_CASE(TestAppendBidLevels)\n{\n  SizedDepth depth;\n  ChangedChecker cc(depth);\n  depth.add_order(1236, 300, true);\n  depth.add_order(1235, 200, true);\n  depth.add_order(1232, 100, true);\n  depth.add_order(1235, 400, true);\n  const DepthLevel* bid = depth.bids();\n  BOOST_CHECK(verify_level(bid, 1236, 1, 300));\n  BOOST_CHECK(verify_level(bid, 1235, 2, 600));\n  BOOST_CHECK(verify_level(bid, 1232, 1, 100));\n  BOOST_CHECK(cc.verify_bid_changed(true, true, true, false, false));\n}\n\nBOOST_AUTO_TEST_CASE(TestInsertBidLevels)\n{\n  SizedDepth depth;\n  ChangedChecker cc(depth);\n  depth.add_order(1234, 800, true);\n\n  BOOST_CHECK(cc.verify_bid_changed(true, false, false, false, false)); \n  cc.reset();\n\n  depth.add_order(1232, 100, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, true, false, false, false));\n  cc.reset();\n\n  depth.add_order(1236, 300, true);\n  BOOST_CHECK(cc.verify_bid_changed(true, true, true, false, false)); \n  cc.reset();\n\n  depth.add_order(1235, 200, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, true, true, true, false));\n  cc.reset();\n\n  depth.add_order(1234, 900, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, false, true, false, false));\n  cc.reset();\n\n  depth.add_order(1231, 700, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, false, false, false, true));\n  cc.reset();\n\n  depth.add_order(1235, 400, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, true, false, false, false));\n  cc.reset();\n\n  depth.add_order(1231, 500, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, false, false, false, true));\n  cc.reset();\n\n  depth.add_order(1233, 200, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, false, false, true, true));\n  cc.reset();\n\n  const DepthLevel* bid = depth.bids();\n  BOOST_CHECK(verify_level(bid, 1236, 1,  300));\n  BOOST_CHECK(verify_level(bid, 1235, 2,  600));\n  BOOST_CHECK(verify_level(bid, 1234, 2, 1700));\n  BOOST_CHECK(verify_level(bid, 1233, 1,  200));\n  BOOST_CHECK(verify_level(bid, 1232, 1,  100));\n}\n\nBOOST_AUTO_TEST_CASE(TestInsertBidLevelsPast5)\n{\n  SizedDepth depth;\n  ChangedChecker cc(depth);\n  depth.add_order(1234, 800, true);\n  BOOST_CHECK(cc.verify_bid_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.add_order(1232, 100, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, true, false, false, false));\n  cc.reset();\n\n  depth.add_order(1236, 300, true);\n  BOOST_CHECK(cc.verify_bid_changed(true, true, true, false, false));\n  cc.reset();\n\n  depth.add_order(1231, 700, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, false, false, true, false));\n  cc.reset();\n\n  depth.add_order(1234, 900, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, true, false, false, false));\n  cc.reset();\n\n  depth.add_order(1235, 400, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, true, true, true, true));\n  cc.reset();\n\n  depth.add_order(1235, 200, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, true, false, false, false));\n  cc.reset();\n\n  depth.add_order(1231, 500, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, false, false, false, true));\n  cc.reset();\n\n  depth.add_order(1230, 200, true);\n\n  BOOST_CHECK(cc.verify_bid_changed(false, false, false, false, false));\n  cc.reset();\n  depth.add_order(1229, 200, true);\n\n  BOOST_CHECK(cc.verify_bid_changed(false, false, false, false, false));\n  cc.reset();\n  const DepthLevel* bid = depth.bids();\n  BOOST_CHECK(verify_level(bid, 1236, 1,  300));\n  BOOST_CHECK(verify_level(bid, 1235, 2,  600));\n  BOOST_CHECK(verify_level(bid, 1234, 2, 1700));\n  BOOST_CHECK(verify_level(bid, 1232, 1,  100));\n  BOOST_CHECK(verify_level(bid, 1231, 2, 1200));\n}\n\nBOOST_AUTO_TEST_CASE(TestInsertBidLevelsTruncate5)\n{\n  SizedDepth depth;\n  ChangedChecker cc(depth);\n  depth.add_order(1234, 800, true);\n  BOOST_CHECK(cc.verify_bid_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.add_order(1232, 100, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, true, false, false, false));\n  cc.reset();\n\n  depth.add_order(1236, 300, true);\n  BOOST_CHECK(cc.verify_bid_changed(true, true, true, false, false));\n  cc.reset();\n\n  depth.add_order(1231, 700, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, false, false, true, false));\n  cc.reset();\n\n  depth.add_order(1234, 900, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, true, false, false, false));\n  cc.reset();\n\n  depth.add_order(1235, 400, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, true, true, true, true));\n  cc.reset();\n\n  depth.add_order(1235, 200, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, true, false, false, false));\n  cc.reset();\n\n  depth.add_order(1231, 500, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, false, false, false, true));\n  cc.reset();\n\n  depth.add_order(1230, 200, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, false, false, false, false));\n  cc.reset();\n\n  depth.add_order(1238, 200, true);\n  BOOST_CHECK(cc.verify_bid_changed(true, true, true, true, true));\n  cc.reset();\n\n  depth.add_order(1238, 250, true);\n  BOOST_CHECK(cc.verify_bid_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.add_order(1237, 500, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, true, true, true, true));\n  cc.reset();\n  const DepthLevel* bid = depth.bids();\n  BOOST_CHECK(verify_level(bid, 1238, 2,  450));\n  BOOST_CHECK(verify_level(bid, 1237, 1,  500));\n  BOOST_CHECK(verify_level(bid, 1236, 1,  300));\n  BOOST_CHECK(verify_level(bid, 1235, 2,  600));\n  BOOST_CHECK(verify_level(bid, 1234, 2, 1700));\n}\n\nBOOST_AUTO_TEST_CASE(TestCloseBid)\n{\n  SizedDepth depth;\n  ChangedChecker cc(depth);\n  depth.add_order(1234, 300, true);\n  BOOST_CHECK(cc.verify_bid_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.add_order(1234, 500, true);\n  BOOST_CHECK(cc.verify_bid_changed(true, false, false, false, false));\n  cc.reset();\n\n  BOOST_CHECK(!depth.close_order(1234, 300, true)); // Does not erase\n  BOOST_CHECK(cc.verify_bid_changed(true, false, false, false, false));\n\n  const DepthLevel* first_bid = depth.bids();\n  BOOST_CHECK(verify_level(first_bid, 1234, 1, 500));\n}\n\nBOOST_AUTO_TEST_CASE(TestCloseEraseBid)\n{\n  SizedDepth depth;\n  ChangedChecker cc(depth);\n  depth.add_order(1235, 300, true);\n  BOOST_CHECK(cc.verify_bid_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.add_order(1235, 400, true);\n  BOOST_CHECK(cc.verify_bid_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.add_order(1234, 500, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, true, false, false, false));\n  cc.reset();\n\n  depth.add_order(1233, 200, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, false, true, false, false));\n  cc.reset();\n\n  BOOST_CHECK(!depth.close_order(1235, 300, true)); // Does not erase\n  BOOST_CHECK(cc.verify_bid_changed(true, false, false, false, false));\n  cc.reset();\n\n  BOOST_CHECK(depth.close_order(1235, 400, true)); // Erase\n  BOOST_CHECK(cc.verify_bid_changed(true, true, true, false, false));\n\n  const DepthLevel* bid = depth.bids();\n  BOOST_CHECK(verify_level(bid, 1234, 1, 500));\n  BOOST_CHECK(verify_level(bid, 1233, 1, 200));\n}\n\nBOOST_AUTO_TEST_CASE(TestAddCloseAddBid)\n{\n  SizedDepth depth;\n  ChangedChecker cc(depth);\n  depth.add_order(1234, 300, true);\n  BOOST_CHECK(cc.verify_bid_changed(true, false, false, false, false));\n  cc.reset();\n  \n  depth.close_order(1234, 300, true);\n  BOOST_CHECK(cc.verify_bid_changed(true, false, false, false, false));\n  cc.reset();\n  \n  depth.add_order(1233, 200, true);\n  BOOST_CHECK(cc.verify_bid_changed(true, false, false, false, false));\n  cc.reset();\n  const DepthLevel* bid = depth.bids();\n  BOOST_CHECK(verify_level(bid, 1233, 1, 200));\n  BOOST_CHECK(verify_level(bid, false, false, false));\n}\n\nBOOST_AUTO_TEST_CASE(TestAddCloseAddHigherBid)\n{\n  SizedDepth depth;\n  ChangedChecker cc(depth);\n  depth.add_order(1234, 300, true);\n  BOOST_CHECK(cc.verify_bid_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.close_order(1234, 300, true);\n  BOOST_CHECK(cc.verify_bid_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.add_order(1235, 200, true);\n  BOOST_CHECK(cc.verify_bid_changed(true, false, false, false, false));\n  cc.reset();\n\n  const DepthLevel* bid = depth.bids();\n  BOOST_CHECK(verify_level(bid, 1235, 1, 200));\n  BOOST_CHECK(verify_level(bid, false, false, false));\n}\n\nBOOST_AUTO_TEST_CASE(TestCloseBidsFreeLevels)\n{\n  SizedDepth depth;\n  ChangedChecker cc(depth);\n  depth.add_order(1234, 800, true);\n  BOOST_CHECK(cc.verify_bid_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.add_order(1232, 100, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, true, false, false, false));\n  cc.reset();\n\n  depth.add_order(1236, 300, true);\n  BOOST_CHECK(cc.verify_bid_changed(true, true, true, false, false));\n  cc.reset();\n\n  depth.add_order(1235, 200, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, true, true, true, false));\n  cc.reset();\n\n  depth.add_order(1234, 900, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, false, true, false, false));\n  cc.reset();\n\n  depth.add_order(1231, 700, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, false, false, false, true));\n  cc.reset();\n\n  depth.add_order(1235, 400, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, true, false, false, false));\n  cc.reset();\n\n  depth.add_order(1231, 500, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, false, false, false, true));\n  cc.reset();\n\n  depth.close_order(1234, 900, true); // No erase\n  BOOST_CHECK(cc.verify_bid_changed(false, false, true, false, false));\n  cc.reset();\n\n  depth.close_order(1232, 100, true); // Erase\n  BOOST_CHECK(cc.verify_bid_changed(false, false, false, true, true));\n  cc.reset();\n\n  depth.close_order(1236, 300, true); // Erase\n  BOOST_CHECK(cc.verify_bid_changed(true, true, true, true, false));\n  cc.reset();\n\n  const DepthLevel* bid = depth.bids();\n  BOOST_CHECK(verify_level(bid, 1235, 2,  600));\n  BOOST_CHECK(verify_level(bid, 1234, 1,  800));\n  BOOST_CHECK(verify_level(bid, 1231, 2, 1200));\n  BOOST_CHECK(verify_level(bid,    0, 0,    0));\n  BOOST_CHECK(verify_level(bid,    0, 0,    0));\n\n  depth.add_order(1233, 350, true); // Insert\n  BOOST_CHECK(cc.verify_bid_changed(false, false, true, true, false));\n  cc.reset();\n\n  depth.add_order(1236, 300, true); // Insert\n  BOOST_CHECK(cc.verify_bid_changed(true, true, true, true, true));\n  cc.reset();\n\n  depth.add_order(1231, 700, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, false, false, false, true));\n  cc.reset();\n  bid = depth.bids();  // reset\n  BOOST_CHECK(verify_level(bid, 1236, 1,  300));\n  BOOST_CHECK(verify_level(bid, 1235, 2,  600));\n  BOOST_CHECK(verify_level(bid, 1234, 1,  800));\n  BOOST_CHECK(verify_level(bid, 1233, 1,  350));\n  BOOST_CHECK(verify_level(bid, 1231, 3, 1900));\n}\n\nBOOST_AUTO_TEST_CASE(TestIncreaseBid)\n{\n  SizedDepth depth;\n  ChangedChecker cc(depth);\n  depth.add_order(1236, 300, true);\n  BOOST_CHECK(cc.verify_bid_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.add_order(1235, 200, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, true, false, false, false));\n  cc.reset();\n\n  depth.add_order(1232, 100, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, false, true, false, false));\n  cc.reset();\n\n  depth.add_order(1235, 400, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, true, false, false, false));\n  cc.reset();\n\n  depth.change_qty_order(1232, 37, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, false, true, false, false));\n  cc.reset();\n\n  depth.change_qty_order(1232, 41, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, false, true, false, false));\n  cc.reset();\n\n  depth.change_qty_order(1235, 201, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, true, false, false, false));\n  cc.reset();\n\n  const DepthLevel* bid = depth.bids();\n  BOOST_CHECK(verify_level(bid, 1236, 1, 300));\n  BOOST_CHECK(verify_level(bid, 1235, 2, 801));\n  BOOST_CHECK(verify_level(bid, 1232, 1, 178));\n}\n\nBOOST_AUTO_TEST_CASE(TestDecreaseBid)\n{\n  SizedDepth depth;\n  ChangedChecker cc(depth);\n  depth.add_order(1236, 300, true);\n  BOOST_CHECK(cc.verify_bid_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.add_order(1235, 200, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, true, false, false, false));\n  cc.reset();\n\n  depth.add_order(1232, 100, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, false, true, false, false));\n  cc.reset();\n\n  depth.add_order(1235, 400, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, true, false, false, false));\n  cc.reset();\n\n  depth.change_qty_order(1236, -37, true);\n  BOOST_CHECK(cc.verify_bid_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.change_qty_order(1236, -41, true);\n  BOOST_CHECK(cc.verify_bid_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.change_qty_order(1235, -201, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, true, false, false, false));\n  cc.reset();\n\n  const DepthLevel* bid = depth.bids();\n  BOOST_CHECK(verify_level(bid, 1236, 1, 222));\n  BOOST_CHECK(verify_level(bid, 1235, 2, 399));\n  BOOST_CHECK(verify_level(bid, 1232, 1, 100));\n}\n\nBOOST_AUTO_TEST_CASE(TestIncreaseDecreaseBid)\n{\n  SizedDepth depth;\n  ChangedChecker cc(depth);\n  depth.add_order(1236, 300, true);\n  BOOST_CHECK(cc.verify_bid_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.add_order(1235, 200, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, true, false, false, false));\n  cc.reset();\n\n  depth.add_order(1232, 100, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, false, true, false, false));\n  cc.reset();\n\n  depth.add_order(1235, 400, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, true, false, false, false));\n  cc.reset();\n\n  depth.change_qty_order(1236, 37, true);\n  BOOST_CHECK(cc.verify_bid_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.change_qty_order(1235, -41, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, true, false, false, false));\n  cc.reset();\n\n  depth.change_qty_order(1232, 60, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, false, true, false, false));\n  cc.reset();\n\n  depth.change_qty_order(1236, -41, true);\n  BOOST_CHECK(cc.verify_bid_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.change_qty_order(1236, 210, true);\n  BOOST_CHECK(cc.verify_bid_changed(true, false, false, false, false));\n  cc.reset();\n  const DepthLevel* bid = depth.bids();\n  BOOST_CHECK(verify_level(bid, 1236, 1, 506));\n  BOOST_CHECK(verify_level(bid, 1235, 2, 559));\n  BOOST_CHECK(verify_level(bid, 1232, 1, 160));\n}\n\nBOOST_AUTO_TEST_CASE(TestAddAsk)\n{\n  SizedDepth depth;\n  ChangedChecker cc(depth);\n  depth.add_order(1234, 100, false);\n  const DepthLevel* first_ask = depth.asks();\n  BOOST_CHECK(verify_level(first_ask, 1234, 1, 100));\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n}\n\nBOOST_AUTO_TEST_CASE(TestAddAsks)\n{\n  SizedDepth depth;\n  ChangedChecker cc(depth);\n  depth.add_order(1234, 100, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.add_order(1234, 200, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.add_order(1234, 300, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n\n  const DepthLevel* first_ask = depth.asks();\n  BOOST_CHECK(verify_level(first_ask, 1234, 3, 600));\n}\n\nBOOST_AUTO_TEST_CASE(TestAppendAskLevels)\n{\n  SizedDepth depth;\n  ChangedChecker cc(depth);\n  depth.add_order(1236, 300, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.add_order(1235, 200, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, true, false, false, false));\n  cc.reset();\n\n  depth.add_order(1232, 100, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, true, true, false, false));\n  cc.reset();\n\n  depth.add_order(1235, 400, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, true, false, false, false));\n  cc.reset();\n  const DepthLevel* ask = depth.asks();\n  BOOST_CHECK(verify_level(ask, 1232, 1, 100));\n  BOOST_CHECK(verify_level(ask, 1235, 2, 600));\n  BOOST_CHECK(verify_level(ask, 1236, 1, 300));\n}\n\nBOOST_AUTO_TEST_CASE(TestInsertAskLevels)\n{\n  SizedDepth depth;\n  ChangedChecker cc(depth);\n  depth.add_order(1234, 800, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.add_order(1232, 100, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, true, false, false, false));\n  cc.reset();\n\n  depth.add_order(1236, 300, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, false, true, false, false));\n  cc.reset();\n\n  depth.add_order(1235, 200, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, false, true, true, false));\n  cc.reset();\n\n  depth.add_order(1234, 900, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, true, false, false, false));\n  cc.reset();\n  depth.add_order(1231, 700, false);\n  depth.add_order(1235, 400, false);\n  depth.add_order(1231, 500, false);\n  const DepthLevel* ask = depth.asks();\n  BOOST_CHECK(verify_level(ask, 1231, 2, 1200));\n  BOOST_CHECK(verify_level(ask, 1232, 1,  100));\n  BOOST_CHECK(verify_level(ask, 1234, 2, 1700));\n  BOOST_CHECK(verify_level(ask, 1235, 2,  600));\n  BOOST_CHECK(verify_level(ask, 1236, 1,  300));\n}\n\nBOOST_AUTO_TEST_CASE(TestInsertAskLevelsPast5)\n{\n  SizedDepth depth;\n  ChangedChecker cc(depth);\n  depth.add_order(1234, 800, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.add_order(1232, 100, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, true, false, false, false));\n  cc.reset();\n\n  depth.add_order(1236, 300, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, false, true, false, false));\n  cc.reset();\n\n  depth.add_order(1231, 700, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, true, true, true, false));\n  cc.reset();\n\n  depth.add_order(1234, 900, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, false, true, false, false));\n  cc.reset();\n\n  depth.add_order(1235, 400, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, false, false, true, true));\n  cc.reset();\n\n  depth.add_order(1235, 200, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, false, false, true, false));\n  cc.reset();\n\n  depth.add_order(1231, 500, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.add_order(1230, 200, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, true, true, true, true));\n  cc.reset();\n\n  depth.add_order(1229, 200, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, true, true, true, true));\n  cc.reset();\n\n  const DepthLevel* ask = depth.asks();\n  BOOST_CHECK(verify_level(ask, 1229, 1,  200));\n  BOOST_CHECK(verify_level(ask, 1230, 1,  200));\n  BOOST_CHECK(verify_level(ask, 1231, 2, 1200));\n  BOOST_CHECK(verify_level(ask, 1232, 1,  100));\n  BOOST_CHECK(verify_level(ask, 1234, 2, 1700));\n}\n\nBOOST_AUTO_TEST_CASE(TestInsertAskLevelsTruncate5)\n{\n  SizedDepth depth;\n  ChangedChecker cc(depth);\n  depth.add_order(1234, 800, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.add_order(1232, 100, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, true, false, false, false));\n  cc.reset();\n\n  depth.add_order(1236, 300, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, false, true, false, false));\n  cc.reset();\n\n  depth.add_order(1231, 700, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, true, true, true, false));\n  cc.reset();\n\n  depth.add_order(1234, 900, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, false, true, false, false));\n  cc.reset();\n\n  depth.add_order(1235, 400, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, false, false, true, true));\n  cc.reset();\n\n  depth.add_order(1235, 200, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, false, false, true, false));\n  cc.reset();\n\n  depth.add_order(1231, 500, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.add_order(1230, 200, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, true, true, true, true));\n  cc.reset();\n\n  depth.add_order(1238, 200, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, false, false, false, false));\n  cc.reset();\n\n  depth.add_order(1232, 250, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, false, true, false, false));\n  cc.reset();\n\n  depth.add_order(1237, 500, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, false, false, false, false));\n  cc.reset();\n  const DepthLevel* ask = depth.asks();\n  BOOST_CHECK(verify_level(ask, 1230, 1,  200));\n  BOOST_CHECK(verify_level(ask, 1231, 2, 1200));\n  BOOST_CHECK(verify_level(ask, 1232, 2,  350));\n  BOOST_CHECK(verify_level(ask, 1234, 2, 1700));\n  BOOST_CHECK(verify_level(ask, 1235, 2,  600));\n}\n\nBOOST_AUTO_TEST_CASE(TestCloseAsk)\n{\n  SizedDepth depth;\n  ChangedChecker cc(depth);\n  depth.add_order(1234, 300, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.add_order(1234, 500, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n  cc.reset();\n  BOOST_CHECK(!depth.close_order(1234, 300, false)); // Does not erase\n  const DepthLevel* first_ask = depth.asks();\n  BOOST_CHECK(verify_level(first_ask, 1234, 1, 500));\n}\n\nBOOST_AUTO_TEST_CASE(TestCloseEraseAsk)\n{\n  SizedDepth depth;\n  ChangedChecker cc(depth);\n  depth.add_order(1233, 300, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.add_order(1234, 500, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, true, false, false, false));\n  cc.reset();\n\n  depth.add_order(1233, 400, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n  cc.reset();\n\n  BOOST_CHECK(!depth.close_order(1233, 300, false)); // Does not erase\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n  cc.reset();\n\n  BOOST_CHECK(depth.close_order(1233, 400, false)); // Erase\n  BOOST_CHECK(cc.verify_ask_changed(true, true, false, false, false));\n  cc.reset();\n  const DepthLevel* first_ask = depth.asks();\n  BOOST_CHECK(verify_level(first_ask, 1234, 1, 500));\n}\n\nBOOST_AUTO_TEST_CASE(TestAddCloseAddAsk)\n{\n  SizedDepth depth;\n  ChangedChecker cc(depth);\n  depth.add_order(1234, 300, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n  cc.reset();\n  \n  depth.close_order(1234, 300, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n  cc.reset();\n  \n  depth.add_order(1233, 200, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n  cc.reset();\n  const DepthLevel* ask = depth.asks();\n  BOOST_CHECK(verify_level(ask, 1233, 1, 200));\n  BOOST_CHECK(verify_level(ask, false, false, false));\n}\n\nBOOST_AUTO_TEST_CASE(TestAddCloseAddHigherAsk)\n{\n  SizedDepth depth;\n  ChangedChecker cc(depth);\n  depth.add_order(1234, 300, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n  cc.reset();\n  \n  depth.close_order(1234, 300, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n  cc.reset();\n  \n  depth.add_order(1235, 200, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));  \n  cc.reset();\n  const DepthLevel* ask = depth.asks();\n  BOOST_CHECK(verify_level(ask, 1235, 1, 200));\n  BOOST_CHECK(verify_level(ask, false, false, false));\n}\n\nBOOST_AUTO_TEST_CASE(TestCloseAsksFreeLevels)\n{\n  SizedDepth depth;\n  ChangedChecker cc(depth);\n  depth.add_order(1234, 800, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.add_order(1232, 100, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, true, false, false, false));\n  cc.reset();\n\n  depth.add_order(1236, 300, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, false, true, false, false));\n  cc.reset();\n\n  depth.add_order(1235, 200, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, false, true, true, false));\n  cc.reset();\n\n  depth.add_order(1234, 900, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, true, false, false, false));\n  cc.reset();\n\n  depth.add_order(1231, 700, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, true, true, true, true));\n  cc.reset();\n\n  depth.add_order(1235, 400, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, false, false, true, false));\n  cc.reset();\n\n  depth.add_order(1231, 500, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.close_order(1234, 900, false); // does not erase\n  BOOST_CHECK(cc.verify_ask_changed(false, false, true, false, false));\n  cc.reset();\n\n  depth.close_order(1232, 100, false); // erase\n  BOOST_CHECK(cc.verify_ask_changed(false, true, true, true, true));\n  cc.reset();\n  depth.close_order(1236, 100, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, false, false, true, false));\n  cc.reset();\n  const DepthLevel* ask = depth.asks();\n  BOOST_CHECK(verify_level(ask, 1231, 2, 1200));\n  BOOST_CHECK(verify_level(ask, 1234, 1,  800));\n  BOOST_CHECK(verify_level(ask, 1235, 2,  600));\n  BOOST_CHECK(verify_level(ask,    0, 0,    0));\n  BOOST_CHECK(verify_level(ask,    0, 0,    0));\n  depth.add_order(1233, 350, false);\n  depth.add_order(1236, 300, false);\n  depth.add_order(1231, 700, false);\n  ask = depth.asks();  // reset\n  BOOST_CHECK(verify_level(ask, 1231, 3, 1900));\n  BOOST_CHECK(verify_level(ask, 1233, 1,  350));\n  BOOST_CHECK(verify_level(ask, 1234, 1,  800));\n  BOOST_CHECK(verify_level(ask, 1235, 2,  600));\n  BOOST_CHECK(verify_level(ask, 1236, 1,  300));\n}\n\nBOOST_AUTO_TEST_CASE(TestIncreaseAsk)\n{\n  SizedDepth depth;\n  ChangedChecker cc(depth);\n  depth.add_order(1236, 300, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.add_order(1235, 200, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, true, false, false, false));\n  cc.reset();\n\n  depth.add_order(1232, 100, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, true, true, false, false));\n  cc.reset();\n\n  depth.add_order(1235, 400, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, true, false, false, false));\n  cc.reset();\n\n  depth.change_qty_order(1232, 37, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.change_qty_order(1232, 41, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.change_qty_order(1235, 201, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, true, false, false, false));\n  cc.reset();\n  const DepthLevel* ask = depth.asks();\n  BOOST_CHECK(verify_level(ask, 1232, 1, 178));\n  BOOST_CHECK(verify_level(ask, 1235, 2, 801));\n  BOOST_CHECK(verify_level(ask, 1236, 1, 300));\n}\n\nBOOST_AUTO_TEST_CASE(TestDecreaseAsk)\n{\n  SizedDepth depth;\n  ChangedChecker cc(depth);\n  depth.add_order(1236, 300, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.add_order(1235, 200, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, true, false, false, false));\n  cc.reset();\n\n  depth.add_order(1232, 100, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, true, true, false, false));\n  cc.reset();\n\n  depth.add_order(1235, 400, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, true, false, false, false));\n  cc.reset();\n\n  depth.change_qty_order(1236, -37, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, false, true, false, false));\n  cc.reset();\n\n  depth.change_qty_order(1236, -41, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, false, true, false, false));\n  cc.reset();\n\n  depth.change_qty_order(1235, -201, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, true, false, false, false));\n  cc.reset();\n  const DepthLevel* ask = depth.asks();\n  BOOST_CHECK(verify_level(ask, 1232, 1, 100));\n  BOOST_CHECK(verify_level(ask, 1235, 2, 399));\n  BOOST_CHECK(verify_level(ask, 1236, 1, 222));\n}\n\nBOOST_AUTO_TEST_CASE(TestIncreaseDecreaseAsk)\n{\n  SizedDepth depth;\n  ChangedChecker cc(depth);\n  depth.add_order(1236, 300, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.add_order(1235, 200, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, true, false, false, false));\n  cc.reset();\n\n  depth.add_order(1232, 100, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, true, true, false, false));\n  cc.reset();\n\n  depth.add_order(1235, 400, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, true, false, false, false));\n  cc.reset();\n\n  depth.change_qty_order(1236, 37, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, false, true, false, false));\n  cc.reset();\n\n  depth.change_qty_order(1235, -41, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, true, false, false, false));\n  cc.reset();\n\n  depth.change_qty_order(1232, 51, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.change_qty_order(1236, -41, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, false, true, false, false));\n  cc.reset();\n\n  depth.change_qty_order(1236, 201, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, false, true, false, false));\n  cc.reset();\n  const DepthLevel* ask = depth.asks();\n  BOOST_CHECK(verify_level(ask, 1232, 1, 151));\n  BOOST_CHECK(verify_level(ask, 1235, 2, 559));\n  BOOST_CHECK(verify_level(ask, 1236, 1, 497));\n}\n\nBOOST_AUTO_TEST_CASE(TestReplaceBid)\n{\n  SizedDepth depth;\n  ChangedChecker cc(depth);\n  depth.add_order(1236, 300, true);\n  BOOST_CHECK(cc.verify_bid_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.add_order(1235, 200, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, true, false, false, false));\n  cc.reset();\n\n  depth.add_order(1232, 100, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, false, true, false, false));\n  cc.reset();\n\n  depth.add_order(1235, 400, true);\n  BOOST_CHECK(cc.verify_bid_changed(false, true, false, false, false));\n  cc.reset();\n\n\n  // Verify Levels \n  const DepthLevel* bid = depth.bids();\n  BOOST_CHECK(verify_level(bid, 1236, 1, 300));\n  BOOST_CHECK(verify_level(bid, 1235, 2, 600));\n  BOOST_CHECK(verify_level(bid, 1232, 1, 100));\n\n  // Replace bid\n  depth.replace_order(1235, 1237, 200, 200, true);\n\n  // Verify Levels \n  bid = depth.bids();\n  BOOST_CHECK(verify_level(bid, 1237, 1, 200));\n  BOOST_CHECK(verify_level(bid, 1236, 1, 300));\n  BOOST_CHECK(verify_level(bid, 1235, 1, 400));\n  BOOST_CHECK(verify_level(bid, 1232, 1, 100));\n\n  BOOST_CHECK(cc.verify_bid_changed(true, true, true, true, false));\n  cc.reset();\n}\n\nBOOST_AUTO_TEST_CASE(TestReplaceAsk)\n{\n  SizedDepth depth;\n  ChangedChecker cc(depth);\n  depth.add_order(1236, 300, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n  cc.reset();\n\n  depth.add_order(1235, 200, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, true, false, false, false));\n  cc.reset();\n\n  depth.add_order(1232, 100, false);\n  BOOST_CHECK(cc.verify_ask_changed(true, true, true, false, false));\n  cc.reset();\n\n  depth.add_order(1235, 400, false);\n  BOOST_CHECK(cc.verify_ask_changed(false, true, false, false, false));\n  cc.reset();\n\n  // Verify Levels \n  const DepthLevel* ask = depth.asks();\n  BOOST_CHECK(verify_level(ask, 1232, 1, 100));\n  BOOST_CHECK(verify_level(ask, 1235, 2, 600));\n  BOOST_CHECK(verify_level(ask, 1236, 1, 300));\n\n  // Replace ask\n  depth.replace_order(1235, 1237, 200, 200, false);\n\n  // Verify Levels \n  ask = depth.asks();\n  BOOST_CHECK(verify_level(ask, 1232, 1, 100));\n  BOOST_CHECK(verify_level(ask, 1235, 1, 400));\n  BOOST_CHECK(verify_level(ask, 1236, 1, 300));\n  BOOST_CHECK(verify_level(ask, 1237, 1, 200));\n\n  BOOST_CHECK(cc.verify_ask_changed(false, true, false, true, false));\n  cc.reset();\n}\n\n} // namespace\n"
  },
  {
    "path": "test/unit/ut_immediate_or_cancel.cpp",
    "content": "// Copyright (c) 2012 - 2017 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n\n#define BOOST_TEST_NO_MAIN LiquibookTest\n#include <boost/test/unit_test.hpp>\n\n#include \"ut_utils.h\"\n\nnamespace liquibook {\n\nusing simple::SimpleOrder;\ntypedef FillCheck<SimpleOrder*> SimpleFillCheck;\n\nOrderConditions IOC(oc_immediate_or_cancel);\nOrderConditions FOK(oc_all_or_none | oc_immediate_or_cancel);\n\nBOOST_AUTO_TEST_CASE(TestIocBidNoMatch)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask2(false, 1252, 100);\n  SimpleOrder ask1(false, 1251, 100);\n  SimpleOrder ask0(false, 1250, 100);\n  SimpleOrder bid0(true,  1250, 100);\n  SimpleOrder bid1(true,  1249, 100);\n  SimpleOrder bid2(true,  1248, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // No Match - will cancel order\n  {\n    SimpleFillCheck fc0(&bid0, 0, 0, IOC);\n    SimpleFillCheck fc1(&bid1, 0, 0);\n    SimpleFillCheck fc2(&bid2, 0, 0);\n    //SimpleFillCheck fc3(&ask0, 0, 0);\n    SimpleFillCheck fc4(&ask1, 0, 0);\n    SimpleFillCheck fc5(&ask2, 0, 0);\n    BOOST_CHECK(add_and_verify(order_book, &bid0, false, false, IOC));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n}\n\nBOOST_AUTO_TEST_CASE(TestIocBidPartialMatch)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask2(false, 1252, 100);\n  SimpleOrder ask1(false, 1251, 100);\n  SimpleOrder ask0(false, 1250, 100);\n  SimpleOrder bid0(true,  1250, 300);\n  SimpleOrder bid1(true,  1249, 100);\n  SimpleOrder bid2(true,  1248, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(3, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // Partial Match - will cancel order\n  {\n    SimpleFillCheck fc0(&bid0, 100, 125000, IOC);\n    SimpleFillCheck fc1(&bid1, 0, 0);\n    SimpleFillCheck fc2(&bid2, 0, 0);\n    SimpleFillCheck fc3(&ask0, 100, 125000);\n    SimpleFillCheck fc4(&ask1, 0, 0);\n    SimpleFillCheck fc5(&ask2, 0, 0);\n    BOOST_CHECK(add_and_verify(order_book, &bid0, true, false, IOC));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n}\n\nBOOST_AUTO_TEST_CASE(TestIocBidFullMatch)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask2(false, 1252, 100);\n  SimpleOrder ask1(false, 1251, 100);\n  SimpleOrder ask0(false, 1250, 400);\n  SimpleOrder bid0(true,  1250, 300);\n  SimpleOrder bid1(true,  1249, 100);\n  SimpleOrder bid2(true,  1248, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(3, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1250, 1, 400));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // Full Match - will complete order\n  {\n    SimpleFillCheck fc0(&bid0, 300, 1250 * 300, IOC);\n    SimpleFillCheck fc1(&bid1, 0, 0);\n    SimpleFillCheck fc2(&bid2, 0, 0);\n    SimpleFillCheck fc3(&ask0, 300, 1250 * 300);\n    SimpleFillCheck fc4(&ask1, 0, 0);\n    SimpleFillCheck fc5(&ask2, 0, 0);\n    BOOST_CHECK(add_and_verify(order_book, &bid0, true, true, IOC));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(3, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n}\n\nBOOST_AUTO_TEST_CASE(TestIocBidMultiMatch)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask2(false, 1252, 100);\n  SimpleOrder ask1(false, 1251, 100);\n  SimpleOrder ask0(false, 1250, 400);\n  SimpleOrder bid0(true,  1251, 500);\n  SimpleOrder bid1(true,  1249, 100);\n  SimpleOrder bid2(true,  1248, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(3, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1250, 1, 400));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // Full Match - will complete order\n  {\n    SimpleFillCheck fc0(&bid0, 500, 625100, IOC);\n    SimpleFillCheck fc1(&bid1, 0, 0);\n    SimpleFillCheck fc2(&bid2, 0, 0);\n    SimpleFillCheck fc3(&ask0, 400, 1250 * 400);\n    SimpleFillCheck fc4(&ask1, 100, 1251 * 100);\n    SimpleFillCheck fc5(&ask2, 0, 0);\n    BOOST_CHECK(add_and_verify(order_book, &bid0, true, true, IOC));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n}\n\nBOOST_AUTO_TEST_CASE(TestFokBidNoMatch)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask2(false, 1252, 100);\n  SimpleOrder ask1(false, 1251, 100);\n  SimpleOrder ask0(false, 1250, 100);\n  SimpleOrder bid0(true,  1250, 100);\n  SimpleOrder bid1(true,  1249, 100);\n  SimpleOrder bid2(true,  1248, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // No Match - will cancel order\n  {\n    SimpleFillCheck fc0(&bid0, 0, 0, FOK);\n    SimpleFillCheck fc1(&bid1, 0, 0);\n    SimpleFillCheck fc2(&bid2, 0, 0);\n    //SimpleFillCheck fc3(&ask0, 0, 0);\n    SimpleFillCheck fc4(&ask1, 0, 0);\n    SimpleFillCheck fc5(&ask2, 0, 0);\n    BOOST_CHECK(add_and_verify(order_book, &bid0, false, false, FOK));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n}\n\nBOOST_AUTO_TEST_CASE(TestFokBidPartialMatch)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask2(false, 1252, 100);\n  SimpleOrder ask1(false, 1251, 100);\n  SimpleOrder ask0(false, 1250, 100);\n  SimpleOrder bid0(true,  1250, 300);\n  SimpleOrder bid1(true,  1249, 100);\n  SimpleOrder bid2(true,  1248, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(3, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // Partial Match - will not fill and will cancel order\n  {\n    SimpleFillCheck fc0(&bid0, 0, 0, FOK);\n    SimpleFillCheck fc1(&bid1, 0, 0);\n    SimpleFillCheck fc2(&bid2, 0, 0);\n    SimpleFillCheck fc3(&ask0, 0, 0);\n    SimpleFillCheck fc4(&ask1, 0, 0);\n    SimpleFillCheck fc5(&ask2, 0, 0);\n    BOOST_CHECK(add_and_verify(order_book, &bid0, false, false, FOK));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(3, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n}\n\nBOOST_AUTO_TEST_CASE(TestFokBidFullMatch)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask2(false, 1252, 100);\n  SimpleOrder ask1(false, 1251, 100);\n  SimpleOrder ask0(false, 1250, 400);\n  SimpleOrder bid0(true,  1250, 300);\n  SimpleOrder bid1(true,  1249, 100);\n  SimpleOrder bid2(true,  1248, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(3, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1250, 1, 400));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // Full Match - will complete order\n  {\n    SimpleFillCheck fc0(&bid0, 300, 1250 * 300, FOK);\n    SimpleFillCheck fc1(&bid1, 0, 0);\n    SimpleFillCheck fc2(&bid2, 0, 0);\n    SimpleFillCheck fc3(&ask0, 300, 1250 * 300);\n    SimpleFillCheck fc4(&ask1, 0, 0);\n    SimpleFillCheck fc5(&ask2, 0, 0);\n    BOOST_CHECK(add_and_verify(order_book, &bid0, true, true, FOK));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(3, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n}\n\nBOOST_AUTO_TEST_CASE(TestFokBidMultiMatch)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask2(false, 1252, 100);\n  SimpleOrder ask1(false, 1251, 100);\n  SimpleOrder ask0(false, 1250, 400);\n  SimpleOrder bid0(true,  1251, 500);\n  SimpleOrder bid1(true,  1249, 100);\n  SimpleOrder bid2(true,  1248, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(3, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1250, 1, 400));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // Full Match - will complete order\n  {\n    SimpleFillCheck fc0(&bid0, 500, 625100, FOK);\n    SimpleFillCheck fc1(&bid1, 0, 0);\n    SimpleFillCheck fc2(&bid2, 0, 0);\n    SimpleFillCheck fc3(&ask0, 400, 1250 * 400);\n    SimpleFillCheck fc4(&ask1, 100, 1251 * 100);\n    SimpleFillCheck fc5(&ask2, 0, 0);\n    BOOST_CHECK(add_and_verify(order_book, &bid0, true, true, FOK));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n}\n\nBOOST_AUTO_TEST_CASE(TestIocAskNoMatch)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask2(false, 1252, 100);\n  SimpleOrder ask1(false, 1251, 100);\n  SimpleOrder ask0(false, 1250, 100);\n  SimpleOrder bid0(true,  1250, 100);\n  SimpleOrder bid1(true,  1249, 100);\n  SimpleOrder bid2(true,  1248, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // No Match - will cancel order\n  {\n    // SimpleFillCheck fc0(&bid0, 0, 0);\n    SimpleFillCheck fc1(&bid1, 0, 0);\n    SimpleFillCheck fc2(&bid2, 0, 0);\n    SimpleFillCheck fc3(&ask0, 0, 0, IOC);\n    SimpleFillCheck fc4(&ask1, 0, 0);\n    SimpleFillCheck fc5(&ask2, 0, 0);\n    BOOST_CHECK(add_and_verify(order_book, &ask0, false, false, IOC));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n}\n\nBOOST_AUTO_TEST_CASE(TestIocAskPartialMatch)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask2(false, 1252, 100);\n  SimpleOrder ask1(false, 1251, 100);\n  SimpleOrder ask0(false, 1250, 300);\n  SimpleOrder bid0(true,  1250, 100);\n  SimpleOrder bid1(true,  1249, 100);\n  SimpleOrder bid2(true,  1248, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(3, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // Partial Match - will cancel order\n  {\n    SimpleFillCheck fc0(&bid0, 100, 125000);\n    SimpleFillCheck fc1(&bid1, 0, 0);\n    SimpleFillCheck fc2(&bid2, 0, 0);\n    SimpleFillCheck fc3(&ask0, 100, 125000, IOC);\n    SimpleFillCheck fc4(&ask1, 0, 0);\n    SimpleFillCheck fc5(&ask2, 0, 0);\n    BOOST_CHECK(add_and_verify(order_book, &ask0, true, false, IOC));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n}\n\nBOOST_AUTO_TEST_CASE(TestIocAskFullMatch)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask2(false, 1252, 100);\n  SimpleOrder ask1(false, 1251, 100);\n  SimpleOrder ask0(false, 1250, 300);\n  SimpleOrder bid0(true,  1250, 300);\n  SimpleOrder bid1(true,  1249, 100);\n  SimpleOrder bid2(true,  1248, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(3, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1250, 1, 300));\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // Full match\n  {\n    SimpleFillCheck fc0(&bid0, 300, 1250 * 300);\n    SimpleFillCheck fc1(&bid1, 0, 0);\n    SimpleFillCheck fc2(&bid2, 0, 0);\n    SimpleFillCheck fc3(&ask0, 300, 1250 * 300, IOC);\n    SimpleFillCheck fc4(&ask1, 0, 0);\n    SimpleFillCheck fc5(&ask2, 0, 0);\n    BOOST_CHECK(add_and_verify(order_book, &ask0, true, true, IOC));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n}\n\nBOOST_AUTO_TEST_CASE(TestIocAskMultiMatch)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask2(false, 1252, 100);\n  SimpleOrder ask1(false, 1251, 100);\n  SimpleOrder ask0(false, 1249, 400);\n  SimpleOrder bid0(true,  1250, 300);\n  SimpleOrder bid1(true,  1249, 100);\n  SimpleOrder bid2(true,  1248, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(3, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1250, 1, 300));\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // Full match\n  {\n    SimpleFillCheck fc0(&bid0, 300, 1250 * 300);\n    SimpleFillCheck fc1(&bid1, 100, 1249 * 100);\n    SimpleFillCheck fc2(&bid2, 0, 0);\n    SimpleFillCheck fc3(&ask0, 400, 499900, IOC);\n    SimpleFillCheck fc4(&ask1, 0, 0);\n    SimpleFillCheck fc5(&ask2, 0, 0);\n    BOOST_CHECK(add_and_verify(order_book, &ask0, true, true, IOC));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n}\n\nBOOST_AUTO_TEST_CASE(TestFokAskNoMatch)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask2(false, 1252, 100);\n  SimpleOrder ask1(false, 1251, 100);\n  SimpleOrder ask0(false, 1250, 100);\n  SimpleOrder bid0(true,  1250, 100);\n  SimpleOrder bid1(true,  1249, 100);\n  SimpleOrder bid2(true,  1248, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // No Match - will cancel order\n  {\n    // SimpleFillCheck fc0(&bid0, 0, 0);\n    SimpleFillCheck fc1(&bid1, 0, 0);\n    SimpleFillCheck fc2(&bid2, 0, 0);\n    SimpleFillCheck fc3(&ask0, 0, 0, FOK);\n    SimpleFillCheck fc4(&ask1, 0, 0);\n    SimpleFillCheck fc5(&ask2, 0, 0);\n    BOOST_CHECK(add_and_verify(order_book, &ask0, false, false, FOK));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n}\n\nBOOST_AUTO_TEST_CASE(TestFokAskPartialMatch)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask2(false, 1252, 100);\n  SimpleOrder ask1(false, 1251, 100);\n  SimpleOrder ask0(false, 1250, 300);\n  SimpleOrder bid0(true,  1250, 100);\n  SimpleOrder bid1(true,  1249, 100);\n  SimpleOrder bid2(true,  1248, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(3, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // Partial Match - will not fill and will cancel order\n  {\n    SimpleFillCheck fc0(&bid0, 0, 0);\n    SimpleFillCheck fc1(&bid1, 0, 0);\n    SimpleFillCheck fc2(&bid2, 0, 0);\n    SimpleFillCheck fc3(&ask0, 0, 0, FOK);\n    SimpleFillCheck fc4(&ask1, 0, 0);\n    SimpleFillCheck fc5(&ask2, 0, 0);\n    BOOST_CHECK(add_and_verify(order_book, &ask0, false, false, FOK));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(3, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n}\n\nBOOST_AUTO_TEST_CASE(TestFokAskFullMatch)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask2(false, 1252, 100);\n  SimpleOrder ask1(false, 1251, 100);\n  SimpleOrder ask0(false, 1250, 300);\n  SimpleOrder bid0(true,  1250, 300);\n  SimpleOrder bid1(true,  1249, 100);\n  SimpleOrder bid2(true,  1248, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(3, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1250, 1, 300));\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // Full Match\n  {\n    SimpleFillCheck fc0(&bid0, 300, 1250 * 300);\n    SimpleFillCheck fc1(&bid1, 0, 0);\n    SimpleFillCheck fc2(&bid2, 0, 0);\n    SimpleFillCheck fc3(&ask0, 300, 1250 * 300, FOK);\n    SimpleFillCheck fc4(&ask1, 0, 0);\n    SimpleFillCheck fc5(&ask2, 0, 0);\n    BOOST_CHECK(add_and_verify(order_book, &ask0, true, true, FOK));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n}\n\nBOOST_AUTO_TEST_CASE(TestFokAskMultiMatch)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask2(false, 1252, 100);\n  SimpleOrder ask1(false, 1251, 100);\n  SimpleOrder ask0(false, 1249, 400);\n  SimpleOrder bid0(true,  1250, 300);\n  SimpleOrder bid1(true,  1249, 100);\n  SimpleOrder bid2(true,  1248, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(3, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1250, 1, 300));\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // Full match\n  {\n    SimpleFillCheck fc0(&bid0, 300, 1250 * 300);\n    SimpleFillCheck fc1(&bid1, 100, 1249 * 100);\n    SimpleFillCheck fc2(&bid2, 0, 0);\n    SimpleFillCheck fc3(&ask0, 400, 499900, FOK);\n    SimpleFillCheck fc4(&ask1, 0, 0);\n    SimpleFillCheck fc5(&ask2, 0, 0);\n    BOOST_CHECK(add_and_verify(order_book, &ask0, true, true, FOK));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n}\n\n} // Namespace\n"
  },
  {
    "path": "test/unit/ut_listeners.cpp",
    "content": "// Copyright (c) 2012 - 2017 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n\n#define BOOST_TEST_NO_MAIN LiquibookTest\n#include <boost/test/unit_test.hpp>\n\n#include \"ut_utils.h\"\n#include \"changed_checker.h\"\n#include <book/order_book.h>\n#include <simple/simple_order.h>\n\nnamespace liquibook {\n\nusing book::OrderBook;\nusing simple::SimpleOrder;\n\ntypedef SimpleOrder* OrderPtr;\ntypedef OrderBook<OrderPtr> TypedOrderBook;\ntypedef DepthOrderBook<OrderPtr> TypedDepthOrderBook;\ntypedef TypedDepthOrderBook::DepthTracker DepthTracker;\n\nclass TradeCbListener : public TradeListener<TypedOrderBook>\n{\npublic:\n  virtual void on_trade(const TypedOrderBook* order_book,\n                        Quantity qty,\n                        Cost cost)\n  {\n    quantities_.push_back(qty);\n    costs_.push_back(cost);\n  }\n\n  void reset()\n  {\n    quantities_.clear();\n    costs_.clear();\n  }\n  std::vector<Quantity> quantities_;\n  std::vector<Cost> costs_;\n};\n\nclass OrderCbListener : public OrderListener<OrderPtr>\n{\npublic:\n  virtual void on_accept(const OrderPtr& order)\n  {\n    accepts_.push_back(order);\n  }\n  virtual void on_reject(const OrderPtr& order, const char* )\n  {\n    rejects_.push_back(order);\n  }\n  virtual void on_fill(const OrderPtr& order, \n                       const OrderPtr& , // matched_order\n                       Quantity ,        // fill_qty\n                       Cost)             // fill_cost\n  {\n    fills_.push_back(order);\n  }\n  virtual void on_cancel(const OrderPtr& order)\n  {\n    cancels_.push_back(order);\n  }\n  virtual void on_cancel_reject(const OrderPtr& order, const char* )\n  {\n    cancel_rejects_.push_back(order);\n  }\n  virtual void on_replace(const OrderPtr& order,\n                          const int32_t& , // size_delta\n                          Price )          // new_price)\n  {\n    replaces_.push_back(order);\n  }\n  virtual void on_replace_reject(const OrderPtr& order, const char* )\n  {\n    replace_rejects_.push_back(order);\n  }\n\n  void reset()\n  {\n    accepts_.clear();\n    rejects_.clear();\n    fills_.clear();\n    cancels_.clear();\n    cancel_rejects_.clear();\n    replaces_.clear();\n    replace_rejects_.clear();\n  }\n\n  typedef std::vector<const SimpleOrder*> OrderVector;\n  OrderVector accepts_;\n  OrderVector rejects_;\n  OrderVector fills_;\n  OrderVector cancels_;\n  OrderVector cancel_rejects_;\n  OrderVector replaces_;\n  OrderVector replace_rejects_;\n};\n\nBOOST_AUTO_TEST_CASE(TestOrderCallbacks)\n{\n  SimpleOrder order0(false, 3250, 100);\n  SimpleOrder order1(true,  3250, 800);\n  SimpleOrder order2(false, 3230, 0);\n  SimpleOrder order3(false, 3240, 200);\n  SimpleOrder order4(true,  3250, 600);\n\n  OrderCbListener listener;\n  TypedOrderBook order_book;\n  order_book.set_order_listener(&listener);\n  // Add order, should be accepted\n  order_book.add(&order0);\n  BOOST_CHECK_EQUAL(1, listener.accepts_.size());\n  listener.reset();\n  // Add matching order, should be accepted, followed by a fill\n  order_book.add(&order1);\n  BOOST_CHECK_EQUAL(1, listener.accepts_.size());\n  BOOST_CHECK_EQUAL(1, listener.fills_.size());\n  listener.reset();\n  // Add invalid order, should be rejected\n  order_book.add(&order2);\n  BOOST_CHECK_EQUAL(1, listener.rejects_.size());\n  listener.reset();\n  // Cancel only valid order, should be cancelled\n  order_book.cancel(&order1);\n  BOOST_CHECK_EQUAL(1, listener.cancels_.size());\n  listener.reset();\n  // Cancel filled order, should be rejected\n  order_book.cancel(&order0);\n  BOOST_CHECK_EQUAL(1, listener.cancel_rejects_.size());\n  listener.reset();\n  // Add a new order and replace it, should be replaced\n  order_book.add(&order3);\n  order_book.replace(&order3, 0, 3250);\n  BOOST_CHECK_EQUAL(1, listener.accepts_.size());\n  BOOST_CHECK_EQUAL(1, listener.replaces_.size());\n  listener.reset();\n  // Add matching order, should be accepted, followed by a fill\n  order_book.add(&order4);\n  BOOST_CHECK_EQUAL(1, listener.accepts_.size());\n  BOOST_CHECK_EQUAL(1, listener.fills_.size());\n  listener.reset();\n  // Replace matched order, with too large of a size decrease, replace\n  // should be rejected\n  order_book.replace(&order3, -500);\n  BOOST_CHECK_EQUAL(0, listener.replaces_.size());\n  BOOST_CHECK_EQUAL(1, listener.replace_rejects_.size());\n}\n\nclass OrderBookCbListener : public OrderBookListener<TypedOrderBook>\n{\npublic:\n\n  virtual void on_order_book_change(const TypedOrderBook* book)\n  {\n    changes_.push_back(book);\n  }\n\n  void reset()\n  {\n    changes_.clear();\n  }\n\n  typedef std::vector<const TypedOrderBook*> OrderBookVector;\n  OrderBookVector changes_;\n};\n\nBOOST_AUTO_TEST_CASE(TestOrderBookCallbacks)\n{\n  SimpleOrder order0(false, 3250, 100);\n  SimpleOrder order1(true,  3250, 800);\n  SimpleOrder order2(false, 3230, 0);\n  SimpleOrder order3(false, 3240, 200);\n  SimpleOrder order4(true,  3250, 600);\n\n  OrderBookCbListener listener;\n  OrderBook<OrderPtr> order_book;\n  order_book.set_order_book_listener(&listener);\n  // Add order, should be accepted\n  order_book.add(&order0);\n  BOOST_CHECK_EQUAL(1, listener.changes_.size());\n  listener.reset();\n  // Add matching order, should be accepted, followed by a fill\n  order_book.add(&order1);\n  BOOST_CHECK_EQUAL(1, listener.changes_.size());\n  listener.reset();\n  // Add invalid order, should be rejected\n  order_book.add(&order2);\n  BOOST_CHECK_EQUAL(0, listener.changes_.size());  // NO CHANGE\n  listener.reset();\n  // Cancel only valid order, should be cancelled\n  order_book.cancel(&order1);\n  BOOST_CHECK_EQUAL(1, listener.changes_.size());\n  listener.reset();\n  // Cancel filled order, should be rejected\n  order_book.cancel(&order0);\n  BOOST_CHECK_EQUAL(0, listener.changes_.size());  // NO CHANGE\n  listener.reset();\n  // Add a new order and replace it, should be replaced\n  order_book.add(&order3);\n  order_book.replace(&order3, 0, 3250);\n  BOOST_CHECK_EQUAL(2, listener.changes_.size());\n  listener.reset();\n  // Add matching order, should be accepted, followed by a fill\n  order_book.add(&order4);\n  BOOST_CHECK_EQUAL(1, listener.changes_.size());\n  listener.reset();\n  // Replace matched order, with too large of a size decrease, replace\n  // should be rejected\n  order_book.replace(&order3, -500);\n  BOOST_CHECK_EQUAL(0, listener.changes_.size());  // NO CHANGE\n}\n\nclass DepthCbListener \n      : public TypedDepthOrderBook::TypedDepthListener\n{\npublic:\n  virtual void on_depth_change(const TypedDepthOrderBook* book,\n                               const DepthTracker* ) // depth\n  {\n    changes_.push_back(book);\n  }\n\n  void reset()\n  {\n    changes_.clear();\n\n  }\n  typedef std::vector<const TypedDepthOrderBook*> OrderBooks;\n  OrderBooks changes_;\n};\n\nBOOST_AUTO_TEST_CASE(TestDepthCallbacks)\n{\n  SimpleOrder buy0(true, 3250, 100);\n  SimpleOrder buy1(true, 3249, 800);\n  SimpleOrder buy2(true, 3248, 300);\n  SimpleOrder buy3(true, 3247, 200);\n  SimpleOrder buy4(true, 3246, 600);\n  SimpleOrder buy5(true, 3245, 300);\n  SimpleOrder buy6(true, 3244, 100);\n  SimpleOrder sell0(false, 3250, 300);\n  SimpleOrder sell1(false, 3251, 200);\n  SimpleOrder sell2(false, 3252, 200);\n  SimpleOrder sell3(false, 3253, 400);\n  SimpleOrder sell4(false, 3254, 300);\n  SimpleOrder sell5(false, 3255, 100);\n  SimpleOrder sell6(false, 3255, 100);\n\n  DepthCbListener listener;\n  TypedDepthOrderBook order_book;\n  order_book.set_depth_listener(&listener);\n  // Add buy orders, should be accepted\n  order_book.add(&buy0);\n  order_book.add(&buy1);\n  order_book.add(&buy2);\n  order_book.add(&buy3);\n  order_book.add(&buy4);\n  BOOST_CHECK_EQUAL(5, listener.changes_.size());\n  listener.reset();\n\n  // Add buy orders past end, should be accepted, but not affect depth\n  order_book.add(&buy5);\n  order_book.add(&buy6);\n  BOOST_CHECK_EQUAL(0, listener.changes_.size());\n  listener.reset();\n\n  // Add sell orders, should be accepted and affect depth\n  order_book.add(&sell5);\n  order_book.add(&sell4);\n  order_book.add(&sell3);\n  order_book.add(&sell2);\n  order_book.add(&sell1);\n  order_book.add(&sell0);\n  BOOST_CHECK_EQUAL(6, listener.changes_.size());\n  listener.reset();\n\n  // Add sell order past end, should be accepted, but not affect depth\n  order_book.add(&sell6);\n  BOOST_CHECK_EQUAL(0, listener.changes_.size());\n  listener.reset();\n}\n\nclass BboCbListener \n      : public TypedDepthOrderBook::TypedBboListener\n{\n  public:\n  virtual void on_bbo_change(const TypedDepthOrderBook* book,\n                             const DepthTracker* ) // depth\n  {\n    changes_.push_back(book);\n  }\n\n  void reset()\n  {\n    changes_.clear();\n  }\n\n  typedef std::vector<const TypedDepthOrderBook*> OrderBooks;\n  OrderBooks changes_;\n};\n\nBOOST_AUTO_TEST_CASE(TestBboCallbacks)\n{\n  SimpleOrder buy0(true, 3250, 100);\n  SimpleOrder buy1(true, 3249, 800);\n  SimpleOrder buy2(true, 3248, 300);\n  SimpleOrder buy3(true, 3247, 200);\n  SimpleOrder buy4(true, 3246, 600);\n  SimpleOrder buy5(true, 3245, 300);\n  SimpleOrder buy6(true, 3244, 100);\n  SimpleOrder sell0(false, 3250, 300);\n  SimpleOrder sell1(false, 3251, 200);\n  SimpleOrder sell2(false, 3252, 200);\n  SimpleOrder sell3(false, 3253, 400);\n  SimpleOrder sell4(false, 3254, 300);\n  SimpleOrder sell5(false, 3255, 100);\n  SimpleOrder sell6(false, 3255, 100);\n\n  BboCbListener listener;\n  TypedDepthOrderBook order_book;\n  order_book.set_bbo_listener(&listener);\n  // Add buy orders, should be accepted\n  order_book.add(&buy0);\n  BOOST_CHECK_EQUAL(1, listener.changes_.size());\n  listener.reset();\n  order_book.add(&buy1);\n  BOOST_CHECK_EQUAL(0, listener.changes_.size());\n  listener.reset();\n  order_book.add(&buy2);\n  BOOST_CHECK_EQUAL(0, listener.changes_.size());\n  listener.reset();\n  order_book.add(&buy3);\n  BOOST_CHECK_EQUAL(0, listener.changes_.size());\n  listener.reset();\n  order_book.add(&buy4);\n  BOOST_CHECK_EQUAL(0, listener.changes_.size());\n  listener.reset();\n\n  // Add buy orders past end, should be accepted, but not affect depth\n  order_book.add(&buy5);\n  BOOST_CHECK_EQUAL(0, listener.changes_.size());\n  listener.reset();\n  order_book.add(&buy6);\n  BOOST_CHECK_EQUAL(0, listener.changes_.size());\n  listener.reset();\n\n  // Add sell orders, should be accepted and affect bbo\n  order_book.add(&sell2);\n  BOOST_CHECK_EQUAL(1, listener.changes_.size());\n  listener.reset();\n  order_book.add(&sell1);\n  BOOST_CHECK_EQUAL(1, listener.changes_.size());\n  listener.reset();\n  order_book.add(&sell0);\n  BOOST_CHECK_EQUAL(1, listener.changes_.size());\n  listener.reset();\n  // Add sell orders worse than best bid, should not effect bbo\n  order_book.add(&sell5);\n  BOOST_CHECK_EQUAL(0, listener.changes_.size());\n  listener.reset();\n  order_book.add(&sell4);\n  BOOST_CHECK_EQUAL(0, listener.changes_.size());\n  listener.reset();\n  order_book.add(&sell3);\n  BOOST_CHECK_EQUAL(0, listener.changes_.size());\n  listener.reset();\n\n  // Add sell order past end, should be accepted, but not affect depth\n  order_book.add(&sell6);\n  BOOST_CHECK_EQUAL(0, listener.changes_.size());\n  listener.reset();\n}\n\nBOOST_AUTO_TEST_CASE(TestTradeCallbacks) \n{\n  SimpleOrder order0(false, 3250, 100);\n  SimpleOrder order1(true,  3250, 800);\n  SimpleOrder order2(false, 3230, 0);\n  SimpleOrder order3(false, 3240, 200);\n  SimpleOrder order4(true,  3250, 600);\n\n  TradeCbListener listener;\n  TypedOrderBook order_book;\n  order_book.set_trade_listener(&listener);\n  // Add order, should be accepted\n  order_book.add(&order0);\n  BOOST_CHECK_EQUAL(0, listener.quantities_.size());\n  listener.reset();\n  // Add matching order, should result in a trade\n  order_book.add(&order1);\n  BOOST_CHECK_EQUAL(1, listener.quantities_.size());\n  BOOST_CHECK_EQUAL(1, listener.costs_.size());\n  BOOST_CHECK_EQUAL(100, listener.quantities_[0]);\n  BOOST_CHECK_EQUAL(100 * 3250, listener.costs_[0]);\n  listener.reset();\n  // Add invalid order, should be rejected\n  order_book.add(&order2);\n  BOOST_CHECK_EQUAL(0, listener.quantities_.size());\n  listener.reset();\n  // Cancel only valid order, should be cancelled\n  order_book.cancel(&order1);\n  BOOST_CHECK_EQUAL(0, listener.quantities_.size());\n  listener.reset();\n  // Cancel filled order, should be rejected\n  order_book.cancel(&order0);\n  BOOST_CHECK_EQUAL(0, listener.quantities_.size());\n  listener.reset();\n  // Add a new order and replace it, should be replaced\n  order_book.add(&order3);\n  order_book.replace(&order3, 0, 3250);\n  BOOST_CHECK_EQUAL(0, listener.quantities_.size());\n  listener.reset();\n  // Add matching order, should be accepted, followed by a fill\n  order_book.add(&order4);\n  BOOST_CHECK_EQUAL(1, listener.quantities_.size());\n  BOOST_CHECK_EQUAL(1, listener.costs_.size());\n  listener.reset();\n  // Replace matched order, with too large of a size decrease, replace\n  // should be rejected\n  order_book.replace(&order3, -500);\n  BOOST_CHECK_EQUAL(0, listener.quantities_.size());\n}\n\n} // namespace liquibook\n"
  },
  {
    "path": "test/unit/ut_main.cpp",
    "content": "// Copyright (c) 2017, Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#define BOOST_TEST_MODULE LiquibookTest\n#include <boost/test/unit_test.hpp>\n"
  },
  {
    "path": "test/unit/ut_market_price.cpp",
    "content": "// Copyright (c) 2012 - 2017 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n\n#define BOOST_TEST_NO_MAIN LiquibookTest\n#include <boost/test/unit_test.hpp>\n\n#include \"ut_utils.h\"\n#include \"changed_checker.h\"\n#include <book/order_book.h>\n#include <simple/simple_order.h>\n\nnamespace liquibook {\n\nusing book::DepthLevel;\nusing book::OrderBook;\nusing book::OrderTracker;\nusing simple::SimpleOrder;\n\nnamespace\n{\n  const bool sideBuy = true;\n  const bool sideSell = false;\n\n  const Price prcMkt = 0;\n  const Price prc0 = 9900;\n\n  const Quantity q100 = 100;\n\n  const bool expectMatch = true;\n  const bool expectNoMatch = false;\n\n  const bool expectComplete = true;\n  const bool expectNoComplete = false;\n}\n\ntypedef OrderTracker<SimpleOrder*> SimpleTracker;\ntypedef test::ChangedChecker<5> ChangedChecker;\n\ntypedef FillCheck<SimpleOrder*> SimpleFillCheck;\n\nBOOST_AUTO_TEST_CASE(TestNoMktToMktWithoutPreviousTrade)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder order0(sideBuy, prcMkt, q100);\n  SimpleOrder order1(sideSell, prcMkt, q100);\n\n  // Check that no market-to-market trade happens without a prior trade\n  BOOST_CHECK(add_and_verify(order_book, &order0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &order1, expectNoMatch));\n\n  SimpleFillCheck fc0(&order0, 0, 0);\n  SimpleFillCheck fc1(&order1, 0, 0);\n\n  BOOST_CHECK_EQUAL(0U, order_book.market_price());\n}\n\nBOOST_AUTO_TEST_CASE(TestTradeSetsMarketPrice)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder order0(sideBuy, prcMkt, q100);\n  SimpleOrder order1(sideSell, prcMkt, q100);\n\n  // Check that no market-to-market trade happens without a prior trade\n  BOOST_CHECK(add_and_verify(order_book, &order0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &order1, expectNoMatch));\n\n  BOOST_CHECK_EQUAL(0U, order_book.market_price());\n\n  SimpleOrder order2(sideBuy, prc0, q100);\n\n  // Scope for fill checks\n  {\n    SimpleFillCheck fc0(&order0, 0, 0);\n    SimpleFillCheck fc1(&order1, q100, q100 * prc0);\n    SimpleFillCheck fc2(&order2, q100, q100 * prc0);\n    BOOST_CHECK(add_and_verify(order_book, &order2, expectMatch, expectComplete));\n  }\n  BOOST_CHECK_EQUAL(prc0, order_book.market_price());\n  \n  SimpleOrder order3(sideSell, prcMkt, q100);\n  // Scope for fill checks\n  {\n    SimpleFillCheck fc0(&order0, q100, q100 * prc0);\n    SimpleFillCheck fc3(&order3, q100, q100 * prc0);\n    BOOST_CHECK(add_and_verify(order_book, &order3, expectMatch, expectComplete));\n  }\n  BOOST_CHECK_EQUAL(prc0, order_book.market_price());\n}\n\nBOOST_AUTO_TEST_CASE(TestExplicitlySettingMarketPriceAllowsMarketToMarketTrades)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder order0(sideBuy, prcMkt, q100);\n  SimpleOrder order1(sideSell, prcMkt, q100);\n\n  // Check that no market-to-market trade happens without a prior trade\n  BOOST_CHECK(add_and_verify(order_book, &order0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(order_book, &order1, expectNoMatch));\n\n  // IF WE MAKE THE MANUAL SETTING OF MARKET PRICE RETROACTIVE\n  // FIX THIS TEST TO REFLECT THAT\n  \n  // Scope for fill checks\n  {\n    SimpleFillCheck fc0(&order0, 0, 0);\n    SimpleFillCheck fc1(&order1, 0, 0);\n    order_book.set_market_price(prc0);\n  }\n\n  SimpleOrder order2(sideBuy, prcMkt, q100);\n  SimpleOrder order3(sideSell, prcMkt, q100);\n  // Scope for fill checks\n  {\n    SimpleFillCheck fc0(&order0, q100, q100 * prc0);\n    SimpleFillCheck fc1(&order1, q100, q100 * prc0);\n    SimpleFillCheck fc2(&order2, q100, q100 * prc0);\n    SimpleFillCheck fc3(&order3, q100, q100 * prc0);\n    BOOST_CHECK(add_and_verify(order_book, &order2, expectMatch, expectComplete));\n    BOOST_CHECK(add_and_verify(order_book, &order3, expectMatch, expectComplete));\n  }\n}\n\n} // namespace\n"
  },
  {
    "path": "test/unit/ut_order_book.cpp",
    "content": "// Copyright (c) 2012 - 2017 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n\n#define BOOST_TEST_NO_MAIN LiquibookTest\n#include <boost/test/unit_test.hpp>\n\n#include \"ut_utils.h\"\n#include \"changed_checker.h\"\n#include <book/order_book.h>\n#include <simple/simple_order.h>\n\nnamespace liquibook {\n\nusing book::DepthLevel;\nusing book::OrderBook;\nusing book::OrderTracker;\nusing simple::SimpleOrder;\n\ntypedef OrderTracker<SimpleOrder*> SimpleTracker;\ntypedef test::ChangedChecker<5> ChangedChecker;\n\ntypedef FillCheck<SimpleOrder*> SimpleFillCheck;\n\nBOOST_AUTO_TEST_CASE(TestBidsMultimapSortCorrect)\n{\n  SimpleOrderBook::Bids bids;\n  SimpleOrder order0(true, 1250, 100);\n  SimpleOrder order1(true, 1255, 100);\n  SimpleOrder order2(true, 1240, 100);\n  SimpleOrder order3(true, MARKET_ORDER_PRICE, 100);\n  SimpleOrder order4(true, 1245, 100);\n\n  // Insert out of price order\n  bids.insert(std::make_pair(book::ComparablePrice(true, order0.price()), SimpleTracker(&order0)));\n  bids.insert(std::make_pair(book::ComparablePrice(true, order1.price()), SimpleTracker(&order1)));\n  bids.insert(std::make_pair(book::ComparablePrice(true, order2.price()), SimpleTracker(&order2)));\n  bids.insert(std::make_pair(book::ComparablePrice(true, order3.price()), SimpleTracker(&order3)));\n  bids.insert(std::make_pair(book::ComparablePrice(true, order4.price()), SimpleTracker(&order4)));\n  \n  // Should access in price order\n  SimpleOrder* expected_order[] = {\n    &order3, &order1, &order0, &order4, &order2\n  };\n\n  SimpleOrderBook::Bids::iterator bid;\n  int index = 0;\n\n  for (bid = bids.begin(); bid != bids.end(); ++bid, ++index) {\n    BOOST_CHECK_EQUAL(expected_order[index]->price(), bid->first);\n    BOOST_CHECK_EQUAL(expected_order[index], bid->second.ptr());\n  }\n\n  // Should be able to search and find\n  BOOST_CHECK((bids.upper_bound(book::ComparablePrice(true, 1245)))->second.ptr()->price() == 1240);\n  BOOST_CHECK((bids.lower_bound(book::ComparablePrice(true, 1245)))->second.ptr()->price() == 1245);\n}\n\nBOOST_AUTO_TEST_CASE(TestAsksMultimapSortCorrect)\n{\n  SimpleOrderBook::Asks asks;\n  SimpleOrder order0(false, 3250, 100);\n  SimpleOrder order1(false, 3235, 800);\n  SimpleOrder order2(false, 3230, 200);\n  SimpleOrder order3(false,    0, 200);\n  SimpleOrder order4(false, 3245, 100);\n  SimpleOrder order5(false, 3265, 200);\n\n  // Insert out of price order\n  asks.insert(std::make_pair(book::ComparablePrice(false, order0.price()), SimpleTracker(&order0)));\n  asks.insert(std::make_pair(book::ComparablePrice(false, order1.price()), SimpleTracker(&order1)));\n  asks.insert(std::make_pair(book::ComparablePrice(false, order2.price()), SimpleTracker(&order2)));\n  asks.insert(std::make_pair(book::ComparablePrice(false, MARKET_ORDER_PRICE), \n                             SimpleTracker(&order3)));\n  asks.insert(std::make_pair(book::ComparablePrice(false, order4.price()), SimpleTracker(&order4)));\n  asks.insert(std::make_pair(book::ComparablePrice(false, order5.price()), SimpleTracker(&order5)));\n  \n  // Should access in price order\n  SimpleOrder* expected_order[] = {\n    &order3, &order2, &order1, &order4, &order0, &order5\n  };\n\n  SimpleOrderBook::Asks::iterator ask;\n  int index = 0;\n\n  for (ask = asks.begin(); ask != asks.end(); ++ask, ++index) {\n    BOOST_CHECK_EQUAL(expected_order[index]->price(), ask->first);\n    BOOST_CHECK_EQUAL(expected_order[index], ask->second.ptr());\n  }\n\n  BOOST_CHECK((asks.upper_bound(book::ComparablePrice(false, 3235)))->second.ptr()->price() == 3245);\n  BOOST_CHECK((asks.lower_bound(book::ComparablePrice(false, 3235)))->second.ptr()->price() == 3235);\n}\n\nBOOST_AUTO_TEST_CASE(TestAddCompleteBid)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask1(false, 1252, 100);\n  SimpleOrder ask0(false, 1251, 100);\n  SimpleOrder bid1(true,  1251, 100);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc1(&bid1, 100, 125100);\n    SimpleFillCheck fc2(&ask0, 100, 125100);\n    BOOST_CHECK(add_and_verify(order_book, &bid1, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n}\nnamespace\n{\n  bool isBuy = true;\n  bool isSell = false;\n  bool expectMatch = true;\n  bool expectNoMatch = false;\n  bool expectComplete = true;\n  bool expectNoComplete = false;\n\n}\n\nBOOST_AUTO_TEST_CASE(TestAddCompleteAsk)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(isSell, 1251, 100);\n  SimpleOrder ask1(isSell, 1250, 100);\n  SimpleOrder bid0(isBuy,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n\n  // Match - complete\n  //Scope for fill checks\n  {\n    SimpleFillCheck fc1(&ask1, 100, 125000);\n    SimpleFillCheck fc2(&bid0, 100, 125000);\n    BOOST_CHECK(add_and_verify(order_book, &ask1, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(   0, 0,   0));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(0, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n}\n\nBOOST_AUTO_TEST_CASE(TestAddMultiMatchBid)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask1(false, 1252, 100);\n  SimpleOrder ask0(false, 1251, 300);\n  SimpleOrder ask2(false, 1251, 200);\n  SimpleOrder bid1(true,  1251, 500);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, false));\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 2, 500));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(3, order_book.asks().size());\n\n  // Match - complete\n  {\n    SimpleFillCheck fc1(&bid1, 500, 1251 * 500);\n    SimpleFillCheck fc2(&ask2, 200, 1251 * 200);\n    SimpleFillCheck fc3(&ask0, 300, 1251 * 300);\n    BOOST_CHECK(add_and_verify(order_book, &bid1, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify remaining\n  BOOST_CHECK_EQUAL(&ask1, order_book.asks().begin()->second.ptr());\n}\n\nBOOST_AUTO_TEST_CASE(TestAddMultiMatchAsk)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask1(false, 9252, 100);\n  SimpleOrder ask0(false, 9251, 300);\n  SimpleOrder ask2(false, 9251, 200);\n  SimpleOrder ask3(false, 9250, 600);\n  SimpleOrder bid0(true,  9250, 100);\n  SimpleOrder bid1(true,  9250, 500);\n  SimpleOrder bid2(true,  9248, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(3, order_book.bids().size());\n  BOOST_CHECK_EQUAL(3, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(9250, 2, 600));\n  BOOST_CHECK(dc.verify_bid(9248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(9251, 2, 500));\n  BOOST_CHECK(dc.verify_ask(9252, 1, 100));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc1(&ask3, 600, 9250 * 600);\n    SimpleFillCheck fc2(&bid0, 100, 9250 * 100);\n    SimpleFillCheck fc3(&bid1, 500, 9250 * 500);\n    BOOST_CHECK(add_and_verify(order_book, &ask3, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(9248, 1, 100));\n  BOOST_CHECK(dc.verify_ask(9251, 2, 500));\n  BOOST_CHECK(dc.verify_ask(9252, 1, 100));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(3, order_book.asks().size());\n\n  // Verify remaining\n  BOOST_CHECK_EQUAL(&bid2, order_book.bids().begin()->second.ptr());\n}\n\nBOOST_AUTO_TEST_CASE(TestAddPartialMatchBid)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(false, 7253, 300);\n  SimpleOrder ask1(false, 7252, 100);\n  SimpleOrder ask2(false, 7251, 200);\n  SimpleOrder bid1(true,  7251, 350);\n  SimpleOrder bid0(true,  7250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(3, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(7250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(7251, 1, 200));\n  BOOST_CHECK(dc.verify_ask(7252, 1, 100));\n  BOOST_CHECK(dc.verify_ask(7253, 1, 300));\n\n  // Match - partial\n  {\n    SimpleFillCheck fc1(&bid1, 200, 7251 * 200);\n    SimpleFillCheck fc2(&ask2, 200, 7251 * 200);\n    BOOST_CHECK(add_and_verify(order_book, &bid1, true, false));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(7251, 1, 150));\n  BOOST_CHECK(dc.verify_bid(7250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(7252, 1, 100));\n  BOOST_CHECK(dc.verify_ask(7253, 1, 300));\n\n  // Verify remaining\n  BOOST_CHECK_EQUAL(&ask1, order_book.asks().begin()->second.ptr());\n  BOOST_CHECK_EQUAL(&bid1, order_book.bids().begin()->second.ptr());\n}\n\nBOOST_AUTO_TEST_CASE(TestAddPartialMatchAsk)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(false, 1253, 300);\n  SimpleOrder ask1(false, 1251, 400);\n  SimpleOrder bid1(true,  1251, 350);\n  SimpleOrder bid0(true,  1250, 100);\n  SimpleOrder bid2(true,  1250, 200);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(3, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1251, 1, 350));\n  BOOST_CHECK(dc.verify_bid(1250, 2, 300));\n  BOOST_CHECK(dc.verify_ask(1253, 1, 300));\n\n  // Match - partial\n  {\n    SimpleFillCheck fc1(&ask1, 350, 1251 * 350);\n    SimpleFillCheck fc2(&bid1, 350, 1251 * 350);\n    BOOST_CHECK(add_and_verify(order_book, &ask1,  true, false));\n  }\n\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 2, 300));\n  BOOST_CHECK(dc.verify_ask(1251, 1,  50));\n  BOOST_CHECK(dc.verify_ask(1253, 1, 300));\n\n  // Verify remaining\n  BOOST_CHECK_EQUAL(&bid0, order_book.bids().begin()->second.ptr());\n  BOOST_CHECK_EQUAL(&ask1, order_book.asks().begin()->second.ptr());\n}\n\nBOOST_AUTO_TEST_CASE(TestAddMultiPartialMatchBid)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask1(false, 1252, 100);\n  SimpleOrder ask2(false, 1251, 200);\n  SimpleOrder ask0(false, 1251, 300);\n  SimpleOrder bid1(true,  1251, 750);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(3, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 2, 500));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // Match - partial\n  {\n    SimpleFillCheck fc1(&bid1, 500, 1251 * 500);\n    SimpleFillCheck fc2(&ask0, 300, 1251 * 300);\n    SimpleFillCheck fc3(&ask2, 200, 1251 * 200);\n    BOOST_CHECK(add_and_verify(order_book, &bid1, true, false));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 1, 250));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // Verify remaining\n  BOOST_CHECK_EQUAL(&ask1, order_book.asks().begin()->second.ptr());\n  BOOST_CHECK_EQUAL(&bid1, order_book.bids().begin()->second.ptr());\n}\n\nBOOST_AUTO_TEST_CASE(TestAddMultiPartialMatchAsk)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(false, 1253, 300);\n  SimpleOrder ask1(false, 1251, 700);\n  SimpleOrder bid1(true,  1251, 370);\n  SimpleOrder bid2(true,  1251, 200);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(3, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1251, 2, 570));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1253, 1, 300));\n\n  // Match - partial\n  {\n    SimpleFillCheck fc1(&ask1, 570, 1251 * 570);\n    SimpleFillCheck fc2(&bid1, 370, 1251 * 370);\n    SimpleFillCheck fc3(&bid2, 200, 1251 * 200);\n    BOOST_CHECK(add_and_verify(order_book, &ask1,  true, false));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 130));\n  BOOST_CHECK(dc.verify_ask(1253, 1, 300));\n\n  // Verify remaining\n  BOOST_CHECK_EQUAL(&bid0, order_book.bids().begin()->second.ptr());\n  BOOST_CHECK_EQUAL(100, order_book.bids().begin()->second.open_qty());\n  BOOST_CHECK_EQUAL(&ask1, order_book.asks().begin()->second.ptr());\n  BOOST_CHECK_EQUAL(130, order_book.asks().begin()->second.open_qty());\n}\n\nBOOST_AUTO_TEST_CASE(TestRepeatMatchBid)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask3(false, 1251, 400);\n  SimpleOrder ask2(false, 1251, 200);\n  SimpleOrder ask1(false, 1251, 300);\n  SimpleOrder ask0(false, 1251, 100);\n  SimpleOrder bid1(true,  1251, 900);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1251, 1, 900));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n\n  // Match - repeated\n  {\n    SimpleFillCheck fc1(&bid1, 100, 125100);\n    SimpleFillCheck fc2(&ask0, 100, 125100);\n    BOOST_CHECK(add_and_verify(order_book, &ask0, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 1, 800));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n\n  {\n    SimpleFillCheck fc1(&bid1, 300, 1251 * 300);\n    SimpleFillCheck fc2(&ask1, 300, 1251 * 300);\n    BOOST_CHECK(add_and_verify(order_book, &ask1, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 1, 500));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n\n  {\n    SimpleFillCheck fc1(&bid1, 200, 1251 * 200);\n    SimpleFillCheck fc2(&ask2, 200, 1251 * 200);\n    BOOST_CHECK(add_and_verify(order_book, &ask2, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 1, 300));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n\n  {\n    SimpleFillCheck fc1(&bid1, 300, 1251 * 300);\n    SimpleFillCheck fc2(&ask3, 300, 1251 * 300);\n    BOOST_CHECK(add_and_verify(order_book, &ask3, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n}\n\nBOOST_AUTO_TEST_CASE(TestRepeatMatchAsk)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(false,  1252, 100);\n  SimpleOrder ask1(false,  1251, 900);\n  SimpleOrder bid0(true, 1251, 100);\n  SimpleOrder bid1(true, 1251, 300);\n  SimpleOrder bid2(true, 1251, 200);\n  SimpleOrder bid3(true, 1251, 400);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_ask(1251, 1, 900));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  BOOST_CHECK_EQUAL(&ask1, order_book.asks().begin()->second.ptr());\n\n  // Match - repeated\n  {\n    SimpleFillCheck fc1(&ask1, 100, 125100);\n    SimpleFillCheck fc2(&bid0, 100, 125100);\n    BOOST_CHECK(add_and_verify(order_book, &bid0, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_ask(1251, 1, 800));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  {\n    SimpleFillCheck fc1(&ask1, 300, 1251 * 300);\n    SimpleFillCheck fc2(&bid1, 300, 1251 * 300);\n    BOOST_CHECK(add_and_verify(order_book, &bid1, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_ask(1251, 1, 500));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  {\n    SimpleFillCheck fc1(&ask1, 200, 1251 * 200);\n    SimpleFillCheck fc2(&bid2, 200, 1251 * 200);\n    BOOST_CHECK(add_and_verify(order_book, &bid2, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_ask(1251, 1, 300));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  {\n    SimpleFillCheck fc1(&ask1, 300, 1251 * 300);\n    SimpleFillCheck fc2(&bid3, 300, 1251 * 300);\n    BOOST_CHECK(add_and_verify(order_book, &bid3, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n}\n\nBOOST_AUTO_TEST_CASE(TestAddMarketOrderBid)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask1(false, 1252, 100);\n  SimpleOrder ask0(false, 1251, 100);\n  SimpleOrder bid1(true,     0, 100);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc1(&bid1, 100, 125100);\n    SimpleFillCheck fc2(&ask0, 100, 125100);\n    BOOST_CHECK(add_and_verify(order_book, &bid1, true, true));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n}\n\nBOOST_AUTO_TEST_CASE(TestAddMarketOrderAsk)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(false, 1252, 100);\n  SimpleOrder ask1(false,    0, 100);\n  SimpleOrder bid1(true,  1251, 100);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1251, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // Match - complete\n  { \n    //ASSERT_NO_THROW(\n      SimpleFillCheck fc1(&bid1, 100, 125100);\n      SimpleFillCheck fc2(&ask1, 100, 125100);\n      BOOST_CHECK(add_and_verify(order_book, &ask1, true, true));\n   // ); \n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n}\n\nBOOST_AUTO_TEST_CASE(TestAddMarketOrderBidMultipleMatch)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask1(false, 12520, 300);\n  SimpleOrder ask0(false, 12510, 200);\n  SimpleOrder bid1(true,      0, 500);\n  SimpleOrder bid0(true,  12500, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(12500, 1, 100));\n  BOOST_CHECK(dc.verify_ask(12510, 1, 200));\n  BOOST_CHECK(dc.verify_ask(12520, 1, 300));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc1(&bid1, 500, 12510 * 200 + 12520 * 300);\n    SimpleFillCheck fc2(&ask0, 200, 12510 * 200);\n    SimpleFillCheck fc3(&ask1, 300, 12520 * 300);\n    BOOST_CHECK(add_and_verify(order_book, &bid1, true, true));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(0, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(12500, 1, 100));\n  BOOST_CHECK(dc.verify_ask(    0, 0,   0));\n}\n\nBOOST_AUTO_TEST_CASE(TestAddMarketOrderAskMultipleMatch)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(false, 12520, 100);\n  SimpleOrder ask1(false,     0, 600);\n  SimpleOrder bid1(true,  12510, 200);\n  SimpleOrder bid0(true,  12500, 400);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(12510, 1, 200));\n  BOOST_CHECK(dc.verify_bid(12500, 1, 400));\n  BOOST_CHECK(dc.verify_ask(12520, 1, 100));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc1(&bid0, 400, 12500 * 400);\n    SimpleFillCheck fc2(&bid1, 200, 12510 * 200);\n    SimpleFillCheck fc3(&ask1, 600, 12500 * 400 + 12510 * 200);\n    BOOST_CHECK(add_and_verify(order_book, &ask1, true, true));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(0, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(    0, 0,   0));\n  BOOST_CHECK(dc.verify_ask(12520, 1, 100));\n}\n\nBOOST_AUTO_TEST_CASE(TestMatchMarketOrderBid)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(false, 1253, 100);\n  SimpleOrder bid1(true,     0, 100);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(0, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_bid(   0, 0,   0));\n  BOOST_CHECK(dc.verify_ask(   0, 0,   0));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc1(&bid1, 100, 125300);\n    SimpleFillCheck fc2(&ask0, 100, 125300);\n    BOOST_CHECK(add_and_verify(order_book, &ask0, true, true));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(0, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(   0, 0,   0));\n}\n\nBOOST_AUTO_TEST_CASE(TestMatchMarketOrderAsk)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(false, 1252, 100);\n  SimpleOrder ask1(false,    0, 100);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(0, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n  BOOST_CHECK(dc.verify_ask(   0, 0,   0));\n  BOOST_CHECK(dc.verify_bid(   0, 0,   0));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc1(&bid0, 100, 125000);\n    SimpleFillCheck fc2(&ask1, 100, 125000);\n    BOOST_CHECK(add_and_verify(order_book, &bid0, true, true));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(0, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n  BOOST_CHECK(dc.verify_ask(   0, 0,   0));\n  BOOST_CHECK(dc.verify_bid(   0, 0,   0));\n}\n\nBOOST_AUTO_TEST_CASE(TestMatchMultipleMarketOrderBid)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(false, 1253, 400);\n  SimpleOrder bid1(true,     0, 100);\n  SimpleOrder bid2(true,     0, 200);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(3, order_book.bids().size());\n  BOOST_CHECK_EQUAL(0, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_ask(   0, 0,   0));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_bid(   0, 0,   0));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc1(&bid1, 100, 1253 * 100);\n    SimpleFillCheck fc2(&bid2, 200, 1253 * 200);\n    SimpleFillCheck fc3(&ask0, 300, 1253 * 300);\n    BOOST_CHECK(add_and_verify(order_book, &ask0, true, false));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_ask(1253, 1, 100));\n  BOOST_CHECK(dc.verify_ask(   0, 0,   0));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_bid(   0, 0,   0));\n}\n\n\nBOOST_AUTO_TEST_CASE(TestMatchMultipleMarketOrderAsk)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(false, 1252, 100);\n  SimpleOrder ask2(false,    0, 400);\n  SimpleOrder ask1(false,    0, 100);\n  SimpleOrder bid0(true,  1250, 300);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(0, order_book.bids().size());\n  BOOST_CHECK_EQUAL(3, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n  BOOST_CHECK(dc.verify_ask(   0, 0,   0));\n  BOOST_CHECK(dc.verify_bid(   0, 0,   0));\n\n  // Match - partiaL\n  {\n    SimpleFillCheck fc1(&bid0, 300, 1250 * 300);\n    SimpleFillCheck fc2(&ask1, 100, 1250 * 100);\n    SimpleFillCheck fc3(&ask2, 200, 1250 * 200);\n    BOOST_CHECK(add_and_verify(order_book, &bid0, true, true));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(0, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n  BOOST_CHECK(dc.verify_ask(   0, 0,   0));\n  BOOST_CHECK(dc.verify_bid(   0, 0,   0));\n}\n\nBOOST_AUTO_TEST_CASE(TestCancelBid)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask2(false, 1252, 100);\n  SimpleOrder ask1(false, 1251, 100);\n  SimpleOrder ask0(false, 1251, 100);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(3, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 2, 200));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // Cancel bid\n  BOOST_CHECK(cancel_and_verify(order_book, &bid0, simple::os_cancelled));\n\n  // Cancel correctness\n  BOOST_CHECK(cancel_and_verify(order_book, &ask1, simple::os_cancelled));\n  BOOST_CHECK(cancel_and_verify(order_book, &ask1, simple::os_cancelled));\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(0,    0,   0));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(0, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n}\n\nBOOST_AUTO_TEST_CASE(TestCancelAskAndMatch)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask1(false, 1252, 100);\n  SimpleOrder ask0(false, 1251, 100);\n  SimpleOrder bid2(true,  1252, 100);\n  SimpleOrder bid0(true,  1250, 100);\n  SimpleOrder bid1(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(2, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1250, 2, 200));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n\n  // Cancel bid\n  BOOST_CHECK(cancel_and_verify(order_book, &ask0, simple::os_cancelled));\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 2, 200));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n  BOOST_CHECK(dc.verify_ask(   0, 0,   0));\n\n  // Match - partiaL\n  {\n    SimpleFillCheck fc1(&bid2, 100, 1252 * 100);\n    SimpleFillCheck fc2(&ask1, 100, 1252 * 100);\n    BOOST_CHECK(add_and_verify(order_book, &bid2, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 2, 200));\n  BOOST_CHECK(dc.verify_ask(   0, 0,   0));\n\n  // Cancel bid\n  BOOST_CHECK(cancel_and_verify(order_book, &bid0, simple::os_cancelled));\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(   0, 0,   0));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(0, order_book.asks().size());\n}\n\nBOOST_AUTO_TEST_CASE(TestCancelBidFail)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(false, 1251, 100);\n  SimpleOrder ask1(false, 1250, 100);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(   0, 0,   0));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_bid(   0, 0,   0));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc1(&ask1, 100, 125000);\n    SimpleFillCheck fc2(&bid0, 100, 125000);\n    BOOST_CHECK(add_and_verify(order_book, &ask1, true, true));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(0, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(   0, 0,   0));\n  BOOST_CHECK(dc.verify_bid(   0, 0,   0));\n\n  // Cancel a filled order\n  BOOST_CHECK(cancel_and_verify(order_book, &bid0, simple::os_complete));\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(   0, 0,   0));\n  BOOST_CHECK(dc.verify_bid(   0, 0,   0));\n}\n\nBOOST_AUTO_TEST_CASE(TestCancelAskFail)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask1(false, 1252, 100);\n  SimpleOrder ask0(false, 1251, 100);\n  SimpleOrder bid1(true,  1251, 100);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_ask(1251, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n  BOOST_CHECK(dc.verify_ask(   0, 0,   0));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_bid(   0, 0,   0));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc1(&bid1, 100, 125100);\n    SimpleFillCheck fc2(&ask0, 100, 125100);\n    BOOST_CHECK(add_and_verify(order_book, &bid1, true, true));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n  BOOST_CHECK(dc.verify_ask(   0, 0,   0));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_bid(   0, 0,   0));\n\n  // Cancel a filled order\n  BOOST_CHECK(cancel_and_verify(order_book, &ask0, simple::os_complete));\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n  BOOST_CHECK(dc.verify_ask(   0, 0,   0));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_bid(   0, 0,   0));\n}\n\nBOOST_AUTO_TEST_CASE(TestCancelBidRestore)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask10(false, 1258, 600);\n  SimpleOrder ask9(false,  1257, 700);\n  SimpleOrder ask8(false,  1256, 100);\n  SimpleOrder ask7(false,  1256, 100);\n  SimpleOrder ask6(false,  1255, 500);\n  SimpleOrder ask5(false,  1255, 200);\n  SimpleOrder ask4(false,  1254, 300);\n  SimpleOrder ask3(false,  1252, 200);\n  SimpleOrder ask2(false,  1252, 100);\n  SimpleOrder ask1(false,  1251, 400);\n  SimpleOrder ask0(false,  1250, 500);\n\n  SimpleOrder bid0(true,   1249, 100);\n  SimpleOrder bid1(true,   1249, 200);\n  SimpleOrder bid2(true,   1249, 200);\n  SimpleOrder bid3(true,   1248, 400);\n  SimpleOrder bid4(true,   1246, 600);\n  SimpleOrder bid5(true,   1246, 500);\n  SimpleOrder bid6(true,   1245, 200);\n  SimpleOrder bid7(true,   1245, 100);\n  SimpleOrder bid8(true,   1245, 200);\n  SimpleOrder bid9(true,   1244, 700);\n  SimpleOrder bid10(true,  1244, 300);\n  SimpleOrder bid11(true,  1242, 300);\n  SimpleOrder bid12(true,  1241, 400);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask0,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask3,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask4,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask5,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask6,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask7,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask8,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask9,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask10, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid0,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid3,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid4,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid5,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid6,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid7,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid8,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid9,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid10, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid11, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid12, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(13, order_book.bids().size());\n  BOOST_CHECK_EQUAL(11, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1249, 3,  500));\n  BOOST_CHECK(dc.verify_bid(1248, 1,  400));\n  BOOST_CHECK(dc.verify_bid(1246, 2, 1100));\n  BOOST_CHECK(dc.verify_bid(1245, 3,  500));\n  BOOST_CHECK(dc.verify_bid(1244, 2, 1000));\n  BOOST_CHECK(dc.verify_ask(1250, 1,  500));\n  BOOST_CHECK(dc.verify_ask(1251, 1,  400));\n  BOOST_CHECK(dc.verify_ask(1252, 2,  300));\n  BOOST_CHECK(dc.verify_ask(1254, 1,  300));\n  BOOST_CHECK(dc.verify_ask(1255, 2,  700));\n\n  // Cancel a bid level (erase)\n  BOOST_CHECK(cancel_and_verify(order_book, &bid3, simple::os_cancelled));\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1249, 3,  500));\n  BOOST_CHECK(dc.verify_bid(1246, 2, 1100));\n  BOOST_CHECK(dc.verify_bid(1245, 3,  500));\n  BOOST_CHECK(dc.verify_bid(1244, 2, 1000));\n  BOOST_CHECK(dc.verify_bid(1242, 1,  300)); // Restored\n  BOOST_CHECK(dc.verify_ask(1250, 1,  500));\n  BOOST_CHECK(dc.verify_ask(1251, 1,  400));\n  BOOST_CHECK(dc.verify_ask(1252, 2,  300));\n  BOOST_CHECK(dc.verify_ask(1254, 1,  300));\n  BOOST_CHECK(dc.verify_ask(1255, 2,  700));\n  \n  // Cancel common bid levels (not erased)\n  BOOST_CHECK(cancel_and_verify(order_book, &bid7, simple::os_cancelled));\n  BOOST_CHECK(cancel_and_verify(order_book, &bid4, simple::os_cancelled));\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1249, 3,  500));\n  BOOST_CHECK(dc.verify_bid(1246, 1,  500)); // Cxl 600\n  BOOST_CHECK(dc.verify_bid(1245, 2,  400)); // Cxl 100\n  BOOST_CHECK(dc.verify_bid(1244, 2, 1000));\n  BOOST_CHECK(dc.verify_bid(1242, 1,  300));\n  BOOST_CHECK(dc.verify_ask(1250, 1,  500));\n  BOOST_CHECK(dc.verify_ask(1251, 1,  400));\n  BOOST_CHECK(dc.verify_ask(1252, 2,  300));\n  BOOST_CHECK(dc.verify_ask(1254, 1,  300));\n  BOOST_CHECK(dc.verify_ask(1255, 2,  700));\n\n  // Cancel the best bid level (erased)\n  BOOST_CHECK(cancel_and_verify(order_book, &bid1, simple::os_cancelled));\n  BOOST_CHECK(cancel_and_verify(order_book, &bid0, simple::os_cancelled));\n  BOOST_CHECK(cancel_and_verify(order_book, &bid2, simple::os_cancelled));\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1246, 1,  500));\n  BOOST_CHECK(dc.verify_bid(1245, 2,  400));\n  BOOST_CHECK(dc.verify_bid(1244, 2, 1000));\n  BOOST_CHECK(dc.verify_bid(1242, 1,  300));\n  BOOST_CHECK(dc.verify_bid(1241, 1,  400));\n  BOOST_CHECK(dc.verify_ask(1250, 1,  500));\n  BOOST_CHECK(dc.verify_ask(1251, 1,  400));\n  BOOST_CHECK(dc.verify_ask(1252, 2,  300));\n  BOOST_CHECK(dc.verify_ask(1254, 1,  300));\n  BOOST_CHECK(dc.verify_ask(1255, 2,  700));\n}\n\nBOOST_AUTO_TEST_CASE(TestCancelAskRestore)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask10(false, 1258, 600);\n  SimpleOrder ask9(false,  1257, 700);\n  SimpleOrder ask8(false,  1256, 100);\n  SimpleOrder ask7(false,  1256, 100);\n  SimpleOrder ask6(false,  1255, 500);\n  SimpleOrder ask5(false,  1255, 200);\n  SimpleOrder ask4(false,  1254, 300);\n  SimpleOrder ask3(false,  1252, 200);\n  SimpleOrder ask2(false,  1252, 100);\n  SimpleOrder ask1(false,  1251, 400);\n  SimpleOrder ask0(false,  1250, 500);\n\n  SimpleOrder bid0(true,   1249, 100);\n  SimpleOrder bid1(true,   1249, 200);\n  SimpleOrder bid2(true,   1249, 200);\n  SimpleOrder bid3(true,   1248, 400);\n  SimpleOrder bid4(true,   1246, 600);\n  SimpleOrder bid5(true,   1246, 500);\n  SimpleOrder bid6(true,   1245, 200);\n  SimpleOrder bid7(true,   1245, 100);\n  SimpleOrder bid8(true,   1245, 200);\n  SimpleOrder bid9(true,   1244, 700);\n  SimpleOrder bid10(true,  1244, 300);\n  SimpleOrder bid11(true,  1242, 300);\n  SimpleOrder bid12(true,  1241, 400);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask0,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask3,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask4,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask5,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask6,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask7,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask8,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask9,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask10, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid0,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid3,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid4,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid5,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid6,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid7,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid8,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid9,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid10, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid11, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid12, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(13, order_book.bids().size());\n  BOOST_CHECK_EQUAL(11, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1249, 3,  500));\n  BOOST_CHECK(dc.verify_bid(1248, 1,  400));\n  BOOST_CHECK(dc.verify_bid(1246, 2, 1100));\n  BOOST_CHECK(dc.verify_bid(1245, 3,  500));\n  BOOST_CHECK(dc.verify_bid(1244, 2, 1000));\n  BOOST_CHECK(dc.verify_ask(1250, 1,  500));\n  BOOST_CHECK(dc.verify_ask(1251, 1,  400));\n  BOOST_CHECK(dc.verify_ask(1252, 2,  300));\n  BOOST_CHECK(dc.verify_ask(1254, 1,  300));\n  BOOST_CHECK(dc.verify_ask(1255, 2,  700));\n\n  // Cancel an ask level (erase)\n  BOOST_CHECK(cancel_and_verify(order_book, &ask1, simple::os_cancelled));\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1249, 3,  500));\n  BOOST_CHECK(dc.verify_bid(1248, 1,  400));\n  BOOST_CHECK(dc.verify_bid(1246, 2, 1100));\n  BOOST_CHECK(dc.verify_bid(1245, 3,  500));\n  BOOST_CHECK(dc.verify_bid(1244, 2, 1000));\n  BOOST_CHECK(dc.verify_ask(1250, 1,  500));\n  BOOST_CHECK(dc.verify_ask(1252, 2,  300));\n  BOOST_CHECK(dc.verify_ask(1254, 1,  300));\n  BOOST_CHECK(dc.verify_ask(1255, 2,  700));\n  BOOST_CHECK(dc.verify_ask(1256, 2,  200)); // Restored\n\n  // Cancel common ask levels (not erased)\n  BOOST_CHECK(cancel_and_verify(order_book, &ask2, simple::os_cancelled));\n  BOOST_CHECK(cancel_and_verify(order_book, &ask6, simple::os_cancelled));\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1249, 3,  500));\n  BOOST_CHECK(dc.verify_bid(1248, 1,  400));\n  BOOST_CHECK(dc.verify_bid(1246, 2, 1100));\n  BOOST_CHECK(dc.verify_bid(1245, 3,  500));\n  BOOST_CHECK(dc.verify_bid(1244, 2, 1000));\n  BOOST_CHECK(dc.verify_ask(1250, 1,  500));\n  BOOST_CHECK(dc.verify_ask(1252, 1,  200)); // Cxl 100\n  BOOST_CHECK(dc.verify_ask(1254, 1,  300));\n  BOOST_CHECK(dc.verify_ask(1255, 1,  200)); // Cxl 500\n  BOOST_CHECK(dc.verify_ask(1256, 2,  200));\n\n  // Cancel the best ask level (erased)\n  BOOST_CHECK(cancel_and_verify(order_book, &ask0, simple::os_cancelled));\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1249, 3,  500));\n  BOOST_CHECK(dc.verify_bid(1248, 1,  400));\n  BOOST_CHECK(dc.verify_bid(1246, 2, 1100));\n  BOOST_CHECK(dc.verify_bid(1245, 3,  500));\n  BOOST_CHECK(dc.verify_bid(1244, 2, 1000));\n  BOOST_CHECK(dc.verify_ask(1252, 1,  200));\n  BOOST_CHECK(dc.verify_ask(1254, 1,  300));\n  BOOST_CHECK(dc.verify_ask(1255, 1,  200));\n  BOOST_CHECK(dc.verify_ask(1256, 2,  200));\n  BOOST_CHECK(dc.verify_ask(1257, 1,  700)); // Restored\n}\n\nBOOST_AUTO_TEST_CASE(TestFillCompleteBidRestoreDepth)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask10(false, 1258, 600);\n  SimpleOrder ask9(false,  1257, 700);\n  SimpleOrder ask8(false,  1256, 100);\n  SimpleOrder ask7(false,  1256, 100);\n  SimpleOrder ask6(false,  1255, 500);\n  SimpleOrder ask5(false,  1255, 200);\n  SimpleOrder ask4(false,  1254, 300);\n  SimpleOrder ask3(false,  1252, 200);\n  SimpleOrder ask2(false,  1252, 100);\n  SimpleOrder ask1(false,  1251, 400);\n  SimpleOrder ask0(false,  1250, 500);\n\n  SimpleOrder bid0(true,   1249, 100);\n  SimpleOrder bid1(true,   1249, 200);\n  SimpleOrder bid2(true,   1249, 200);\n  SimpleOrder bid3(true,   1248, 400);\n  SimpleOrder bid4(true,   1246, 600);\n  SimpleOrder bid5(true,   1246, 500);\n  SimpleOrder bid6(true,   1245, 200);\n  SimpleOrder bid7(true,   1245, 100);\n  SimpleOrder bid8(true,   1245, 200);\n  SimpleOrder bid9(true,   1244, 700);\n  SimpleOrder bid10(true,  1244, 300);\n  SimpleOrder bid11(true,  1242, 300);\n  SimpleOrder bid12(true,  1241, 400);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask0,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask3,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask4,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask5,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask6,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask7,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask8,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask9,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask10, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid0,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid3,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid4,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid5,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid6,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid7,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid8,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid9,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid10, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid11, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid12, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(13, order_book.bids().size());\n  BOOST_CHECK_EQUAL(11, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1249, 3,  500));\n  BOOST_CHECK(dc.verify_bid(1248, 1,  400));\n  BOOST_CHECK(dc.verify_bid(1246, 2, 1100));\n  BOOST_CHECK(dc.verify_bid(1245, 3,  500));\n  BOOST_CHECK(dc.verify_bid(1244, 2, 1000));\n  BOOST_CHECK(dc.verify_ask(1250, 1,  500));\n  BOOST_CHECK(dc.verify_ask(1251, 1,  400));\n  BOOST_CHECK(dc.verify_ask(1252, 2,  300));\n  BOOST_CHECK(dc.verify_ask(1254, 1,  300));\n  BOOST_CHECK(dc.verify_ask(1255, 2,  700));\n\n  // Fill the top bid level (erase) and add an ask level (insert)\n  SimpleOrder cross_ask(false,  1249, 800);\n  {\n    SimpleFillCheck fc1(&bid0,      100, 1249 * 100);\n    SimpleFillCheck fc2(&bid1,      200, 1249 * 200);\n    SimpleFillCheck fc3(&bid2,      200, 1249 * 200);\n    SimpleFillCheck fc4(&cross_ask, 500, 1249 * 500);\n    BOOST_CHECK(add_and_verify(order_book, &cross_ask, true, false));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1248, 1,  400));\n  BOOST_CHECK(dc.verify_bid(1246, 2, 1100));\n  BOOST_CHECK(dc.verify_bid(1245, 3,  500));\n  BOOST_CHECK(dc.verify_bid(1244, 2, 1000));\n  BOOST_CHECK(dc.verify_bid(1242, 1,  300)); // Restored\n  BOOST_CHECK(dc.verify_ask(1249, 1,  300)); // Inserted\n  BOOST_CHECK(dc.verify_ask(1250, 1,  500));\n  BOOST_CHECK(dc.verify_ask(1251, 1,  400));\n  BOOST_CHECK(dc.verify_ask(1252, 2,  300));\n  BOOST_CHECK(dc.verify_ask(1254, 1,  300));\n  \n  // Fill the top bid level (erase) but do not add an ask level (no insert)\n  SimpleOrder cross_ask2(false,  1248, 400);\n  {\n    SimpleFillCheck fc1(&bid3,       400, 1248 * 400);\n    SimpleFillCheck fc4(&cross_ask2, 400, 1248 * 400);\n    BOOST_CHECK(add_and_verify(order_book, &cross_ask2, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1246, 2, 1100));\n  BOOST_CHECK(dc.verify_bid(1245, 3,  500));\n  BOOST_CHECK(dc.verify_bid(1244, 2, 1000));\n  BOOST_CHECK(dc.verify_bid(1242, 1,  300));\n  BOOST_CHECK(dc.verify_bid(1241, 1,  400)); // Restored\n  BOOST_CHECK(dc.verify_ask(1249, 1,  300));\n  BOOST_CHECK(dc.verify_ask(1250, 1,  500));\n  BOOST_CHECK(dc.verify_ask(1251, 1,  400));\n  BOOST_CHECK(dc.verify_ask(1252, 2,  300));\n  BOOST_CHECK(dc.verify_ask(1254, 1,  300));\n\n  // Fill the top bid level (erase) and add ask level (insert),\n  //    but nothing to restore\n  SimpleOrder cross_ask3(false,  1246, 2400);\n  {\n    SimpleFillCheck fc1(&bid4,        600, 1246 * 600);\n    SimpleFillCheck fc2(&bid5,        500, 1246 * 500);\n    SimpleFillCheck fc3(&cross_ask3, 1100, 1246 * 1100);\n    BOOST_CHECK(add_and_verify(order_book, &cross_ask3, true, false));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1245, 3,  500));\n  BOOST_CHECK(dc.verify_bid(1244, 2, 1000));\n  BOOST_CHECK(dc.verify_bid(1242, 1,  300));\n  BOOST_CHECK(dc.verify_bid(1241, 1,  400));\n  BOOST_CHECK(dc.verify_bid(   0, 0,    0)); // Nothing to restore\n  BOOST_CHECK(dc.verify_ask(1246, 1, 1300));\n  BOOST_CHECK(dc.verify_ask(1249, 1,  300));\n  BOOST_CHECK(dc.verify_ask(1250, 1,  500));\n  BOOST_CHECK(dc.verify_ask(1251, 1,  400));\n  BOOST_CHECK(dc.verify_ask(1252, 2,  300));\n\n  // Partial fill the top bid level (reduce) \n  SimpleOrder cross_ask4(false,  1245, 250);\n  {\n    SimpleFillCheck fc1(&bid6,        200, 1245 * 200);\n    SimpleFillCheck fc2(&bid7,         50, 1245 *  50);\n    SimpleFillCheck fc3(&cross_ask4,  250, 1245 * 250);\n    BOOST_CHECK(add_and_verify(order_book, &cross_ask4, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1245, 2,  250)); // 1 filled, 1 reduced\n  BOOST_CHECK(dc.verify_bid(1244, 2, 1000));\n  BOOST_CHECK(dc.verify_bid(1242, 1,  300));\n  BOOST_CHECK(dc.verify_bid(1241, 1,  400));\n  BOOST_CHECK(dc.verify_bid(   0, 0,    0));\n  BOOST_CHECK(dc.verify_ask(1246, 1, 1300));\n  BOOST_CHECK(dc.verify_ask(1249, 1,  300));\n  BOOST_CHECK(dc.verify_ask(1250, 1,  500));\n  BOOST_CHECK(dc.verify_ask(1251, 1,  400));\n  BOOST_CHECK(dc.verify_ask(1252, 2,  300));\n}\n\nBOOST_AUTO_TEST_CASE(TestFillCompleteAskRestoreDepth)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask10(false, 1258, 600);\n  SimpleOrder ask9(false,  1257, 700);\n  SimpleOrder ask8(false,  1256, 100);\n  SimpleOrder ask7(false,  1256, 100);\n  SimpleOrder ask6(false,  1255, 500);\n  SimpleOrder ask5(false,  1255, 200);\n  SimpleOrder ask4(false,  1254, 300);\n  SimpleOrder ask3(false,  1252, 200);\n  SimpleOrder ask2(false,  1252, 100);\n  SimpleOrder ask1(false,  1251, 400);\n  SimpleOrder ask0(false,  1250, 500);\n\n  SimpleOrder bid0(true,   1249, 100);\n  SimpleOrder bid1(true,   1249, 200);\n  SimpleOrder bid2(true,   1249, 200);\n  SimpleOrder bid3(true,   1248, 400);\n  SimpleOrder bid4(true,   1246, 600);\n  SimpleOrder bid5(true,   1246, 500);\n  SimpleOrder bid6(true,   1245, 200);\n  SimpleOrder bid7(true,   1245, 100);\n  SimpleOrder bid8(true,   1245, 200);\n  SimpleOrder bid9(true,   1244, 700);\n  SimpleOrder bid10(true,  1244, 300);\n  SimpleOrder bid11(true,  1242, 300);\n  SimpleOrder bid12(true,  1241, 400);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask0,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask3,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask4,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask5,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask6,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask7,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask8,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask9,  false));\n  BOOST_CHECK(add_and_verify(order_book, &ask10, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid0,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid3,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid4,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid5,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid6,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid7,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid8,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid9,  false));\n  BOOST_CHECK(add_and_verify(order_book, &bid10, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid11, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid12, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(13, order_book.bids().size());\n  BOOST_CHECK_EQUAL(11, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1249, 3,  500));\n  BOOST_CHECK(dc.verify_bid(1248, 1,  400));\n  BOOST_CHECK(dc.verify_bid(1246, 2, 1100));\n  BOOST_CHECK(dc.verify_bid(1245, 3,  500));\n  BOOST_CHECK(dc.verify_bid(1244, 2, 1000));\n  BOOST_CHECK(dc.verify_ask(1250, 1,  500));\n  BOOST_CHECK(dc.verify_ask(1251, 1,  400));\n  BOOST_CHECK(dc.verify_ask(1252, 2,  300));\n  BOOST_CHECK(dc.verify_ask(1254, 1,  300));\n  BOOST_CHECK(dc.verify_ask(1255, 2,  700));\n\n  // Fill the top ask level (erase) and add a bid level (insert)\n  SimpleOrder cross_bid(true,  1250, 800);\n  {\n    SimpleFillCheck fc1(&ask0,      500, 1250 * 500);\n    SimpleFillCheck fc4(&cross_bid, 500, 1250 * 500);\n    BOOST_CHECK(add_and_verify(order_book, &cross_bid, true, false));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 1,  300));\n  BOOST_CHECK(dc.verify_bid(1249, 3,  500));\n  BOOST_CHECK(dc.verify_bid(1248, 1,  400));\n  BOOST_CHECK(dc.verify_bid(1246, 2, 1100));\n  BOOST_CHECK(dc.verify_bid(1245, 3,  500));\n  BOOST_CHECK(dc.verify_ask(1251, 1,  400));\n  BOOST_CHECK(dc.verify_ask(1252, 2,  300));\n  BOOST_CHECK(dc.verify_ask(1254, 1,  300));\n  BOOST_CHECK(dc.verify_ask(1255, 2,  700));\n  BOOST_CHECK(dc.verify_ask(1256, 2,  200)); // Restored\n\n  // Fill the top ask level (erase) but do not add an bid level (no insert)\n  SimpleOrder cross_bid2(true,  1251, 400);\n  {\n    SimpleFillCheck fc1(&ask1,       400, 1251 * 400);\n    SimpleFillCheck fc4(&cross_bid2, 400, 1251 * 400);\n    BOOST_CHECK(add_and_verify(order_book, &cross_bid2, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 1,  300));\n  BOOST_CHECK(dc.verify_bid(1249, 3,  500));\n  BOOST_CHECK(dc.verify_bid(1248, 1,  400));\n  BOOST_CHECK(dc.verify_bid(1246, 2, 1100));\n  BOOST_CHECK(dc.verify_bid(1245, 3,  500));\n  BOOST_CHECK(dc.verify_ask(1252, 2,  300));\n  BOOST_CHECK(dc.verify_ask(1254, 1,  300));\n  BOOST_CHECK(dc.verify_ask(1255, 2,  700));\n  BOOST_CHECK(dc.verify_ask(1256, 2,  200));\n  BOOST_CHECK(dc.verify_ask(1257, 1,  700)); // Restored\n\n  // Fill the top ask level (erase) and add bid level (insert),\n  //    but nothing to restore\n  SimpleOrder cross_bid3(true,  1252, 2400);\n  {\n    SimpleFillCheck fc1(&ask2,        100, 1252 * 100);\n    SimpleFillCheck fc2(&ask3,        200, 1252 * 200);\n    SimpleFillCheck fc3(&cross_bid3,  300, 1252 * 300);\n    BOOST_CHECK(add_and_verify(order_book, &cross_bid3, true, false));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1252, 1, 2100)); // Insert\n  BOOST_CHECK(dc.verify_bid(1250, 1,  300));\n  BOOST_CHECK(dc.verify_bid(1249, 3,  500));\n  BOOST_CHECK(dc.verify_bid(1248, 1,  400));\n  BOOST_CHECK(dc.verify_bid(1246, 2, 1100));\n  BOOST_CHECK(dc.verify_ask(1254, 1,  300));\n  BOOST_CHECK(dc.verify_ask(1255, 2,  700));\n  BOOST_CHECK(dc.verify_ask(1256, 2,  200));\n  BOOST_CHECK(dc.verify_ask(1257, 1,  700));\n  BOOST_CHECK(dc.verify_ask(1258, 1,  600)); // Restored\n\n  // Fill the top ask level (erase) but nothing to restore\n  SimpleOrder cross_bid4(true,  1254, 300);\n  {\n    SimpleFillCheck fc2(&ask4,        300, 1254 * 300);\n    SimpleFillCheck fc3(&cross_bid4,  300, 1254 * 300);\n    BOOST_CHECK(add_and_verify(order_book, &cross_bid4, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1252, 1, 2100));\n  BOOST_CHECK(dc.verify_bid(1250, 1,  300));\n  BOOST_CHECK(dc.verify_bid(1249, 3,  500));\n  BOOST_CHECK(dc.verify_bid(1248, 1,  400));\n  BOOST_CHECK(dc.verify_bid(1246, 2, 1100));\n  BOOST_CHECK(dc.verify_ask(1255, 2,  700));\n  BOOST_CHECK(dc.verify_ask(1256, 2,  200));\n  BOOST_CHECK(dc.verify_ask(1257, 1,  700));\n  BOOST_CHECK(dc.verify_ask(1258, 1,  600));\n  BOOST_CHECK(dc.verify_ask(   0, 0,    0)); // Nothing to restore\n\n  // Partial fill the top ask level (reduce) \n  SimpleOrder cross_bid5(true,  1255, 550);\n  {\n    SimpleFillCheck fc1(&ask5,        200, 1255 * 200);\n    SimpleFillCheck fc2(&ask6,        350, 1255 * 350);\n    SimpleFillCheck fc3(&cross_bid5,  550, 1255 * 550);\n    BOOST_CHECK(add_and_verify(order_book, &cross_bid5, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1252, 1, 2100));\n  BOOST_CHECK(dc.verify_bid(1250, 1,  300));\n  BOOST_CHECK(dc.verify_bid(1249, 3,  500));\n  BOOST_CHECK(dc.verify_bid(1248, 1,  400));\n  BOOST_CHECK(dc.verify_bid(1246, 2, 1100));\n  BOOST_CHECK(dc.verify_ask(1255, 1,  150)); // 1 filled, 1 reduced\n  BOOST_CHECK(dc.verify_ask(1256, 2,  200));\n  BOOST_CHECK(dc.verify_ask(1257, 1,  700));\n  BOOST_CHECK(dc.verify_ask(1258, 1,  600));\n  BOOST_CHECK(dc.verify_ask(   0, 0,    0));\n}\n\nBOOST_AUTO_TEST_CASE(TestReplaceSizeIncrease)\n{\n  SimpleOrderBook order_book;\n  ChangedChecker cc(order_book.depth());\n  SimpleOrder ask0(false, 1252, 300);\n  SimpleOrder ask1(false, 1251, 200);\n  SimpleOrder bid0(true,  1250, 100);\n  SimpleOrder bid1(true,  1249, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 200));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 300));\n\n  // Verify changed stamps\n  BOOST_CHECK(cc.verify_bid_changed(true, true, false, false, false));\n  BOOST_CHECK(cc.verify_ask_changed(true, true, false, false, false));\n  cc.reset();\n\n  // Replace size\n  BOOST_CHECK(replace_and_verify(order_book, &bid0, 25));\n  BOOST_CHECK(replace_and_verify(order_book, &ask0, 50));\n\n  // Verify changed stamps\n  BOOST_CHECK(cc.verify_bid_changed(true, false, false, false, false));\n  BOOST_CHECK(cc.verify_ask_changed(false, true, false, false, false));\n  cc.reset();\n\n  // Verify orders\n  BOOST_CHECK_EQUAL(125, bid0.order_qty());\n  BOOST_CHECK_EQUAL(350, ask0.order_qty());\n  \n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 1, 125));\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 200));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 350));\n}\n\nBOOST_AUTO_TEST_CASE(TestReplaceSizeDecrease)\n{\n  SimpleOrderBook order_book;\n  ChangedChecker cc(order_book.depth());\n  SimpleOrder ask1(false, 1252, 200);\n  SimpleOrder ask0(false, 1252, 300);\n  SimpleOrder bid1(true,  1251, 100);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1251, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 2, 500));\n\n  // Verify changed stamps\n  BOOST_CHECK(cc.verify_bid_changed(true, true,false, false, false));\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n  cc.reset();\n\n  // Replace size\n  BOOST_CHECK(replace_and_verify(order_book, &bid0, -60));\n  BOOST_CHECK(replace_and_verify(order_book, &ask0, -150));\n\n  // Verify orders\n  BOOST_CHECK_EQUAL(40, bid0.order_qty());\n  BOOST_CHECK_EQUAL(150, ask0.order_qty());\n  \n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1250, 1,  40));\n  BOOST_CHECK(dc.verify_ask(1252, 2, 350));\n\n  // Verify changed stamps\n  BOOST_CHECK(cc.verify_bid_changed(false, true, false, false, false));\n  BOOST_CHECK(cc.verify_ask_changed(true,false, false, false, false));\n  cc.reset();\n}\n\nBOOST_AUTO_TEST_CASE(TestReplaceSizeDecreaseCancel)\n{\n  SimpleOrderBook order_book;\n  ChangedChecker cc(order_book.depth());\n  SimpleOrder ask1(false, 1252, 200);\n  SimpleOrder ask0(false, 1252, 300);\n  SimpleOrder bid1(true,  1251, 400);\n  SimpleOrder bid0(true,  1250, 100);\n  SimpleOrder bid2(true,  1249, 700);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_ask(1252, 2, 500));\n  BOOST_CHECK(dc.verify_bid(1251, 1, 400));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1249, 1, 700));\n\n  // Verify changed stamps\n  BOOST_CHECK(cc.verify_bid_changed(true, true, true, false, false));\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n  cc.reset();\n\n  // Partial Fill existing book\n  SimpleOrder cross_bid(true,  1252, 125);\n  SimpleOrder cross_ask(false, 1251, 100);\n  \n  // Bid matching best ask\n  {\n    SimpleFillCheck fc1(&cross_bid, 125, 1252 * 125);\n    SimpleFillCheck fc2(&ask0,      125, 1252 * 125);\n    BOOST_CHECK(add_and_verify(order_book, &cross_bid, true, true));\n  }\n\n  BOOST_CHECK(cc.verify_bid_changed(false, false, false, false, false));\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n  cc.reset();\n\n  // Ask matching best bid\n  {\n    SimpleFillCheck fc1(&cross_ask, 100, 1251 * 100);\n    SimpleFillCheck fc2(&bid1,      100, 1251 * 100);\n    BOOST_CHECK(add_and_verify(order_book, &cross_ask, true, true));\n  }\n\n  BOOST_CHECK(cc.verify_bid_changed(true, false, false, false, false));\n  BOOST_CHECK(cc.verify_ask_changed(false, false, false, false, false));\n\n  // Verify quantity\n  BOOST_CHECK_EQUAL(175, ask0.open_qty());\n  BOOST_CHECK_EQUAL(300, bid1.open_qty());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 1, 300));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1249, 1, 700));\n  BOOST_CHECK(dc.verify_ask(1252, 2, 375));\n\n  // Replace size - cancel\n  BOOST_CHECK(replace_and_verify(\n      order_book, &ask0, -175, PRICE_UNCHANGED, simple::os_cancelled)); \n\n  // Verify orders\n  BOOST_CHECK_EQUAL(125, ask0.order_qty());\n  BOOST_CHECK_EQUAL(0, ask0.open_qty());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 1, 300));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1249, 1, 700));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 200));\n\n  // Replace size - reduce level\n  BOOST_CHECK(replace_and_verify(\n      order_book, &bid1, -100, PRICE_UNCHANGED, simple::os_accepted)); \n\n  // Verify orders\n  BOOST_CHECK_EQUAL(300, bid1.order_qty());\n  BOOST_CHECK_EQUAL(200, bid1.open_qty());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 1, 200));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1249, 1, 700));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 200));\n\n  // Replace size - cancel and erase level\n  BOOST_CHECK(replace_and_verify(\n      order_book, &bid1, -200, PRICE_UNCHANGED, simple::os_cancelled)); \n\n  // Verify orders\n  BOOST_CHECK_EQUAL(100, bid1.order_qty());\n  BOOST_CHECK_EQUAL(0, bid1.open_qty());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1249, 1, 700));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 200));\n}\n\nBOOST_AUTO_TEST_CASE(TestReplaceSizeDecreaseTooMuch)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask1(false, 1252, 200);\n  SimpleOrder ask0(false, 1252, 300);\n  SimpleOrder bid1(true,  1251, 100);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1251, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 2, 500));\n\n  SimpleOrder cross_bid(true,  1252, 200);\n  // Partial fill existing order\n  {\n    SimpleFillCheck fc1(&cross_bid, 200, 1252 * 200);\n    SimpleFillCheck fc2(&ask0,      200, 1252 * 200);\n    BOOST_CHECK(add_and_verify(order_book, &cross_bid, true, true));\n  }\n\n  // Verify open quantity\n  BOOST_CHECK_EQUAL(100, ask0.open_qty());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 2, 300));\n\n  // Replace size - not enough left\n  BOOST_CHECK( ! order_book.replace(&ask0, -150, PRICE_UNCHANGED));\n\n  // Verify change\n  BOOST_CHECK_EQUAL(simple::os_cancelled, ask0.state());\n  BOOST_CHECK_EQUAL(200U, ask0.order_qty());\n  BOOST_CHECK_EQUAL(0U, ask0.open_qty());\n\n  // Verify depth unchanged\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 200));\n}\n\nBOOST_AUTO_TEST_CASE(TestReplaceSizeIncreaseDecrease)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask1(false, 1252, 200);\n  SimpleOrder ask0(false, 1251, 300);\n  SimpleOrder bid1(true,  1251, 100);\n  SimpleOrder bid0(true,  1250, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1250, 1, 100));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 300));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 200));\n\n  // Replace size\n  BOOST_CHECK(replace_and_verify(order_book, &ask0, 50));\n  BOOST_CHECK(replace_and_verify(order_book, &bid0, 25));\n\n  BOOST_CHECK(replace_and_verify(order_book, &ask0, -100));\n  BOOST_CHECK(replace_and_verify(order_book, &bid0, 25));\n\n  BOOST_CHECK(replace_and_verify(order_book, &ask0, 300));\n  BOOST_CHECK(replace_and_verify(order_book, &bid0, -75));\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 1, 75));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 550));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 200));\n}\n\nBOOST_AUTO_TEST_CASE(TestReplaceBidPriceChange)\n{\n  SimpleOrderBook order_book;\n  ChangedChecker cc(order_book.depth());\n  SimpleOrder ask0(false, 1253, 300);\n  SimpleOrder ask1(false, 1252, 200);\n  SimpleOrder bid1(true,  1251, 140);\n  SimpleOrder bid0(true,  1250, 120);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1251, 1, 140));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 120));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 200));\n  BOOST_CHECK(dc.verify_ask(1253, 1, 300));\n\n  // Verify changed stamps\n  BOOST_CHECK(cc.verify_bid_changed(true, true, false, false, false));\n  BOOST_CHECK(cc.verify_ask_changed(true, true, false, false, false));\n  cc.reset();\n\n  // Replace price increase 1250 -> 1251\n  BOOST_CHECK(replace_and_verify(order_book, &bid0, SIZE_UNCHANGED, 1251));\n\n  // Verify price change in book\n  SimpleOrderBook::Bids::const_iterator bid = order_book.bids().begin();\n  BOOST_CHECK_EQUAL(1251, bid->first);\n  BOOST_CHECK_EQUAL(&bid1, bid->second.ptr());\n  BOOST_CHECK_EQUAL(1251, (++bid)->first);\n  BOOST_CHECK_EQUAL(&bid0, bid->second.ptr());\n  BOOST_CHECK(order_book.bids().end() == ++bid);\n\n  // Verify order\n  BOOST_CHECK_EQUAL(1251, bid0.price());\n  BOOST_CHECK_EQUAL(120, bid0.order_qty());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 2, 260));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 200));\n  BOOST_CHECK(dc.verify_ask(1253, 1, 300));\n\n  // Verify changed stamps\n  BOOST_CHECK(cc.verify_bid_changed(true, true, false, false, false));\n  BOOST_CHECK(cc.verify_ask_changed(false, false, false, false, false));\n  cc.reset();\n\n  // Replace price decrease 1251 -> 1250\n  BOOST_CHECK(replace_and_verify(order_book, &bid1, SIZE_UNCHANGED, 1250));\n\n  // Verify price change in book\n  bid = order_book.bids().begin();\n  BOOST_CHECK_EQUAL(1251, bid->first);\n  BOOST_CHECK_EQUAL(&bid0, bid->second.ptr());\n  BOOST_CHECK_EQUAL(1250, (++bid)->first);\n  BOOST_CHECK_EQUAL(&bid1, bid->second.ptr());\n  BOOST_CHECK(order_book.bids().end() == ++bid);\n\n  // Verify order\n  BOOST_CHECK_EQUAL(1250, bid1.price());\n  BOOST_CHECK_EQUAL(140, bid1.order_qty());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 1, 120));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 140));\n  BOOST_CHECK(dc.verify_bid(   0, 0,   0));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 200));\n  BOOST_CHECK(dc.verify_ask(1253, 1, 300));\n\n  // Verify changed stamps\n  BOOST_CHECK(cc.verify_bid_changed(true, true, false, false, false));\n  BOOST_CHECK(cc.verify_ask_changed(false, false, false, false, false));\n}\n\nBOOST_AUTO_TEST_CASE(TestReplaceAskPriceChange)\n{\n  SimpleOrderBook order_book;\n  ChangedChecker cc(order_book.depth());\n\n  SimpleOrder ask0(false, 1253, 300);\n  SimpleOrder ask1(false, 1252, 200);\n  SimpleOrder bid1(true,  1251, 140);\n  SimpleOrder bid0(true,  1250, 120);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n\n  // Verify changed stamps\n  BOOST_CHECK(cc.verify_bid_changed(true, true, false, false, false));\n  BOOST_CHECK(cc.verify_ask_changed(true, true, false, false, false));\n  cc.reset();\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1251, 1, 140));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 120));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 200));\n  BOOST_CHECK(dc.verify_ask(1253, 1, 300));\n\n  // Replace price increase 1252 -> 1253\n  BOOST_CHECK(replace_and_verify(order_book, &ask1, SIZE_UNCHANGED, 1253));\n\n  // Verify changed stamps\n  BOOST_CHECK(cc.verify_bid_changed(false, false, false, false, false));\n  BOOST_CHECK(cc.verify_ask_changed(true, true, false, false, false));\n  cc.reset();\n\n  // Verify price change in book\n  SimpleOrderBook::Asks::const_iterator ask = order_book.asks().begin();\n  BOOST_CHECK_EQUAL(1253, ask->first);\n  BOOST_CHECK_EQUAL(&ask0, ask->second.ptr());\n  BOOST_CHECK_EQUAL(1253, (++ask)->first);\n  BOOST_CHECK_EQUAL(&ask1, ask->second.ptr());\n  BOOST_CHECK(order_book.asks().end() == ++ask);\n\n  // Verify order\n  BOOST_CHECK_EQUAL(1253, ask1.price());\n  BOOST_CHECK_EQUAL(200, ask1.order_qty());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 1, 140));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 120));\n  BOOST_CHECK(dc.verify_ask(1253, 2, 500));\n\n  // Replace price decrease 1253 -> 1252\n  BOOST_CHECK(replace_and_verify(order_book, &ask0, SIZE_UNCHANGED, 1252));\n\n  // Verify price change in book\n  ask = order_book.asks().begin();\n  BOOST_CHECK_EQUAL(1252, ask->first);\n  BOOST_CHECK_EQUAL(&ask0, ask->second.ptr());\n  BOOST_CHECK_EQUAL(1253, (++ask)->first);\n  BOOST_CHECK_EQUAL(&ask1, ask->second.ptr());\n  BOOST_CHECK(order_book.asks().end() == ++ask);\n\n  // Verify order\n  BOOST_CHECK_EQUAL(1252, ask0.price());\n  BOOST_CHECK_EQUAL(300, ask0.order_qty());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 1, 140));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 120));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 300));\n  BOOST_CHECK(dc.verify_ask(1253, 1, 200));\n  BOOST_CHECK(dc.verify_ask(   0, 0,   0));\n}\n\nBOOST_AUTO_TEST_CASE(TestReplaceBidPriceChangeErase)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(false, 1253, 300);\n  SimpleOrder ask1(false, 1252, 200);\n  SimpleOrder bid1(true,  1251, 140);\n  SimpleOrder bid0(true,  1250, 120);\n  SimpleOrder bid2(true,  1249, 100);\n  SimpleOrder bid3(true,  1248, 200);\n  SimpleOrder bid4(true,  1247, 400);\n  SimpleOrder bid5(true,  1246, 800);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid3, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid4, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid5, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1251, 1, 140));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 120));\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 200));\n  BOOST_CHECK(dc.verify_bid(1247, 1, 400));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 200));\n  BOOST_CHECK(dc.verify_ask(1253, 1, 300));\n\n  // Replace price increase 1250 -> 1251\n  BOOST_CHECK(replace_and_verify(order_book, &bid0, SIZE_UNCHANGED, 1251));\n\n  // Verify price change in book\n  SimpleOrderBook::Bids::const_iterator bid = order_book.bids().begin();\n  BOOST_CHECK_EQUAL(1251, bid->first);\n  BOOST_CHECK_EQUAL(&bid1, bid->second.ptr());\n  BOOST_CHECK_EQUAL(1251, (++bid)->first);\n  BOOST_CHECK_EQUAL(&bid0, bid->second.ptr());\n  BOOST_CHECK_EQUAL(1249, (++bid)->first);\n  BOOST_CHECK_EQUAL(&bid2, bid->second.ptr());\n\n  // Verify order\n  BOOST_CHECK_EQUAL(1251, bid0.price());\n  BOOST_CHECK_EQUAL(120, bid0.order_qty());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 2, 260));\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 200));\n  BOOST_CHECK(dc.verify_bid(1247, 1, 400));\n  BOOST_CHECK(dc.verify_bid(1246, 1, 800));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 200));\n  BOOST_CHECK(dc.verify_ask(1253, 1, 300));\n\n  // Replace price decrease 1251 -> 1250\n  BOOST_CHECK(replace_and_verify(order_book, &bid1, SIZE_UNCHANGED, 1250));\n\n  // Verify price change in book\n  bid = order_book.bids().begin();\n  BOOST_CHECK_EQUAL(1251, bid->first);\n  BOOST_CHECK_EQUAL(&bid0, bid->second.ptr());\n  BOOST_CHECK_EQUAL(1250, (++bid)->first);\n  BOOST_CHECK_EQUAL(&bid1, bid->second.ptr());\n  BOOST_CHECK_EQUAL(1249, (++bid)->first);\n  BOOST_CHECK_EQUAL(&bid2, bid->second.ptr());\n\n  // Verify order\n  BOOST_CHECK_EQUAL(1250, bid1.price());\n  BOOST_CHECK_EQUAL(140, bid1.order_qty());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 1, 120));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 140));\n  BOOST_CHECK(dc.verify_bid(1249, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 200));\n  BOOST_CHECK(dc.verify_bid(1247, 1, 400));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 200));\n  BOOST_CHECK(dc.verify_ask(1253, 1, 300));\n}\n\nBOOST_AUTO_TEST_CASE(TestReplaceAskPriceChangeErase)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask5(false, 1258, 304);\n  SimpleOrder ask4(false, 1256, 330);\n  SimpleOrder ask3(false, 1255, 302);\n  SimpleOrder ask2(false, 1254, 310);\n  SimpleOrder ask0(false, 1253, 300);\n  SimpleOrder ask1(false, 1252, 200);\n  SimpleOrder bid1(true,  1251, 140);\n  SimpleOrder bid0(true,  1250, 120);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask3, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask4, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask5, false));\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1251, 1, 140));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 120));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 200));\n  BOOST_CHECK(dc.verify_ask(1253, 1, 300));\n  BOOST_CHECK(dc.verify_ask(1254, 1, 310));\n  BOOST_CHECK(dc.verify_ask(1255, 1, 302));\n  BOOST_CHECK(dc.verify_ask(1256, 1, 330));\n\n  // Replace price increase 1252 -> 1253\n  BOOST_CHECK(replace_and_verify(order_book, &ask1, SIZE_UNCHANGED, 1253));\n\n  // Verify price change in book\n  SimpleOrderBook::Asks::const_iterator ask = order_book.asks().begin();\n  BOOST_CHECK_EQUAL(1253, ask->first);\n  BOOST_CHECK_EQUAL(&ask0, ask->second.ptr());\n  BOOST_CHECK_EQUAL(1253, (++ask)->first);\n  BOOST_CHECK_EQUAL(&ask1, ask->second.ptr());\n  BOOST_CHECK_EQUAL(1254, (++ask)->first);\n  BOOST_CHECK_EQUAL(&ask2, ask->second.ptr());\n\n  // Verify order\n  BOOST_CHECK_EQUAL(1253, ask1.price());\n  BOOST_CHECK_EQUAL(200, ask1.order_qty());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 1, 140));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 120));\n  BOOST_CHECK(dc.verify_ask(1253, 2, 500));\n  BOOST_CHECK(dc.verify_ask(1254, 1, 310));\n  BOOST_CHECK(dc.verify_ask(1255, 1, 302));\n  BOOST_CHECK(dc.verify_ask(1256, 1, 330));\n  BOOST_CHECK(dc.verify_ask(1258, 1, 304));\n\n  // Replace price decrease 1253 -> 1252\n  BOOST_CHECK(replace_and_verify(order_book, &ask0, SIZE_UNCHANGED, 1252));\n\n  // Verify price change in book\n  ask = order_book.asks().begin();\n  BOOST_CHECK_EQUAL(1252, ask->first);\n  BOOST_CHECK_EQUAL(&ask0, ask->second.ptr());\n  BOOST_CHECK_EQUAL(1253, (++ask)->first);\n  BOOST_CHECK_EQUAL(&ask1, ask->second.ptr());\n  BOOST_CHECK_EQUAL(1254, (++ask)->first);\n  BOOST_CHECK_EQUAL(&ask2, ask->second.ptr());\n\n  // Verify order\n  BOOST_CHECK_EQUAL(1252, ask0.price());\n  BOOST_CHECK_EQUAL(300, ask0.order_qty());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 1, 140));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 120));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 300));\n  BOOST_CHECK(dc.verify_ask(1253, 1, 200));\n  BOOST_CHECK(dc.verify_ask(1254, 1, 310));\n  BOOST_CHECK(dc.verify_ask(1255, 1, 302));\n  BOOST_CHECK(dc.verify_ask(1256, 1, 330));\n}\n\n// A potential problem\n// When restroing a level into the depth, the orders (and thus the restored\n// level already reflect the post-fill quantity, but the fill callback has \n// yet to be processed.  As such, a multilevel fill can have fills at the \n// restoration price double-counted\n// but the \nBOOST_AUTO_TEST_CASE(TestBidMultiLevelFillRestore)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask1(false, 0, 1300);\n  SimpleOrder ask0(false, 1252, 100);\n  SimpleOrder bid0(true,  1251, 200);\n  SimpleOrder bid1(true,  1250, 200);\n  SimpleOrder bid2(true,  1250, 200);\n  SimpleOrder bid3(true,  1248, 200);\n  SimpleOrder bid4(true,  1247, 200);\n  SimpleOrder bid5(true,  1246, 200);\n  SimpleOrder bid6(true,  1245, 200); // Partial match\n  SimpleOrder bid7(true,  1244, 200);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid2, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid3, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid4, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid5, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid6, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid7, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(8, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1251, 1, 200));\n  BOOST_CHECK(dc.verify_bid(1250, 2, 400));\n  BOOST_CHECK(dc.verify_bid(1248, 1, 200));\n  BOOST_CHECK(dc.verify_bid(1247, 1, 200));\n  BOOST_CHECK(dc.verify_bid(1246, 1, 200));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc0(&bid0,  200,  250200);\n    SimpleFillCheck fc1(&bid1,  200,  250000);\n    SimpleFillCheck fc2(&bid2,  200,  250000);\n    SimpleFillCheck fc3(&bid3,  200,  249600);\n    SimpleFillCheck fc4(&bid4,  200,  249400);\n    SimpleFillCheck fc5(&bid5,  200,  249200);\n    SimpleFillCheck fc6(&bid6,  100,  124500);\n    SimpleFillCheck fc7(&ask1, 1300, 1622900);\n    BOOST_CHECK(add_and_verify(order_book, &ask1, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_ask(1252, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1245, 1, 100));\n  BOOST_CHECK(dc.verify_bid(1244, 1, 200));\n}\n\nBOOST_AUTO_TEST_CASE(TestAskMultiLevelFillRestore)\n{\n  SimpleOrderBook order_book;\n  SimpleOrder ask0(false,  1251, 200); // Partial match\n  SimpleOrder ask1(false,  1250, 200);\n  SimpleOrder ask2(false,  1250, 300);\n  SimpleOrder ask3(false,  1248, 200);\n  SimpleOrder ask4(false,  1247, 200);\n  SimpleOrder ask5(false,  1245, 200);\n  SimpleOrder ask6(false,  1245, 200);\n  SimpleOrder ask7(false,  1244, 200);\n  SimpleOrder bid1(true, 0, 1550);\n  SimpleOrder bid0(true, 1242, 100);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask2, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask3, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask4, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask5, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask6, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask7, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(8, order_book.asks().size());\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_ask(1244, 1, 200));\n  BOOST_CHECK(dc.verify_ask(1245, 2, 400));\n  BOOST_CHECK(dc.verify_ask(1247, 1, 200));\n  BOOST_CHECK(dc.verify_ask(1248, 1, 200));\n  BOOST_CHECK(dc.verify_ask(1250, 2, 500));\n  BOOST_CHECK(dc.verify_bid(1242, 1, 100));\n\n  // Match - complete\n  {\n    SimpleFillCheck fc7(&ask7,  200,  248800);\n    SimpleFillCheck fc6(&ask6,  200,  249000);\n    SimpleFillCheck fc5(&ask5,  200,  249000);\n    SimpleFillCheck fc4(&ask4,  200,  249400);\n    SimpleFillCheck fc3(&ask3,  200,  249600);\n    SimpleFillCheck fc2(&ask2,  300,  375000);\n    SimpleFillCheck fc1(&ask1,  200,  250000);\n    SimpleFillCheck fc0(&ask0,   50,   62550);\n    SimpleFillCheck fc8(&bid1, 1550, 1933350);\n    BOOST_CHECK(add_and_verify(order_book, &bid1, true, true));\n  }\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_ask(1251, 1, 150));\n  BOOST_CHECK(dc.verify_bid(1242, 1, 100));\n}\n\nBOOST_AUTO_TEST_CASE(TestReplaceBidMatch)\n{\n  SimpleOrderBook order_book;\n  ChangedChecker cc(order_book.depth());\n  SimpleOrder ask1(false, 1254, 200);\n  SimpleOrder ask0(false, 1253, 300);\n  SimpleOrder bid1(true,  1251, 140);\n  SimpleOrder bid0(true,  1250, 120);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1251, 1, 140));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 120));\n  BOOST_CHECK(dc.verify_ask(1253, 1, 300));\n  BOOST_CHECK(dc.verify_ask(1254, 1, 200));\n\n  // Verify changed stamps\n  BOOST_CHECK(cc.verify_bid_changed(true, true, false, false, false));\n  BOOST_CHECK(cc.verify_ask_changed(true, true, false, false, false));\n  cc.reset();\n\n  // Replace price increase new best 1250 -> 1252\n  BOOST_CHECK(replace_and_verify(order_book, &bid0, SIZE_UNCHANGED, 1252));\n\n  // Verify price change in book\n  SimpleOrderBook::Bids::const_iterator bid = order_book.bids().begin();\n  BOOST_CHECK_EQUAL(1252, bid->first);\n  BOOST_CHECK_EQUAL(&bid0, bid->second.ptr());\n  BOOST_CHECK_EQUAL(1251, (++bid)->first);\n  BOOST_CHECK_EQUAL(&bid1, bid->second.ptr());\n  BOOST_CHECK(order_book.bids().end() == ++bid);\n\n  // Verify order\n  BOOST_CHECK_EQUAL(1252, bid0.price());\n  BOOST_CHECK_EQUAL(120, bid0.order_qty());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1252, 1, 120));\n  BOOST_CHECK(dc.verify_bid(1251, 1, 140));\n  BOOST_CHECK(dc.verify_ask(1253, 1, 300));\n  BOOST_CHECK(dc.verify_ask(1254, 1, 200));\n\n  // Verify changed stamps\n  BOOST_CHECK(cc.verify_bid_changed(true, true, true, false, false));\n  BOOST_CHECK(cc.verify_ask_changed(false, false, false, false, false));\n  cc.reset();\n\n  // Match - complete\n  {\n    SimpleFillCheck fc0(&ask0,  140, 140 * 1253);\n    SimpleFillCheck fc1(&bid1,  140, 140 * 1253);\n    // Replace price increase match 1251 -> 1253\n    BOOST_CHECK(replace_and_verify(order_book, &bid1, SIZE_UNCHANGED, 1253,\n                  simple::os_complete, 140));\n  }\n\n  // Verify price change in book\n  bid = order_book.bids().begin();\n  BOOST_CHECK_EQUAL(1252, bid->first);\n  BOOST_CHECK_EQUAL(&bid0, bid->second.ptr());\n  BOOST_CHECK(order_book.bids().end() == ++bid);\n\n  // Verify order\n  BOOST_CHECK_EQUAL(1253, bid1.price());\n  BOOST_CHECK_EQUAL(140, bid1.order_qty());\n  BOOST_CHECK_EQUAL(0, bid1.open_qty());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1252, 1, 120));\n  BOOST_CHECK(dc.verify_bid(   0, 0,   0));\n  BOOST_CHECK(dc.verify_ask(1253, 1, 160));\n  BOOST_CHECK(dc.verify_ask(1254, 1, 200));\n\n  // Verify changed stamps\n  BOOST_CHECK(cc.verify_bid_changed(true, true, true, false, false));\n  BOOST_CHECK(cc.verify_ask_changed(true, false, false, false, false));\n}\n\nBOOST_AUTO_TEST_CASE(TestReplaceAskMatch)\n{\n  SimpleOrderBook order_book;\n  ChangedChecker cc(order_book.depth());\n  SimpleOrder ask1(false, 1254, 200);\n  SimpleOrder ask0(false, 1253, 300);\n  SimpleOrder bid1(true,  1251, 140);\n  SimpleOrder bid0(true,  1250, 120);\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, &bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, &bid1, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, &ask1, false));\n\n  // Verify depth\n  DepthCheck<SimpleOrderBook> dc(order_book.depth());\n  BOOST_CHECK(dc.verify_bid(1251, 1, 140));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 120));\n  BOOST_CHECK(dc.verify_ask(1253, 1, 300));\n  BOOST_CHECK(dc.verify_ask(1254, 1, 200));\n\n  // Verify changed stamps\n  BOOST_CHECK(cc.verify_bid_changed(true, true, false, false, false));\n  BOOST_CHECK(cc.verify_ask_changed(true, true, false, false, false));\n  cc.reset();\n\n  // Replace price decrease new best 1254 -> 1252\n  BOOST_CHECK(replace_and_verify(order_book, &ask1, SIZE_UNCHANGED, 1252));\n\n  // Verify price change in book\n  SimpleOrderBook::Asks::const_iterator ask = order_book.asks().begin();\n  BOOST_CHECK_EQUAL(1252, ask->first);\n  BOOST_CHECK_EQUAL(&ask1, ask->second.ptr());\n  BOOST_CHECK_EQUAL(1253, (++ask)->first);\n  BOOST_CHECK_EQUAL(&ask0, ask->second.ptr());\n  BOOST_CHECK(order_book.asks().end() == ++ask);\n\n  // Verify order\n  BOOST_CHECK_EQUAL(1252, ask1.price());\n  BOOST_CHECK_EQUAL(200, ask1.order_qty());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1251, 1, 140));\n  BOOST_CHECK(dc.verify_bid(1250, 1, 120));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 200));\n  BOOST_CHECK(dc.verify_ask(1253, 1, 300));\n\n  // Verify changed stamps\n  BOOST_CHECK(cc.verify_bid_changed(false, false, false, false, false));\n  BOOST_CHECK(cc.verify_ask_changed(true, true, true, false, false));\n  cc.reset();\n\n  // Match - complete\n  {\n    SimpleFillCheck fc0(&ask0,  140, 140 * 1251);\n    SimpleFillCheck fc1(&bid1,  140, 140 * 1251);\n    // Replace price decrease match 1253 -> 1251\n    BOOST_CHECK(replace_and_verify(order_book, &ask0, SIZE_UNCHANGED, 1251,\n                  simple::os_accepted, 140));\n  }\n\n  // Verify price change in book\n  ask = order_book.asks().begin();\n  BOOST_CHECK_EQUAL(1251, ask->first);\n  BOOST_CHECK_EQUAL(&ask0, ask->second.ptr());\n  BOOST_CHECK_EQUAL(1252, (++ask)->first);\n  BOOST_CHECK_EQUAL(&ask1, ask->second.ptr());\n  BOOST_CHECK(order_book.asks().end() == ++ask);\n\n  // Verify order\n  BOOST_CHECK_EQUAL(1251, ask0.price());\n  BOOST_CHECK_EQUAL(300, ask0.order_qty());\n  BOOST_CHECK_EQUAL(160, ask0.open_qty());\n\n  // Verify depth\n  dc.reset();\n  BOOST_CHECK(dc.verify_bid(1250, 1, 120));\n  BOOST_CHECK(dc.verify_bid(   0, 0,   0));\n  BOOST_CHECK(dc.verify_ask(1251, 1, 160));\n  BOOST_CHECK(dc.verify_ask(1252, 1, 200));\n\n  // Verify changed stamps\n  BOOST_CHECK(cc.verify_bid_changed(true, true, false, false, false));\n  BOOST_CHECK(cc.verify_ask_changed(true, true, true, false, false));\n}\n\n} // namespace\n"
  },
  {
    "path": "test/unit/ut_order_book_shared_ptr.cpp",
    "content": "// Copyright (c) 2012 - 2017 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n\n#define BOOST_TEST_NO_MAIN LiquibookTest\n#include <boost/test/unit_test.hpp>\n\n#include \"ut_utils.h\"\n#include \"changed_checker.h\"\n#include <book/order_book.h>\n#include <simple/simple_order.h>\n#include <simple/simple_order_book.h>\n#include <memory>\n\nnamespace liquibook {\n\nusing book::DepthLevel;\nusing book::OrderBook;\nusing book::OrderTracker;\nusing simple::SimpleOrder;\n\n\ntypedef std::shared_ptr<SimpleOrder> SimpleOrderPtr;\nclass SharedPtrOrderBook : public OrderBook<SimpleOrderPtr>\n{\n  virtual void perform_callback(OrderBook<SimpleOrderPtr>::TypedCallback& cb)\n  {\n    switch(cb.type) {\n      case TypedCallback::cb_order_accept:\n        cb.order->accept();\n        break;\n      case TypedCallback::cb_order_fill: {\n        Cost fill_cost = cb.price * cb.quantity;\n        cb.order->fill(cb.quantity, fill_cost, 0);\n        cb.matched_order->fill(cb.quantity, fill_cost, 0);\n        break;\n      }\n      case TypedCallback::cb_order_cancel:\n        cb.order->cancel();\n        break;\n      case TypedCallback::cb_order_replace:\n        cb.order->replace(cb.delta, cb.price);\n        break;\n      default:\n        // Nothing\n        break;\n    }\n  }\n};\n\ntypedef FillCheck<SimpleOrderPtr> SharedFillCheck;\n\nBOOST_AUTO_TEST_CASE(TestSharedPointerBuild)\n{\n  SharedPtrOrderBook order_book;\n  SimpleOrderPtr ask1(new SimpleOrder(false, 1252, 100));\n  SimpleOrderPtr ask0(new SimpleOrder(false, 1251, 100));\n  SimpleOrderPtr bid1(new SimpleOrder(true,  1251, 100));\n  SimpleOrderPtr bid0(new SimpleOrder(true,  1250, 100));\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, ask1, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Match - complete\n  {\n    SharedFillCheck fc1(bid1, 100, 125100);\n    SharedFillCheck fc2(ask0, 100, 125100);\n    BOOST_CHECK(add_and_verify(order_book, bid1, true, true));\n  }\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(1, order_book.asks().size());\n}\n\nBOOST_AUTO_TEST_CASE(TestSharedCancelBid)\n{\n  SharedPtrOrderBook order_book;\n  SimpleOrderPtr ask1(new SimpleOrder(false, 1252, 100));\n  SimpleOrderPtr ask0(new SimpleOrder(false, 1251, 100));\n  SimpleOrderPtr bid0(new SimpleOrder(true,  1250, 100));\n\n  // No match\n  BOOST_CHECK(add_and_verify(order_book, bid0, false));\n  BOOST_CHECK(add_and_verify(order_book, ask0, false));\n  BOOST_CHECK(add_and_verify(order_book, ask1, false));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(1, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n\n  // Cancel bid\n  BOOST_CHECK(cancel_and_verify(order_book, bid0, simple::os_cancelled));\n\n  // Verify sizes\n  BOOST_CHECK_EQUAL(0, order_book.bids().size());\n  BOOST_CHECK_EQUAL(2, order_book.asks().size());\n}\n\n} // namespace\n"
  },
  {
    "path": "test/unit/ut_stop_orders.cpp",
    "content": "// Copyright (c) 2012 - 2017 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n\n#define BOOST_TEST_NO_MAIN LiquibookTest\n#include <boost/test/unit_test.hpp>\n\n#include \"ut_utils.h\"\n#include \"changed_checker.h\"\n#include <book/order_book.h>\n#include <simple/simple_order.h>\n\nnamespace liquibook {\n\nusing book::DepthLevel;\nusing book::OrderBook;\nusing book::OrderTracker;\nusing simple::SimpleOrder;\n\nnamespace\n{\n  const bool sideBuy = true;\n  const bool sideSell = false;\n\n  const Price prcMkt = 0;\n  const Price prc53 = 53;\n  const Price prc54 = 54;\n  const Price prc55 = 55;\n  const Price prc56 = 56;\n  const Price prc57 = 57;\n\n  const Quantity q100 = 100;\n  const Quantity q1000 = 1000;\n\n  const bool expectMatch = true;\n  const bool expectNoMatch = false;\n\n  const bool expectComplete = true;\n  const bool expectNoComplete = false;\n}\n\ntypedef OrderTracker<SimpleOrder*> SimpleTracker;\ntypedef test::ChangedChecker<5> ChangedChecker;\n\ntypedef FillCheck<SimpleOrder*> SimpleFillCheck;\n\nBOOST_AUTO_TEST_CASE(TestStopOrdersOffMarketNoTrade)\n{\n  SimpleOrderBook book;\n  SimpleOrder order0(sideBuy, prc55, q100);\n  SimpleOrder order1(sideSell, prcMkt, q100);\n\n  // Enter order to generate a trade establishing market price\n  BOOST_CHECK(add_and_verify(book, &order0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(book, &order1, expectMatch, expectComplete));\n\n  BOOST_CHECK_EQUAL(prc55, book.market_price());\n\n  SimpleOrder order2(sideBuy, prcMkt, q100, prc56);\n  SimpleOrder order3(sideSell, prcMkt, q100, prc54);\n  BOOST_CHECK(add_and_verify(book, &order2, expectNoMatch));\n  BOOST_CHECK(add_and_verify(book, &order3, expectNoMatch));\n  \n  // Orders were accepted, but not traded\n  BOOST_CHECK_EQUAL(simple::os_accepted, order2.state());\n  BOOST_CHECK_EQUAL(simple::os_accepted, order3.state());\n}\n\nBOOST_AUTO_TEST_CASE(TestStopMarketOrdersOnMarketTradeImmediately)\n{\n  SimpleOrderBook book;\n  SimpleOrder order0(sideBuy, prc55, q100);\n  SimpleOrder order1(sideSell, prcMkt, q100);\n\n  // Enter order to generate a trade establishing market price\n  BOOST_CHECK(add_and_verify(book, &order0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(book, &order1, expectMatch, expectComplete));\n\n  BOOST_CHECK_EQUAL(prc55, book.market_price());\n\n  SimpleOrder order2(sideBuy, prcMkt, q100, prc55);\n  SimpleOrder order3(sideSell, prcMkt, q100, prc55);\n  BOOST_CHECK(add_and_verify(book, &order2, expectNoMatch));\n  BOOST_CHECK(add_and_verify(book, &order3, expectMatch, expectComplete));\n}\n\nBOOST_AUTO_TEST_CASE(TestStopMarketOrdersTradeWhenStopPriceReached)\n{\n  SimpleOrderBook book;\n  SimpleOrder order0(sideBuy, prc53, q100);\n  SimpleOrder order1(sideSell, prc57, q100);\n  book.set_market_price(prc55);\n\n  // Enter seed orders and be sure they don't trade with each other.\n  BOOST_CHECK(add_and_verify(book, &order0, expectNoMatch));\n  BOOST_CHECK(add_and_verify(book, &order1, expectNoMatch));\n\n  // enter stop orders.  Be sure they don't trade yet\n  SimpleOrder order2(sideBuy, prcMkt, q100, prc56);\n  SimpleOrder order3(sideSell, prcMkt, q100, prc54);\n  BOOST_CHECK(add_and_verify(book, &order2, expectNoMatch));\n  BOOST_CHECK(add_and_verify(book, &order3, expectNoMatch));\n\n  SimpleOrder order4(sideBuy, prc56, q1000, 0, book::oc_all_or_none);\n  SimpleOrder order5(sideSell, prc56, q1000, 0, book::oc_all_or_none);\n\n  // Scope for fill checks\n  {\n    SimpleFillCheck fc0(&order0, 0, 0);\n    SimpleFillCheck fc1(&order1, q100, q100 * prc57);\n    SimpleFillCheck fc2(&order2, q100, q100 * prc57);\n    // Trade at 56 which should trigger order2 which should trade with order 1 at order 1's price\n    BOOST_CHECK(add_and_verify(book, &order4, expectNoMatch, expectNoComplete, book::oc_all_or_none));\n    BOOST_CHECK(add_and_verify(book, &order5, expectMatch, expectComplete, book::oc_all_or_none));\n  }\n  BOOST_CHECK_EQUAL(prc57, book.market_price());\n\n  SimpleOrder order6(sideBuy, prc54, q1000, 0, book::oc_all_or_none);\n  SimpleOrder order7(sideSell, prc54, q1000, 0, book::oc_all_or_none);\n\n  // Scope for fill checks\n  {\n    SimpleFillCheck fc0(&order0, q100, q100 * prc53);\n    SimpleFillCheck fc3(&order3, q100, q100 * prc53);\n    // Trade at 54 which should trigger order3 which should trade with order 0 at order 0's price\n    BOOST_CHECK(add_and_verify(book, &order6, expectNoMatch, expectNoComplete, book::oc_all_or_none));\n    BOOST_CHECK(add_and_verify(book, &order7, expectMatch, expectComplete, book::oc_all_or_none));\n  }\n  BOOST_CHECK_EQUAL(prc53, book.market_price());\n}\n\nBOOST_AUTO_TEST_CASE(TestStopOrdersCancelBeforeTrigger)\n{\n  SimpleOrderBook book;\n  book.set_market_price(prc55);\n\n  SimpleOrder bid(sideBuy, prcMkt, q100, prc56);\n  SimpleOrder ask(sideSell, prcMkt, q100, prc54);\n  BOOST_CHECK(add_and_verify(book, &bid, expectNoMatch));\n  BOOST_CHECK(add_and_verify(book, &ask, expectNoMatch));\n  \n  // Orders were accepted, but not traded\n  BOOST_CHECK_EQUAL(simple::os_accepted, bid.state());\n  BOOST_CHECK_EQUAL(simple::os_accepted, ask.state());\n  // Cancel bid and ask\n  BOOST_CHECK(cancel_and_verify(book, &bid, simple::os_cancelled));\n  BOOST_CHECK(cancel_and_verify(book, &ask, simple::os_cancelled));\n}\n\n} // namespace\n"
  },
  {
    "path": "test/unit/ut_utils.h",
    "content": "// Copyright (c) 2012 -- 2017 Object Computing, Inc.\n// All rights reserved.\n// See the file license.txt for licensing information.\n#pragma once\n\n#include \"depth_check.h\"\n#include <book/order_book.h>\n#include <simple/simple_order_book.h>\n#include <simple/simple_order.h>\n\n\nusing namespace liquibook::book;\n\nnamespace liquibook {\n\ntypedef simple::SimpleOrderBook<5> SimpleOrderBook;\ntypedef simple::SimpleOrderBook<5>::DepthTracker SimpleDepth;\n\ntemplate <class OrderBook, class OrderPtr>\nbool add_and_verify(OrderBook& order_book,\n                    const OrderPtr& order,\n                    const bool match_expected,\n                    const bool complete_expected = false,\n                    OrderConditions conditions = 0)\n{\n  const bool matched = order_book.add(order, conditions);\n  if (matched == match_expected) {\n    if (complete_expected) {\n      // State should be complete\n      return simple::os_complete == order->state();\n    } else if (conditions & oc_immediate_or_cancel) {\n      // State should be cancelled\n      return simple::os_cancelled == order->state();\n    } else {\n      // State should be accepted\n      return simple::os_accepted == order->state();\n    }\n  } else {\n    return false;\n  }\n}\n\n\ntemplate <class OrderBook, class OrderPtr>\nbool cancel_and_verify(OrderBook& order_book,\n                       const OrderPtr& order,\n                       simple::OrderState expected_state)\n{\n  order_book.cancel(order);\n  return expected_state == order->state();\n}\n\ntemplate <class OrderBook, class OrderPtr>\nbool replace_and_verify(OrderBook& order_book,\n                        const OrderPtr& order,\n                        int32_t size_change,\n                        Price new_price = PRICE_UNCHANGED,\n                        simple::OrderState expected_state = simple::os_accepted,\n                        Quantity match_qty = 0)\n{\n  // Calculate\n  Quantity expected_order_qty = order->order_qty() + size_change;\n  Quantity expected_open_qty = order->open_qty() + size_change - match_qty;\n  Price expected_price = \n      (new_price == PRICE_UNCHANGED) ? order->price() : new_price;\n\n  // Perform\n  order_book.replace(order, size_change, new_price);\n\n  // Verify\n  bool correct = true;\n  if (expected_state != order->state()) {\n    correct = false;\n    std::cout << \"State \" << order->state() << std::endl;\n  }\n  if (expected_order_qty != order->order_qty()) {\n    correct = false;\n    std::cout << \"Order Qty \" << order->order_qty() << std::endl;\n  }\n  if (expected_open_qty != order->open_qty()) {\n    correct = false;\n    std::cout << \"Open Qty \" << order->open_qty() << std::endl;\n  }\n  if (expected_price != order->price()) {\n    correct = false;\n    std::cout << \"Price \" << order->price() << std::endl;\n  }\n  return correct;\n}\n\ntemplate <class OrderPtr>\nclass FillCheck {\npublic:\n  FillCheck(OrderPtr order, \n            Quantity filled_qty,\n            Cost filled_cost,\n            OrderConditions conditions = 0)\n  : order_(order),\n    expected_filled_qty_(order->filled_qty() + filled_qty),\n    expected_open_qty_(order->order_qty() - expected_filled_qty_),\n    expected_filled_cost_(order->filled_cost() + (filled_cost)),\n    conditions_(conditions)\n  {\n  }\n\n  ~FillCheck() {\n    verify_filled();\n  }\n\n  private:\n  OrderPtr order_;\n  Quantity expected_filled_qty_;\n  Quantity expected_open_qty_;\n  Cost expected_filled_cost_;\n  OrderConditions conditions_;\n\n  void verify_filled() {\n    if (expected_filled_qty_ !=  order_->filled_qty()) {\n      std::cout << \"filled_qty \" << order_->filled_qty() \n                << \" expected \" << expected_filled_qty_ << std::endl;\n      throw std::runtime_error(\"Unexpected filled quantity\");\n    }\n    if (expected_open_qty_ !=  order_->open_qty()) {\n      std::cout << \"open_qty \" << order_->open_qty() \n                << \" expected \" << expected_open_qty_ << std::endl;\n      throw std::runtime_error(\"Unexpected open quantity\");\n    }\n    if (expected_filled_cost_ !=  order_->filled_cost()) {\n      std::cout << \"filled_cost \" << order_->filled_cost() \n                << \" expected \" << expected_filled_cost_ << std::endl;\n      throw std::runtime_error(\"Unexpected filled cost\");\n    }\n    // If the order was filled, and is not complete\n    if (order_->state() != simple::os_complete && !expected_open_qty_) {\n      std::cout << \"state \" << order_->state() \n                << \" expected \" << simple::os_complete << std::endl;\n      throw std::runtime_error(\"Unexpected state with no open quantity\");\n    // Else If the order was not filled\n    } else if (expected_open_qty_) {\n      bool IOC = ((conditions_ & oc_immediate_or_cancel) != 0);\n      if (order_->state() != simple::os_accepted && !IOC) {\n        std::cout << \"state \" << order_->state() \n                  << \" expected \" << simple::os_accepted << std::endl;\n        throw std::runtime_error(\"Unexpected state with open quantity\");\n      }\n      if (order_->state() != simple::os_cancelled && IOC) {\n        std::cout << \"state \" << order_->state() \n                  << \" expected \" << simple::os_cancelled << std::endl;\n        throw std::runtime_error(\"Unexpected state for IOC with open quantity\");\n      }\n    } \n  }\n};\n\n\n} // namespace\n"
  },
  {
    "path": "ut_run.bat",
    "content": "bin\\test\\liquibook_unit_test.exe\n"
  },
  {
    "path": "web/css/liquibook.css",
    "content": ".highlight {\n  color: red;\n}\n"
  },
  {
    "path": "web/easy.html",
    "content": "\n<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <title>Liquibook</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta name=\"description\" content=\"\">\n    <meta name=\"author\" content=\"Jeff Schmitz\">\n\n    <!-- Le styles -->\n    <link href=\"css/bootstrap.min.css\" rel=\"stylesheet\">\n    <link href=\"css/liquibook.css\" rel=\"stylesheet\">\n    <style>\n      body {\n        padding-top: 60px; /* 60px to make the container go all the way to the bottom of the topbar */\n      }\n    </style>\n    <link href=\"css/bootstrap-responsive.min.css\" rel=\"stylesheet\">\n\n    <!-- HTML5 shim, for IE6-8 support of HTML5 elements -->\n    <!--[if lt IE 9]>\n      <script src=\"js/html5shiv.js\"></script>\n    <![endif]-->\n\n    <!-- Fav and touch icons -->\n    <link rel=\"apple-touch-icon-precomposed\" sizes=\"144x144\" href=\"../assets/ico/apple-touch-icon-144-precomposed.png\">\n    <link rel=\"apple-touch-icon-precomposed\" sizes=\"114x114\" href=\"../assets/ico/apple-touch-icon-114-precomposed.png\">\n      <link rel=\"apple-touch-icon-precomposed\" sizes=\"72x72\" href=\"../assets/ico/apple-touch-icon-72-precomposed.png\">\n                    <link rel=\"apple-touch-icon-precomposed\" href=\"../assets/ico/apple-touch-icon-57-precomposed.png\">\n                                   <link rel=\"shortcut icon\" href=\"../assets/ico/favicon.png\">\n  </head>\n\n  <body>\n\n    <div class=\"navbar navbar-inverse navbar-fixed-top\">\n      <div class=\"navbar-inner\">\n        <div class=\"container\">\n          <button type=\"button\" class=\"btn btn-navbar\" data-toggle=\"collapse\" data-target=\".nav-collapse\">\n            <span class=\"icon-bar\"></span>\n            <span class=\"icon-bar\"></span>\n            <span class=\"icon-bar\"></span>\n          </button>\n          <a class=\"brand\" href=\"index.html\">Liquibook</a>\n          <div class=\"nav-collapse collapse\">\n            <ul class=\"nav\">\n              <li><a href=\"index.html\">Home</a></li>\n              <li><a href=\"fast.html\">Fast</a></li>\n              <li><a href=\"flexible.html\">Flexible</a></li>\n              <li class=\"active\"><a href=\"easy.html\">Easy</a></li>\n              <li><a href=\"get-started.html\">Get Started</a></li>\n            </ul>\n          </div><!--/.nav-collapse -->\n        </div>\n      </div>\n    </div>\n\n    <div class=\"container\">\n\n      <h1>Liquibook is Easy.  <span class=\"highlight\">Kindergarten Easy</span></h1>\n      <p>To be usable, Liquibook must be easy to integrate.  You need to:</p>\n\n      <ul>\n        <li>Create a class that implements the Order Interface</li>\n        <li>Instantiate OrderBook and use interface</li>\n        <li>Handle callbacks by overriding OrderBook::perform_callback()</li>\n        <li>Either call OrderBook::perform_callbacks() in the calling thread, or signal a background thread to do it. </li>\n      </ul>\n\n      <h2>How do I...?</h2>\n\n      <ul>\n        <li>Use my Order class - Just bind your <i>pointer to order</i> type to the OrderBook template.</li>\n        <pre>class MyOrderBook : public OrderBook&lt;MyOrder*&gt; { ... }</pre>\n        <li>Use shared pointers - just pass a shared pointer type as the OrderBook template argument.</li>\n        <pre>typedef boost::shared_ptr<SimpleOrder> MyOrderPtr;\nclass MyOrderBook : public OrderBook&lt;MyOrderPtr&gt; { ... }</pre>\n        <li>Track aggregate depth levels - instantiate Depth in your child OrderBook, and manipulate it in the callback handling, like impl::SimpleOrderBook does.</li>\n        <pre>depth_.add_order(...);\ndepth_.fill_order(...);\ndepth_.close_order(...);\ndepth_.replace_order(...);\ndepth_.ignore_fill_qty(...);\n</pre>\n        <li>Track more than 5 depth levels - Just instantiate Depth with the number you want.</li>\n        <pre>typedef book::Depth<10> MyDepth</pre>\n        <li>Track BBO only - Just instantiate Depth with one level.</li>\n        <pre>typedef book::Depth<10> MyBBO</pre>\n        <li></li>\n        <li></li>\n        <li></li>\n        <li></li>\n      </ul>\n\n    </div> <!-- /container -->\n\n    <!-- Le javascript\n    ================================================== -->\n    <!-- Placed at the end of the document so the pages load faster -->\n    <script src=\"js/jquery-1.9.1.min.js\"></script>\n    <scriprt src=\"js/bootstrap.min.js\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "web/fast.html",
    "content": "\n<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <title>Liquibook</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta name=\"description\" content=\"\">\n    <meta name=\"author\" content=\"Jeff Schmitz\">\n\n    <!-- Le styles -->\n    <link href=\"css/bootstrap.min.css\" rel=\"stylesheet\">\n    <link href=\"css/liquibook.css\" rel=\"stylesheet\">\n    <style>\n      body {\n        padding-top: 60px; /* 60px to make the container go all the way to the bottom of the topbar */\n      }\n    </style>\n    <link href=\"css/bootstrap-responsive.min.css\" rel=\"stylesheet\">\n\n    <!-- HTML5 shim, for IE6-8 support of HTML5 elements -->\n    <!--[if lt IE 9]>\n      <script src=\"js/html5shiv.js\"></script>\n    <![endif]-->\n\n    <!-- Fav and touch icons -->\n    <link rel=\"apple-touch-icon-precomposed\" sizes=\"144x144\" href=\"../assets/ico/apple-touch-icon-144-precomposed.png\">\n    <link rel=\"apple-touch-icon-precomposed\" sizes=\"114x114\" href=\"../assets/ico/apple-touch-icon-114-precomposed.png\">\n      <link rel=\"apple-touch-icon-precomposed\" sizes=\"72x72\" href=\"../assets/ico/apple-touch-icon-72-precomposed.png\">\n                    <link rel=\"apple-touch-icon-precomposed\" href=\"../assets/ico/apple-touch-icon-57-precomposed.png\">\n                                   <link rel=\"shortcut icon\" href=\"../assets/ico/favicon.png\">\n  </head>\n\n  <body>\n\n    <div class=\"navbar navbar-inverse navbar-fixed-top\">\n      <div class=\"navbar-inner\">\n        <div class=\"container\">\n          <button type=\"button\" class=\"btn btn-navbar\" data-toggle=\"collapse\" data-target=\".nav-collapse\">\n            <span class=\"icon-bar\"></span>\n            <span class=\"icon-bar\"></span>\n            <span class=\"icon-bar\"></span>\n          </button>\n          <a class=\"brand\" href=\"index.html\">Liquibook</a>\n          <div class=\"nav-collapse collapse\">\n            <ul class=\"nav\">\n              <li><a href=\"index.html\">Home</a></li>\n              <li class=\"active\"><a href=\"fast.html\">Fast</a></li>\n              <li><a href=\"flexible.html\">Flexible</a></li>\n              <li><a href=\"easy.html\">Easy</a></li>\n              <li><a href=\"get-started.html\">Get Started</a></li>\n            </ul>\n          </div><!--/.nav-collapse -->\n        </div>\n      </div>\n    </div>\n\n    <div class=\"container\">\n\n      <h1>Liquibook is fast.  <span class=\"highlight\">Blazing Fast</span></h1>\n      <p>Liquibook was designed to meet the needs of the most demanding customers.</p>\n      <p>Therefore it:</p>\n\n      <ul>\n        <li>Is written in C++</li>\n        <li>Has no floating point comparisons</li>\n        <li>Performs minimal copying of data from your order objects</li>\n      </ul>\n\n      <h2>How Fast?</h2>\n\n      <p>The included performance tests show Liquibook handling <b>over 2 million</b> orders per second.</p>\n\n      <h2>What Does the Performance Test Actually Do?</h2>\n\n      <p>The included performance test allocates a number of orders, and then runs for a given duration, measuring the time to handle them.  If the orders run out before the test completes, the test is rerun with double the number of orders until an iteration completes.</p>\n\n      <p>When complete, it checks the number of orders processed before the end of the test, and reports that, as well as the number of resulting matches (trades).</p>\n\n      <p>The test runs against three different order books:</p>\n\n      <ul>\n        <li>Raw order book matching engine</li>\n        <li>Order book matching engine with BBO tracking</li>\n        <li>Order book matching engine with 5 levels of aggregation (market depth)</li>\n      </ul>\n\n      <p>The quoted times is for the <b>slowest</b> of these, with 5 levels of aggregation.  You can see the performance history on <a href=\"https://github.com/objectcomputing/liquibook/blob/master/PERFORMANCE.md\">GitHub</a> where 2 second tests are recorded.</p>\n\n    </div> <!-- /container -->\n\n    <!-- Le javascript\n    ================================================== -->\n    <!-- Placed at the end of the document so the pages load faster -->\n    <script src=\"js/jquery-1.9.1.min.js\"></script>\n    <script src=\"js/bootstrap.min.js\"></script>\n  </body>\n</html>\n\n"
  },
  {
    "path": "web/flexible.html",
    "content": "\n<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <title>Liquibook</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta name=\"description\" content=\"\">\n    <meta name=\"author\" content=\"Jeff Schmitz\">\n\n    <!-- Le styles -->\n    <link href=\"css/bootstrap.min.css\" rel=\"stylesheet\">\n    <link href=\"css/liquibook.css\" rel=\"stylesheet\">\n    <style>\n      body {\n        padding-top: 60px; /* 60px to make the container go all the way to the bottom of the topbar */\n      }\n    </style>\n    <link href=\"css/bootstrap-responsive.min.css\" rel=\"stylesheet\">\n\n    <!-- HTML5 shim, for IE6-8 support of HTML5 elements -->\n    <!--[if lt IE 9]>\n      <script src=\"js/html5shiv.js\"></script>\n    <![endif]-->\n\n    <!-- Fav and touch icons -->\n    <link rel=\"apple-touch-icon-precomposed\" sizes=\"144x144\" href=\"../assets/ico/apple-touch-icon-144-precomposed.png\">\n    <link rel=\"apple-touch-icon-precomposed\" sizes=\"114x114\" href=\"../assets/ico/apple-touch-icon-114-precomposed.png\">\n      <link rel=\"apple-touch-icon-precomposed\" sizes=\"72x72\" href=\"../assets/ico/apple-touch-icon-72-precomposed.png\">\n                    <link rel=\"apple-touch-icon-precomposed\" href=\"../assets/ico/apple-touch-icon-57-precomposed.png\">\n                                   <link rel=\"shortcut icon\" href=\"../assets/ico/favicon.png\">\n  </head>\n\n  <body>\n\n    <div class=\"navbar navbar-inverse navbar-fixed-top\">\n      <div class=\"navbar-inner\">\n        <div class=\"container\">\n          <button type=\"button\" class=\"btn btn-navbar\" data-toggle=\"collapse\" data-target=\".nav-collapse\">\n            <span class=\"icon-bar\"></span>\n            <span class=\"icon-bar\"></span>\n            <span class=\"icon-bar\"></span>\n          </button>\n          <a class=\"brand\" href=\"index.html\">Liquibook</a>\n          <div class=\"nav-collapse collapse\">\n            <ul class=\"nav\">\n              <li><a href=\"index.html\">Home</a></li>\n              <li><a href=\"fast.html\">Fast</a></li>\n              <li class=\"active\"><a href=\"flexible.html\">Flexible</a></li>\n              <li><a href=\"easy.html\">Easy</a></li>\n              <li><a href=\"get-started.html\">Get Started</a></li>\n            </ul>\n          </div><!--/.nav-collapse -->\n        </div>\n      </div>\n    </div>\n\n    <div class=\"container\">\n\n      <h1>Liquibook is flexible.  <span class=\"highlight\">Acrobat Flexible</span></h1>\n      <p>Liquibook is desingned to meet a wide array of use cases.</p>\n      <p>This means you get to choose:</p>\n\n      <ul>\n        <li>Your Order class</li>\n        <li>Your pointer preference (smart or standard)</li>\n        <li>Your threading model</li>\n        <li>Your identifiers</li>\n        <li>Your downstream handling</li>\n        <li>Your add-ons</li>\n      </ul>\n\n      <h2>How is it so Flexible?</h2>\n\n      <p>Your Order class is used, it must only implement a trivial interface.  If you don't have one, a sample one is included.</p>\n\n      <p>The OrderBook class is a template, which accepts a pointer type as a parameter.  You can use any pointer type which dereferences using the -&gt; operator.</p>\n\n      <p>Liquibook is not an application, but a library, usable within your application.  As such, it has no synchronization, nor background threads.  You choose whether to have mutliple threads and how to synchronize them.</p>\n\n      <p>Liquibook does not use order IDs, user IDs, account IDs, or symbols, just Order pointers.  Any mapping from order ID to pointer is done outside of Liquibook.</p>\n\n      <p>Liquibook further assumes all orders given to an order book are for the order book's symbol, and mapping from symbol to order book is  done outside of Liquibook.</p>\n\n      <p>Liquibook does none of the downstream handling, such as feed publishing, resulting from a trade or a quote.  After all, that is feed-specific.  Instead, liquibook queues up callbacks, which you handle in your code.</p>\n\n      <p>Liquibook includes optional add-on classes, for depth/BBO tracking, that can easily be integrated in the handling of callbacks.  For an example see SimpleOrderBook in the impl directory.</p>\n\n    </div> <!-- /container -->\n\n    <!-- Le javascript\n    ================================================== -->\n    <!-- Placed at the end of the document so the pages load faster -->\n    <script src=\"js/jquery-1.9.1.min.js\"></script>\n    <script src=\"js/bootstrap.min.js\"></script>\n  </body>\n</html>\n\n"
  },
  {
    "path": "web/fluid.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <title>Liquibook</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta name=\"description\" content=\"\">\n    <meta name=\"author\" content=\"Jeff Schmitz\">\n\n    <!-- Le styles -->\n    <link href=\"css/bootstrap.min.css\" rel=\"stylesheet\">\n    <style type=\"text/css\">\n      body {\n        padding-top: 60px;\n        padding-bottom: 40px;\n      }\n      .sidebar-nav {\n        padding: 9px 0;\n      }\n\n      @media (max-width: 980px) {\n        /* Enable use of floated navbar text */\n        .navbar-text.pull-right {\n          float: none;\n          padding-left: 5px;\n          padding-right: 5px;\n        }\n      }\n    </style>\n    <link href=\"css/bootstrap-responsive.min.css\" rel=\"stylesheet\">\n\n    <!-- HTML5 shim, for IE6-8 support of HTML5 elements -->\n    <!--[if lt IE 9]>\n      <script src=\"../assets/js/html5shiv.js\"></script>\n    <![endif]-->\n\n    <!-- Fav and touch icons -->\n    <link rel=\"apple-touch-icon-precomposed\" sizes=\"144x144\" href=\"../assets/ico/apple-touch-icon-144-precomposed.png\">\n    <link rel=\"apple-touch-icon-precomposed\" sizes=\"114x114\" href=\"../assets/ico/apple-touch-icon-114-precomposed.png\">\n      <link rel=\"apple-touch-icon-precomposed\" sizes=\"72x72\" href=\"../assets/ico/apple-touch-icon-72-precomposed.png\">\n                    <link rel=\"apple-touch-icon-precomposed\" href=\"../assets/ico/apple-touch-icon-57-precomposed.png\">\n                                   <link rel=\"shortcut icon\" href=\"../assets/ico/favicon.png\">\n  </head>\n\n  <body>\n\n    <div class=\"navbar navbar-inverse navbar-fixed-top\">\n      <div class=\"navbar-inner\">\n        <div class=\"container-fluid\">\n          <button type=\"button\" class=\"btn btn-navbar\" data-toggle=\"collapse\" data-target=\".nav-collapse\">\n            <span class=\"icon-bar\"></span>\n            <span class=\"icon-bar\"></span>\n            <span class=\"icon-bar\"></span>\n          </button>\n          <a class=\"brand\" href=\"#\">Liquibook</a>\n          <div class=\"nav-collapse collapse\">\n            <p class=\"navbar-text pull-right\">\n              From <a href=\"http://www.ociweb.com\" class=\"navbar-link\">Object Computing Inc</a>\n            </p>\n            <ul class=\"nav\">\n              <li class=\"active\"><a href=\"#\">Home</a></li>\n              <li><a href=\"#about\">About</a></li>\n              <li><a href=\"#contact\">Contact</a></li>\n            </ul>\n          </div><!--/.nav-collapse -->\n        </div>\n      </div>\n    </div>\n\n    <div class=\"container-fluid\">\n      <div class=\"row-fluid\">\n        <div class=\"span3\">\n          <div class=\"well sidebar-nav\">\n            <ul class=\"nav nav-list\">\n              <li class=\"nav-header\">Sidebar</li>\n              <li class=\"active\"><a href=\"#\">Link</a></li>\n              <li><a href=\"#\">Link</a></li>\n              <li><a href=\"#\">Link</a></li>\n              <li><a href=\"#\">Link</a></li>\n              <li class=\"nav-header\">Sidebar</li>\n              <li><a href=\"#\">Link</a></li>\n              <li><a href=\"#\">Link</a></li>\n              <li><a href=\"#\">Link</a></li>\n              <li><a href=\"#\">Link</a></li>\n              <li><a href=\"#\">Link</a></li>\n              <li><a href=\"#\">Link</a></li>\n              <li class=\"nav-header\">Also from OCI</li>\n              <li><a href=\"#\">QuickFAST</a></li>\n              <li><a href=\"#\">OpenDDS</a></li>\n              <li><a href=\"#\">MPC</a></li>\n            </ul>\n          </div><!--/.well -->\n        </div><!--/span-->\n        <div class=\"span9\">\n          <div class=\"hero-unit\">\n            <h1>Liquibook</h1>\n            <h2>C++ Limit Order Book Matching Engine</h2>\n            <p>Liquibook is an open source limit order book mathing engine, written in C++.  It focues on speed and flexibility, and is ready to integrate into your projects.</p>\n            <p><a href=\"#\" class=\"btn btn-primary btn-large\">Learn more &raquo;</a></p>\n          </div>\n          <div class=\"row-fluid\">\n            <div class=\"span4\">\n              <h2>Fast</h2>\n              <p>Supports upwards of 2 million order insertions per second.  Performs no floating point comparisons.</p>\n              <p><a class=\"btn\" href=\"#\">View details &raquo;</a></p>\n            </div><!--/span-->\n            <div class=\"span4\">\n              <h2>Modular</h2>\n              <p>Includes optional add-ons for order aggregation by price (market depth) and BBO tracking.</p>\n              <p><a class=\"btn\" href=\"#\">View details &raquo;</a></p>\n            </div><!--/span-->\n            <div class=\"span4\">\n              <h2>Minimal</h2>\n              <p>Copies minimal number of fields.</p>\n              <p><a class=\"btn\" href=\"#\">View details &raquo;</a></p>\n            </div><!--/span-->\n          </div><!--/row-->\n          <div class=\"row-fluid\">\n            <div class=\"span4\">\n              <h2>Flexible</h2>\n              <p>Works with your design - does not impose threading decisions, shared pointers, or an order class.</p>\n              <p><a class=\"btn\" href=\"#\">View details &raquo;</a></p>\n            </div><!--/span-->\n            <div class=\"span4\">\n              <h2>Easy</h2>\n              <p>Requires your order class implement only 4 methods.</p>\n              <p><a class=\"btn\" href=\"#\">View details &raquo;</a></p>\n            </div><!--/span-->\n            <div class=\"span4\">\n              <h2>Open</h2>\n              <p>Completely non-viral, open source license to meet your needs.</p>\n              <p><a class=\"btn\" href=\"#\">View details &raquo;</a></p>\n            </div><!--/span-->\n          </div><!--/row-->\n        </div><!--/span-->\n      </div><!--/row-->\n\n      <hr>\n\n      <footer>\n        <p>&copy; Object Computing, Inc. 2013</p>\n      </footer>\n\n    </div><!--/.fluid-container-->\n\n    <script src=\"js/jquery.js\"></script>\n    <script src=\"js/bootstrap-min.js\"></script>\n\n  </body>\n</html>\n"
  },
  {
    "path": "web/get-started.html",
    "content": "\n<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <title>Liquibook</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta name=\"description\" content=\"\">\n    <meta name=\"author\" content=\"Jeff Schmitz\">\n\n    <!-- Le styles -->\n    <link href=\"css/bootstrap.min.css\" rel=\"stylesheet\">\n    <link href=\"css/liquibook.css\" rel=\"stylesheet\">\n    <style>\n      body {\n        padding-top: 60px; /* 60px to make the container go all the way to the bottom of the topbar */\n      }\n    </style>\n    <link href=\"css/bootstrap-responsive.min.css\" rel=\"stylesheet\">\n\n    <!-- HTML5 shim, for IE6-8 support of HTML5 elements -->\n    <!--[if lt IE 9]>\n      <script src=\"js/html5shiv.js\"></script>\n    <![endif]-->\n\n    <!-- Fav and touch icons -->\n    <link rel=\"apple-touch-icon-precomposed\" sizes=\"144x144\" href=\"../assets/ico/apple-touch-icon-144-precomposed.png\">\n    <link rel=\"apple-touch-icon-precomposed\" sizes=\"114x114\" href=\"../assets/ico/apple-touch-icon-114-precomposed.png\">\n      <link rel=\"apple-touch-icon-precomposed\" sizes=\"72x72\" href=\"../assets/ico/apple-touch-icon-72-precomposed.png\">\n                    <link rel=\"apple-touch-icon-precomposed\" href=\"../assets/ico/apple-touch-icon-57-precomposed.png\">\n                                   <link rel=\"shortcut icon\" href=\"../assets/ico/favicon.png\">\n  </head>\n\n  <body>\n\n    <div class=\"navbar navbar-inverse navbar-fixed-top\">\n      <div class=\"navbar-inner\">\n        <div class=\"container\">\n          <button type=\"button\" class=\"btn btn-navbar\" data-toggle=\"collapse\" data-target=\".nav-collapse\">\n            <span class=\"icon-bar\"></span>\n            <span class=\"icon-bar\"></span>\n            <span class=\"icon-bar\"></span>\n          </button>\n          <a class=\"brand\" href=\"index.html\">Liquibook</a>\n          <div class=\"nav-collapse collapse\">\n            <ul class=\"nav\">\n              <li><a href=\"index.html\">Home</a></li>\n              <li><a href=\"#\">Fast</a></li>\n              <li><a href=\"flexible.html\">Flexible</a></li>\n              <li><a href=\"easy.html\">Easy</a></li>\n              <li class=\"active\"><a href=\"get-started.html\">Get Started</a></li>\n            </ul>\n          </div><!--/.nav-collapse -->\n        </div>\n      </div>\n    </div>\n\n    <div class=\"container\">\n\n      <h1>Liquibook is Fast</h1>\n      <p>Liquibook was designed to meet the needs of the most demanding customers.  This means:</p>\n\n      <ul>\n        <li>Written in C++</li>\n        <li>No floating point comparisons</li>\n        <li>Minimal copying of data from your order objects</li>\n      </ul>\n\n      <h2>How Fast?</h2>\n\n      <p>The included performance tests show Liquibook handling <b>over 2 million</b> orders per second.</p>\n\n      <h2>What Does the Performance Test Actually Do?</h2>\n\n      <p>The included performance test allocates a number of orders, and then runs for a given duration, measuring the time to handle them.  If the orders run out before the test completes, the test is rerun with double the number of orders until an iteration completes.</p>\n\n      <p>When complete, it checks the number of orders processed before the end of the test, and reports that, as well as the number of resulting matches (trades).</p>\n\n      <p>The test runs against three different order books:</p>\n\n      <ul>\n        <li>Raw order book matching engine</li>\n        <li>Order book matching engine with BBO tracking</li>\n        <li>Order book matching engine with 5 levels of aggregation (market depth)</li>\n      </ul>\n\n      <p>The quoted times is for the <b>slowest</b> of these, with 5 levels of aggregation.  You can see the performance history on <a href=\"https://github.com/objectcomputing/liquibook/blob/master/PERFORMANCE.md\">GitHub</a>.</p>\n\n    </div> <!-- /container -->\n\n    <!-- Le javascript\n    ================================================== -->\n    <!-- Placed at the end of the document so the pages load faster -->\n    <script src=\"js/jquery-1.9.1.min.js\"></script>\n    <script src=\"js/bootstrap.min.js\"></script>\n  </body>\n</html>\n\n"
  },
  {
    "path": "web/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <title>Liquibook Matching Engine</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta name=\"description\" content=\"\">\n    <meta name=\"author\" content=\"Jeff Schmitz\">\n\n    <!-- Le styles -->\n    <link href=\"css/bootstrap.min.css\" rel=\"stylesheet\">\n    <style type=\"text/css\">\n      body {\n        padding-top: 20px;\n        padding-bottom: 60px;\n      }\n\n      /* Custom container */\n      .container {\n        margin: 0 auto;\n        max-width: 1000px;\n      }\n      .container > hr {\n        margin: 60px 0;\n      }\n\n      /* Main marketing message and sign up button */\n      .jumbotron {\n        margin: 80px 0;\n        text-align: center;\n      }\n      .jumbotron h1 {\n        font-size: 100px;\n        line-height: 1;\n      }\n      .jumbotron .lead {\n        font-size: 24px;\n        line-height: 1.25;\n      }\n      .jumbotron .btn {\n        font-size: 21px;\n        padding: 14px 24px;\n      }\n\n      /* Supporting marketing content */\n      .marketing {\n        margin: 60px 0;\n      }\n      .marketing p + h4 {\n        margin-top: 28px;\n      }\n\n\n      /* Customize the navbar links to be fill the entire space of the .navbar */\n      .navbar .navbar-inner {\n        padding: 0;\n      }\n      .navbar .nav {\n        margin: 0;\n        display: table;\n        width: 100%;\n      }\n      .navbar .nav li {\n        display: table-cell;\n        width: 1%;\n        float: none;\n      }\n      .navbar .nav li a {\n        font-weight: bold;\n        text-align: center;\n        border-left: 1px solid rgba(255,255,255,.75);\n        border-right: 1px solid rgba(0,0,0,.1);\n      }\n      .navbar .nav li:first-child a {\n        border-left: 0;\n        border-radius: 3px 0 0 3px;\n      }\n      .navbar .nav li:last-child a {\n        border-right: 0;\n        border-radius: 0 3px 3px 0;\n      }\n    </style>\n    <link href=\"css/bootstrap-responsive.min.css\" rel=\"stylesheet\">\n\n    <!-- HTML5 shim, for IE6-8 support of HTML5 elements -->\n    <!--[if lt IE 9]>\n      <script src=\"js/html5shiv.js\"></script>\n    <![endif]-->\n\n    <!-- Fav and touch icons -->\n    <link rel=\"apple-touch-icon-precomposed\" sizes=\"144x144\" href=\"../assets/ico/apple-touch-icon-144-precomposed.png\">\n    <link rel=\"apple-touch-icon-precomposed\" sizes=\"114x114\" href=\"../assets/ico/apple-touch-icon-114-precomposed.png\">\n      <link rel=\"apple-touch-icon-precomposed\" sizes=\"72x72\" href=\"../assets/ico/apple-touch-icon-72-precomposed.png\">\n                    <link rel=\"apple-touch-icon-precomposed\" href=\"../assets/ico/apple-touch-icon-57-precomposed.png\">\n                                   <link rel=\"shortcut icon\" href=\"../assets/ico/favicon.png\">\n  </head>\n\n  <body>\n\n    <div class=\"container\">\n\n      <div class=\"masthead\">\n        <h3 class=\"muted\">Liquibook</h3>\n        <div class=\"navbar\">\n          <div class=\"navbar-inner\">\n            <div class=\"container\">\n              <ul class=\"nav\">\n                <li class=\"active\"><a href=\"#\">Home</a></li>\n                <li><a href=\"#\">Projects</a></li>\n                <li><a href=\"#\">Services</a></li>\n                <li><a href=\"#\">Downloads</a></li>\n                <li><a href=\"#\">About</a></li>\n                <li><a href=\"#\">Contact</a></li>\n              </ul>\n            </div>\n          </div>\n        </div><!-- /.navbar -->\n      </div>\n\n      <!-- Jumbotron -->\n      <div class=\"jumbotron\">\n        <h1>Liquibook</h1>\n        <h2>Open source C++ limit order book matching engine</h2>\n        <p class=\"lead\">Liquibook is a fast and flexible matching engine.  It works with your design choices, and works with any protocol.</p>\n        <a class=\"btn btn-large btn-success\" href=\"get-started.html\">Get started today</a>\n      </div>\n\n      <!-- Example row of columns -->\n      <div class=\"row-fluid\">\n        <div class=\"span4\">\n          <h2>Fast</h2>\n          <p>Supports upwards of 2 million order insertions per second.  Performs no floating point comparisons.</p>\n          <p><a class=\"btn\" href=\"fast.html\">More &raquo;</a></p>\n        </div>\n        <div class=\"span4\">\n          <h2>Flexible</h2>\n          <p>Works with your design - does not impose a threading model, shared pointers, or a specific order class.</p>\n          <p><a class=\"btn\" href=\"flexible.html\">More &raquo;</a></p>\n       </div>\n        <div class=\"span4\">\n          <h2>Easy</h2>\n          <p>Requires your order class implement only 4 methods.  Modular design allows you to easily add BBO or market depth support.</p>\n          <p><a class=\"btn\" href=\"easy.html\">More &raquo;</a></p>\n        </div>\n      </div>\n\n      <hr>\n\n      <div class=\"footer\">\n        <p>&copy; Object Computing, Inc. 2013</p>\n      </div>\n\n    </div> <!-- /container -->\n\n    <!-- Le javascript\n    ================================================== -->\n    <!-- Placed at the end of the document so the pages load faster -->\n    <script src=\"js/jquery-1.9.1.min.js\"></script>\n    <script src=\"js/bootstrap.min.js\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "web/sub-template.html",
    "content": "\n<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <title>Liquibook</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta name=\"description\" content=\"\">\n    <meta name=\"author\" content=\"Jeff Schmitz\">\n\n    <!-- Le styles -->\n    <link href=\"css/bootstrap.min.css\" rel=\"stylesheet\">\n    <link href=\"css/liquibook.css\" rel=\"stylesheet\">\n    <style>\n      body {\n        padding-top: 60px; /* 60px to make the container go all the way to the bottom of the topbar */\n      }\n    </style>\n    <link href=\"css/bootstrap-responsive.min.css\" rel=\"stylesheet\">\n\n    <!-- HTML5 shim, for IE6-8 support of HTML5 elements -->\n    <!--[if lt IE 9]>\n      <script src=\"js/html5shiv.js\"></script>\n    <![endif]-->\n\n    <!-- Fav and touch icons -->\n    <link rel=\"apple-touch-icon-precomposed\" sizes=\"144x144\" href=\"../assets/ico/apple-touch-icon-144-precomposed.png\">\n    <link rel=\"apple-touch-icon-precomposed\" sizes=\"114x114\" href=\"../assets/ico/apple-touch-icon-114-precomposed.png\">\n      <link rel=\"apple-touch-icon-precomposed\" sizes=\"72x72\" href=\"../assets/ico/apple-touch-icon-72-precomposed.png\">\n                    <link rel=\"apple-touch-icon-precomposed\" href=\"../assets/ico/apple-touch-icon-57-precomposed.png\">\n                                   <link rel=\"shortcut icon\" href=\"../assets/ico/favicon.png\">\n  </head>\n\n  <body>\n\n    <div class=\"navbar navbar-inverse navbar-fixed-top\">\n      <div class=\"navbar-inner\">\n        <div class=\"container\">\n          <button type=\"button\" class=\"btn btn-navbar\" data-toggle=\"collapse\" data-target=\".nav-collapse\">\n            <span class=\"icon-bar\"></span>\n            <span class=\"icon-bar\"></span>\n            <span class=\"icon-bar\"></span>\n          </button>\n          <a class=\"brand\" href=\"index.html\">Liquibook</a>\n          <div class=\"nav-collapse collapse\">\n            <ul class=\"nav\">\n              <li><a href=\"index.html\">Home</a></li>\n              <li class=\"active\"><a href=\"#\">Fast</a></li>\n              <li><a href=\"flexible.html\">Flexible</a></li>\n              <li><a href=\"easy.html\">Easy</a></li>\n              <li><a href=\"get-started.html\">Get Started</a></li>\n            </ul>\n          </div><!--/.nav-collapse -->\n        </div>\n      </div>\n    </div>\n\n    <div class=\"container\">\n\n      <h1>Liquibook is Fast</h1>\n      <p>Liquibook was designed to meet the needs of the most demanding customers.  This means:</p>\n\n      <ul>\n        <li>Written in C++</li>\n        <li>No floating point comparisons</li>\n        <li>Minimal copying of data from your order objects</li>\n      </ul>\n\n      <h2>How Fast?</h2>\n\n      <p>The included performance tests show Liquibook handling <b>over 2 million</b> orders per second.</p>\n\n      <h2>What Does the Performance Test Actually Do?</h2>\n\n      <p>The included performance test allocates a number of orders, and then runs for a given duration, measuring the time to handle them.  If the orders run out before the test completes, the test is rerun with double the number of orders until an iteration completes.</p>\n\n      <p>When complete, it checks the number of orders processed before the end of the test, and reports that, as well as the number of resulting matches (trades).</p>\n\n      <p>The test runs against three different order books:</p>\n\n      <ul>\n        <li>Raw order book matching engine</li>\n        <li>Order book matching engine with BBO tracking</li>\n        <li>Order book matching engine with 5 levels of aggregation (market depth)</li>\n      </ul>\n\n      <p>The quoted times is for the <b>slowest</b> of these, with 5 levels of aggregation.  You can see the performance history on <a href=\"https://github.com/objectcomputing/liquibook/blob/master/PERFORMANCE.md\">GitHub</a>.</p>\n\n    </div> <!-- /container -->\n\n    <!-- Le javascript\n    ================================================== -->\n    <!-- Placed at the end of the document so the pages load faster -->\n    <script src=\"js/jquery-1.9.1.min.js\"></script>\n    <script src=\"js/bootstrap.min.js\"></script>\n  </body>\n</html>\n\n"
  },
  {
    "path": "winenv.bat",
    "content": "@REM Copyright (c) 2017 Object Computing, Inc.\n@REM All rights reserved.\n@REM See the file license.txt for licensing information.\n\nREM Setting up LiquiBook environment\n\n@REM LiquiBook depends on MPC V 3.6 or later. (http://www.ociweb.com/products/mpc)\n@REM LiquiBook depends on BOOST V 1.43.0 or later. (http://www.boost.org/)\n@REM Assumes VC10(Visual Studio 2010), VC12(Visual Studio 2013), or VC14 (Visual Studio 2015)\n@REM installed in the default location (see VC_ROOT below) and VC..COMNTOOLS is set.\n\n@REM Customize this file by setting variables to suit your environment\n@REM Also you should customize the LiquiBook.features file to enable particular features on your system.\n\n@REM --------START: DELETE THESE LINES AFTER CUSTOMIZING ----\n@ECHO Please make a copy of %~f0 and customize it according to the instructions in the file.\n@ECHO You should also customize %~dp0\\Liquibook.features\n@goto end\n@REM --------END: DELETE THESE LINES AFTER CUSTOMIZING ----\n\n@echo off\nREM =====================================================================================\nREM EDIT THE FOLLOWING LINES OR SET THESE VALUES IN YOUR ENVIRONMENT BEFORE RUNNING SETUP\nif \"a\" == \"a%MPC_ROOT%\" set MPC_ROOT=c:\\MPC\\MPC_4_1_22\nif \"a\" == \"a%BOOST_VERSION%\" set BOOST_VERSION=boost_1_61_0\nif \"a\" == \"a%BOOST_ROOT%\" set BOOST_ROOT=c:\\boost\\%BOOST_VERSION%\n\n@REM TODO: For the pub/sub example program set QUICKFAST_ROOT \n@rem to the actual quickfast directory and \n@rem define XEERCESROOT\nif \"a\" == \"a%QUICKFAST_ROOT%\" set QUICKFAST_ROOT=noQuickFAST\nif \"a\" == \"a%XERCESROOT%\" set XERCESROOT=C:\\Progs\\xerces\\xerces-c-3.1.1-x86_64-windows-vc-10.0\n\nREM END OF VALUES TO BE SET\nREM =====================================================================================\n\nREM Microsoft moved 32 bit apps to a new program files directory on 64 bit systems\nset PROGRAM_FILES_X86=Program Files\nif exist \"C:\\Program Files (x86)\" set PROGRAM_FILES_X86=Program Files (x86)\n\nREM Verify setup by checking for expected files/directories\nset SETUP_CHECKING=MPC_ROOT=%MPC_ROOT%\nif not exist \"%MPC_ROOT%\\mpc.pl\" goto setup_is_bad\n\nset SETUP_CHECKING=BOOST_ROOT=%BOOST_ROOT%\nif not exist \"%BOOST_ROOT%\\boost\" goto setup_is_bad\n\nREM if you are not running unit tests, delete the REM on the next line\nREM goto noBoost\nset SETUP_CHECKING=BOOST_ROOT lib=%BOOST_ROOT%\\lib\nif not exist \"%BOOST_ROOT%\\lib\" goto setup_is_bad\n:noBoost\n\nREM If you are not building the pub/sub app remove the REM on the next line\nREM goto noPubSub\n\nset SETUP_CHECKING=QUICKFAST_ROOT contains QuickFASTApplication.mpb\nif not exist %QUICKFAST_ROOT%\\QuickFASTApplication.mpb goto setup_is_bad\n\nset SETUP_CHECKING=XERCESROOT=%XERCESROOT%\nif not exist \"%XERCESROOT%\\lib\" goto setup_is_bad\n\n:noPubSub\n\nREM Find visual studio.  \nREM You can short-circuit this by setting VCVER before running this\nREM However this also skips the check to see if VC is installed in the expected place\n\nrem if VCVER is already set, skip the discovery\nif not \"a\" == \"a%VCVER%\" goto setup_is_ok\n\nset SETUP_CHECKING=Setup checking visual studio common tools\n\nset VCVER=15\nset SETUP_CHECKING=VS150COMNTOOLS=%VS150COMNTOOLS%\nset VS_COMMON_TOOLS=%VS150COMNTOOLS%\nset VC_ROOT=C:\\%PROGRAM_FILES_X86%\\Microsoft Visual Studio 15.0\\VC\\bin\nif exist \"%VS_COMMON_TOOLS%VSVARS32.BAT\" goto setup_is_ok\n\nset VCVER=14\nset SETUP_CHECKING=VS140COMNTOOLS=%VS140COMNTOOLS%\nset VS_COMMON_TOOLS=%VS140COMNTOOLS%\nset VC_ROOT=C:\\%PROGRAM_FILES_X86%\\Microsoft Visual Studio 14.0\\VC\\bin\nif exist \"%VS_COMMON_TOOLS%VSVARS32.BAT\" goto setup_is_ok\n\nset VCVER=13\nset SETUP_CHECKING=VS130COMNTOOLS=%VS130COMNTOOLS%\nset VS_COMMON_TOOLS=%VS130COMNTOOLS%\nset VC_ROOT=C:\\%PROGRAM_FILES_X86%\\Microsoft Visual Studio 13.0\\VC\\bin\nif exist \"%VS_COMMON_TOOLS%VSVARS32.BAT\" goto setup_is_ok\n\nset VCVER=12\nset SETUP_CHECKING=VS120COMNTOOLS=%VS120COMNTOOLS%\nset VS_COMMON_TOOLS=%VS130COMNTOOLS%\nset VC_ROOT=C:\\%PROGRAM_FILES_X86%\\Microsoft Visual Studio 12.0\\VC\\bin\nif exist \"%VS_COMMON_TOOLS%VSVARS32.BAT\" goto setup_is_ok\n\nset VCVER=11\nset SETUP_CHECKING=VS110COMNTOOLS=%VS110COMNTOOLS%\nset VS_COMMON_TOOLS=%VS110COMNTOOLS%\nset VC_ROOT=C:\\%PROGRAM_FILES_X86%\\Microsoft Visual Studio 11.0\\VC\\bin\nif exist \"%VS_COMMON_TOOLS%VSVARS32.BAT\" goto setup_is_ok\n\nset VCVER=10\nset SETUP_CHECKING=VS100COMNTOOLS=%VS100COMNTOOLS%\nset VS_COMMON_TOOLS=%VS100COMNTOOLS%\nset VC_ROOT=C:\\%PROGRAM_FILES_X86%\\Microsoft Visual Studio 10.0\\VC\\bin\nif exist \"%VS_COMMON_TOOLS%VSVARS32.BAT\" goto setup_is_ok\n\nset VCVER=9\nset SETUP_CHECKING=VS90COMNTOOLS=%VS90COMNTOOLS%\nset VS_COMMON_TOOLS=%VS90COMNTOOLS%\nset VC_ROOT=C:\\%PROGRAM_FILES_X86%\\Microsoft Visual Studio 9.0\\VC\\bin\nif exist \"%VS_COMMON_TOOLS%VSVARS32.BAT\" goto setup_is_ok\n\nset VCVER=8\nset SETUP_CHECKING=VS80COMNTOOLS=%VS80COMNTOOLS%\nset VS_COMMON_TOOLS=%VS80COMNTOOLS%\nset VC_ROOT=C:\\%PROGRAM_FILES_X86%\\Microsoft Visual Studio 8.0\\VC\\bin\nif exist \"%VS_COMMON_TOOLS%VSVARS32.BAT\" goto setup_is_ok\nREM goto setup_is_bad  (you are here) REM Find visual studio.  \nrem if VCVER is already set, skip the discovery\nif not \"a\" == \"a%VCVER%\" goto setup_is_ok\n\nREM goto setup_is_bad  (you are here) \n\n:setup_is_bad\nECHO Setup check failed: %SETUP_CHECKING%\nECHO Edit the setup.cmd file or change environment variables\ngoto end\n\n:setup_is_ok\nset SETUP_CHECKING=\nset LIQUIBOOK_ROOT=%~dp0\n\ncall \"%VS_COMMON_TOOLS%VSVARS32.BAT\" >nul\n\nREM: This avoids growing PATH and INCLUDE every time setup is run\nif \"a\" == \"a%BASE_PATH%\" set BASE_PATH=%PATH%\nif \"a\" == \"a%BASE_INCLUDE%\" set BASE_INCLUDE=%INCLUDE%\n\nset RELEASE_PATH=%LiquiBook_ROOT%\\bin;%LiquiBook_ROOT%\\Output\\Release;%MPC_ROOT%;%BOOST_ROOT%\\lib;%LiquiBook_ROOT%\\lib;%BASE_PATH%\nset DEBUG_PATH=%LiquiBook_ROOT%\\bin;%LiquiBook_ROOT%\\Output\\Debug;%MPC_ROOT%;%BOOST_ROOT%\\lib;%LiquiBook_ROOT%\\lib;%BASE_PATH%\n\nif \"a\" == \"a%QUICKFAST_ROOT%\" goto noQuickFAST\nset RELEASE_PATH=%RELEASE_PATH%;%QUICKFAST_ROOT%\\Output\\Release\nset DEBUG_PATH=%DEBUG_PATH%;%QUICKFAST_ROOT%\\Output\\Debug\n:noQuickFAST\n\nif \"a\" == \"a%XERCESROOT%\" goto noXERCES\nset RELEASE_PATH=%RELEASE_PATH%;%XERCESROOT%\\bin\nset DEBUG_PATH=%DEBUG_PATH%;%XERCESROOT%\\bin\n:noXERCES\n\nset PATH=%DEBUG_PATH%\nset INCLUDE=%BOOST_ROOT%\\include;%BASE_INCLUDE%\n\ntitle LiquiBook\n:end\n\n\n"
  },
  {
    "path": "winenv_clear.bat",
    "content": "@REM Copyright (c) 2009, 2010 Object Computing, Inc.\n@REM All rights reserved.\n@REM See the file license.txt for licensing information.\n\nREM This undefines the variables set by Setup to make it easy to rerun\nREM setup after making changes.  It should not be needed unless you are\nREM editing the setup.cmd file.\nset MPC_ROOT=\nset XERCESROOT=\nset XERCES_LIBNAME=\nset BOOST_VERSION=\nset BOOST_ROOT=\nset QUICKFAST_ROOT=\n"
  }
]