Skip to content

Latest commit

 

History

History
140 lines (104 loc) · 20.2 KB

0068-MATC-matching_engine.md

File metadata and controls

140 lines (104 loc) · 20.2 KB

Matching engine

Acceptance Criteria

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:

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:

  • 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)

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)
  • 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:

When a market moves into an auction:

When a market market exits an auction:

Summary

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.

Guide-level explanation

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.

Continuous Mode

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.

Order books construction

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

Matching Process

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:

  1. 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.
  2. 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:
    1. Call the current price level current price
    2. Check the price level which has the next resting on-book order, set this to be the outer price for the check.
    3. 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's ask, or vice versa). Retain those where this price < outer price
    4. Within these, select either the minimum upper price (if the incoming order is a buy) or the maximum lower price (if the incoming order is a sell), call this amm 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) between amm bound price and outer price. From this form an interval current price, outer price.
    5. Now, for each AMM within this range, calculate the volume of trading required to move each from the current price to the outer price. Call the sum of this volume total volume.
    6. If remaining volume <= total volume split trades between the AMMs according to their proportional contribution to total 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.
    7. If remaining volume > total volume execute all trades to move the respective AMMs to their boundary at outer price. Now, return to step 1 with current 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.
    8. 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.

See also