Thursday, September 10, 2015

Financial data exploratory analysis (part 5)

Portfolio Trading

In the previous post, we see how to define a trading prediction model based on historical data by using the quantmod package. We also notice why it is necessary to introduce a new function able to fulfill the need of implementing and verifying the success of a portfolio trading strategy based upon the model just produced. My portfolio trading strategy will use the following basic information:

  • initial portfolio status
  • available funds
  • parameters driving how/when the buy orders should be issued
  • parameters driving how/when the sell orders should be issued

All those parameters can be collected into a control structure given as input to our trading portfolio function together with the ticker OHLC object, the trading interval and the quantmod model.

As output, I like to have a dataframe reporting with the same frequency used for model building, the following:

  • portfolio.Open, the money value of our portfolio at open market time
  • portfolio.Close, the money value of our portfolio at close market time
  • portfolio.Gain, the percentage gain of our portfolio to date
  • own.shares, the ticker shares in our portfolio to date
  • average.price, the ticker shares buy average price
  • available.funds.Open, the available funds at open market time
  • available.funds.Close, the available funds at close market time
  • action, the trading action to date, one between hold, buy, sell
  • quantity, the quantity of shares bought, sold in the case within the day
  • trade.value, the money value of our daily trade

All those parameters allow for a basic understanding of the performance of our trading strategy. Of course the following aspects should be considered:

  • I am driving a basic scenario of trading having in mind general-purpose investor needs
  • I am not including other important details of the trading, to mention some:
    • bid ask spread
    • required price
    • the actual value the share is bought or sold

However, to keep it simple let us start with the requirements above mentioned. It is possible to detail it later once we have gain confidence in what I am going to show you.

Preliminary behavior to the tradePortfolio() function call is:

  • download ticker OHLC data
  • update OHLC data frequency, I mean change it from daily to weekly for example
  • define some trading strategy, I mean next ticker gain forecast model
  • specify quantmod model
  • extract quantmod model correspoding data
  • quantmod model build
  • quantmod model dump and plot

Herein some example code. Required libraries are quantmod, rpart and rpart.plot.

setwd("~/R/aroundrblog/Finance")
suppressPackageStartupMessages(library(quantmod))
suppressPackageStartupMessages(library(rpart))
suppressPackageStartupMessages(library(rpart.plot))
suppressPackageStartupMessages(library(knitr))

Herein below, I download OHLC ticker data and convert it to weekly frequency. Then I specify a model which aim to forecast the next weekly ticker gain based on the last two weekly Close/Open price ratio. Then model is build using as all 2013 year data for training purpose. Model dump and plot are shown.

ticker <- "YHOO"
getSymbols(ticker, src='yahoo')
##     As of 0.4-0, 'getSymbols' uses env=parent.frame() and
##  auto.assign=TRUE by default.
## 
##  This  behavior  will be  phased out in 0.5-0  when the call  will
##  default to use auto.assign=FALSE. getOption("getSymbols.env") and 
##  getOptions("getSymbols.auto.assign") are now checked for alternate defaults
## 
##  This message is shown once per session and may be disabled by setting 
##  options("getSymbols.warning4.0"=FALSE). See ?getSymbols for more details.
## [1] "YHOO"
ticker = to.weekly(YHOO)

q.model <- specifyModel(Next(OpCl(ticker)) ~ (Lag(OpCl(ticker),0:1)))

model.data <- modelData(q.model)
head(model.data)
##            Next.OpCl.ticker Lag.OpCl.ticker.0.1.Lag.0
## 2007-01-12     -0.074966535               0.063176893
## 2007-01-19      0.006822298              -0.074966535
## 2007-01-26      0.025668486               0.006822298
## 2007-02-02      0.037321242               0.025668486
## 2007-02-09      0.089450287               0.037321242
## 2007-02-16      0.009433931               0.089450287
##            Lag.OpCl.ticker.0.1.Lag.1
## 2007-01-12               0.073114120
## 2007-01-19               0.063176893
## 2007-01-26              -0.074966535
## 2007-02-02               0.006822298
## 2007-02-09               0.025668486
## 2007-02-16               0.037321242
model <- buildModel(q.model, method='rpart', training.per=c('2013-02-01','2013-12-31'),
                    control=rpart.control(minsplit=5))

