Search code examples
rtime-seriesback-testing

How to code and plot the performance of two trading strategies


So I have the monthly returns on the SP500 in addition to the risk free rate in a zoo timeseries object called SP500.df . I want to backtest two different trading strategies and plot them in a graph. In form of either cumulative return, or just how much 1$ intial investment would be at end of period.

  • Strategy 1: buy and hold SP500 the whole period.

  • Strategy 2: Hold SP500 from nov - april (winter), then switch to risk free rate from may - october (summer).

Notice that I also have extracted the winter and summer return in two respective vectors. called Winter_returns and summer_returns.

mkt= returns
rf= risk free rate

this is how dataframe SP500.df looks:

dput(head(SP500.df, 10))

structure(c(0.0286195, 0.03618317, -0.01363269, 0.02977401, 0.04461314, 
0.0015209, -0.03207303, -0.0079275, 0.01882991, 0.00584478, 0.02372219, 
0.03299206, -0.017908, 0.02540426, 0.04163062, -0.00317315, -0.03732322, 
-0.0109474, 0.0147047, 0.00087712, 0.00608527826274047, 0.00495046849033236, 
0.00503506482970477, 0.00481634688889247, 0.00424210936461577, 
0.00358500724272255, 0.00424210936461577, 0.00480928182207086, 
0.00485872460615713, 0.00487990531586144, 1, 1, 1, 1, 0, 0, 0, 
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 
0, 0), .Dim = c(10L, 6L), .Dimnames = list(NULL, c("MKT", "CAP", 
"RF", "dummy", "dummyJAN", "adjdummy")), index = structure(c(-36494, 
-36466, -36435, -36405, -36374, -36344, -36313, -36282, -36252, 
-36221), class = "Date"), class = "zoo")

Solution

  • Here is a way.
    Define a calculations function calc and apply it to the column MKT to have strategy 1 then create a vector of all returns/rates rates and apply the function to it. The plot uses base R graphics.

    library(zoo)
    
    calc <- function(x, returns) x*cumprod((1 + returns))
    
    strat1 <- calc(1, SP500.df$MKT)
    strat1
    #> 1870-01-31 1870-02-28 1870-03-31 1870-04-30 1870-05-31 1870-06-30 1870-07-31 
    #>   1.028620   1.065838   1.051308   1.082610   1.130908   1.132628   1.096301 
    #> 1870-08-31 1870-09-30 1870-10-31 
    #>   1.087610   1.108090   1.114567
    
    
    i_winter <- SP500.df$dummy == 1
    rates <- numeric(NROW(SP500.df))
    rates[i_winter] <- SP500.df$MKT[i_winter]
    rates[!i_winter] <- SP500.df$RF[!i_winter]
    strat2 <- calc(1, rates)
    strat2
    #>  [1] 1.028620 1.065838 1.051308 1.082610 1.087202 1.091100 1.095728 1.100998
    #>  [9] 1.106347 1.111746
    
    matplot(cbind(strat1, strat2), pch = 19)
    matlines(cbind(strat1, strat2), lty = "solid")
    legend("bottomright", legend = c("strategy 1", "strategy 2"), 
           col = 1:2, lty = "solid", pch = 19)
    

    Created on 2022-02-07 by the reprex package (v2.0.1)

    With ggplot2 graphics, create a temporary data.frame and pipe it to package tidyr's reshaping function pivot_longer. Then pipe the result to ggplot.

    library(ggplot2)
    
    data.frame(
      date = index(SP500.df),
      strategy1 = strat1,
      strategy2 = strat2
    ) |> 
      tidyr::pivot_longer(-date) |> 
      ggplot(aes(date, value, color = name)) +
      geom_line() +
      geom_point() +
      scale_color_manual(values = c("black", "red")) +
      theme_bw()
    

    Created on 2022-02-07 by the reprex package (v2.0.1)