James Bachini

Order Execution Strategy Tests 📋

Order Execution

In this article I’m going to test different methods to find the best order execution strategy for buying and selling cryptocurrency. I’m going to define a test to enter and exit a delta neutral position, write trading bot code for each strategy in NodeJS and execute each on an isolated exchange sub-account to see which order execution strategy is the most effective. Effectively I’m trying to find out the most cost effective method to trade cryptocurrency and futures positions on exchanges such as Binance & FTX.

  1. Order Execution Strategy [Video]
  2. Exchange Order Book Explained
  3. Limit Orders vs Market Orders
  4. Delta Neutral Cash & Carry Trade
  5. The Order Execution Test
  6. Order Execution Strategies
  7. Execution Strategy Code
  8. Results & Conclusion

Order Execution Strategy [Video]

James On YouTube

Exchange Order Book Explained

Cryptocurrency exchanges are built around an order book and a matching engine. The order book is a list of prices and volumes at which buyers and sellers are willing to buy or sell an asset. A buyer will set a bid for a specific amount (volume) at a certain price at which they are willing to buy. A seller will set an ask for a specific amount at a price at which they are willing to sell.

Below we have the Binance order book for BTC/USDT with bids below in green and asks above in red. The gap between the leading bid and the leading ask price is called the spread.

Binance Order Book
Binance Order Book for BTC/USDT

Limit Orders vs Market Orders

A user can place different order types in to the order book. The two we will focus on in this article are limit orders and market orders.

James On YouTube

A limit order places a bid below or an ask above the current market price. This is not executed instantly unless someone is willing to take the other side of the trade. For example if a trader wants to buy Bitcoin in the order book above they might put a limit order in at $40159 for 1 BTC. This places the order in the order book in a competitive position but wont execute unless the price moves down from the current price of $40162.

A market order in contrast to this executes immediately at the current market price. So if the same trader used a market order for 1 BTC it would first take the liquidity from the $40170 level then continue up the order book to $40177 where there is enough volume to fill the order. The average price for the order would work out around $40176 a full $14 above the current market price.

This shows the cost of instant execution which is increased in line with the volume of an order. It’s worth stating here that this is the problem that automated market makers like Uniswap v3 are trying to solve. However there are times when market orders serve their purpose, such as:-

  • Time sensitive trades like the Twitter trading bot that needs to execute as soon as Elon Musk tweets about Doge
  • Small orders where liquidity isn’t an issue and the cost savings don’t justify the execution time.
  • When liquidity is drying up, prior to a level collapsing ideally you want to take the last remaining bid volume to aggressively short.

When time isn’t critical limit orders can provide cost savings in both slippage and fees as exchanges often have lower fees or even rebates for market maker orders where you are adding a limit order to the order book and providing liquidity.

90% of the time I tend to use batched limit orders because I’m either rebalancing which isn’t time critical or running market maker type strategies which wouldn’t be profitable with market orders.


Delta Neutral Cash & Carry Trade

If/when the markets get a bit frothy again I want to place a trade to buy a spot position and sell a futures position. I want to lock in a yield for as long as possible so I’m going to be looking at BTC and ETH futures contracts on Binance, FTX and Huobi. FTX currently has a December 2021 future contract which I’ll be using for this test.

The general idea is to buy 1 x spot Bitcoin and short sell 1 x BTC-1231 futures contract and hold it until expiry to collect the premium. If Bitcoin goes up or down it doesn’t matter because one position will hedge the other.

I’m going to be using the asset from the spot position as collateral for the futures position and also lend out a managed (via script) proportion of that asset using the spot lending program.

I want to execute quite a large trade as optimally as possible with no time constraints so I will batch my order down to small amounts and build the position up slowly.

In the tests below I’m going try to find out the most cost effective order execution strategy to build up this position.


The Order Execution Test

I’m going to be testing five different strategies using a isolated FTX sub-account for each test. Each sub-account will be filled with a $1000 USD balance at the start.