model@fitted.model
## n= 48 
## 
## node), split, n, deviance, yval
##       * denotes terminal node
## 
##   1) root 48 4.782837e-02  0.014575700  
##     2) Lag.OpCl.ticker.0.1.Lag.1< 0.004439411 19 1.171213e-02  0.001198999  
##       4) Lag.OpCl.ticker.0.1.Lag.1>=-0.0108401 9 5.612584e-03 -0.011584030  
##         8) Lag.OpCl.ticker.0.1.Lag.1< -0.00537906 4 7.223112e-04 -0.023542240 *
##         9) Lag.OpCl.ticker.0.1.Lag.1>=-0.00537906 5 3.860680e-03 -0.002017452  
##          18) Lag.OpCl.ticker.0.1.Lag.1>=-0.000755803 3 1.426650e-03 -0.020017440 *
##          19) Lag.OpCl.ticker.0.1.Lag.1< -0.000755803 2 4.033451e-06  0.024982530 *
##       5) Lag.OpCl.ticker.0.1.Lag.1< -0.0108401 10 3.305307e-03  0.012703720  
##        10) Lag.OpCl.ticker.0.1.Lag.1< -0.01312584 8 2.547570e-03  0.008457823  
##          20) Lag.OpCl.ticker.0.1.Lag.1>=-0.0295945 2 5.817894e-04 -0.011050870 *
##          21) Lag.OpCl.ticker.0.1.Lag.1< -0.0295945 6 9.508757e-04  0.014960720 *
##        11) Lag.OpCl.ticker.0.1.Lag.1>=-0.01312584 2 3.663088e-05  0.029687310 *
##     3) Lag.OpCl.ticker.0.1.Lag.1>=0.004439411 29 3.048901e-02  0.023339750  
##       6) Lag.OpCl.ticker.0.1.Lag.1>=0.04632919 9 2.201388e-03  0.000771833  
##        12) Lag.OpCl.ticker.0.1.Lag.0>=-0.00898223 7 3.375160e-04 -0.003288263 *
##        13) Lag.OpCl.ticker.0.1.Lag.0< -0.00898223 2 1.344614e-03  0.014982170 *
##       7) Lag.OpCl.ticker.0.1.Lag.1< 0.04632919 20 2.164111e-02  0.033495310  
##        14) Lag.OpCl.ticker.0.1.Lag.1< 0.03258854 15 1.556012e-02  0.026400750  
##          28) Lag.OpCl.ticker.0.1.Lag.1>=0.02455003 5 6.339454e-03  0.006100402  
##            56) Lag.OpCl.ticker.0.1.Lag.0< -0.009535946 2 2.498836e-03 -0.006493894 *
##            57) Lag.OpCl.ticker.0.1.Lag.0>=-0.009535946 3 3.311897e-03  0.014496600 *
##          29) Lag.OpCl.ticker.0.1.Lag.1< 0.02455003 10 6.129883e-03  0.036550920  
##            58) Lag.OpCl.ticker.0.1.Lag.1< 0.01598028 6 4.137488e-03  0.026186960  
##             116) Lag.OpCl.ticker.0.1.Lag.1>=0.007428941 3 5.346758e-04  0.006895524 *
##             117) Lag.OpCl.ticker.0.1.Lag.1< 0.007428941 3 1.369857e-03  0.045478390 *
##            59) Lag.OpCl.ticker.0.1.Lag.1>=0.01598028 4 3.812181e-04  0.052096870 *
##        15) Lag.OpCl.ticker.0.1.Lag.1>=0.03258854 5 3.061020e-03  0.054779010  
##          30) Lag.OpCl.ticker.0.1.Lag.1>=0.03570818 3 2.092971e-03  0.045361740 *
##          31) Lag.OpCl.ticker.0.1.Lag.1< 0.03570818 2 3.029117e-04  0.068904920 *
rpart.plot(model@fitted.model)

