I'm using the quantmodpackage. I've got a vector of tickers like this :
c("AAPL","GOOG","IBM","GS","AMZN","GE")
and I want to create a function to calculate the EBIT margin of a stock (= operating income / total revenue). So for a given stock, I use the following piece of code which only works for GE (provided a ".f" is added a the end of the ticker) :
require(quantmod)
getFinancials("GE",period="A")
ebit.margin <- function(stock.ticker.f){
return(stock.ticker$IS$A["Operating Income",]/stock.ticker$IS$A["Total Revenue",])
}
ebit.margin("GE")
I would like to generalize this function in order to use then the applyfunction. There are several difficulties :
when applying the quantmod::getFinancialfunction to a ticker, the financial statements of the stocks are saved in the default environment. The viewFinancialhas then to be used to get and print the financial statements. I need a way to get access to the financial statements directly into the function
The function's argument function is a string like "GE.f" but it would more convenient to enter directly the ticker ("GE"). I've tried to use the paste0 and gsub to get a string like "GE.f" it doesn't work because "GE.f" doesn't belong to the financials class.
To sum up, I'm a bit lost...
It's easier if you use auto.assign=FALSE
s <- c("AAPL","GOOG","IBM","GS","AMZN","GE")
fin <- lapply(s, getFinancials, auto.assign=FALSE)
names(fin) <- s
lapply(fin, function(x) x$IS$A["Operating Income", ] / x$IS$A["Total Revenue",])
#$AAPL
#2012-09-29 2011-09-24 2010-09-25 2009-09-26
# 0.3529596 0.3121507 0.2818704 0.2736278
#
#$GOOG
#2012-12-31 2011-12-31 2010-12-31 2009-12-31
# 0.2543099 0.3068724 0.3540466 0.3514585
#
#$IBM
#2012-12-31 2011-12-31 2010-12-31 2009-12-31
# 0.2095745 0.1964439 0.1974867 0.1776439
#
#$GS
#2012-12-31 2011-12-31 2010-12-31 2009-12-31
#0.2689852 0.1676678 0.2804621 0.3837401
#
#$AMZN
#2012-12-31 2011-12-31 2010-12-31 2009-12-31
#0.01106510 0.01792957 0.04110630 0.04606471
#
#$GE
#2012-12-31 2011-12-31 2010-12-31 2009-12-31
#0.11811969 0.13753327 0.09415548 0.06387029
Anaother option is to laod your tickers in an new environnement.
tickers <- new.env()
s <- c("AAPL","GOOG","IBM","GS","AMZN","GE")
lapply(s, getFinancials,env=tickers)
sapply(ls(envir=tickers),
function(x) {x <- get(x) ## get the varible name
x$IS$A["Operating Income", ] / x$IS$A["Total Revenue",]})
AAPL.f AMZN.f GE.f GOOG.f GS.f IBM.f
2012-09-29 0.3529596 0.01106510 0.11811969 0.2543099 0.2689852 0.2095745
2011-09-24 0.3121507 0.01792957 0.13753327 0.3068724 0.1676678 0.1964439
2010-09-25 0.2818704 0.04110630 0.09415548 0.3540466 0.2804621 0.1974867
2009-09-26 0.2736278 0.04606471 0.06387029 0.3514585 0.3837401 0.1776439
EDIT
No need to use ls, get.... just the handy eapply (thanks #GSee) which applies FUN to the named values from an environment and returns the results as a list
eapply(tickers, function(x)
x$IS$A["Operating Income", ] / x$IS$A["Total Revenue",])
Related
quantmode newbie here,
My end goal is to have a CSV file including monthly stock prices, I've downloaded the data using getSymbols using this code:
Symbols <- c("DIS", "TSLA","ATVI", "MSFT", "FB", "ABT","AAPL","AMZN",
"BAC","NFLX","ADBE","WMT","SRE","T","MS")
Data <- new.env()
getSymbols(c("^GSPC",Symbols),from="2015-01-01",to="2020-12-01"
,periodicity="monthly",
env=Data)
the line above works fine, now I need to create a data frame that only includes the adjusted prices for all the symbols with a data column ofc,
any help, please? :)
Desired output would be something similar to this
enter image description here
Another straightforward way to get your monthly data:
tickers <- c('AMZN','FB','GOOG','AAPL')
getSymbols(tickers,periodicity="monthly")
head(do.call("merge.xts",c(lapply(mget(tickers),"[",,6),all=FALSE)),3)
AMZN.Adjusted FB.Adjusted GOOG.Adjusted AAPL.Adjusted
2012-06-01 228.35 31.10 288.9519 17.96558
2012-07-01 233.30 21.71 315.3032 18.78880
2012-08-01 248.27 18.06 341.2658 20.46477
Note the logical argument all = FALSE is the equivalent of an innerjoin and you get data when all of your stocks have prices. all = TRUE fills data which is not available with NAs (outerjoin).
To write the file you can use:
write.zoo(monthlyPrices,file = 'filename.csv',sep=',',quote=FALSE)
First get your data from the environment:
require(quantmod)
# your code
dat <- mget(ls(Data), env=Data)
Then draw the data from the Objects:
newdat <- as.data.frame(sapply( names(dat), function(x) coredata(dat[[x]])[,1] ))
Note that this takes the Opening values (see: dat[[x]])[,1]), the Objects have more, e.g.:
names(dat[["AAPL"]])
[1] "AAPL.Open" "AAPL.High" "AAPL.Low" "AAPL.Close"
[5] "AAPL.Volume" "AAPL.Adjusted"
Last, get the dates (assumes symmetric dates for all symbols):
rownames(newdat) <- index(dat[["AAPL"]])
# OR, more universal, by extracting from the complete list:
rownames(newdat) <-
as.data.frame( sapply( names(dat), function(x) as.character(index(dat[[x]])) ) )[,1]
head(newdat, 3)
AAPL ABT ADBE AMZN ATVI BAC DIS FB GSPC MS
2015-01-01 27.8475 45.25 72.70 312.58 20.24 17.99 94.91 78.58 2058.90 39.05
2015-02-01 29.5125 44.93 70.44 350.05 20.90 15.27 91.30 76.11 1996.67 33.96
2015-03-01 32.3125 47.34 79.14 380.85 23.32 15.79 104.35 79.00 2105.23 35.64
MSFT NFLX SRE T TSLA WMT
2015-01-01 46.66 49.15143 111.78 33.59 44.574 86.27
2015-02-01 40.59 62.84286 112.38 33.31 40.794 84.79
2015-03-01 43.67 67.71429 108.20 34.56 40.540 83.93
Writing the csv:
write.csv(newdat, "file.csv")
I am looking for a way to rename the columns of several objects with a for loop or other method in R. Ultimately, I want to be able to bind the rows of each Stock object into one large data frame, but cannot due to differing column names. Example below:
AAPL <-
Date AAPL.Open AAPL.High AAPL.Low AAPL.Close AAPL.Volume AAPL.Adjusted Stock pct_change
2020-05-14 304.51 309.79 301.53 309.54 39732300 309.54 AAPL 0.61
2020-05-15 300.35 307.90 300.21 307.71 41561200 307.71 AAPL -0.59
GOOG <-
Date GOOG.Open GOOG.High GOOG.Low GOOG.Close GOOG.Volume GOOG.Adjusted Stock pct_change
2020-05-14 1335.02 1357.420 1323.910 1356.13 1603100 1356.13 GOOG 0.50
2020-05-15 1350.00 1374.480 1339.000 1373.19 1705700 1373.19 GOOG 1.26
For this example I have 2 objects (AAPL and GOOG), but realistically I would be working with many more. Can I create a for loop to iterate through each object, and rename the 2nd column of each to "Open", 3rd column to "High", 4th column to "Low",.... etc so I can then bind all these objects together?
I already have a column named "Stock", so I do not need the Ticker part of the column name.
Using quantmod we can read a set of stock ticker symbols, clean their names & rbind() into a single data frame.
There are three key features illustrated within this answer, including:
Use of get() to access the objects written by quantmod::getSymbols() once they are loaded into memory.
Use of the symbol names passed into lapply() to add a symbol column to each data frame.
Conversion of the dates stored as row names in the xts objects written by getSymbols() to a data frame column.
First, we'll use getSymbols() to read data from yahoo.com.
library(quantmod)
from.dat <- as.Date("12/02/19",format="%m/%d/%y")
to.dat <- as.Date("12/06/19",format="%m/%d/%y")
theSymbols <- c("AAPL","AXP","BA","CAT","CSCO","CVX","XOM","GS","HD","IBM",
"INTC","JNJ","KO","JPM","MCD","MMM","MRK","MSFT","NKE","PFE","PG",
"TRV","UNH","UTX","VZ","V","WBA","WMT","DIS","DOW")
getSymbols(theSymbols,from=from.dat,to=to.dat,src="yahoo")
# since quantmod::getSymbols() writes named data frames, need to use
# get() with the symbol names to access each data frame
head(get(theSymbols[[1]]))
> head(get(theSymbols[[1]]))
AAPL.Open AAPL.High AAPL.Low AAPL.Close AAPL.Volume AAPL.Adjusted
2019-12-02 267.27 268.25 263.45 264.16 23621800 262.8231
2019-12-03 258.31 259.53 256.29 259.45 28607600 258.1370
2019-12-04 261.07 263.31 260.68 261.74 16795400 260.4153
2019-12-05 263.79 265.89 262.73 265.58 18606100 264.2359
Having illustrated how to access the symbol objects in the global environment, we'll use lapply() to extract the dates from the row names, clean the column headings, and write the symbol name as a column for each symbol's data object.
# convert to list
symbolData <- lapply(theSymbols,function(x){
y <- as.data.frame(get(x))
colnames(y) <- c("open","high","low","close","volume","adjusted")
y$date <- rownames(y)
y$symbol <- x
y
})
Finally, we convert the list of data frames to a single data frame.
#combine to single data frame
combinedData <- do.call(rbind,symbolData)
rownames(combinedData) <- 1:nrow(combinedData)
...and the output:
> nrow(combinedData)
[1] 120
> head(combinedData)
open high low close volume adjusted date symbol
1 267.27 268.25 263.45 264.16 23621800 262.8231 2019-12-02 AAPL
2 258.31 259.53 256.29 259.45 28607600 258.1370 2019-12-03 AAPL
3 261.07 263.31 260.68 261.74 16795400 260.4153 2019-12-04 AAPL
4 263.79 265.89 262.73 265.58 18606100 264.2359 2019-12-05 AAPL
5 120.31 120.36 117.07 117.26 5538200 116.2095 2019-12-02 AXP
6 116.04 116.75 114.65 116.57 3792300 115.5256 2019-12-03 AXP
>
If you can guarantee the order of these columns this should do it:
for(df in list(AAPL, GOOG))
colnames(df) <- c("Date", "Open", "High", "Low", "Close", "Volume", "Adjusted", "Stock", "pct_change")
With lapply, we can loop over the list and remove the prefix in the column names with sub. This can be done without any external packages
lst1 <- lapply(list(AAPL, GOOG), function(x) {
colnames(x) <- sub(".*\\.", "", colnames(x))
x})
I am downloading some data using R package tseries,
require('tseries')
tickers<- c('JPM','AAPL','MSFT','FB','GE');
prices = matrix(NA,nrow=40,ncol=6)
startdate<-'2015-02-02'
enddate<-'2015-03-30'# 40 rows dim()
for(i in 1:5){
prices[,i]<-get.hist.quote(
instrument=tickers[i],
start=startdate,
end=enddate,
quote='AdjClose',
provider='yahoo')
}
colnames(prices)<-c('JPM','AAPL','MSFT','FB','GE');
I want to construct a matrix saving the adjclose price and date information, but I don't know how to access the zoo date column, say when I construct a zoo object using get.hist.quote(), I can view the object like this
But when I save them to matrix, the date column is missing
Here Map applied to get.hist.quote will create a zoo object for each ticker. Then we use zoo's multiway merge.zoo to merge them all together creating a final zoo object prices:
prices <- do.call(merge,
Map(get.hist.quote, tickers,
start=startdate,
end=enddate,
quote='AdjClose',
provider='yahoo')
)
I would probably keep all the series in a zoo object. This can be done like in the following code, thereby also avoiding your for-loop etc. You can always convert this object to a matrix by as.matrix() afterwards.
prices <-lapply(tickers, get.hist.quote, start=startdate, end=enddate, quote='AdjClose')
prices <- Reduce(cbind, prices)
names(prices) <- tickers
prices <- as.matrix(prices)
head(prices)
JPM AAPL MSFT FB GE
2015-02-02 55.10 118.16 40.99 74.99 23.99
2015-02-03 56.35 118.18 41.31 75.40 24.25
2015-02-04 56.01 119.09 41.54 75.63 23.94
2015-02-05 56.40 119.94 42.15 75.61 24.28
2015-02-06 57.51 118.93 42.11 74.47 24.30
2015-02-09 57.44 119.72 42.06 74.44 24.42
I'm trying to apply a function to a column in a dataframe that contains dates and keep getting an error. I'm not exactly sure what I'm doing wrong.
My dataframe:
dates total
1 2014-12-08 01:10:00 163.7
2 2014-12-08 01:10:00 163.9
3 2014-12-08 01:12:00 163.6
4 2014-12-08 08:27:00 163.0
5 2014-12-08 08:35:00 163.7
6 2014-12-08 08:39:00 162.4
I want to replace the dates by either 'morning' or 'night' or alternatively created a new column with 'morning' or 'night'. the approach that i took involved unclassing the date so i could get the hour. I defined a night as before 4am or after 5pm. I put this in a function called timeofday:
timeofday <- function(x) {
bmk <- unclass(x)
if (bmk$hour < 4) {
return("night")
} else if (bmk$hour > 17) {
return("night")
} else {
return("morning")
}
}
I then did the following:
timeofday(df$dates)
Warning message:
In if (bmk$hour < 4) { :
the condition has length > 1 and only the first element will be used
Any help on identifying the issue would be greatly appreciated.
you could also use cut as in:
cut(unclass(x)$hour-7,c(0,15,24)-8,c('night','morning'))
(note that you have to shift your frame of reference so that you don't have two 'night' categories with this solution)
Your code contains this if statement
if (bmk$hour < 4)
If bmk is a vector, like in your case, you have an if statement containing a vector and therefore it will take account of the first element of the vector only.
This is the workaround
sapply(df$dates, timeofday)
I am having trouble deleting duplicated rows in an xts object. I have a R script that will download tick financial data of a currency and convert it to an xts object of OHLC format. The script also pulls new data every 15 minutes. The new data is downloaded from the first trade of today to the last recorded trade of today. The old previous data downloaded was stored in .Rdata format and called. Then the new data is added to the old data and it overwrites the old data in .Rdata format.
Here is an example of what my data looks like:
.Open .High .Low .Close .Volume .Adjusted
2012-01-07 00:00:11 6.69683 7.01556 6.38000 6.81000 48387.58 6.81000
2012-01-08 00:00:09 6.78660 7.20000 6.73357 7.11358 57193.53 7.11358
2012-01-09 00:00:57 7.08362 7.19100 5.81000 6.32570 148406.85 6.32570
2012-01-10 00:01:01 6.32687 6.89000 6.00100 6.36000 110210.25 6.36000
2012-01-11 00:00:07 6.44904 7.13800 6.41266 6.90000 99442.07 6.90000
2012-01-12 00:01:02 6.90000 6.99700 6.33700 6.79999 140116.52 6.79999
2012-01-13 00:02:01 6.78211 6.80400 6.40000 6.41000 60228.77 6.41000
2012-01-14 00:00:23 6.42000 6.50000 6.23150 6.31894 25392.98 6.31894
Now if I run the script again I will add the new data to the xts.
.Open .High .Low .Close .Volume .Adjusted
2012-01-07 00:00:11 6.69683 7.01556 6.38000 6.81000 48387.58 6.81000
2012-01-08 00:00:09 6.78660 7.20000 6.73357 7.11358 57193.53 7.11358
2012-01-09 00:00:57 7.08362 7.19100 5.81000 6.32570 148406.85 6.32570
2012-01-10 00:01:01 6.32687 6.89000 6.00100 6.36000 110210.25 6.36000
2012-01-11 00:00:07 6.44904 7.13800 6.41266 6.90000 99442.07 6.90000
2012-01-12 00:01:02 6.90000 6.99700 6.33700 6.79999 140116.52 6.79999
2012-01-13 00:02:01 6.78211 6.80400 6.40000 6.41000 60228.77 6.41000
2012-01-14 00:00:23 6.42000 6.50000 6.23150 6.31894 25392.98 6.31894
2012-01-14 00:00:23 6.42000 6.75000 6.22010 6.57157 75952.01 6.57157
As you can see the last line is the same day as the second to last line. I want to keep the last row for the last date and delete the second to last row. When I try the following code to delete duplicated rows it does not work, the duplicated rows stay there.
xx <- mt.xts[!duplicated(mt.xts$Index),]
xx
.Open .High .Low .Close .Volume .Adjusted
I do not get any result. How can I delete duplicate data entries in an xts object using the Index as the indicator of duplication?
Should't it be index(mt.xts) rather than mt.xts$Index?
The following seems to work.
# Sample data
library(xts)
x <- xts(
1:10,
rep( seq.Date( Sys.Date(), by="day", length=5 ), each=2 )
)
# Remove rows with a duplicated timestamp
y <- x[ ! duplicated( index(x) ), ]
# Remove rows with a duplicated timestamp, but keep the latest one
z <- x[ ! duplicated( index(x), fromLast = TRUE ), ]
In my case,
x <- x[! duplicated( index(x) ),]
did not work as intended, because the system somehow makes date-time unique in each row.
x <- x[! duplicated( coredata(x) ),]
This may work if the previous solution did not help.