The matching engine co-ordinates the trading of incoming orders with existing orders already on an order book.
In a market that is in Continuous Trading
An Immediate or Cancel (IOC) order:
-
Incoming MARKET orders will be matched against the opposite side of the book (0068-MATC-001). For product spot: (0068-MATC-061)
- If not enough volume is available to fully fill the order, the remaining will be cancelled (0068-MATC-002). For product spot: (0068-MATC-062)
-
Incoming LIMIT orders will be matched against the opposite side of the book, (0068-MATC-003). For product spot: (0068-MATC-063)
- If there is no match the order will be cancelled. (0068-MATC-004). For product spot: (0068-MATC-064)
- If there is a partial match then the remaining will be cancelled. (0068-MATC-005). For product spot: (0068-MATC-065)
-
Incoming PEGGED orders will be rejected by the wallet as they are not valid. (0068-MATC-006)
-
Incoming LIMIT: POST-ONLY TRUE orders will be rejected by the wallet as they are not valid. (0068-MATC-057). For product spot: (0068-MATC-066)
-
For Reduce-Only = True orders:
- Incoming MARKET orders which reduce the trader's absolute position will be matched against the opposite side of the book (0068-MATC-056)
- If not enough volume is available to fully fill the order, the remaining will be cancelled (0068-MATC-043)
- Incoming MARKET orders which increase the trader's absolute position will be stopped (0068-MATC-044)
- Incoming LIMIT orders which reduce the trader's absolute position will be matched against the opposite side of the book (0068-MATC-045)
- Incoming LIMIT orders which increase the trader's absolute position will be stopped (0068-MATC-046)
- Incoming PEGGED orders will be rejected by the wallet as they are not valid. (0068-MATC-058)
- Incoming LIMIT: POST-ONLY TRUE orders will be rejected by the wallet as they are not valid. (0068-MATC-059)
- Incoming MARKET orders which reduce the trader's absolute position will be matched against the opposite side of the book (0068-MATC-056)
A Fill or KILL (FOK) order:
-
Incoming MARKET MARKET orders will be matched fully if the volume is available, otherwise the order is cancelled. (0068-MATC-008). For product spot: (0068-MATC-067)
-
Incoming LIMIT orders will either be:
- Fully matched if possible to the other side of the book (0068-MATC-009). For product spot: (0068-MATC-068)
- if a complete fill is not possible the order is stopped without trading at all. (0068-MATC-010). For product spot: (0068-MATC-069)
-
Incoming PEGGED orders will be rejected by the wallet as they are not valid. (0068-MATC-011)
-
Incoming LIMIT: POST-ONLY TRUE orders will be rejected by the wallet as they are not valid. (0068-MATC-039). For product spot: (0068-MATC-070)
-
For Reduce-Only = TRUE orders:
- Incoming MARKET orders which reduce the trader's absolute position will be matched against the opposite side of the book (0068-MATC-047)
- If not enough volume is available to fully fill the order, the order will be cancelled(0068-MATC-048)
- Incoming MARKET orders which increase the trader's absolute position will be stopped (0068-MATC-049)
- Incoming LIMIT orders which reduce the trader's absolute position will be matched against the opposite side of the book (0068-MATC-050)
- Incoming LIMIT orders which increase the trader's absolute position will be stopped (0068-MATC-051)
- Incoming PEGGED orders will be rejected by the wallet as they are not valid. (0068-MATC-052)
- Incoming LIMIT: POST-ONLY TRUE orders will be rejected by the wallet as they are not valid. (0068-MATC-053)
- Incoming MARKET orders which reduce the trader's absolute position will be matched against the opposite side of the book (0068-MATC-047)
For Good 'Til Time (GTT) / Good 'Till Cancelled (GTC) / Good For Normal (GFN) orders:
- Incoming MARKET orders are rejected by the wallet validation layer. (0068-MATC-013). For product spot: (0068-MATC-071)
- Incoming LIMIT orders match if possible, any remaining is placed on the book. (0068-MATC-014). For product spot: (0068-MATC-072)
- Incoming PEGGED orders are repriced and placed on the book if the price is valid, except GFN which are rejected by the wallet validation layer. (0068-MATC-015)
- otherwise they are parked. (0068-MATC-016)
- Incoming LIMIT: POST-ONLY TRUE orders will be placed fully on the book if no orders currently cross. (0068-MATC-040). For product spot: (0068-MATC-073)
- An order which totally crosses with an existing order on the book will be STOPPED in full with none executed. (0068-MATC-041). For product spot: (0068-MATC-074)
- An order partially crossing with an existing order on the book will be STOPPED in full with none executed. (0068-MATC-042). For product spot: (0068-MATC-075)
- A market will enter auction if the volume on either side of the book is empty. (0068-MATC-017)
- A market will enter auction if the mark price moves by a larger amount than the price monitoring settings allow. (0068-MATC-018). For product spot: (0068-MATC-076)
- All attempts to self trade are prevented and the aggressive side is STOPPED if completely unfilled or PARTIALLY_FILLED if some matching occurred before the self trade. The passive side is left untouched. (0068-MATC-019). For product spot: (0068-MATC-077)
- All orders with Reduce-Only set to TRUE are rejected as invalid. (0068-MATC-054)
In a market that is currently in Auction Trading:
- IOC/FOK/GFN
- Incoming orders have their status set to REJECTED and are not processed further. (0068-MATC-021). For product spot: (0068-MATC-078)
- GTC/GTT/GFA
- All MARKET orders are rejected. (0068-MATC-022). For product spot: (0068-MATC-079)
- LIMIT orders are placed into the book and no matching takes place. (0068-MATC-023). For product spot: (0068-MATC-080)
- LIMIT: POST-ONLY TRUE orders are placed into the book and no matching takes place. (0068-MATC-055). For product spot: (0068-MATC-081)
- The indicative price and volume values are updated after every change to the order book. (0068-MATC-024). For product spot: (0068-MATC-082)
- PEGGED orders are parked (and have their status set to PARKED). (0068-MATC-025)
- It is possible to self trade to uncross an auction. (0068-MATC-038). For product spot: (0068-MATC-083)
When a market moves into an auction:
- All PEGGED orders are parked (and have their status set to PARKED). (0068-MATC-026)
- All GFN orders are cancelled. (0068-MATC-027). For product spot: (0068-MATC-084)
- All GTC/GTT orders remain on the book untouched. (0068-MATC-028). For product spot: (0068-MATC-085)
When a market market exits an auction:
-
The book is uncrossed. (0068-MATC-029). For product spot: (0068-MATC-086)
- Self trading is allowed during uncrossing. (0068-MATC-030). For product spot: (0068-MATC-087)
-
All GFA orders are cancelled. (0068-MATC-031). For product spot: (0068-MATC-088)
-
PEGGED orders are repriced where possible. (0068-MATC-032)
-
Any persistent order that is currently ACTIVE or PARKED can be cancelled. (0068-MATC-033). For product spot: (0068-MATC-060)
-
The price of any persistent order can be updated (0068-MATC-034). For product spot: (0068-MATC-089)
-
The size of any persistent order can be updated (0068-MATC-035). For product spot: (0068-MATC-090)
-
The TIF of any persistent order can be updated to and from GTC and GTT only. Expiry time is required if amending to GTT and must not be given if amending to GTC. (0068-MATC-036). For product spot: (0068-MATC-092)
-
An update to an order that is not ACTIVE or PARKED (Stopped, Cancelled, Expired, Filled) will be rejected (0068-MATC-037). For product spot: (0068-MATC-091)
The matching engine is responsible for updating and maintaining the state of the order book. The order book contains two lists of orders in price and time order, one for the buy side and one for the sell side. As new orders come into the matching engine, they are analysed to see if they will match against current orders to create trades or will be placed in the order book if they are persistent order types. If the matching engine is running in continuous trading mode, the matching will take place as the orders arrive. If it is running in auction mode, all the orders are placed on the order book and are only matched when we attempt to leave the auction. Indicative price and volume details are generated during an auction after each new order is added.
The matching engine consists of an order book and the logic to handle new orders arriving into the engine. The matching engine can be in one of two possible states, continuous trading or auction trading. In continuous trading the incoming orders are processed immediately. In auction mode incoming orders are placed on the order book and are not processed for matching until we attempt to uncross.
New orders arrive at the engine and are checked for validity including if they are of the right type (not GFA). If the order can be matched to an order already on the book, that matching will take place. If the order does not match against an existing order and the order type is persistent, we place the order into the correct side of the order book at the price level given by the order. If there are already orders in the book at the same price level, the new order will be added after all existing orders at that price to keep the time ordering correct. If a cancel order is received, we remove the existing order from the order book. If an amend order is received we remove the existing order and re-insert the amended version.
Auction Mode
New orders arrive at the engine and no matching is performed. Instead the order is checked for validity (GFA) and then placed directly onto the order book in price and time priority. When the auction is uncrossed, orders which are in the crossed range are matched until there are no further orders crossed.
An order book is made up of two halves, the buy and the sell side. Each side contains all the persistent orders which have not yet been fully matched. They are sorted in price and then time first order. This ensures that when we are looking for matches we can search through the opposite side of the book and know that the closest match will be top of the list and if there are multiple orders at that price level they will be ordered in the time that they arrived.
Given an order book that looks like this in the market display:
Ask Quantity | Price | Bid Quantity |
---|---|---|
10 | 120 | |
20 | 110 | |
5 | 100 | |
90 | 10 | |
80 | 15 |
For all incoming active orders, the matching process will coordinate between the on- and off-book sources of liquidity. When an order comes in which may immediately trade (there are not already resting orders of the same type for the best applicable price) the following steps should be followed. If at any point the order's full volume has traded the process is immediately halted:
- For the first applicable price level (the first valid price with no orders on the same side, implying an order could theoretically immediately trade there, one tick above best bid for an incoming buy and one tick below best ask for an incoming sell), all on-book orders should be checked. Any volume at this price level which can be met through on-book orders will then trade.
- For any
remaining volume
, the AMMs will be checked. This requires an algorithm to ensure the protocol does not have to check every price level individually:- Call the current price level
current price
- Check the price level which has the next resting on-book order, set this to be the
outer price
for the check. - Check all active AMMs, querying their quote price API with the smallest trade unit on the market in the direction of trading (if the incoming order is a
buy
, query the AMM'sask
, or vice versa). Retain those where this price <outer price
- Within these, select either the minimum
upper price
(if the incoming order is a buy) or the maximumlower price
(if the incoming order is a sell), call thisamm bound price
. This is the range where all of these AMMs are active. Finally, select either the minimum (for a buy) or maximum (for a sell) betweenamm bound price
andouter price
. From this form an intervalcurrent price, outer price
. - Now, for each AMM within this range, calculate the volume of trading required to move each from the
current price
to theouter price
. Call the sum of this volumetotal volume
. - If
remaining volume <= total volume
split trades between the AMMs according to their proportional contribution tototal volume
(e.g. larger liquidity receives a higher proportion of the trade). This ensures their mid prices will move equally. Each of these trades should count as a single aggressive trade with the given AMM and pay fees accordingly. - If
remaining volume > total volume
execute all trades to move the respective AMMs to their boundary atouter price
. Now, return to step1
withcurrent price = outer price
, checking first for on-book liquidity at the new level then following this process again until all order volume is traded or liquidity exhausted. - For all trades generated in the previous two steps, an execution price should be calculated using the AMM's API to return a price for a given volume. These prices should be rounded to the nearest valid market tick in the AMM's favour (i.e. round upwards when the AMM is selling and downwards when the AMM is buying). This process can be optimised as when splitting trades between AMMs according to their respective commitment sizes they will each end up at the same executed price, so only one AMM's price need be calculated.
- Call the current price level