Next step is to define some control strategy for our portfolio trading simulation, the following ones:s

  • signal threshold for sell and buy
  • trading dates
  • control structure reporting:
    • the initial portfolio status, comprising:
      • portfolio money value,
      • owned shares and their average buy price
      • if we want to do first a buy trading action or a sell trading action
    • the available funds
    • the money amount of a single buy
    • a flag specifying if a buy trading position should engage all available current funds
    • the money amount of a single sell
    • a flag specifying if a sell trading position should engage all available portfolio shares
    • the signal thresholds for sell and buy as percentage of price variation against our model prediction

Here is an example:

signal.threshold <- c(-0.02, 0.05)

dates <- c('2014-01-01', '2014-12-24')

control <- list("initial" = c("portfolio" = 0, 
                              "own.shares" = 0, 
                              "average.price"= 0, 
                              "buy.first" = TRUE, 
                              "sell.first" = FALSE
                              ),
                "available.funds" = 6000, 
                "single.buy" = 2000, 
                "buy.all" = FALSE, 
                "single.sell" = 0,
                "sell.all" = TRUE, 
                "signal.threshold" = signal.threshold)

What aboveshown means that the investor intends:

  • to sell when model forecasted price variation is below or equal 2%
  • to buy when model forecasted price variation is above or equal 5%
  • to trade from 2014-01-01 up to 2014-12-24
  • to have an initial empty portfolio
  • to open a long position first (buy), it cannot be else starting from an empty portfolio and being not allowed for uncovered short positions
  • to have $6,000 available for trading
  • to open long position (buy) of $2,000 per day
  • not to engage all available funds in a single buy order
  • to sell all owned shares by a single sell order
  • the signal threshold as above explained

At this point, I can show you the tradePortfolio() function I have in mind. You can see I have also defined a couple of utility functions, searchTradingDay() and adjustTradingDate() to adjust the investor specified start and end trading dates with the closest actual trading ones.

searchTradingDay <- function(ticker, date, nextd) {
  trading.date <- index(ticker)
  if (nextd == TRUE) {
    compare <- (date < trading.date)
  } else {
    compare <- (date > trading.date)
  }
  is.trading <- which(compare == nextd)
  return (trading.date[is.trading[1]])
}

adjustTradingDate <- function(ticker, trade.date) {
  price <- coredata(ticker[trade.date[[1]]])
  if (length(price) == 0) {
    work.date.1 <- searchTradingDay(ticker, trade.date[[1]], TRUE)
  } else {
    work.date.1 <- as.Date(trade.date[[1]])
  }
  price <- coredata(ticker[trade.date[[2]]])
  if (length(price) == 0) {
    work.date.2 <- searchTradingDay(ticker, trade.date[[2]], FALSE)
  } else {
    work.date.2 <- as.Date(trade.date[[2]])
  }
  return (c(work.date.1, work.date.2))
}

