Thursday, September 24, 2015

Portfolio trading again

Reworking the trading portfolio procedure

In the previous post, I implemented a trading portfolio procedure able to compute the time evolution of a portfolio as driven by quantmod library model based buy/sell signals. Those signals are determined by a machine learning model build by taking advantage of the quantmod package as well. Two basic elements determine the quantmod model:

  • the formula, binding the desidered forecast to the covariates
  • the method choosen as machine learning algorithm

As a result, the portfolio time evolution is returned as a sequence of buy/hold/sell actions determining gains or losses. However, final portfolio gain/loss percentage is not enough for judging how much our trading model is good or bad. As improvement, I would like to compare its result with that obtained by buy/sell signals driven by well known trading indicators, for example EMA, MACD, RSI. So the key issue is to add capability to our framework to process a buy/sell signal array somehow determined and output the portfolio data frame, as shown in my previous post.

At the purpose, I reworked tradingPortfolio() so that it takes advantage of a new procedure tradingPortfolioWithSignal(). Such latter procedure can also be used for processing an array of buy/sell signals previously computed by whatsoever method.

Herein below my reworked code.

Specifically, here is package loading and two utility functions.

suppressPackageStartupMessages(library(quantmod))

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))
}

Here is new procedure tradePortfolioWithSignal().

tradePortfolioWithSignal <- function(ticker.trade, control, signal) {

  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)
  buy.todo <- buy.first
  sell.todo <- sell.first
  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")
  bought.all <- FALSE

  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[i] == 1 && bought.all == FALSE && 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
          bought.all <- TRUE
      } 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"] <- 
        ifelse(bought.all, 0, 
               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[i] == -1 &&
                 buy.todo == FALSE &&
                 portfolio.df[i-1,"portfolio.Close"] > 0) {
    
      action <- "sell"
      bought.all <- FALSE
      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"]
    }
  }
  
  portfolio.df
}

Here is reworked tradePortfolio() which takes advantage of tradePortfolioWithSignal() by first computing a trading signal based on quantmod library machine learning models.

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)]
  
  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);

  portfolio <- tradePortfolioWithSignal(ticker.trade, control, signal.zoo[,2])
  
  list(portfolio, signal.zoo, fitted.zoo)
}

In my next post, I will introduce an example of comparison between a machine learning based trading portfolio strategy and a basic trading indicator one.

No comments:

Post a Comment

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