Every 19 minutes –for 25– hours a password for an updated time series (given as an encrypted pandas dataframe) of multiple stratiegies applied to a given unnamed future is provided. Every release of new data provdes more time in the time series and a new strategy. The goal was to make a submission every 19 minutes to find the best portfolio (how much of the portfolio should be held as a long or short position in each strategy). The consraints were such that no position could be more than 10% of portfolio.
The project started with using the recursive_mean.py
strategy which was intentionally simple so that we could start making forecasts early. The hypothesis was that dividing the time series into sections (five initially, changed to six as time series got longer over time) then taking the mean of each section would allow us to check the overall consistency of a strategy (by seeing a cont. increase or decrease in the sectioned means). Assuming it is continuosly downwards, then the position held is short; if it's continuosly increasing, the positon held is long; otherwise, the strategy is deemed to volatile given the simplicity of the strategy and so no position is held. There is no weighting, so each position is an equal amount of the portfolio and the mean is taken with lower resolution if there aren't at least 10 positions (to meet the constraint of no position having more than 10% portfolio). The focus was to have a simple strategy so that we would in essence have a low time-to-market while working on a better one.
The strategy implemented in sharpe_ratio.py
utilises the Sharpe ratio to maximise and minimise risk (some strategies had insane volatitily, so we deemed minimising risk very important). We start by calculating the expected return and volatility using the standard deviation based on weight of positions, average returns, and covariance matrix. The goal is to maximise the return per unit of risk calculated with the Sharpe ratio. The optimisation algorithm has certain constraints, however, those being: the weights (protfolio positions) must sum to 1 (100% of portfolio); and the risk must be minimised (as a slight priority to maximising returns). The goal with this strategy was to take smart risks and find more opportunities than the previous simple strategy.
Here is the link to the data (extract in project). Only the password for the final dataframe is in the repository but that is a superset of all the other data anyway. Then run python recursive_mean.py > answer.txt
to see the portfolio in answer.txt
as per the simple strategy (sharpe_ratio.py
submissions were done more manually to make sure the data was cleaned properly).
The password to the encrypted data was provied to everyone over a public Slack channel and submissions had to be a pretty printed dictionary submitted via a google form which became a pain to do manually every 19 minutes with all the other work to do. We also needed a little bit of a break at some point and couldn't have one if we needed to submit every 19 minutes so we used the Slack API to create a bot that would read the public channel for messages from the user who sent the password. Some people did try to impersonate the bot so it became necessary to check for the specific member ID. It was also necessary to check the contents of the message as not all messages from the user/bot were the bot update, rather, the user responding to a message. The message is then parsed for the encrypted file name and password and saved to out.txt
which is then read by the implemented strategy to create the submission dictionary in answer.txt
. A local server is running so that a seperate script running with TamperMonkey can read the answer.txt
file and use it to fill out the google form every 19 minutes. Those scripts ran in my browser with an extension but the files are also in this project.
In the end we ended up being finalists (top 9) out of some ~100 teams with a sharpe ratio of 1.24.