# tradePortfolio() function which implements our trading strategy against the ticker OHLC historical data
tradePortfolio <- function(ticker, model, dates, control) {
  adj.trade.dates <- adjustTradingDate(ticker, dates)
  
  ticker.trade <- ticker[seq(from = adj.trade.dates[[1]], to = adj.trade.dates[[2]], by=1)]
  
  buy.first <- ifelse(is.null(control$initial) | control$initial["buy.first"], TRUE, FALSE)
  sell.first <- ifelse(is.null(control$initial) == FALSE & 
                       control$available.funds > control$single.buy &
                       control$initial["sell.first"], TRUE, FALSE)

  # using some of the tradeModel code
  quantmod <- getModelData(model);
  model.data <- modelData(quantmod,adj.trade.dates);
  fitted.zoo <- predict(quantmod@fitted.model, model.data)
  if(class(fitted.zoo) != "zoo") {
    fitted.zoo <- zoo(as.vector(fitted.zoo),index(model.data))
  }
  signal.threshold <- control$signal.threshold
  signal.zoo <- ifelse(fitted.zoo < signal.threshold[1] | fitted.zoo > signal.threshold[2],
                       ifelse(fitted.zoo > 0, 1, -1), 0)
  market.zoo <- model.data[,1]
  signal.zoo <- merge(market.zoo,signal.zoo)
  index(signal.zoo) <- index(signal.zoo);
   
  # starting loop on signal
  len <- nrow(ticker.trade)
  portfolio.Open <- rep(control$initial["portfolio"], len)
  portfolio.Close <- rep(control$initial["portfolio"], len)
  portfolio.Gain <- rep(0, len)
  own.shares <- rep(control$initial["own.shares"], len)
  average.price <- rep(control$initial["average.price"], len)
  available.funds.Open <- rep(0, len)
  available.funds.Close <- rep(0, len)
  action <- rep(NA, len)
  quantity <- rep(0,len)
  trade.value <- rep(0,len)
  
  portfolio.df <- data.frame(portfolio.Open,
                             portfolio.Close, 
                             portfolio.Gain, 
                             own.shares, 
                             average.price, 
                             available.funds.Open,
                             available.funds.Close, 
                             action, 
                             quantity,
                             trade.value, 
                             Op(ticker.trade), 
                             Cl(ticker.trade), 
                             Lo(ticker.trade), 
                             Hi(ticker.trade))

  cn <- colnames(portfolio.df)
  l <- length(cn)
  colnames(portfolio.df)[(l-3):l] <- c("ticker.Open", "ticker.Close", "ticker.Low", "ticker.High")

  buy.todo <- buy.first
  sell.todo <- sell.first

  for (i in 1:len) {
    
    ifelse (i > 1, portfolio.df[i, "available.funds.Open"] <- portfolio.df[i-1, "available.funds.Close"],
                   portfolio.df[i, "available.funds.Open"] <- control$available.funds)

    if (signal.zoo[i,2] == 1 &&
        sell.todo == FALSE &&
        portfolio.df[i, "available.funds.Open"] >= control$single.buy) {

      action <- "buy"

      trade.value <- as.numeric(coredata(Op(ticker.trade)[i]))
      
      if (control$buy.all == TRUE) {
        quantity <- portfolio.df[i, "available.funds.Open"]/trade.value
      } else {
        quantity <- floor(control$single.buy/trade.value)
      }
  
      value.close <- quantity*as.numeric(coredata(Cl(ticker.trade)[i]))
      
      portfolio.df[i, "portfolio.Open"] <- ifelse(i==1, 0, portfolio.df[i-1, "portfolio.Close"])
      
      portfolio.df[i, "portfolio.Close"] <- ifelse(i==1, 
                                                   value.close, 
                                                   portfolio.df[i-1, "portfolio.Close"] + value.close)
      
      portfolio.df[i, "portfolio.Gain"] <- ifelse(i==1, 0, portfolio.df[i-1, "portfolio.Gain"])
      
      portfolio.df[i, "own.shares"] <- ifelse(i==1, quantity, portfolio.df[i-1, "own.shares"] + quantity)
      
      temp <- portfolio.df[i-1, "own.shares"] * portfolio.df[i-1, "average.price"]
      portfolio.df[i, "average.price"] <- ifelse(i==1, 
                                                 trade.value,
                                                 (temp + trade.value * quantity)/portfolio.df[i, "own.shares"])

      portfolio.df[i, "available.funds.Close"] <- portfolio.df[i, "available.funds.Open"] - 
                                                  trade.value * quantity
      
      portfolio.df[i, "action"] <- action
      
      portfolio.df[i, "quantity"] <- quantity
      
      portfolio.df[i, "trade.value"] <- trade.value
      
      buy.todo = FALSE
    
    } else if (signal.zoo[i,2] == -1 &&
               buy.todo == FALSE &&
               portfolio.df[i-1, "portfolio.Close"] > 0) {
      
      action <- "sell"
      
      trade.value <- as.numeric(coredata(Cl(ticker.trade)[i]))
  
      portfolio.df[i, "action"] <- action
      
      portfolio.df[i, "trade.value"] <- trade.value
      
      portfolio.df[i, "portfolio.Open"] <- portfolio.df[i-1, "own.shares"] * trade.value
      
      if (control$sell.all == TRUE) {
        quantity <- portfolio.df[i-1, "own.shares"]
      } else {
        quantity <- min(portfolio.df[i-1, "own.shares"], floor(control$single.sell/trade.value))
      }
      
      portfolio.df[i, "own.shares"] <- portfolio.df[i-1, "own.shares"] - quantity
  
      portfolio.df[i, "available.funds.Close"] <- portfolio.df[i, "available.funds.Open"] + 
                                                  trade.value * quantity
      
      portfolio.df[i, "portfolio.Close"] <- portfolio.df[i, "own.shares"]*trade.value
      
      portfolio.df[i, "available.funds.Close"] <- portfolio.df[i, "available.funds.Open"] + 
                                                  trade.value * quantity
      
      portfolio.df[i, "portfolio.Gain"] <- 100*((portfolio.df[i, "available.funds.Close"]/control$available.funds)-1)
      
      portfolio.df[i, "quantity"] <- quantity
      
      value.close <- trade.value*quantity
      
      if (portfolio.df[i, "own.shares"] == 0) {
         portfolio.df[i, "average.price"] <- 0
      } else {
        temp <- portfolio.df[i-1, "own.shares"] * portfolio.df[i-1, "average.price"]
        portfolio.df[i, "average.price"] <- (temp - trade.value * quantity)/portfolio.df[i, "own.shares"]
      }
      
      sell.todo <- FALSE
    
    } else if (i > 1) {
      
      share.price <- as.numeric(coredata(Op(ticker.trade)[i]))
      
      portfolio.df[i, "portfolio.Open"] <- portfolio.df[i-1, "own.shares"]*share.price

      portfolio.df[i, "own.shares"] <- portfolio.df[i-1, "own.shares"]
      
      if (portfolio.df[i, "portfolio.Open"] == 0) {
        portfolio.df[i, "average.price"] <- 0
      } else {
        portfolio.df[i, "average.price"] <- portfolio.df[i-1, "average.price"]
      }
      
      share.price <- as.numeric(coredata(Cl(ticker.trade)[i]))
      
      portfolio.df[i, "portfolio.Close"] <- portfolio.df[i-1, "own.shares"]*share.price
      
      portfolio.df[i, "portfolio.Gain"] <- portfolio.df[i-1, "portfolio.Gain"] 
      
      portfolio.df[i, "available.funds.Open"] <- portfolio.df[i-1, "available.funds.Close"]
      
      portfolio.df[i, "available.funds.Close"] <- portfolio.df[i, "available.funds.Open"]
      
      portfolio.df[i, "action"] <- "hold"
    
    } else if (i == 1) {
    
      share.price <- as.numeric(coredata(Op(ticker.trade)[i]))
      
      portfolio.df[i, "action"] <- "hold"
      
      portfolio.df[i, "available.funds.Close"] <- portfolio.df[i, "available.funds.Open"]
    }

  }

  list(portfolio.df, signal.zoo)
}

