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.