# R programs to use for Math/Econ 565 class # Fall 2017 at American University John Nolan jpnolan@american.edu # Revised 6/19/2024 to read data from Yahoo finance # as described in https://www.datasciencecentral.com/getting-historical-data-from-yahoo-finance-in-r/ # Dates are in (year,month,day) format, e.g. c(2023,12,31) is December31, 2023 with most recent data first ########################################################################################## get.stock.price <- function( symbol, start.date, stop.date, full.table=FALSE, print.info=TRUE ) { # gets stock price data from Google Finance for specifed symbol # default is to return ADJUSTED closing price if( print.info ) cat(symbol," ") t1 <- ISOdate(start.date[1],start.date[2],start.date[3],hour=0) t2 <- ISOdate(stop.date[1],stop.date[2],stop.date[3],hour=24) url <- paste("https://query1.finance.yahoo.com/v7/finance/download/", symbol, "?period1=", as.integer(t1), "&period2=", as.integer(t2), "&interval=1d&events=history", sep="") # changed from Yahoo Finance (who apparently stopped supporting this) to Google Finance 6 Oct 2017 #url <- paste("http://finance.google.com/finance/historical?q=",symbol, # "&startdate=",paste(start.date,collapse="-"),"&enddate=",paste(stop.date,collapse="-"), # "&output=csv",sep="") #cat("url=",url,"\n\n") x <- read.csv(url) # in S-Plus, use read.table(url,sep=","), but note that it treats # the dates as row labels, not a separate column # data has most recent days first, going back to start date n <- length(x$Date) date <- as.character(x$Date[c(1,n)]) if (print.info) cat("has", n,"values from",date[1],"to",date[2],"\n") # data comes back in reverse order, starting with most recent. # reverse the order if (full.table) { # return full table return( x ) } else return(x$Adj.Close) # return just the closing prices } ########################################################################################## get.portfolio.returns = function( symbols, start.date, stop.date ){ # get a table (data.frame) of values for a list of stocks in the stated time period n = length(symbols) for (i in 1:n) { t1 = get.stock.price( symbols[i], start.date=start.date, stop.date=stop.date,full.table=T) # need to merge columns, possibly with mismatching dates a = data.frame(t1$Date,t1$Close) names(a) = c("Date",symbols[i]) if (i == 1) {b=a} else {b = merge(b,a,sort=FALSE)} } # leave off the date column nn = dim(b)[1] cat(" ",nn,"dates with values for all stocks,",nn-1,"returns calculated\n") b = b[,2:ncol(b)] bb = data.frame(apply(b,2,"log.ratio")) names(bb) = symbols return(bb) } ########################################################################################## log.ratio <- function(x) { return(diff(log(x))) } ########################################################################################## trimmed.hist <- function(x,low=-Inf,high=+Inf,nclass=20,...) { # histogram with data in x "trimmed" to exclude values below "low" or above "high" # useful to see a histogram of data that is visually distorted by extreme values y <- x[ (x > low) & (x < high) ] hist(y,nclass=nclass,...) cat("original data had",length(x),"values, trimmed data has",length(y),"values\n") invisible(y)} ########################################################################################## # four plots on one window, use some color and show histogram of returns with normal fit plot.basics <- function( symbol, start.date, stop.date ){ all <- get.stock.price(symbol,start.date=start.date,stop.date=stop.date,full.table=TRUE) xx <- all$Close yy <- log.ratio(xx) par(mfrow=c(2,2)) # start a new graph window with 4 plot areas plot(xx,type='l',main=paste(symbol," price\n", start.date[1],"/",start.date[2],"/",start.date[3], " to ",stop.date[1],"/",stop.date[2],"/",stop.date[3],sep=""), col='blue', xlab="day",ylab="price") plot(yy,type='l',main="return",col='blue',xlab="day",ylab="return") plot(all$Volume,type='l',col='blue',xlab="day",ylab="",main="Volume") bnds <- max(abs(yy))*c(-1,1) hist(yy,prob=TRUE,main="histogram of returns",col='blue',xlim=bnds,xlab='return',nclass=50) mu <- mean(yy); s <- sd(yy) cat("normal fit: mean=",mu," std. dev=",s,"\n") z <- seq(bnds[1],bnds[2],length=101) w <- dnorm(z,mean=mean(yy),sd=sd(yy)) lines(z,w,type='l', xlab="return",ylab="",col='red',lwd=2 ) text(0.6*bnds[2],max(w)/2,"normal fit",col='red') return() } ########################################################################################## cat("Finance tools for R - Math 565/Econ 565 Fall 2017, American University\n") # simple test - retrieve price of Google stock for January 2024 get.stock.price( "GOOG", start.date=c(2024,1,1), stop.date=c(2024,1,31) ) # plot of price, return, volume and histogram of returns plot.basics( "GOOG", start.date=c(2023,1,1), stop.date=c(2023,11,31) ) # get returns for a portfolio with 3 stocks: Google, Ford, IBM for January 2024 get.portfolio.returns( symbols=c("GOOG", "Ford", "IBM"), start.date=c(2024,1,1), stop.date=c(2024,1,31))