And here is an example of tradePortfolio() call and corresponding results dump.

res <- tradePortfolio(ticker, model, dates, control)

porfolioTradingHistory <- res[[1]]
signalHistory <- res[[2]]

kable(porfolioTradingHistory, caption = "Portfolio trading history")
Portfolio trading history
portfolio.Open portfolio.Close portfolio.Gain own.shares average.price available.funds.Open available.funds.Close action quantity trade.value ticker.Open ticker.Close ticker.Low ticker.High
2014-01-03 0.00 0.00 0.0000000 0 0.00000 6000.00000 6000.00000 hold 0 0.00 40.46 40.12 39.31 40.58
2014-01-10 0.00 0.00 0.0000000 0 0.00000 6000.00000 6000.00000 hold 0 0.00 40.05 41.23 39.75 41.72
2014-01-17 0.00 0.00 0.0000000 0 0.00000 6000.00000 6000.00000 hold 0 0.00 41.16 40.01 39.47 41.31
2014-01-24 0.00 0.00 0.0000000 0 0.00000 6000.00000 6000.00000 hold 0 0.00 39.98 37.91 37.62 40.40
2014-01-31 0.00 0.00 0.0000000 0 0.00000 6000.00000 6000.00000 hold 0 0.00 37.60 36.01 34.45 38.32
2014-02-07 0.00 0.00 0.0000000 0 0.00000 6000.00000 6000.00000 hold 0 0.00 35.94 37.23 34.66 37.27
2014-02-14 0.00 0.00 0.0000000 0 0.00000 6000.00000 6000.00000 hold 0 0.00 38.00 38.23 37.25 38.91
2014-02-21 0.00 0.00 0.0000000 0 0.00000 6000.00000 6000.00000 hold 0 0.00 38.31 37.29 37.22 38.59
2014-02-28 0.00 0.00 0.0000000 0 0.00000 6000.00000 6000.00000 hold 0 0.00 37.23 38.67 36.82 39.38
2014-03-07 0.00 0.00 0.0000000 0 0.00000 6000.00000 6000.00000 hold 0 0.00 37.65 38.70 37.43 40.15
2014-03-14 0.00 0.00 0.0000000 0 0.00000 6000.00000 6000.00000 hold 0 0.00 38.63 37.60 36.45 38.78
2014-03-21 0.00 0.00 0.0000000 0 0.00000 6000.00000 6000.00000 hold 0 0.00 39.00 37.94 37.42 39.94
2014-03-28 0.00 0.00 0.0000000 0 0.00000 6000.00000 6000.00000 hold 0 0.00 38.00 35.90 35.05 38.04
2014-04-04 0.00 0.00 0.0000000 0 0.00000 6000.00000 6000.00000 hold 0 0.00 36.46 34.26 33.83 36.86
2014-04-11 0.00 0.00 0.0000000 0 0.00000 6000.00000 6000.00000 hold 0 0.00 34.11 32.87 32.15 35.00
2014-04-17 0.00 0.00 0.0000000 0 0.00000 6000.00000 6000.00000 hold 0 0.00 33.55 36.38 32.64 37.30
2014-04-25 0.00 0.00 0.0000000 0 0.00000 6000.00000 6000.00000 hold 0 0.00 36.60 34.48 34.29 36.85
2014-05-02 0.00 0.00 0.0000000 0 0.00000 6000.00000 6000.00000 hold 0 0.00 34.67 36.87 33.65 37.12
2014-05-09 0.00 0.00 0.0000000 0 0.00000 6000.00000 6000.00000 hold 0 0.00 36.68 33.76 33.41 37.17
2014-05-16 0.00 0.00 0.0000000 0 0.00000 6000.00000 6000.00000 hold 0 0.00 33.99 33.41 33.10 34.69
2014-05-23 0.00 0.00 0.0000000 0 0.00000 6000.00000 6000.00000 hold 0 0.00 33.41 35.02 33.28 35.08
2014-05-30 0.00 0.00 0.0000000 0 0.00000 6000.00000 6000.00000 hold 0 0.00 35.00 34.65 34.13 35.17
2014-06-06 0.00 0.00 0.0000000 0 0.00000 6000.00000 6000.00000 hold 0 0.00 34.69 35.92 34.26 36.08
2014-06-13 0.00 2031.70 0.0000000 55 35.86000 6000.00000 4027.69994 buy 55 35.86 35.86 36.94 35.54 37.06
2014-06-20 1925.00 1872.75 0.0000000 55 35.86000 4027.69994 4027.69994 hold 0 0.00 35.00 34.05 33.97 35.49
2014-06-27 1877.15 1883.75 0.0000000 55 35.86000 4027.69994 4027.69994 hold 0 0.00 34.13 34.25 33.02 34.55
2014-07-03 1987.70 0.00 0.2566648 0 0.00000 4027.69994 6015.39989 sell 55 36.14 34.93 36.14 34.85 36.15
2014-07-11 0.00 1948.65 0.2566648 55 36.15000 6015.39989 4027.14978 buy 55 36.15 36.15 35.43 34.10 36.23
2014-07-18 1969.00 1833.15 0.2566648 55 36.15000 4027.14978 4027.14978 hold 0 0.00 35.80 33.33 32.93 35.95
2014-07-25 1834.25 1986.60 0.2566648 55 36.15000 4027.14978 4027.14978 hold 0 0.00 33.35 36.12 33.16 36.55
2014-08-01 1992.65 1959.10 0.2566648 55 36.15000 4027.14978 4027.14978 hold 0 0.00 36.23 35.62 35.31 36.99
2014-08-08 1964.05 1975.05 0.2566648 55 36.15000 4027.14978 4027.14978 hold 0 0.00 35.71 35.91 35.40 36.66
2014-08-15 1985.50 2005.85 0.2566648 55 36.15000 4027.14978 4027.14978 hold 0 0.00 36.10 36.47 35.15 36.57
2014-08-22 2022.35 2090.55 0.2566648 55 36.15000 4027.14978 4027.14978 hold 0 0.00 36.77 38.01 36.75 38.20
2014-08-29 2090.55 4093.07 0.2566648 107 37.11710 4027.14978 2043.86983 buy 52 38.14 38.14 38.51 37.54 38.72
2014-09-05 4162.30 4236.13 0.2566648 107 37.11710 2043.86983 2043.86983 hold 0 0.00 38.90 39.59 38.69 39.80
2014-09-12 4236.13 6337.25 0.2566648 156 38.12942 2043.86983 67.20983 buy 49 40.34 40.34 42.88 40.26 43.20
2014-09-19 6860.88 6385.08 0.2566648 156 38.12942 67.20983 67.20983 hold 0 0.00 43.98 40.93 39.55 44.01
2014-09-26 6204.12 6342.96 0.2566648 156 38.12942 67.20983 67.20983 hold 0 0.00 39.77 40.66 37.90 40.80
2014-10-03 6303.96 6400.68 0.2566648 156 38.12942 67.20983 67.20983 hold 0 0.00 40.41 41.03 39.69 41.69
2014-10-10 6427.20 6177.60 0.2566648 156 38.12942 67.20983 67.20983 hold 0 0.00 41.20 39.60 39.59 41.73
2014-10-17 6165.12 5998.20 0.2566648 156 38.12942 67.20983 67.20983 hold 0 0.00 39.52 38.45 36.20 40.07
2014-10-24 6001.32 6786.00 0.2566648 156 38.12942 67.20983 67.20983 hold 0 0.00 38.47 43.50 38.25 43.65
2014-10-31 6756.36 7183.80 0.2566648 156 38.12942 67.20983 67.20983 hold 0 0.00 43.31 46.05 43.29 46.52
2014-11-07 7183.80 7573.80 0.2566648 156 38.12942 67.20983 67.20983 hold 0 0.00 46.05 48.55 45.74 48.67
2014-11-14 7612.80 8073.00 0.2566648 156 38.12942 67.20983 67.20983 hold 0 0.00 48.80 51.75 48.10 51.95
2014-11-21 8085.48 7962.24 0.2566648 156 38.12942 67.20983 67.20983 hold 0 0.00 51.83 51.04 50.00 52.62
2014-11-28 7995.00 8071.44 0.2566648 156 38.12942 67.20983 67.20983 hold 0 0.00 51.25 51.74 51.07 52.26
2014-12-05 8023.08 7954.44 0.2566648 156 38.12942 67.20983 67.20983 hold 0 0.00 51.43 50.99 49.66 51.43
2014-12-12 7837.44 0.00 31.7441691 0 0.00000 67.20983 7904.65014 sell 156 50.24 50.52 50.24 48.29 51.17
2014-12-19 0.00 0.00 31.7441691 0 0.00000 7904.65014 7904.65014 hold 0 0.00 50.42 50.88 48.81 51.47
2014-12-26 0.00 0.00 31.7441691 0 0.00000 7904.65014 7904.65014 hold 0 0.00 50.99 50.86 49.93 51.60

