This repository documents our submission for the Optiver Ready Trader Go competition. This competition involves creating a algorithmic trading strategy to trade a Future and ETF, both of which are highly correlated.
The Future was highly liquid, while the ETF was highly illiquid.
We were also provided with some basic template files (refer to the /ready_trader_go folder) and some market data for backtesting (refer to the /data folder) to interface with the trading system, and we had to follow these competition rules.
We tried out a variety of different strategies, which can be split into 2 categories: arbitrage through pairs trading, and market making around the midprice.
We first started by experimenting with the arbitrage strategies, where we performed pairs trading on the ETF and Future by buying the underpriced instrument and selling the overpriced instrument. This was implemented in the following strategies:
- Arbitrage strategy between the ETF and Future. Refer to arbitrage.py
- Arbitrage strategy that took into account the momentum of the prices (e.g. if both the ETF and Future prices are going up, buy more of the underpriced instrument, and sell a smaller quantity of the overpriced instrument). Refer to momentumArbitrage.py
While the above models were effective by themselves, they performed poorly when put alongside other traders, due to the diminishing amount of arbitrage opportunities for each trader.
As such, we decided to switch to a market-neutral market-making approach instead, whereby we seeked to profit from trading the bid-ask spread. This was implemented in the following strategies:
- Mid-price trader. Refer to midtrader.py
- Mid-price trader with adjustment for current inventory levels. Theoretically this should be more profitable than the midtrader above, but it was not the case for us. Refer to midtraderInvAdj.py
- [Final model that was submitted] Avellaneda-Stoikov Market Making Model. This model allowed us to adjust for inventory and volatility in a much more profitable way. Refer to ASModel.py
From extensive testing, we concluded that the Avellaneda-Stoikov Market Making Model was the most reliable model across different market conditions.
This model works by finding an optimal reservation price (i.e. fair price we wish to trade our instrument), and optimal bid-ask spread (i.e. how wide of a spread we wish to market make).
You'll need Python version 3.11 or above and PySide6 for the GUI. To install PySide6, you can run:
pip3 install PySide6
Afterwards, you can run the different autotrader algorithms against each other by running:
python3 rtg.py run [AUTOTRADER FILENAME [AUTOTRADER FILENAME]]
For example, this is how to run the Avellaneda-Stoikov model alone:
python3 rtg.py run ASModel.py
And this is how to run all the models to see how they compare:
python3 rtg.py run ASModel.py arbitrage.py momentumArbitrage.py midtrader.py midtraderInvAdj.py
To backtest against different market data, update the "MarketDataFile" attribute in the exchange.json file. To increase the speed of backtesting, adjust the "Speed" attribute.
- Avellaneda M. & Stoikov S. (2006). High Frequency Trading in a Limit Order Book
- Hummingbot Foundation. (2021). A comprehensive guide to Avellaneda & Stoikov’s market-making strategy
- Beckham Wee
- Riley Ang
- Regan Tan