Select tickers, get prices, choose numbers of shares to purchase
options(warn=-1)
options("getSymbols.warning4.0"=FALSE)
# 1.
getPrices <- function(tickers,
as.of.dates=seq(from=as.Date("2007-01-01"),
to=Sys.Date(),
by="day"),
src="yahoo",
api.key=NULL){
# Get closing prices for a vector of tickers
# Catch the special ticker "CASHX" and handle carefully
# Args:
# tickers: character vector of ticker symbols
# as.of.dates: date, or a vector of dates
# src: "yahoo", "av", or "tiingo"
# api.key: character string required if src="av" or src="tiingo"
# Returns:
# xts object of closing prices at the given dates
# Depends on:
# getSymbols and Cl functions from package 'quantmod'
# if src="av" or src="tiingo", then package 'jsonlite' is also required
print("Getting prices...")
myPrices <- NULL
for (tkr in tickers) {
print(tkr)
if (tkr != "CASHX") {
# HACK! getSymbols appears to have a bug when src="yahoo" is used.
# The argument "to" evidently must be one day later than the last desired day!
tmp <- getSymbols(
tkr,
from=as.of.dates[1],
to=(as.Date(tail(as.of.dates, 1)) + 1),
src=src,
api.key=api.key,
return.class="xts",
auto.assign=FALSE)
tmp <- tmp[as.of.dates, ] # Extract desired dates
tmp <- Cl(tmp) # Extract closing prices only
index(tmp) <- as.Date(index(tmp)) # To fix a wierdness when using src="tiingo"
}
else { # Add a column for CASHX
tmp <- as.xts(rep(1.0, length(as.of.dates)), as.Date(as.of.dates))
}
myPrices <- cbind(myPrices, tmp)
}#end for
colnames(myPrices) <- tickers
return(myPrices)
}#end getPrices
library(quantmod)
myTickers <- c("WMT", "COST", "TGT", "M", "WDAY", "XPO", "GPN", "CMCSA", "DFS", "T", "DPZ",
"V", "AWK", "MRK", "ADP", "ATUS", "L", "ORCL", "PVH", "ATVI", "CASHX")
as.of.dates <- c("2020-03-27", "2020-04-03")
myPrices <- getPrices(myTickers, as.of.dates)
print(myPrices)
Simply put the maximum 5% in cash reserve, and equally distribute the rest funds to each of the 20 stocks.
((1e6*0.95)/20)/myPrices['2020-03-27']
shares = c(434, 167, 501, 8590, 349, 898, 328, 1374, 1237, 1592,
140, 294, 393, 662, 362, 2117, 1409, 953, 1250, 834)
equityValue = sum(shares * head(as.numeric(myPrices['2020-03-27']), -1))
leftCash = 1e6 - equityValue
leftCash
myShares = c(shares, leftCash)
sum(myShares * myPrices['2020-03-27'])
transCost = 0.0010*equityValue
transCost
cashReserve = leftCash - transCost
cashReserve
myShares = c(shares, cashReserve)
myShares
totalValue = sum(myShares*myPrices['2020-03-27'])
totalValue
writeHoldings <- function(account.name, as.of.date, tickers, num.shares){
# Write holdings to a csv file named like "H-uwid-2020-03-27.csv"
# Args:
# account.name: account identifier
# as.of.date: date of the holdings, ccyy-mm-dd format
# tickers: character vector of ticker symbols
# num.shares: numeric vector of numbers of shares
# Returns:
# data frame containing the columns written to the file
# Make a data frame
holdings <- data.frame(
ticker = tickers,
num.shares = num.shares,
stringsAsFactors = FALSE)
# Compose the file name
filename <- paste("H-", account.name, "-", as.Date(as.of.date), ".csv", sep="")
# Write to a file
write.csv(holdings, file=filename, row.names=FALSE)
return(holdings)
}#end writeHoldings
# Example of use
uwid <- "hzcfrm"
aDate <- "2020-03-27"
tmp <- writeHoldings(uwid, aDate, myTickers, myShares)
# To save the data frame in your workspace, give it unique name
assign("holdings.0327", tmp)
holdings.0327
# Checking there are 20 equity securities
length(myTickers) - 1
# Checking the maximum weight in any secuirity is 20% and the maximum weight left in cash is 5%
print(mean(head(as.numeric(myShares*myPrices['2020-03-27']), -1) < 0.2*totalValue) == 1)
print(tail(as.numeric(myShares*myPrices['2020-03-27']), 1) < 0.05*totalValue)
# 2. Calculating transition period return
transReturn = ((sum(myShares * myPrices['2020-03-27'])/1e6) - 1) * 100
transReturn
getSplitfactors <- function(tkr,
as.of.dates=seq(from=as.Date("2007-01-01"),
to=Sys.Date(),
by="day"),
src="yahoo",
api.key=NULL){
# Get cumulative split factors between dates
# Args:
# tkr: a character ticker symbol
# as.of.dates: a vector of two or more dates
# src: only "yahoo" is valid at present
# api.key: character string required if src="av" or src="tiingo" (not valid at present)
# Returns:
# xts object of cumulative split factors between the given dates
# Depends on:
# getSplits function from package 'quantmod'
print(paste("Getting split factors for ticker", tkr, sep=" "))
splitfactors <- 1
for (t in 2:length(as.of.dates)){
# HACK! getSplits appears to have a bug when src="yahoo" is used.
# The argument 'to' evidently must be one day later than the last desired day!
splits <- getSplits(tkr,
from=(as.Date(as.of.dates[t - 1]) + 1),
to=as.Date(as.of.dates[t]) + 1,
src=src,
api.key=api.key,
return.class="xts",
auto.assign=FALSE)
splits.cum <- prod(splits)
if (is.na(splits.cum)){
splits.cum <- 1
}
splitfactors <- c(splitfactors, splits.cum)
}#end for
splitfactors.xts <- as.xts(splitfactors, as.Date(as.of.dates))
colnames(splitfactors.xts) <- tkr
return(splitfactors.xts)
}#end getSplitfactors
# With getSplitfactors, the dates are aligned
splitfactors <- NULL
for (tkr in myTickers){
if (tkr != "CASHX"){
# Get split factors
tkrtmp <- getSplitfactors(tkr, as.of.dates)
splitfactors <- cbind(splitfactors, tkrtmp)
}
}
# Add a column for CASHX
colnames(tkrtmp) <- "CASHX"
tkrtmp[ , "CASHX"] <- 1.0
splitfactors <- cbind(splitfactors, tkrtmp)
print(splitfactors)
getDivpershare <- function(tkr,
as.of.dates=seq(from=as.Date("2007-01-01"),
to=Sys.Date(),
by="day"),
src="yahoo",
api.key=NULL){
# Get cumulative dividend per share between dates
# Args:
# tkr: a character ticker symbol
# as.of.dates: a vector of two or more dates
# src: only "yahoo" is valid at present
# api.key: character string required if src="av" or src="tiingo" (not valid at present)
# Returns:
# xts object of cumulative dividend per share between the given dates
# Depends on:
# getDividends function from package 'quantmod'
print(paste("Getting dividends per share for ticker", tkr, sep=" "))
divps <- 0
for (t in 2:length(as.of.dates)){
# HACK! getDividends appears to have a bug when src="yahoo" is used.
# The argument 'to' evidently must be one day later than the last desired day!
# ALSO: Sometimes a result is returned for a date one day before the 'from' day!
# To be safe, the 'from' day is advanced by two.
# If as.of.dates[t - 1] is a Friday, then as.Date(as.of.dates[t - 1]) + 2 is a Sunday.
div <- getDividends(tkr,
from=(as.Date(as.of.dates[t - 1]) + 2),
to=(as.Date(as.of.dates[t]) + 1),
src=src,
api.key=api.key,
return.class="xts",
auto.assign=FALSE)
div.cum <- sum(div)
if (is.na(div.cum)){
div.cum <- 0
}
divps <- c(divps, div.cum)
}#end for
divps.xts <- as.xts(divps, as.Date(as.of.dates))
colnames(divps.xts) <- tkr
return(divps.xts)
}#end getDivpershare
# With getDivpershare, the dates are aligned
divps <- NULL
for (tkr in myTickers){
if (tkr != "CASHX"){
# Get dividend per share
tkrtmp <- getDivpershare(tkr, as.of.dates)
divps <- cbind(divps, tkrtmp)
}
}
# Add a column for CASHX
colnames(tkrtmp) <- "CASHX"
tkrtmp[ , "CASHX"] <- 0.0
divps <- cbind(divps, tkrtmp)
print(divps)
# Calculate the dividend amount for CMCSA
divCMCSA = as.numeric(divps['2020-04-03', 'CMCSA']*holdings.0327[holdings.0327$ticker=='CMCSA', 'num.shares'])
divCMCSA
# Account for the dividend amount by adjusting liquidty reserve
holdings.0327[holdings.0327$ticker=='CASHX', 'num.shares'] = holdings.0327[holdings.0327$ticker=='CASHX',
'num.shares']+divCMCSA
holdings.0327[holdings.0327$ticker=='CASHX', 'num.shares']
# Updated holdings dataframe
holdings.0327
# Also modify the myShares
myShares[length(myShares)] = tail(myShares, 1) + divCMCSA
tail(myShares, 1)
mgmtFee = (sum(myShares * myPrices['2020-04-03']))*0.0002
mgmtFee
# Account for weekly management fee by adjusting liquidty reserve
holdings.0327[holdings.0327$ticker=='CASHX', 'num.shares'] = holdings.0327[holdings.0327$ticker=='CASHX',
'num.shares'] - mgmtFee
holdings.0327[holdings.0327$ticker=='CASHX', 'num.shares']
holdings.0327
# Also modify myShares
myShares[length(myShares)] = tail(myShares, 1) - mgmtFee
tail(myShares, 1)
# Trade 1: Buying 100 shares of WMT
myShares[1] = head(myShares, 1) + 100
myShares[length(myShares)] = tail(myShares, 1) - 100*myPrices['2020-04-03', 'WMT']*(1 + 0.0010)
myShares
# Trade 2: Selling 1000 shares of M
myShares[4] = myShares[4] - 1000
myShares[length(myShares)] = tail(myShares, 1) + 1000*myPrices['2020-04-03', 'M']*(1 - 0.0010)
myShares
# Checking the maximum weight in any secuirity is 20% and the maximum weight left in cash is 5%
print(mean(head(as.numeric(myShares*myPrices['2020-04-03']), -1) < 0.2*sum(myShares*myPrices['2020-04-03'])) == 1)
print(tail(as.numeric(myShares*myPrices['2020-04-03']), 1) < 0.05*sum(myShares*myPrices['2020-04-03']))
# Write a holdings file
aDate <- "2020-04-03"
tmp <- writeHoldings(uwid, aDate, myTickers, myShares)
assign("holdings.0403", tmp)
# Caculating income return
iR = (divCMCSA/sum(holdings.0327$num.shares * myPrices['2020-03-27'])) * 100
iR
# Calculating price return
pR = ((sum(holdings.0403$num.shares * myPrices['2020-04-03']) - divCMCSA)/
sum(holdings.0327$num.shares * myPrices['2020-03-27'])- 1) * 100
pR
# Calculating total return
tR = (sum(holdings.0403$num.shares * myPrices['2020-04-03'])/
sum(holdings.0327$num.shares * myPrices['2020-03-27']) - 1) * 100
tR
writeAccountSummary <- function(account.name, as.of.dates, deposits, withdrawals,
dividends, fees, tc, values,
income.returns, price.returns, total.returns) {
# Write an account summary file in .csv format named like "A-uwid-2020-04-03.csv"
# Args:
# account.name: account identifier
# as.of.dates: vector of dates, ccyy-mm-dd format
# deposits: numeric vector of deposit amounts
# withdrawals: numeric vector of withdrawal amounts
# dividends: numeric vector of dividend amounts
# fees: numeric vector of fee amounts
# tc: numeric vector of transaction cost amounts
# values: numeric vector of account values
# income.returns: numeric vector of period income returns between dates
# price.returns: numeric vector of period price returns between dates
# total.returns: numeric vector of period total returns between dates
# Returns:
# data frame containing the columns written to the file
numDates <- length(as.of.dates)
# Make a data frame
AccountSummary <- data.frame(
account.name = rep(account.name, numDates),
as.of.date = as.of.dates,
deposits = deposits,
withdrawals = withdrawals,
dividends = dividends,
fees = fees,
tc = tc,
value = values,
income.return = income.returns,
price.return = price.returns,
total.return = total.returns,
stringsAsFactors = FALSE)
# Compose the file name
filename <- paste("A-", account.name, "-", tail(as.of.dates, 1), ".csv", sep="")
# Write to a file
write.csv(AccountSummary, file=filename, row.names=FALSE)
return(AccountSummary)
}#end writeAccountSummary
# Example of use
uwid <- "hzcfrm"
dates <- c("2020-03-27", "2020-04-03")
deposits <- c(1000000, 0)
withdrawals <- c(0, 0)
dividends <- c(0, divCMCSA)
fees <- c(0, mgmtFee)
tc <- c(transCost, (100*myPrices['2020-04-03', 'WMT'] + 1000*myPrices['2020-04-03', 'M'])*0.0010)
values <- c(sum(holdings.0327$num.shares * myPrices['2020-03-27']),
sum(holdings.0403$num.shares * myPrices['2020-04-03']))
incomereturns <- c(0, iR)
pricereturns <- c(transReturn, pR)
totalreturns <- c(transReturn, tR)
tmp <- writeAccountSummary(uwid, dates, deposits, withdrawals, dividends, fees, tc, values,
incomereturns, pricereturns, totalreturns)
# To save the data frame in your workspace, give it unique name
assign('summary.0403', tmp)
summary.0403