Let us dump only active trading records to ease the post trading analysis.

portfolioTradingHistFIlt <- subset(porfolioTradingHistory, action != "hold")
kable(portfolioTradingHistFIlt, caption = "Filtered Portfolio trading history")
Filtered Portfolio trading history
portfolio.Open portfolio.Close portfolio.Gain own.shares average.price available.funds.Open available.funds.Close action quantity trade.value ticker.Open ticker.Close ticker.Low ticker.High
2014-06-13 0.00 2031.70 0.0000000 55 35.86000 6000.00000 4027.69994 buy 55 35.86 35.86 36.94 35.54 37.06
2014-07-03 1987.70 0.00 0.2566648 0 0.00000 4027.69994 6015.39989 sell 55 36.14 34.93 36.14 34.85 36.15
2014-07-11 0.00 1948.65 0.2566648 55 36.15000 6015.39989 4027.14978 buy 55 36.15 36.15 35.43 34.10 36.23
2014-08-29 2090.55 4093.07 0.2566648 107 37.11710 4027.14978 2043.86983 buy 52 38.14 38.14 38.51 37.54 38.72
2014-09-12 4236.13 6337.25 0.2566648 156 38.12942 2043.86983 67.20983 buy 49 40.34 40.34 42.88 40.26 43.20
2014-12-12 7837.44 0.00 31.7441691 0 0.00000 67.20983 7904.65014 sell 156 50.24 50.52 50.24 48.29 51.17