A trading bot will then execute 20ish buy orders for $20 each on the BTC/USD spot market and 20 sell orders on the BTC-1231 futures market. The script will wait for each batch to complete across all the strategies before starting the next order. I’ve also added a time delay between batches so that it executes across multiple market conditions.

I’ll try and run the test during a period of low volatility so price movement and execution time of the strategies doesn’t make a large difference.

Once all strategies are complete and a target of $800 in volume has been achieved I’ll reverse the trading bot to sell spot and buy futures to close the position.

I’ll repeat this process three times to level out any anomalies and compare the final balances in the sub-accounts at the end to calculate the cost of order execution.

Criticisms of this test:

  • It’s a limited data set on one exchange for one trading period which may not reflect the same market conditions that I would actually be carrying out this trade (a blow off top hopefully).
  • I get maker rebates from FTX because I stake their FTT token. This will likely bias the results towards limit orders compared to running the same test on a new account.
  • The liquidity on the BTC-1231 futures market is quite low compared to the perpetual futures and spot markets which could make a difference to execution time and the effectiveness of different strategies.
  • All the tests are executing in parallel on the same markets and they could potentially interfere with each other. BTC/USD is very liquid and on $20 batch sizes I don’t think it will have too much of an effect however.

Order Execution Strategies

In an ideal world I would be able to get limit order through simultaneously on both markets. I need the positions to balance so I don’t want market price to move between the spot and the futures order and there’s a benefit to faster execution.

S1 – Market Order Base Line

This will provide a base line to compare further strategies. I’ll be asynchronously firing a market order on each market simultaneously every 30 seconds.

There’s a chance that this strategy could do well simply because we aren’t waiting for the market to move against us to execute the trade.

https://github.com/jamesbachini/Order-Execution-Tests/blob/main/strategies/s1.js

S2 – Limit Order Future, Market Order Spot

This strategy will execute a place only limit order at the current bid/ask price on the least liquid market, in this case that will be the futures market. When that limit order is confirmed as having gone through the bot will place a market market order on the spot market.

https://github.com/jamesbachini/Order-Execution-Tests/blob/main/strategies/s2.js

S3 – Balanced Limit Orders

This strategy will place limit orders on both markets matching and following the leading bid/ask price. Once one order is completed the strategy will wait for the other order is executed before placing new orders on both markets for the next batch. At any one time there may have exposure to one batch size of market volatility. This is likely to be negative because the market has moved against us executing the first order while our second order is moving up/down to chase the price change.

https://github.com/jamesbachini/Order-Execution-Tests/blob/main/strategies/s3.js

S4 – Market Maker Orders

Same strategy as above but I’ll define a spread away from the leading bid/ask prices of 0.05% ($20 with Bitcoin trading at $40k) to effectively straddle the current pricing in a similar fashion to a market maker strategy. This may or may not increase the exposure risk as orders are likely only going to get executed on larger moves. This will likely increase order completion time but there’s little negatives to providing more liquidity here so it would likely scale well.

This is a simplified example of a market maker strategy. In practice market makers would calculate a fair value, often based on EMA’s and move their prices accordingly.

In initial testing I found that the spot market executed much faster than the futures due to the greater liquidity and trading volume so I moved the margin to 0.06% for spot and 0.02% for futures. In production it might be an idea to have these as flexible amounts where the margin starts high reduces over time until the order is filled.

https://github.com/jamesbachini/Order-Execution-Tests/blob/main/strategies/s4.js

S5 – Cross Market Moving Average

This strategy will use a 5 minute simple moving average (SMA) of the spread between the markets. I ideally want the futures price to be higher and the spot to be lower so when this premium increases past the mean I’ll execute the balanced limit order strategy and when it decreases below the 5 minute average I’ll pause.

This strategy may end up only executing when markets go up and staying idle for long periods of time when markets are going down. I could factor in some kind of adjustment factor to offset this and calculate a fair spread but that might be overcomplicating things and something I can look to optimise at a later date.

The risk is that in production market movements could be quite different from what they are today and sitting idle waiting for execution might not be optimal. Pricing wise this uses current bid/ask prices with a placeOnly limit order the same as S3.

