R/stoch_oscilator_strategy_back_test.R

#' Back test on historical stock data
#'
#' This function is backtesting simple stochastic oscillator strategy on chosen stock data.
#' Function on its own is providing data to back tests from google finance.
#'
#' @param symbol Symbol of a stock exchange data.
#' @param initial_portfolio Initial amount of money involved in investment.
#' @param investment_size Percentage size of portfolio which will be involved in every single
#' teoretic transaction during investment period.
#' @param start_date Start date for back tests.
#' @param end_date  End date for back tests.
#' @return A plot and statement for portfolio, during given period of tests.
#' @examples
#' stoch_oscilator_strategy_back_test("GOOG", 10000, 0.01, "2010-01-01", "2017-05-01")
#' stoch_oscilator_strategy_back_test("YHOO", 10000, 0.007, "2006-01-01", "2016-12-30")
#' @export
stoch_oscilator_strategy_back_test <-function(symbol, initial_portfolio, investment_size, start_date, end_date){

  # tests
  assertthat::assert_that(is.character(symbol))
  assertthat::assert_that( !(class(try(as.Date( start_date, format = "%Y-%m-%d" ))) == "try-error" || is.na(start_date)),
                           msg = "start_date is incorrect, enter in the format \"%Y-%m-%d\" "
                           )
  assertthat::assert_that( !(class(try(as.Date( end_date, format = "%Y-%m-%d" ))) == "try-error" || is.na(end_date)),
                           msg = "end_date is incorrect, enter in the format \"%Y-%m-%d\" "
  )
  assertthat::assert_that(is.numeric(initial_portfolio))
  assertthat::assert_that(is.numeric(investment_size))
  assertthat::assert_that(investment_size < 0.05,
                          msg = "investment_size has to be less then 5% of initial_portfolio because the strategy could lead to almost instant bankruptcy ")
  assertthat::assert_that(investment_size > 0,
                          msg = "investment_size has to be positive number")
  assertthat::assert_that(initial_portfolio > 5000,
                          msg = "initial_portfolio has to to be greater then 5000 USD because
                          with less capital we should not invest on the US stock market")


  # get data
  options(warn = -1)
  data <- quantmod::getSymbols(symbol, src = "google", from = start_date, to = end_date, env = NULL)
  options(warn = 1)
  data <- na.omit(merge(data, TTR::stoch(quantmod::Cl(data))))

  # test that the columns are in set order
  assertthat::assert_that(grepl("Close",colnames(data)[4]))

  # create signals according to strategy. 1 - buy, -1 - sell, 0 - outside the market
  data$sig <- NA
  fast_over_slow <- data$fastD > data$slowD
  data$sig <- rep(0, nrow(data))
  data$sig[which(diff(fast_over_slow) == 1 & data$slowD < 0.2)] <- 1
  data$sig[which(diff(fast_over_slow) == -1 & data$slowD > 0.8)] <- -1

  for(i in 2 : length(data$sig)){
    if(data$sig[i] == 0){data$sig[i] <- data$sig[i - 1]}
  }

  fi.stoch <- as.numeric(data$sig)

  #test that strategy vector is builded only from values: 0,1,-1
  assertthat::assert_that(all(grepl("^1$", fi.stoch) |  grepl("^-1$", fi.stoch)  |  grepl("^0$", fi.stoch)))

  # count returns
  returns <- as.numeric(diff(data[ , 4]))
  returns <- returns[2 : length(returns)]
  returns <- c(returns, 0)

  # count changes in portfolio
  portfolio_returns <- returns * fi.stoch * investment_size * initial_portfolio
  portfolio<-initial_portfolio +cumsum(portfolio_returns)

  # plot porfolio over during period
  plot(portfolio, type="l", xlab="Investment day", main = "Account balance")

  # print statements
  print(paste("At the end of investment period, portfolio value is equal to: ",  round(portfolio[length(portfolio)])))
  print(paste("During the investment period, the portfolio achieves the lowest value at the level of: ", round(min(portfolio))))
  print(paste("During the investment period, the portfolio achieves the highest value at the level of: ", round(max(portfolio))))
}
mrepsilon/PawelKawskiPackage documentation built on May 21, 2019, 2:22 p.m.