So, no trading activity until June 13th when a buy order is issued. Sell order is issued on July13th as the prediction model foresees a loss higher than the specified sell threshold. At that time, no remarkable portfolio gain is achieved. Then other three buy orders are issued and the overall portfolio is closed on December 12th. The sell performed define a satisfactory portfolio gain percentage.

To inspect the signal values, we can dump:

signalHistory
##            Next.OpCl.ticker signal.zoo
## 2014-01-03      0.029463197          0
## 2014-01-10     -0.027939796         -1
## 2014-01-17     -0.051775888          0
## 2014-01-24     -0.042287236          0
## 2014-01-31      0.035893184          0
## 2014-02-07      0.006052632          0
## 2014-02-14     -0.026624901          0
## 2014-02-21      0.038678431          0
## 2014-02-28      0.027888418          0
## 2014-03-07     -0.026663292          0
## 2014-03-14     -0.027179513          0
## 2014-03-21     -0.055263105          0
## 2014-03-28     -0.060340128          0
## 2014-04-04     -0.036353033          0
## 2014-04-11      0.084351776          0
## 2014-04-17     -0.057923446          0
## 2014-04-25      0.063455469          0
## 2014-05-02     -0.079607470          0
## 2014-05-09     -0.017063900          0
## 2014-05-16      0.048189165          0
## 2014-05-23     -0.009999943          0
## 2014-05-30      0.035456876          0
## 2014-06-06      0.030117066         -1
## 2014-06-13     -0.027142886          1
## 2014-06-20      0.003515939          0
## 2014-06-27      0.034640681          0
## 2014-07-03     -0.019917067         -1
## 2014-07-11     -0.068994332          1
## 2014-07-18      0.083058506          0
## 2014-07-25     -0.016836903          0
## 2014-08-01      0.005600700          0
## 2014-08-08      0.010249391          0
## 2014-08-15      0.033723089          0
## 2014-08-22      0.009701075          0
## 2014-08-29      0.017737737          1
## 2014-09-05      0.062964824          0
## 2014-09-12     -0.069349704          1
## 2014-09-19      0.022378677          0
## 2014-09-26      0.015342712          0
## 2014-10-03     -0.038835023          1
## 2014-10-10     -0.027074873          0
## 2014-10-17      0.130751205          0
## 2014-10-24      0.063264787          0
## 2014-10-31      0.054288818          0
## 2014-11-07      0.060450841          0
## 2014-11-14     -0.015242156          0
## 2014-11-21      0.009561015          0
## 2014-11-28     -0.008555279          0
## 2014-12-05     -0.005542320          0
## 2014-12-12      0.009123424         -1
## 2014-12-19     -0.002549539         -1
## 2014-12-26     -0.009867772          0

You can see now the difference with the tradeModel() function. Even though -1 signals are raised first, no actual gain against the market is accounted as the portfolio does not yet hold any shares. When June 13th +1 signal is raised, a correspondingly buy order is issued and recorded in our portfolio history table. And so on. Now we can match our model signals with concrete portfolio related trading actions and record consequent gains or losses.

You can play with different signal thresholds and buy/sell options to see how the results remarkably change in terms of loss or gain. Therefore you are advised. Please do not think to win all the times against the market with this or any other trading strategy you may want to define. Greed is good, yes...however...

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.