Smart Order Routing with Atreyu
Securities can usually be traded through several different exchanges. Since each exchange operates independently, the price of the security can be different across the exchanges. Smart Order Routing is a process of sending your orders to specific exchanges in an effort to achieve the best order fills while taking into consideration price, liquidity, costs, speed, and the likelihood of execution.
With the new Atreyu Brokerage integration on QuantConnect, it’s now possible to send your orders to specific exchanges. So in today’s tutorial, we first review the process of capturing fragmented liquidity. Then, we write an algorithm to send our orders to the exchange with the best price.
Capturing Fragmented Liquidity
When a security trades on an exchange, traders can place limit orders to buy and sell the security. The limit orders are held on the exchange’s order book until they are filled or canceled. Let’s say we have the following sell limit orders for a security at two exchanges:
|Price||Number of shares for sale|
|Exchange A||Exchange B|
If we were to purchase 10 shares, we would receive the best price by sending the buy order to Exchange A because the buy order would be filled at a price of $100/share. In contrast, if we were to send the order to Exchange B, the buy order would be filled at a price of $101/share.
If we were to purchase 20 shares instead, we would receive the best price by purchasing 10 shares from Exchange A and 10 shares from Exchange B. The resulting average fill price would be
where Qi is the quantity of shares purchased on Exchange i and Pi is the cost of purchasing Qi shares on Exchange i.
Furthermore, if we were to purchase 50 shares, we would receive the best price by purchasing 20 shares from Exchange A and 30 shares from Exchange B. In this case, the resulting average fill price would be
In general, the average cost of purchasing shares at multiple price levels is
where p is a vector of price levels and q is a vector containing the number of shares at each price level.
Some sophisticated traders even extend the concept of Smart Order Routing to include exchanges listed in foreign countries. For instance, Alibaba Group Holdings trades in the Hong Kong market and an American depositary receipt (ADR) of it trades in the US market. In some cases, it can be cheaper to buy shares on the Hong Kong market with Hong Kong Dollars instead of buying shares in the US market with US Dollars.
National Best Bid and Offer
The National Best Bid and Offer (NBBO) is the price of the highest bid and lowest ask across all of the US exchanges. In the example limit order book above, if Exchange A and Exchange B were the only two exchanges in the market, the $10 ask from Exchange A would be the ask component of the NBBO.
As ticks are passed into our algorithms that we backtest on the QuantConnect platform, the ticks are grouped into a Slice object that spans one millisecond. The Slice object contains all of the trades that occurred and all of the quotes that were flagged as the NBBO during that millisecond. For instance, let’s say we have a Slice object that contains the following quotes:
|Exchange||Ask Size||Ask Price||Bid Size||Bid Price|
The quotes are ordered chronologically in the Slice object. From the quotes above, we can see that the ARCA bid price is lower than the bid price of the first NASDAQ quote. This implies that the first NASDAQ quote was filled or canceled before the ARCA quote arrived.
The QuantConnect platform does not currently support level-2 data. That is, we only have access to the NBBOs that occurred during each Slice of ticks, not the full limit order book of each exchange. Therefore in this tutorial, we implement Smart Order Routing using only the NBBO in the current Slice.
To implement our Smart Order Router algorithm, we first set the brokerage model to be the Atreyu brokerage model and subscribed to tick data for a volatile security.
SetBrokerageModel(BrokerageName.Atreyu); AddEquity("TSLA", Resolution.Tick);
To ensure our backtest places many orders, we instructed the algorithm to trade every minute. During the first minute, it worked towards acquiring a target holding of 500 shares. Each minute that followed, the sign of the target holding was flipped. To determine which exchange we’d like to send the order, we first collected all of the NBBO quotes from each exchange. When it was time to purchase, we reduced the set of quotes to just the sell quotes on the exchanges and selected the most recent one.
return ticks .Where(IsQuote) .Where(tick => tick.AskPrice != 0) .LastOrDefault();
When placing each buy order, we routed the order to the exchange with the NBBO quote and made sure not to exceed the size of the quote.
_orderProperties.Exchange = _exchangeMapper.GetExchangeFromName(quote.Exchange); var quantity = Math.Min(_targetHoldings - currentHoldings, quote.AskSize); MarketOrder(_symbol, quantity, orderProperties: _orderProperties);
The process for submitting sell orders is similar, except we select the most recent NBBO bid quote and submit a market order with a negative quantity.
The default fill model processes trades at the NBBO, however, to make this explicit we created a custom fill model. The fill model set the fill price of the order to the price of the most competitive quote on the exchange where the order was routed.
fill.FillPrice = quote.AskPrice;
This is essentially an estimate because there can be thousands of quotes per second for active securities, and no way to know for sure if this would be the final fill price in live trading.
We backtested the Smart Order Routing algorithm over January 2021 and compared the order fill prices with the NBBO prices when the orders were submitted. The algorithm placed 57,842 orders and they were all filled at the NBBO prices recorded in the current Slice. To reproduce our results, backtest the Smart Order Routing algorithm and then compare the fill price of each order against the NBBO price in the order tag.