https://github.com/jamesbachini/Order-Execution-Tests/blob/main/strategies/s5.js


Execution Strategy Code

For the code I’ll be opening up a web socket to the FTX exchange to get a feed of live order book price updates. In previous tests I found this was more effective than the REST API. From there I’ll be doing event based updates checking for price changes and cancelling and reordering where necessary.

In this test code there is no method of checking for volumes on market orders. For $20 batch sizes on BTC markets I feel this isn’t required but if it was scaled up or an order needed to be pushed through asap then that would need to be added and is available via web socket data feed.

A single websocket feed is used for both markets and to share data between strategies and navigate FTX API limits.

None of this code is production ready and should only be used for testing.

Full Open Source Code: https://github.com/jamesbachini/Order-Execution-Tests/

I’m using a simple promise loop to place the orders asynchronously and then wait for all to complete before moving on to the next batch. One fault in the testing framework is that strategy 5 (cross market moving average) may hold up other strategies as well which may dilute the effectiveness of waiting for the moving average in the results as all strategies will be affected.

  for (let batch = 1; batch <= 20; batch++) {
    const promise1 = s1.execute();
    const promise2 = s2.execute();
    await Promise.all([promise1, promise2]);
  }

I’m using the REST API for placing and cancelling orders. I’ve always done this over websockets because I have found previously that the REST API’s work better when exchanges are struggling with volume which normally coincides with peak volatility and needing to get orders through.


Results & Conclusion

After the first test run opening the position the balances stood above their starting point due to the decrease in futures premium while executing and holding. S3 & S5 were slightly ahead in terms of account value.

S1 – Account Value: $1000.76
S2 – Account Value: $1001.67
S3 – Account Value: $1002.10
S4 – Account Value: $1001.81
S5 – Account Value: $1002.17

I then closed the position and reopened it again twice for a total of three runs and approximately $50,000 USD trading volume.

The final results are:-

S1 – Market Orders
Account Value: $993.23 – Average Batch Time: 3.3 secs

S2 – Limit Future, Market Spot
Account Value: $997.65 – Average Batch Time: 25.6 secs

S3 – Balanced Limit Orders
Account Value: $999.24 – Average Batch Time: 26.5 secs

S4 – Market Maker
Account Value: $998.80 – Average Batch Time: 169.9 secs

S5 – Cross Chain Moving Average
Account Value: $1000.30 – Average Batch Time: 47.3 secs

S5 – Cross Market Moving Average is the clear winner with a positive balance after three rotations in and out of the position.

S1 – Market Orders performed the worse and it shows the clear price that is paid for instant execution of orders.

I did get Elon’d at one point during the second test and there was a big spike in both volume and price which later dropped back. This may have affected the results but this kind of volatility is par for the course in crypto markets and the results didn’t differ too much from the other tests.

Further Development – There’s more opportunity here to build this out across multiple markets and exchanges looking for the best value position at any one time and providing liquidity at fair price. It would be possible to connect data feeds from all the exchanges and use moving averages and simple algorithms to work out where current value is on spot and futures markets.

Going forwards I’ll monitor and chart the low time frame price movements between futures and spot markets on at least Binance & FTX to try and fine tune the cross market moving average strategy and make it as efficient as possible.


I hope that these tests have provided some insights in to how tests can be developed to improve order execution strategies.


Get The Blockchain Sector Newsletter, binge the YouTube channel and connect with me on Twitter

The Blockchain Sector newsletter goes out a few times a month when there is breaking news or interesting developments to discuss. All the content I produce is free, if you’d like to help please share this content on social media.

Thank you.

James Bachini

Disclaimer: Not a financial advisor, not financial advice. The content I create is to document my journey and for educational and entertainment purposes only. It is not under any circumstances investment advice. I am not an investment or trading professional and am learning myself while still making plenty of mistakes along the way. Any code published is experimental and not production ready to be used for financial transactions. Do your own research and do not play with funds you do not want to lose.