Using Brexit polls to build an algorithm to trade GBP/USD

Last 23rd of June a referendum took place in the United Kingdom, in which the voters decided to leave the European Union. After the results were published, the GBP/USD dropped significantly. But, could one have created a trading strategy for the GBP/USD, that was based solely in the polls that were periodically published?

After the referendum, I wanted test if this was possible. The model I wanted to build should have the following features:

  • The strategy would only buy/short sell the GBP/USD, if in that day a new poll was published. Then, in the following day the operation would be closed.
  • Positive polls for the remain campaign should have a positive impact for the pound, and viceversa. Moreover, the greater the difference between the percentage of remain and leave votes is, the bigger this impact should be.
  • The closer the referendum day is, the higher the impact of the poll should be.
  • If the polls suggest that the remain and leave campaign will receive the same amount of votes more or less, the GBP/USD should follow the trend it previously had.

Taking this features in mind, I tested the following model:


Here, R(t) denotes the exchange rate of GBP/USD, T indicates the time at which the referendum will take place, and P(t) indicates the percentage of remain votes of the latest poll, for day t. This differential equation satisfies all the features I asked to the model:

  • If a poll is published on a day, and the poll is favorable for the remain campaign, then P(t)-0.5 is positive, so that the GBP/USD will tend to go up. And viceversa, if it is favorable for the leave campaign, P(t)-0.5 would be negative, so that the exchange rate will tend to go down.
  • If t is close to T, that is, we are close to the referendum day, \frac{t}{T} would be close to 1, and if t is not close to T, it would be close to 0. Thus, the closer we are to the referendum day, the greater the influence of the poll would be.
  • The term R'(t) makes the GBP/USD to follow the previous trend. The greater the derivative is, the higher the strength of the trend would be.

Intuitively, think of the differential equation as a moving bicycle that is speeding up. However, there is wind around the bicycle, that depending on its direction and strength would make the bicycle slower or faster. The bicycle represents the exchange rate GBP/USD, and the wind represents the polls: depending on the direction, it will move the rate in one direction or the other. But in all cases, the bicycle will try continue to move its current direction.

So, how could we solve the differential equation? An easy way consists of using finite differences, in order to numerically approximate the solution. The term R''(t) would be approximated as

R''(t) \approx \dfrac{R_{r+1}-2R_r+R_{r-1}}{\Delta t^2}

Where R_r:=R(r\Delta t), and \Delta t is the time step (since we are using daily data, \Delta t=1). Now, we could approximate R'(t) as:

R'(t)\approx \dfrac{R_r-R_{r-1}}{\Delta t}

Using all this information, and denoting P_r:=P(r\Delta t), we get



The poll data was obtained from the BBC’s site. The information of the exchange rate GBP/USD and the polls are gathered in this spreadsheet. The returns are shown in the following chart:


The returns from the 13th of September 2015 and  the 22nd of June 2016 was 11.9%. In the same period of time, the S&P 500 lost -0.38%, and the FTSE 100 returned about 0.9%. Taking a look to the chart, one can see that until March 2016 more or less the returns remained quite flat. However, from March to June the returns increased a lot, probably due to the fact that in this period the polls became more important and relevant, when it comes to the GBP/USD exchange rate.


The Code

The code is shown below, and it is also available in GitHub.

money<-c(1000); #Start with 1000$
for (i in i0:(nrow(data)-1)) {
  if ($Remain[i])) {
    money<-c(money, money[length(money)]);
    cat("Stay still.\n")
  nextDay=2*data$Exchange[i]-data$Exchange[i-1]+(i-i0)/T * (data$Remain[i]-0.5)+(data$Exchange[i]-data$Exchange[i-1])
  if (nextDay>data$Exchange[i]*(1+margin) & data$Exchange[i]*0.01>m) {
    money<-c(money, money[length(money)]*as.numeric(data$Exchange[i+1])/as.numeric(data$Exchange[i]));
    cat("Buy. Money:" , money[length(money)], "\n");
  else if (nextDay<data$Exchange[i]*(1-margin) & data$Exchange[i]*0.01>m) {
    money<-c(money, money[length(money)]*as.numeric(data$Exchange[i])/as.numeric(data$Exchange[i+1]));
    cat("Sell. Money:" , money[length(money)], "\n");
  else {
    money<-c(money, money[length(money)]);
    cat("Stay still.\n")
money.zoo<-zoo(money, as.Date(data$Date[-(1:i0)], "%d/%m/%Y"));
exchange.zoo<-zoo(1000*data$Exchange[(i0):(nrow(data)-1)]/as.numeric(data$Exchange[i0]), as.Date(data$Date[-(1:i0)], "%d/%m/%Y"));
z<-as.zoo(cbind(money.zoo, exchange.zoo))
plot(x = z, ylab = "Retrns", xlab="Date", main = "Cumulative Returns", screens=1, col=c("red", "blue"))
legend(x = "topleft", legend = c("Strategy", "GBP/USD returns"), 
       lty = 1,col = c("red", "blue"))

Further improvement

The model can be generalized a bit, in the following way:

R''(t)=\alpha \left ( \dfrac{t}{T}\right)^\beta(P(t)-0.5)+\gamma R'(t)

Based on this model, the constants \alpha,\beta,\gamma that offer the best fit could be found, in order to improve a bit the performance of the model.

MonteCarlo and Arima for stock selection

A few days ago, in this post, I talked about how ARIMA models could be used to forecast the S&P 500 index, and use this information in order to buy or sell the index every day, if the algorithm predicts an increase or decrease in the price, respectively.

In this post, I will go a step further. The idea of the trading algorithm will be the following:

  • Given a day, for each stock of a certain index, select the best ARIMA model for this stock.
  • Then, simulate different possible trajectories of the price of this stock.
  • Now, estimate the probability of the stock going up, dividing the number of trajectories that actually increased their price, by the total number of trajectories. This way of estimating probabilities is called Monte Carlo method.
  • Now, since this process was repeated for a big number of stocks, we may sort them appropiately. If p_i is the probability of a price rise for stock i, this stock would be a good candidate to buy if p_i was close to 1. However, if it is close to 0, it would also be a good candidate, but for short selling. Thus, we pick the stock such that |p_i-0.5| is the maximum.
  • Now, once we have calculated the stock where the maximum is attained, we go long or short depending if the probability was greater or less than 0.5.

Once I have explained how the algorithm will work Continue reading

Trading strategy for the S&P 500 index based on ARIMA models

ARIMA models are a family of models for time series that are used to forecast future behaviour. It can be (and it is) used in finance, and in particular in trading. In this post I will try to show a specific use for a trading strategy based on these models, and it will be applied to the S&P 500 index.

ARIMA models are denoted by ARIMA(p,d,q), where:

  • p is the order of the autorregresive factor.
  • d is the order of differenciation, in order to obtain a stationary time series.
  • q is the order of the moving-average.

R will be used to implement this strategy. In particular, the timeSeries, quantmod and forecast libraries will be used Continue reading