Inspiration

In this market, we make one key assumption: there is an ‘invisible force’ that constantly causes the mean expected value of both instruments to converge in the long run. As such, there are multiple teams with multiple trading strategies that attempt to exploit this, by capitalising on situations where arbitrage is found.

Taking the arbitrage-capitalising strategy as a K0 strategy in the Level-k framework, we adopt a different approach: we attempt to develop a K1 strategy by taking advantage of the fact that teams are trying to capitalise on arbitrage situations. Since the convergence to the same mean value is catalysed by these arbitrage trading strategies, a mean reversal strategy will be most appropriate in this situation.

What it does

The algorithm first calculates an overall long-term moving average and a short-term moving average of the two instruments combined, due to the assumption that the two instruments are closely correlated as any arbitrage between them will be corrected by other teams using an arbitrage strategy.

The purpose of the long-term moving average is to get an estimate of the value of the instrument that is unaffected by short-term price fluctuations, while the short-term moving average captures the short term fluctuation of the instrument.

We then take an average of the long-term and short-term moving averages to get the predicted actual value of the two instruments.

Should the expected value of any instrument deviate significantly from our calculated value, we will enter the market to either buy the discounted instrument, or sell the over-priced instrument.

How we built it

We want a codebase that is lean, efficient, and easy-to-comprehend. We adopted a functional approach in designing the code.

In the main section of the code, we ran a while loop that executes our algorithm every 250ms (a maximum of 240 orders a minute). Within the algorithm, we knew that we needed two key functions: one function that extracts and ‘prettifies’ the data, and another that processes the data and makes orders according to our strategy. Within each key function exists multiple smaller functions that fulfill the single responsibility principle. This makes the code easy to debug and maintain in the future.

We achieved much success, given that our strategy - the second key function - only spans 60 lies of code. This is a testament to the simplicity of our codebase, which is what we have set out to do from the very beginning of the challenge.

Challenges we ran into

Our initial approach was to make use of the arbitrage condition to adjust our position and make profits. We used the expected value of each instrument to determine whether or not arbitrage exists, and adjusted our orders accordingly. This is defined as a K0 strategy, one that is agnostic to other players in the market. This proved ineffective as other teams were employing the same strategy and we had to compete for bids and asks once the arbitrage condition is met. This combined with our algorithmic inefficiencies led to our team making sustained losses. Despite tweaking around with the various parameters, we did not get good performance.

This inspired us to change our strategy towards mean-reversion, a K1 strategy that attempts to exploit others’ arbitrage-capitalising strategies. We found greater success with this and eventually stuck with it, whilst tweaking parameters to get the best performance.

Accomplishments that we're proud of

Having no prior experience in stock trading, we are glad that we managed to write an algorithm that was able to make a stable and positive PnL in the market. The first version of our code performed terribly and we suffered a large negative PnL in the process. However, after doing extensive research into trading strategies and theories, coupled with our experience gained from our initial failures, we have managed to revamp our code and significantly improve the outcome.

What we learned

Through this challenge, we learnt more about how trading works and the various terminologies involved. In addition, we realised that trading algorithmically was much more complex than simply just buying at a lower price and selling at a higher price. Although trading strategies can theoretically work, when placed in the actual market they might not perform ideally due to competition from other teams’ algorithms. Therefore our strategy must preempt future market conditions in order to stand a chance against other competing algorithms.

What's next for Optiver Challenge

Currently, the market only involves two instruments and a negative position is permitted, as a simplification of the real world problem. Moving on, we could expand the market to include more instruments, which would greatly increase the algorithmic complexity.

Built With

Share this project:

Updates