{"id":23550402,"url":"https://github.com/coralblocks/coralme","last_synced_at":"2025-04-28T10:51:31.727Z","repository":{"id":158539952,"uuid":"634081646","full_name":"coralblocks/CoralME","owner":"coralblocks","description":"A simple, fast and garbage-free matching engine order book that you can use as a starting point for your matching engines.","archived":false,"fork":false,"pushed_at":"2025-04-23T15:00:11.000Z","size":166,"stargazers_count":41,"open_issues_count":0,"forks_count":25,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-04-23T15:24:00.315Z","etag":null,"topics":["finance","garbage-collector","low-latency","matching-engine"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/coralblocks.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-04-29T01:59:11.000Z","updated_at":"2025-04-23T15:00:15.000Z","dependencies_parsed_at":"2024-11-22T01:23:56.723Z","dependency_job_id":"6532b724-6922-4e09-9246-e49f0de663b3","html_url":"https://github.com/coralblocks/CoralME","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coralblocks%2FCoralME","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coralblocks%2FCoralME/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coralblocks%2FCoralME/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coralblocks%2FCoralME/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/coralblocks","download_url":"https://codeload.github.com/coralblocks/CoralME/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251300263,"owners_count":21567409,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["finance","garbage-collector","low-latency","matching-engine"],"created_at":"2024-12-26T10:16:06.741Z","updated_at":"2025-04-28T10:51:31.716Z","avatar_url":"https://github.com/coralblocks.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# CoralME\nA simple, fast and garbage-free matching engine order book that you can use as a starting point for your matching engines.\n\n\u003cpre\u003e\n\u003cb\u003eNote:\u003c/b\u003e For a detailed discussion of how a \u003cb\u003efirst-class electronic exchange\u003c/b\u003e can be built\nfrom the ground up using the \u003ca href=\"https://www.coralblocks.com/index.php/state-of-the-art-distributed-systems-with-coralmq/\"\u003esequencer architecture\u003c/a\u003e you should refer to \u003ca href=\"https://www.coralblocks.com/index.php/building-a-first-class-exchange-architecture-with-coralsequencer/\"\u003ethis article\u003c/a\u003e.\n\u003c/pre\u003e\n\n## What is it?\nCoralME is an order book data-structure that matches orders based on price-time priority. It maintains limit orders resting in an order book until they are either canceled or filled. Whenever an order changes its state, a callback is issued to registered listeners.\n\n## What people usually mean by the term _Matching Engine_?\nUsually when people talk about a _Matching Engine_, what they are really referring to is the full solution for an electronic exchange. That would include gateways, drop copies, market data, balances, reports, monitors, margins, compliance, fees, etc. Plus the _messaging middleware_ to tie all these pieces together. In that context, **the matching engine is really just one of the many parts of an electronic exchange**. It is an important part, the central nervous systems of an exchange, which maintains orders resting inside order books, and matches them when liquidity takers meet liquidity providers (i.e. market makers).\n\n\u003c!-- For a detailed discussion of how a **first-class electronic exchange** can be built from the ground up using the sequencer architecture you should refer to [this article](https://www.coralblocks.com/index.php/building-a-first-class-exchange-architecture-with-coralsequencer/). --\u003e\n\n\n## Quick Start\nRefer to [Example.java](https://github.com/coralblocks/CoralME/blob/main/src/main/java/com/coralblocks/coralme/example/Example.java) for a bunch of order matching use-cases.\n\nThe [OrderBookTest.java](https://github.com/coralblocks/CoralME/blob/main/src/test/java/com/coralblocks/coralme/OrderBookTest.java) might give you some good ideas as well but I find the [Example.java](https://github.com/coralblocks/CoralME/blob/main/src/main/java/com/coralblocks/coralme/example/Example.java) easier to follow.\n\n## Features\n- Fast\n- Garbage-free\n- Callback oriented\n- Price levels\n- Price improvement for fills\n- MARKET and LIMIT order types\n- IOC, GTC and DAY\n- MAKER (of liquidity) and TAKER (of liquidity) execution sides\n- NORMAL, CROSSED, LOCKED, ONESIDED and EMPTY book states\n- ClientID, ClientOrderID and OrderID\n- ExecutionID and ExecutionMatchID\n- Can optionally check and disallow trade to self\n- Supports cancelation of open size as well as [reduction of total size](https://chatgpt.com/share/6808fbb1-d840-8013-82a8-9ae1854c7707) (executed + open)\n\n## How can I check that it is zero garbage?\nCheck [NoGCTest.java](https://github.com/coralblocks/CoralME/blob/main/src/main/java/com/coralblocks/coralme/example/NoGCTest.java) to see that it creates a book and populates this book with 10 orders _one million times_. And on each of these one million times it does a bunch of executions, rejects, cancelations, reduces, etc. Run this test with `-verbose:gc -Xms128m -Xmx256m` and you will always see **zero GC activity**. _No matter how many iterations you perform, the gc activity is always zero_. If you want to see some GC activity, you can turn on a flag that forces the creation of garbage by [producing some strings](https://github.com/coralblocks/CoralME/blob/bb9461313537987db43339e429b7314e58bbb784/src/main/java/com/coralblocks/coralme/example/NoGCTest.java#L103) in the middle of the loop.\n\n##### Creating ZERO garbage\n```\n$ ./bin/runGCTest.sh\njava -verbose:gc -Xms128m -Xmx256m -cp target/classes com.coralblocks.coralme.example.NoGCTest false 1000000\n1000000 ... DONE!\n```\n##### Forcing the creation of garbage (pass true to runGCTest.sh)\n```\n$ ./bin/runGCTest.sh true\njava -verbose:gc -Xms128m -Xmx256m -cp target/classes com.coralblocks.coralme.example.NoGCTest true 1000000\n60870[GC (Allocation Failure)  33280K-\u003e1224K(125952K), 0.0005392 secs]\n146061[GC (Allocation Failure)  34504K-\u003e1200K(125952K), 0.0005032 secs]\n231254[GC (Allocation Failure)  34480K-\u003e1240K(125952K), 0.0003991 secs]\n316449[GC (Allocation Failure)  34520K-\u003e1208K(125952K), 0.0004686 secs]\n401642[GC (Allocation Failure)  34488K-\u003e1264K(125952K), 0.0004315 secs]\n486832[GC (Allocation Failure)  34544K-\u003e1200K(129536K), 0.0004712 secs]\n590373[GC (Allocation Failure)  41648K-\u003e1128K(129536K), 0.0005286 secs]\n693917[GC (Allocation Failure)  41576K-\u003e1128K(128512K), 0.0002270 secs]\n794836[GC (Allocation Failure)  40552K-\u003e1128K(129024K), 0.0002390 secs]\n895759[GC (Allocation Failure)  40552K-\u003e1128K(129024K), 0.0002202 secs]\n996679[GC (Allocation Failure)  40552K-\u003e1128K(129024K), 0.0002492 secs]\n1000000 ... DONE!\n```\n\n## Callbacks Supported\n```Java\npublic interface OrderBookListener {\n    \n    public void onOrderReduced(OrderBook orderBook, long time, Order order, \n                                 long canceledSize, long reduceNewTotalSize);\n    \n    public void onOrderCanceled(OrderBook orderBook, long time, Order order, \n                                  long canceledSize, CancelReason cancelReason);\n    \n    public void onOrderExecuted(OrderBook orderBook, long time, Order order, \n                                  ExecuteSide executeSide, long executeSize, \n                                  long executePrice, long executeId, long executeMatchId);\n    \n    public void onOrderAccepted(OrderBook orderBook, long time, Order order);\n    \n    public void onOrderRejected(OrderBook orderBook, long time, Order order, \n                                  RejectReason rejectReason);\n    \n    public void onOrderRested(OrderBook orderBook, long time, Order order,\n                                long restSize, long restPrice);\n\n    public void onOrderTerminated(OrderBook orderBook, long time, Order order);\n    \n}\n```\n\n## Code Snippet\n```Java\n\nfinal long CLIENT_ID = 1001L;\n\nlong orderId = 0;\n\n// This OrderBookListener will print all callbacks to System.out\nOrderBookLogger orderBookLogger = new OrderBookLogger();\n\nOrderBook orderBook = new OrderBook(\"AAPL\", orderBookLogger);\n\norderBook.createLimit(CLIENT_ID, String.valueOf(++orderId), orderId, Side.BUY, 200, 150.44, TimeInForce.DAY);\n\n/*\n\t-----\u003e onOrderAccepted called:\n\t  orderBook=AAPL\n\t  time=1700598048045000000\n\t  order=Order [id=1, clientId=1001, clientOrderId=1, side=BUY, security=AAPL, originalSize=200, openSize=200, \n\t\t\t\t\texecutedSize=0, canceledSize=0, price=150.44, type=LIMIT, tif=DAY]\n\t\n\t-----\u003e onOrderRested called:\n\t  orderBook=AAPL\n\t  time=1700598048047000000\n\t  order=Order [id=1, clientId=1001, clientOrderId=1, side=BUY, security=AAPL, originalSize=200, openSize=200, \n\t\t\t\t\texecutedSize=0, canceledSize=0, price=150.44, type=LIMIT, tif=DAY]\n\t  restSize=200\n\t  restPrice=150.44\n*/\n\norderBook.showLevels();\n\n/*\n   200 @    150.44 (orders=1)\n-------- \n*/\n\norderBook.showOrders();\n\n/*\n   200 @    150.44 (id=1)\n-------- \t\t\t  \n*/\n\norderBook.createLimit(CLIENT_ID, String.valueOf(++orderId), orderId, Side.BUY, 500, 149.44, TimeInForce.DAY);\n\n/* \n\t-----\u003e onOrderAccepted called:\n\t  orderBook=AAPL\n\t  time=1700598048049000000\n\t  order=Order [id=2, clientId=1001, clientOrderId=2, side=BUY, security=AAPL, originalSize=500, openSize=500, \n\t\t\t\t\texecutedSize=0, canceledSize=0, price=149.44, type=LIMIT, tif=DAY]\n\t\n\t-----\u003e onOrderRested called:\n\t  orderBook=AAPL\n\t  time=1700598048050000000\n\t  order=Order [id=2, clientId=1001, clientOrderId=2, side=BUY, security=AAPL, originalSize=500, openSize=500, \n\t\t\t\t\texecutedSize=0, canceledSize=0, price=149.44, type=LIMIT, tif=DAY]\n\t  restSize=500\n\t  restPrice=149.44\t\n*/\n\norderBookLogger.off(); // omit callbacks output for clarity\n\norderBook.createLimit(CLIENT_ID, String.valueOf(++orderId), orderId, Side.BUY, 100, 149.44, TimeInForce.GTC);\norderBook.createLimit(CLIENT_ID, String.valueOf(++orderId), orderId, Side.BUY, 100, 148.14, TimeInForce.DAY);\n\norderBook.createLimit(CLIENT_ID, String.valueOf(++orderId), orderId, Side.SELL, 300, 153.24, TimeInForce.GTC);\norderBook.createLimit(CLIENT_ID, String.valueOf(++orderId), orderId, Side.SELL, 500, 156.43, TimeInForce.DAY);\norderBook.createLimit(CLIENT_ID, String.valueOf(++orderId), orderId, Side.SELL, 1500, 158.54, TimeInForce.DAY);\n\norderBook.showLevels();\n\n/*\n   100 @    148.14 (orders=1)\n   600 @    149.44 (orders=2)\n   200 @    150.44 (orders=1)\n--------      2.80\n   300 @    153.24 (orders=1)\n   500 @    156.43 (orders=1)\n  1500 @    158.54 (orders=1)\t\t\n*/\n\norderBook.showOrders();\n\n/*\n   100 @    148.14 (id=4)\n   500 @    149.44 (id=2)\n   100 @    149.44 (id=3)\n   200 @    150.44 (id=1)\n--------      2.80\n   300 @    153.24 (id=5)\n   500 @    156.43 (id=6)\n  1500 @    158.54 (id=7)\n*/\n\norderBookLogger.on();\n\n// Buy 100 @ market\n\norderBook.createMarket(CLIENT_ID, String.valueOf(++orderId), orderId, Side.BUY, 100);\n\n/*\n\t-----\u003e onOrderAccepted called:\n\t  orderBook=AAPL\n\t  time=1700598048051000000\n\t  order=Order [id=8, clientId=1001, clientOrderId=8, side=BUY, security=AAPL, originalSize=100, openSize=100, \n\t\t\t\t\texecutedSize=0, canceledSize=0, type=MARKET]\n\t\n\t-----\u003e onOrderExecuted called:\n\t  orderBook=AAPL\n\t  time=1700598048051000000\n\t  order=Order [id=5, clientId=1001, clientOrderId=5, side=SELL, security=AAPL, originalSize=300, openSize=200, \n\t\t\t\t\texecutedSize=100, canceledSize=0, price=153.24, type=LIMIT, tif=GTC]\n\t  executeSide=MAKER\n\t  executeSize=100\n\t  executePrice=153.24\n\t  executeId=1\n\t  executeMatchId=1\n\t\n\t-----\u003e onOrderExecuted called:\n\t  orderBook=AAPL\n\t  time=1700598048051000000\n\t  order=Order [id=8, clientId=1001, clientOrderId=8, side=BUY, security=AAPL, originalSize=100, openSize=0, \n\t\t\t\t\texecutedSize=100, canceledSize=0, type=MARKET]\n\t  executeSide=TAKER\n\t  executeSize=100\n\t  executePrice=153.24\n\t  executeId=2\n\t  executeMatchId=1\n\t\n\t-----\u003e onOrderTerminated called:\n\t  orderBook=AAPL\n\t  time=1700598048051000000\n\t  order=Order [id=8, clientId=1001, clientOrderId=8, side=BUY, security=AAPL, originalSize=100, openSize=0, \n\t\t\t\t\texecutedSize=100, canceledSize=0, type=MARKET]\n*/\n\norderBook.showLevels();\n\n/*\n   100 @    148.14 (orders=1)\n   600 @    149.44 (orders=2)\n   200 @    150.44 (orders=1)\n--------      2.80\n   200 @    153.24 (orders=1)\n   500 @    156.43 (orders=1)\n  1500 @    158.54 (orders=1) \n*/\n\n// cancel 100 shares from order with id = 1\n\nOrder order = orderBook.getOrder(1);\norder.cancel(100);\n\n/*\n\t-----\u003e onOrderReduced called:\n\t  orderBook=AAPL\n\t  time=1700598048053000000\n\t  order=Order [id=1, clientId=1001, clientOrderId=1, side=BUY, security=AAPL, originalSize=200, openSize=100, \n\t\t\t\t\texecutedSize=0, canceledSize=100, price=150.44, type=LIMIT, tif=DAY]\n\t  canceledSize=100\n\t  reduceNewTotalSize=100\t\n*/\n\norderBook.showLevels();\n\n/*\n   100 @    148.14 (orders=1)\n   600 @    149.44 (orders=2)\n   100 @    150.44 (orders=1)\n--------      2.80\n   200 @    153.24 (orders=1)\n   500 @    156.43 (orders=1)\n  1500 @    158.54 (orders=1)\t \n*/\n\n// now cancel the order\n\norder.cancel();\n\n/*\n\t-----\u003e onOrderCanceled called:\n\t  orderBook=AAPL\n\t  time=1700598048053000000\n\t  order=Order [id=1, clientId=1001, clientOrderId=1, side=BUY, security=AAPL, originalSize=200, openSize=0, \n\t\t\t\t\texecutedSize=0, canceledSize=200, price=150.44, type=LIMIT, tif=DAY]\n\t  canceledSize=100\n\t  cancelReason=USER\n\t\n\t-----\u003e onOrderTerminated called:\n\t  orderBook=AAPL\n\t  time=1700598048053000000\n\t  order=Order [id=1, clientId=1001, clientOrderId=1, side=BUY, security=AAPL, originalSize=200, openSize=0, \n\t\t\t\t\texecutedSize=0, canceledSize=200, price=150.44, type=LIMIT, tif=DAY]\n*/\n\norderBook.showLevels();\n\n/*\n   100 @    148.14 (orders=1)\n   600 @    149.44 (orders=2)\n--------      3.80\n   200 @    153.24 (orders=1)\n   500 @    156.43 (orders=1)\n  1500 @    158.54 (orders=1)\t\n*/\n\n// hit the sell side of the book with a LIMIT IOC and notice your price improvement\n\norderBook.createLimit(CLIENT_ID, String.valueOf(++orderId), orderId, Side.BUY, 3000, 155.00, TimeInForce.IOC);\n\n/*\n\t-----\u003e onOrderAccepted called:\n\t  orderBook=AAPL\n\t  time=1700598048054000000\n\t  order=Order [id=9, clientId=1001, clientOrderId=9, side=BUY, security=AAPL, originalSize=3000, openSize=3000, \n\t\t\t\t\texecutedSize=0, canceledSize=0, price=155.0, type=LIMIT, tif=IOC]\n\t\n\t-----\u003e onOrderExecuted called:\n\t  orderBook=AAPL\n\t  time=1700598048054000000\n\t  order=Order [id=5, clientId=1001, clientOrderId=5, side=SELL, security=AAPL, originalSize=300, openSize=0, \n\t\t\t\t\texecutedSize=300, canceledSize=0, price=153.24, type=LIMIT, tif=GTC]\n\t  executeSide=MAKER\n\t  executeSize=200\n\t  executePrice=153.24\n\t  executeId=3\n\t  executeMatchId=2\n\t\n\t-----\u003e onOrderTerminated called:\n\t  orderBook=AAPL\n\t  time=1700598048054000000\n\t  order=Order [id=5, clientId=1001, clientOrderId=5, side=SELL, security=AAPL, originalSize=300, openSize=0, \n\t\t\t\t\texecutedSize=300, canceledSize=0, price=153.24, type=LIMIT, tif=GTC]\n\t\n\t-----\u003e onOrderExecuted called:\n\t  orderBook=AAPL\n\t  time=1700598048054000000\n\t  order=Order [id=9, clientId=1001, clientOrderId=9, side=BUY, security=AAPL, originalSize=3000, openSize=2800, \n\t\t\t\t\texecutedSize=200, canceledSize=0, price=155.0, type=LIMIT, tif=IOC]\n\t  executeSide=TAKER\n\t  executeSize=200\n\t  executePrice=153.24\n\t  executeId=4\n\t  executeMatchId=2\n\t\n\t-----\u003e onOrderCanceled called:\n\t  orderBook=AAPL\n\t  time=1700598048055000000\n\t  order=Order [id=9, clientId=1001, clientOrderId=9, side=BUY, security=AAPL, originalSize=3000, openSize=0, \n\t\t\t\t\texecutedSize=200, canceledSize=2800, price=155.0, type=LIMIT, tif=IOC]\n\t  canceledSize=2800\n\t  cancelReason=MISSED\n\t\n\t-----\u003e onOrderTerminated called:\n\t  orderBook=AAPL\n\t  time=1700598048055000000\n\t  order=Order [id=9, clientId=1001, clientOrderId=9, side=BUY, security=AAPL, originalSize=3000, openSize=0, \n\t\t\t\t\texecutedSize=200, canceledSize=2800, price=155.0, type=LIMIT, tif=IOC]\n*/\n\norderBook.showLevels();\n\n/*\n   100 @    148.14 (orders=1)\n   600 @    149.44 (orders=2)\n--------      6.99\n   500 @    156.43 (orders=1)\n  1500 @    158.54 (orders=1)\t\t \n*/\n\norderBookLogger.off();\n\norderBook.createLimit(CLIENT_ID, String.valueOf(++orderId), orderId, Side.SELL, 3000, 160.00, TimeInForce.DAY);\n\norderBook.showLevels();\n\n/*\n   100 @    148.14 (orders=1)\n   600 @    149.44 (orders=2)\n--------      6.99\n   500 @    156.43 (orders=1)\n  1500 @    158.54 (orders=1)\n  3000 @    160.00 (orders=1)\n*/\n\n// now hit two ask levels, price improve and sit on the book at 159.00\n\norderBookLogger.on();\n\norderBook.createLimit(CLIENT_ID, String.valueOf(++orderId), orderId, Side.BUY, 3900, 159.00, TimeInForce.DAY);\n\n/*\n\t-----\u003e onOrderAccepted called:\n\t  orderBook=AAPL\n\t  time=1700598048056000000\n\t  order=Order [id=11, clientId=1001, clientOrderId=11, side=BUY, security=AAPL, originalSize=3900, openSize=3900, \n\t\t\t\t\texecutedSize=0, canceledSize=0, price=159.0, type=LIMIT, tif=DAY]\n\t\n\t-----\u003e onOrderExecuted called:\n\t  orderBook=AAPL\n\t  time=1700598048056000000\n\t  order=Order [id=6, clientId=1001, clientOrderId=6, side=SELL, security=AAPL, originalSize=500, openSize=0, \n\t\t\t\t\texecutedSize=500, canceledSize=0, price=156.43, type=LIMIT, tif=DAY]\n\t  executeSide=MAKER\n\t  executeSize=500\n\t  executePrice=156.43\n\t  executeId=5\n\t  executeMatchId=3\n\t\n\t-----\u003e onOrderTerminated called:\n\t  orderBook=AAPL\n\t  time=1700598048056000000\n\t  order=Order [id=6, clientId=1001, clientOrderId=6, side=SELL, security=AAPL, originalSize=500, openSize=0, \n\t\t\t\t\texecutedSize=500, canceledSize=0, price=156.43, type=LIMIT, tif=DAY]\n\t\n\t-----\u003e onOrderExecuted called:\n\t  orderBook=AAPL\n\t  time=1700598048056000000\n\t  order=Order [id=11, clientId=1001, clientOrderId=11, side=BUY, security=AAPL, originalSize=3900, openSize=3400, \n\t\t\t\t\texecutedSize=500, canceledSize=0, price=159.0, type=LIMIT, tif=DAY]\n\t  executeSide=TAKER\n\t  executeSize=500\n\t  executePrice=156.43\n\t  executeId=6\n\t  executeMatchId=3\n\t\n\t-----\u003e onOrderExecuted called:\n\t  orderBook=AAPL\n\t  time=1700598048056000000\n\t  order=Order [id=7, clientId=1001, clientOrderId=7, side=SELL, security=AAPL, originalSize=1500, openSize=0, \n\t\t\t\t\texecutedSize=1500, canceledSize=0, price=158.54, type=LIMIT, tif=DAY]\n\t  executeSide=MAKER\n\t  executeSize=1500\n\t  executePrice=158.54\n\t  executeId=7\n\t  executeMatchId=4\n\t\n\t-----\u003e onOrderTerminated called:\n\t  orderBook=AAPL\n\t  time=1700598048056000000\n\t  order=Order [id=7, clientId=1001, clientOrderId=7, side=SELL, security=AAPL, originalSize=1500, openSize=0, \n\t\t\t\t\texecutedSize=1500, canceledSize=0, price=158.54, type=LIMIT, tif=DAY]\n\t\n\t-----\u003e onOrderExecuted called:\n\t  orderBook=AAPL\n\t  time=1700598048056000000\n\t  order=Order [id=11, clientId=1001, clientOrderId=11, side=BUY, security=AAPL, originalSize=3900, openSize=1900, \n\t\t\t\t\texecutedSize=2000, canceledSize=0, price=159.0, type=LIMIT, tif=DAY]\n\t  executeSide=TAKER\n\t  executeSize=1500\n\t  executePrice=158.54\n\t  executeId=8\n\t  executeMatchId=4\n\t\n\t-----\u003e onOrderRested called:\n\t  orderBook=AAPL\n\t  time=1700598048056000000\n\t  order=Order [id=11, clientId=1001, clientOrderId=11, side=BUY, security=AAPL, originalSize=3900, openSize=1900, \n\t\t\t\t\texecutedSize=2000, canceledSize=0, price=159.0, type=LIMIT, tif=DAY]\n\t  restSize=1900\n\t  restPrice=159.0\n*/\n\norderBook.showOrders();\n\n/*\n   100 @    148.14 (id=4)\n   500 @    149.44 (id=2)\n   100 @    149.44 (id=3)\n  1900 @    159.00 (id=11)    \u003c==== You order sat here after hitting some asks...\n--------      1.00\n  3000 @    160.00 (id=10)\t \n*/\n    \n ```\n \n\n \n \n\n\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoralblocks%2Fcoralme","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcoralblocks%2Fcoralme","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoralblocks%2Fcoralme/lists"}