Getting data of multiple stocks into one xts object - r

I'm trying to get all the price data of DJIA components and combine them into a single dataframe, then export it to a .csv file.
This is what I have currently, but I'm not sure how to proceed.
# dates
fr <- '2010-01-01'
to <- '2022-01-01'
DJIA_list <- c("MMM", "AXP", "AAPL", "BA", "CAT", "CVX", "CSCO", "KO", "DOW", "XOM",
"GS", "HD", "INTC", "IBM", "JNJ", "JPM", "MCD", "MRK", "MSFT","NKE",
"PFE", "PG", "RTX", "TSLA", "TRV", "UNH", "VZ", "V", "WBA", "WMT")
count <- 1
# Getting adjusted prices of assets
for (i in DJIA_list){
asset <- getSymbols(i, src = 'yahoo', from = as.Date(fr), to = as.Date(to), auto.assign = FALSE)
assign(paste0("var_", i), asset[,6])
count <- count + 1
}
I now have a bunch of xts objects named like var_MMM, var_AAPL etc... Not sure how best to deal with them next. I tried to install the qmao add-on but it didn't work for me either.

This is how you would do it with quantmod working with just xts objects
library(quantmod)
fr <- '2010-01-01'
to <- '2022-01-01'
DJIA_list <- c("MMM", "AXP", "AAPL") # extend after testing to the symbols you desire
mktdata <- new.env()
getSymbols(DJIA_list, env = mktdata, from = fr, to = to)
out <- eapply(mktdata, Ad)
out <- do.call(merge, out) # can combine with the above line if you understand what eapply() is doing)
#xts is a zoo object, so can use the write.zoo handler to write to .csv in the format of a data.frame
write.zoo(out, "dj.csv")

You can get the price data easily with the tidyquant library.
library(tidyquant)
#> Loading required package: lubridate
#>
#> Attaching package: 'lubridate'
#> The following objects are masked from 'package:base':
#>
#> date, intersect, setdiff, union
#> Loading required package: PerformanceAnalytics
#> Loading required package: xts
#> Loading required package: zoo
#>
#> Attaching package: 'zoo'
#> The following objects are masked from 'package:base':
#>
#> as.Date, as.Date.numeric
#>
#> Attaching package: 'PerformanceAnalytics'
#> The following object is masked from 'package:graphics':
#>
#> legend
#> Loading required package: quantmod
#> Loading required package: TTR
#> Registered S3 method overwritten by 'quantmod':
#> method from
#> as.zoo.data.frame zoo
#> == Need to Learn tidyquant? ====================================================
#> Business Science offers a 1-hour course - Learning Lab #9: Performance Analysis & Portfolio Optimization with tidyquant!
#> </> Learn more at: https://university.business-science.io/p/learning-labs-pro </>
library(tidyverse)
DJIA_list <- c("MMM", "AXP", "AAPL", "BA", "CAT", "CVX", "CSCO", "KO", "DOW", "XOM",
"GS", "HD", "INTC", "IBM", "JNJ", "JPM", "MCD", "MRK", "MSFT","NKE",
"PFE", "PG", "RTX", "TSLA", "TRV", "UNH", "VZ", "V", "WBA", "WMT")
stock_prices <- tq_get(DJIA_list,
get = "stock.prices",
from = "2010-01-01",
to = "2022-01-01")
#> Registered S3 method overwritten by 'tune':
#> method from
#> required_pkgs.model_spec parsnip
stock_prices %>%
select(date, symbol, adjusted) %>%
pivot_wider(names_from = symbol,
values_from = adjusted) %>%
tail()
#> # A tibble: 6 x 31
#> date MMM AXP AAPL BA CAT CVX CSCO KO DOW XOM GS
#> <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 2021-12-23 175. 164. 176. 204. 206. 116. 61.9 58.2 55.1 61.0 385.
#> 2 2021-12-27 177. 164. 180. 203. 206. 119. 63.0 58.7 55.9 61.9 388.
#> 3 2021-12-28 178. 164. 179. 206. 207. 119. 63.2 58.9 56.6 61.7 388.
#> 4 2021-12-29 178. 163. 179. 204. 207. 118. 63.6 59.0 57.1 61.2 386.
#> 5 2021-12-30 178. 164. 178. 203. 206. 117. 63.2 58.8 56.8 60.8 386.
#> 6 2021-12-31 178. 163. 178. 201. 207. 117. 63.0 59.2 56.7 61.2 383.
#> # ... with 19 more variables: HD <dbl>, INTC <dbl>, IBM <dbl>, JNJ <dbl>,
#> # JPM <dbl>, MCD <dbl>, MRK <dbl>, MSFT <dbl>, NKE <dbl>, PFE <dbl>,
#> # PG <dbl>, RTX <dbl>, TSLA <dbl>, TRV <dbl>, UNH <dbl>, VZ <dbl>, V <dbl>,
#> # WBA <dbl>, WMT <dbl>
Created on 2022-01-14 by the reprex package (v2.0.1)

Related

Why are daily returns all zeros using Quantmod?

I used the following code:
getSymbols(c("TSLA", "AAPL", "CSCO", "IBM"))
tsla<-TSLA['2022-01-03::2023-01-03']
aapl=AAPL['2022-01-03::2023-01-03']
csco=CSCO['2022-01-03::2023-01-03']
ibm=IBM['2022-01-03::2023-01-03']
tsla<-tsla$TSLA.Adjusted
aapl<-aapl$AAPL.Adjusted
csco<-csco$CSCO.Adjusted
ibm<-ibm$IBM.Adjusted
stkdata=cbind(tsla, aapl, csco, ibm)
n<-length(stkdata[,1])
rets<-log(stkdata[2:n,]/stkdata[1:(n-1),])
It produces all zeros.
After I assigned stkdata[2:n] to x and stkdata[1:n-1] to y, R shows
x[1,]
TSLA.Adjusted AAPL.Adjusted CSCO.Adjusted IBM.Adjusted
2022-01-04 383.1967 178.3907 59.26239 129.9028
y[1,]
TSLA.Adjusted AAPL.Adjusted CSCO.Adjusted IBM.Adjusted
2022-01-03 399.9267 180.6839 60.75242 128.0392
This is fine. But
x[1,]/y[1,]
Data:
numeric(0)
Index:
Date of length 0
What could be the problem? Thanks ahead!
This behavior is expected because arithmetic and logical operations on xts objects are done on observations that have the same date.
You should use the lag() function to change the datetime index alignment. log(stkdata / lag(stkdata)).
Note that you have to be very careful using lag() with dplyr loaded. It breaks how base R's lag() function is supposed to work, which breaks lag(my_xts). It also breaks lag() on all other types of objects that have their own lag() method (e.g. zoo).
1) getSymbols can place the results into a local environment and then we can iterate over its elements using eapply. Then use diff with arithmetic=FALSE causing diff to perform division rather than subtraction.
If x is the ratio of the current price to the prior price then
while it is true that log(x) approximately equals x-1 if the return is small we don't really need to use that approximation and can calculate the return exactly using x-1.
Regarding the question, xts objects do not combine by position but by time. Removing the first or last element of an xts object does not change the times so the code in the question is dividing stkdata by itself except for the positions on the end which have been removed.
Try the code below.
library(quantmod)
tickers <- c("TSLA", "AAPL", "CSCO", "IBM")
getSymbols(tickers, env = e <- new.env(), from = "2022-01-03", to = "2023-01-03")
stks <- do.call("merge", eapply(e, Ad))
rets <- diff(stks, arithmetic = FALSE) - 1
2) A variation is to use getSymbols to load the data into the current R workspace, as in the question, and then use mget.
library(quantmod)
tickers <- c("TSLA", "AAPL", "CSCO", "IBM")
getSymbols(tickers, from = "2022-01-03", to = "2023-01-03")
stks <- do.call("merge", lapply(mget(tickers), Ad))
rets <- diff(stks, arithmetic = FALSE) - 1
With tidyquant you can calculate daily log returns as such:
library(tidyquant)
library(tidyverse)
df = tq_get(c("TSLA", "AAPL", "CSCO", "IBM"),
from = "2022-01-03",
to = "2023-01-04")
log_return = df %>%
group_by(symbol) %>%
tq_mutate(select = adjusted,
mutate_fun = periodReturn,
period = "daily",
type = "log",
col_rename = "log_returns")
# A tibble: 1,008 × 9
# Groups: symbol [4]
symbol date open high low close volume adjusted log_returns
<chr> <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 TSLA 2022-01-03 383. 400. 379. 400. 103931400 400. 0
2 TSLA 2022-01-04 397. 403. 374. 383. 100248300 383. -0.0427
3 TSLA 2022-01-05 382. 390. 360. 363. 80119800 363. -0.0550
4 TSLA 2022-01-06 359 363. 340. 355. 90336600 355. -0.0218
5 TSLA 2022-01-07 360. 360. 337. 342. 84164700 342. -0.0361
6 TSLA 2022-01-10 333. 353. 327. 353. 91815000 353. 0.0299
7 TSLA 2022-01-11 351. 359. 346. 355. 66063300 355. 0.00592
8 TSLA 2022-01-12 360. 372. 358. 369. 83739000 369. 0.0385
9 TSLA 2022-01-13 370. 372. 342. 344. 97209900 344. -0.0699
10 TSLA 2022-01-14 340. 351. 338. 350. 72924300 350. 0.0173
# … with 998 more rows
# ℹ Use `print(n = ...)` to see more rows
Plotting
log_return %>%
ggplot() +
aes(x = date, y = log_returns, col = symbol) +
geom_line() +
facet_wrap(~ symbol) +
theme_tq()

R Tidyquant adding a price difference column to a tibble

I'm trying to add a column to a Tidyquant tibble. Here's the code:
library(tidyquant)
symbol <- 'AAPL'
start_date <- as.Date('2022-01-01')
end_date <- as.Date('2022-03-31')
prices <- tq_get(symbol,
from = start_date,
to = end_date,
get = 'stock.prices')
head(prices)
# A tibble: 6 x 8
symbol date open high low close volume adjusted
<chr> <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 AAPL 2022-01-03 178. 183. 178. 182. 104487900 182.
2 AAPL 2022-01-04 183. 183. 179. 180. 99310400 179.
3 AAPL 2022-01-05 180. 180. 175. 175. 94537600 175.
4 AAPL 2022-01-06 173. 175. 172. 172 96904000 172.
5 AAPL 2022-01-07 173. 174. 171. 172. 86709100 172.
6 AAPL 2022-01-10 169. 172. 168. 172. 106765600 172.
Now, I'm attempting to add the change_on_day column (that's just the difference in the 'adjusted' prices between one day and the next) using the following:
prices$change_on_day <- diff(prices$adjusted)
The error message is:
Error: Assigned data `diff(prices$adjusted)` must be compatible with existing data.
x Existing data has 61 rows.
x Assigned data has 60 rows.
i Only vectors of size 1 are recycled.
How would I add this price difference column?
Thanks!
If you are trying to get today's value from the previous date value then you should be able to do that with the lag() function
prices %>%
mutate(change_on_day=adjusted-lag(adjusted,1))
We can use tq_transmute with quantmod::periodReturn setting the period argument to 'daily' in order to calculate daily returns.
library(tidyquant)
symbol <- "AAPL"
start_date <- as.Date("2022-01-01")
end_date <- as.Date("2022-03-31")
prices <- tq_get(symbol,
from = start_date,
to = end_date,
get = "stock.prices"
)
stock_returns_monthly <- prices %>%
tq_transmute(
select = adjusted,
mutate_fun = periodReturn,
period = "daily",
col_rename = "change_on_day"
)
stock_returns_monthly
#> # A tibble: 61 × 2
#> date change_on_day
#> <date> <dbl>
#> 1 2022-01-03 0
#> 2 2022-01-04 -0.0127
#> 3 2022-01-05 -0.0266
#> 4 2022-01-06 -0.0167
#> 5 2022-01-07 0.000988
#> 6 2022-01-10 0.000116
#> 7 2022-01-11 0.0168
#> 8 2022-01-12 0.00257
#> 9 2022-01-13 -0.0190
#> 10 2022-01-14 0.00511
#> # … with 51 more rows
Created on 2022-04-18 by the reprex package (v2.0.1)
For more information check this vignette

Trouble using object in dataframe after a pipe (decomposition of a msts object)

I do time series decomposition and I want to save the resulting objects in a dataframe. It works if I store the results in a object and use it to make the dataframe afterwards:
# needed packages
library(tidyverse)
library(forecast)
# some "time series"
vec <- 1:1000 + rnorm(1000)
# store pipe results
pipe_out <-
# do decomposition
decompose(msts(vec, start= c(2001, 1, 1), seasonal.periods= c(7, 365.25))) %>%
# relevant data
.$seasonal
# make a dataframe with the stored seasonal data
data.frame(ts= pipe_out)
But doing the same as a one-liner fails:
decompose(msts(vec, start= c(2001, 1, 1), seasonal.periods= c(7, 365.25))) %>%
data.frame(ts= .$seasonal)
I get the error
Error in as.data.frame.default(x[[i]], optional = TRUE, stringsAsFactors = stringsAsFactors) :
cannot coerce class ‘"decomposed.ts"’ to a data.frame
I thought that the pipe simply moves forward the things that came up in the last step which saves us storing those things in objects. If so, shouldn't both codes result in the very same output?
EDIT (from comments)
The first code works but it is a bad solution because if one wants to extract all the vectors of the decomposed time series one would need to do it in multiple steps. Something like the following would be better:
decompose(msts(vec, start= c(2001, 1, 1),
seasonal.periods= c(7, 365.25))) %>%
data.frame(seasonal= .$seasonal, x=.$x, trend=.$trend, random=.$random)
It's unclear from your example whether you want to extract $x or $seasonal. Either way, you can extract part of a list either with the `[[`() function in base or the alias extract2() in magrittr, as you prefer. You should then use the . when you create a data.frame in the last step.
Cleaning up the code a bit to be consistent with the piping, the following works:
library(magrittr)
library(tidyverse)
library(forecast)
vec <- 1:1000 + rnorm(1000)
vec %>%
msts(start = c(2001, 1, 1), seasonal.periods= c(7, 365.25)) %>%
decompose %>%
`[[`("seasonal") %>%
# extract2("seasonal") %>% # Another option, uncomment if preferred
data.frame(ts = .) %>%
head # Just for the reprex, remove as required
#> ts
#> 1 -1.17332998
#> 2 0.07393265
#> 3 0.37631946
#> 4 0.30640395
#> 5 1.04279779
#> 6 0.20470768
Created on 2019-11-28 by the reprex package (v0.3.0)
Edit based on comment:
To do what you mention in the comments, you need to use curly brackets (see e.g. here for an explanation why). Hence, the following works:
library(magrittr)
library(tidyverse)
library(forecast)
vec <- 1:1000 + rnorm(1000)
vec %>%
msts(start= c(2001, 1, 1), seasonal.periods = c(7, 365.25)) %>%
decompose %>%
{data.frame(seasonal = .$seasonal,
trend = .$trend)} %>%
head
#> seasonal trend
#> 1 -0.4332034 NA
#> 2 -0.6185832 NA
#> 3 -0.5899566 NA
#> 4 0.7640938 NA
#> 5 -0.4374417 NA
#> 6 -0.8739449 NA
However, for your specific use case, it may be clearer and easier to use magrittr::extract and then simply bind_cols:
vec %>%
msts(start= c(2001, 1, 1), seasonal.periods = c(7, 365.25)) %>%
decompose %>%
magrittr::extract(c("seasonal", "trend")) %>%
bind_cols %>%
head
#> # A tibble: 6 x 2
#> seasonal trend
#> <dbl> <dbl>
#> 1 -0.433 NA
#> 2 -0.619 NA
#> 3 -0.590 NA
#> 4 0.764 NA
#> 5 -0.437 NA
#> 6 -0.874 NA
Created on 2019-11-29 by the reprex package (v0.3.0)
With daily data, decompose() does not work well because it will only handle the annual seasonality and will give relatively poor estimates of it. If the data involve human behaviour, it will probably have both weekly and annual seasonal patterns.
Also, msts objects are not great for daily data either because they don't store the dates explicitly.
I suggest you use tsibble objects with an STL decomposition instead. Here is an example using your data.
library(tidyverse)
library(tsibble)
library(feasts)
mydata <- tsibble(
day = as.Date(seq(as.Date("2001-01-01"), length=1000, by=1)),
vec = 1:1000 + rnorm(1000)
)
#> Using `day` as index variable.
mydata
#> # A tsibble: 1,000 x 2 [1D]
#> day vec
#> <date> <dbl>
#> 1 2001-01-01 0.161
#> 2 2001-01-02 2.61
#> 3 2001-01-03 1.37
#> 4 2001-01-04 3.15
#> 5 2001-01-05 4.43
#> 6 2001-01-06 7.35
#> 7 2001-01-07 7.10
#> 8 2001-01-08 10.0
#> 9 2001-01-09 9.16
#> 10 2001-01-10 10.2
#> # … with 990 more rows
# Compute a decomposition
mydata %>% STL(vec)
#> # A dable: 1,000 x 7 [1D]
#> # STL Decomposition: vec = trend + season_year + season_week + remainder
#> day vec trend season_year season_week remainder season_adjust
#> <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 2001-01-01 0.161 14.7 -14.6 0.295 -0.193 14.5
#> 2 2001-01-02 2.61 15.6 -14.2 0.0865 1.04 16.7
#> 3 2001-01-03 1.37 16.6 -15.5 0.0365 0.240 16.9
#> 4 2001-01-04 3.15 17.6 -13.0 -0.0680 -1.34 16.3
#> 5 2001-01-05 4.43 18.6 -13.4 -0.0361 -0.700 17.9
#> 6 2001-01-06 7.35 19.5 -12.4 -0.122 0.358 19.9
#> 7 2001-01-07 7.10 20.5 -13.4 -0.181 0.170 20.7
#> 8 2001-01-08 10.0 21.4 -12.7 0.282 1.10 22.5
#> 9 2001-01-09 9.16 22.2 -13.8 0.0773 0.642 22.9
#> 10 2001-01-10 10.2 22.9 -12.7 0.0323 -0.0492 22.9
#> # … with 990 more rows
Created on 2019-11-30 by the reprex package (v0.3.0)
The output is a dable (decomposition table) which behaves like a dataframe most of the time. So you can extract the trend column, or either of the seasonal component columns in the usual way.

Looping with quantmod

I'm new to R, loops and quantmod. I'm trying to convince quantmod to skip any ticker it's unable to process and continue on to the next ticker symbol, instead of stopping. I thought I'd found my answer here how do I loop through all the stocks with quantmod and ttr? but I'm not able to get Rime's solution to work:
If the loop breaks, say on the 50th iteration, then just re run the last block of code by changing the following
# Actual loop:
# IF IT BREAKS ON THE 50th ITERATION, it must be skipped, therefore change it to 51
for(i in 51:length(symbols)) {
symbols[i]-> symbol
...
Below is my original code, which only returns 8 of the many values(so I assume that 9 is the trouble spot).
library(gdata)
d = read.xls("~/Documents/TEST.xlsx", sheet = 1, stringsAsFactors=F)
library(quantmod)
sym <- as.character(d[,1])
results <- NULL
for (ii in sym){
data1 <- getSymbols(Symbols = ii,
src = "yahoo",
from = Sys.Date() - 100,
auto.assign = FALSE)
de = head(data1,150)
colnames(de) <- c("open","high","low","close","volume","adj.")
overnightRtn <- (as.numeric(de[2:nrow(de),"open"])/as.numeric(de[1:(nrow(de)-1),"close"])) - 1
results <- rbind(results,cbind(
paste(round(min(overnightRtn,na.rm=T),5),"%",sep="")))
}
colnames(results) <- c("overnightRtn2")
rownames(results) <- sym
View(results)
When I change for(ii in sym) to for(ii in 9:length(sym)) I get an error:
could not find function "getSymbols.9"
Here is the start of d[,1] :
[1] "ABX" "ACC" "ACCO" "ACE" "ACG" "ACH" "ACI" "ACM" "ACMP" "ACN"
There are some workarounds for errors when looping in R, one way to do this will be using the tryCatchfunction, juba showed here how to do it. I also made sure that the for loop will only continue when the data1variable is assigned some value.
Change your for loop for the following code and it should work for what you are asking.
for (ii in sym){
data1 <- NULL # NULL data1
data1 <- tryCatch(getSymbols(Symbols = ii,
src = "yahoo",
from = Sys.Date() - 100,
auto.assign = FALSE),
error=function(e){}) # empty function for error handling
if(is.null(data1)) next() # if data1 is still NULL go to next ticker
de = head(data1,150)
colnames(de) <- c("open","high","low","close","volume","adj.")
overnightRtn <- (as.numeric(de[2:nrow(de),"open"])/as.numeric(de[1:(nrow(de)-1),"close"])) - 1
results <- rbind(results,cbind(
paste(round(min(overnightRtn,na.rm=T),5),"%",sep="")))
}
You might try the tidyquant package which takes care of error handling internally. It also doesn't require for-loops so it will save you a significant amount of code. The tq_get() function is responsible for getting stock prices. You can use the complete_cases argument to adjust how errors are handled.
Example with complete_cases = TRUE: Automatically removes "bad apples"
library(tidyquant)
# get data with complete_cases = TRUE automatically removes bad apples
c("AAPL", "GOOG", "BAD APPLE", "NFLX") %>%
tq_get(get = "stock.prices", complete_cases = TRUE)
#> Warning in value[[3L]](cond): Error at BAD APPLE during call to get =
#> 'stock.prices'. Removing BAD APPLE.
#> # A tibble: 7,680 × 8
#> symbol date open high low close volume adjusted
#> <chr> <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 AAPL 2007-01-03 86.29 86.58 81.90 83.80 309579900 10.85709
#> 2 AAPL 2007-01-04 84.05 85.95 83.82 85.66 211815100 11.09807
#> 3 AAPL 2007-01-05 85.77 86.20 84.40 85.05 208685400 11.01904
#> 4 AAPL 2007-01-08 85.96 86.53 85.28 85.47 199276700 11.07345
#> 5 AAPL 2007-01-09 86.45 92.98 85.15 92.57 837324600 11.99333
#> 6 AAPL 2007-01-10 94.75 97.80 93.45 97.00 738220000 12.56728
#> 7 AAPL 2007-01-11 95.94 96.78 95.10 95.80 360063200 12.41180
#> 8 AAPL 2007-01-12 94.59 95.06 93.23 94.62 328172600 12.25892
#> 9 AAPL 2007-01-16 95.68 97.25 95.45 97.10 311019100 12.58023
#> 10 AAPL 2007-01-17 97.56 97.60 94.82 94.95 411565000 12.30168
#> # ... with 7,670 more rows
Example with complete_cases = FALSE: Returns nested data frame.
library(tidyquant)
# get data with complete_cases = FALSE returns a nested data frame
c("AAPL", "GOOG", "BAD APPLE", "NFLX") %>%
tq_get(get = "stock.prices", complete_cases = FALSE)
#> Warning in value[[3L]](cond): Error at BAD APPLE during call to get =
#> 'stock.prices'.
#> Warning in value[[3L]](cond): Returning as nested data frame.
#> # A tibble: 4 × 2
#> symbol stock.prices
#> <chr> <list>
#> 1 AAPL <tibble [2,560 × 7]>
#> 2 GOOG <tibble [2,560 × 7]>
#> 3 BAD APPLE <lgl [1]>
#> 4 NFLX <tibble [2,560 × 7]>
In both cases the user gets a WARNING message. The prudent user will read them and try to determine what the issue is. Most important, the long running script will not fail.

Convert data frame with date column to timeseries

I've got a data frame with the following data:
>PRICE
DATE CLOSE
1 20070103 54.700
2 20070104 54.770
3 20070105 55.120
4 20070108 54.870
5 20070109 54.860
6 20070110 54.270
7 20070111 54.770
8 20070112 55.360
9 20070115 55.760
...
As you can see my DATE column represents a date (yyyyMMdd) and my CLOSE column represents prices.
I now have to calculate CalmarRatio, from the PerformanceAnalytics package.
I'm new to R, so i can't understand everything, but from what i have googled to the moment i see that the R parameter to that function needs to be a time-series-like object.
Is there any way i can convert my array to a time-series object given that there might not be data for every date in a period (only for the ones i specify)?
Your DATE column may represent a date, but it is actually either a character, factor, integer, or a numeric vector.
First, you need to convert the DATE column to a Date object. Then you can create an xts object from the CLOSE and DATE columns of your PRICE data.frame. Finally, you can use the xts object to calculate returns and the Calmar ratio.
PRICE <- structure(list(
DATE = c(20070103L, 20070104L, 20070105L, 20070108L, 20070109L,
20070110L, 20070111L, 20070112L, 20070115L),
CLOSE = c(54.7, 54.77, 55.12, 54.87, 54.86, 54.27, 54.77, 55.36, 55.76)),
.Names = c("DATE", "CLOSE"), class = "data.frame",
row.names = c("1", "2", "3", "4", "5", "6", "7", "8", "9"))
library(PerformanceAnalytics) # loads/attaches xts
# Convert DATE to Date class
PRICE$DATE <- as.Date(as.character(PRICE$DATE),format="%Y%m%d")
# create xts object
x <- xts(PRICE$CLOSE,PRICE$DATE)
CalmarRatio(Return.calculate(x))
# [,1]
# Calmar Ratio 52.82026
Most people find working with the time series class to be a big pain. You should consider using the zoo class from package zoo. It will not complain about missing times , only about duplicates. The PerformanceAnalytics functions are almost certainly going to be expecting 'zoo' or its descendant class 'xts'.
pricez <- read.zoo(text=" DATE CLOSE
1 20070103 54.700
2 20070104 54.770
3 20070105 55.120
4 20070108 54.870
5 20070109 54.860
6 20070110 54.270
7 20070111 54.770
8 20070112 55.360
9 20070115 55.760
")
index(pricez) <- as.Date(as.character(index(pricez)), format="%Y%m%d")
pricez
2007-01-03 2007-01-04 2007-01-05 2007-01-08 2007-01-09 2007-01-10 2007-01-11 2007-01-12 2007-01-15
54.70 54.77 55.12 54.87 54.86 54.27 54.77 55.36 55.76
An alternative solution is to use the tidyquant package, which allows the functionality of the financial packages, including time series functionality, to be used with data frames. The following examples shows how you can get the Calmar Ratio for multiple assets. The tidyquant vignettes go into more details on how to use the package.
library(tidyquant)
# Get prices
price_tbl <- c("FB", "AMZN", "NFLX", "GOOG") %>%
tq_get(get = "stock.prices",
from = "2010-01-01",
to = "2016-12-31")
price_tbl
#> # A tibble: 6,449 × 8
#> symbol date open high low close volume adjusted
#> <chr> <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 FB 2012-05-18 42.05 45.00 38.00 38.23 573576400 38.23
#> 2 FB 2012-05-21 36.53 36.66 33.00 34.03 168192700 34.03
#> 3 FB 2012-05-22 32.61 33.59 30.94 31.00 101786600 31.00
#> 4 FB 2012-05-23 31.37 32.50 31.36 32.00 73600000 32.00
#> 5 FB 2012-05-24 32.95 33.21 31.77 33.03 50237200 33.03
#> 6 FB 2012-05-25 32.90 32.95 31.11 31.91 37149800 31.91
#> 7 FB 2012-05-29 31.48 31.69 28.65 28.84 78063400 28.84
#> 8 FB 2012-05-30 28.70 29.55 27.86 28.19 57267900 28.19
#> 9 FB 2012-05-31 28.55 29.67 26.83 29.60 111639200 29.60
#> 10 FB 2012-06-01 28.89 29.15 27.39 27.72 41855500 27.72
#> # ... with 6,439 more rows
# Convert to period returns
return_tbl <- price_tbl %>%
group_by(symbol) %>%
tq_transmute(ohlc_fun = Ad,
mutate_fun = periodReturn,
period = "daily")
return_tbl
#> Source: local data frame [6,449 x 3]
#> Groups: symbol [4]
#>
#> symbol date daily.returns
#> <chr> <date> <dbl>
#> 1 FB 2012-05-18 0.00000000
#> 2 FB 2012-05-21 -0.10986139
#> 3 FB 2012-05-22 -0.08903906
#> 4 FB 2012-05-23 0.03225806
#> 5 FB 2012-05-24 0.03218747
#> 6 FB 2012-05-25 -0.03390854
#> 7 FB 2012-05-29 -0.09620809
#> 8 FB 2012-05-30 -0.02253811
#> 9 FB 2012-05-31 0.05001770
#> 10 FB 2012-06-01 -0.06351355
#> # ... with 6,439 more rows
# Calculate performance
return_tbl %>%
tq_performance(Ra = daily.returns,
performance_fun = CalmarRatio)
#> Source: local data frame [4 x 2]
#> Groups: symbol [4]
#>
#> symbol CalmarRatio
#> <chr> <dbl>
#> 1 FB 0.50283172
#> 2 AMZN 0.91504597
#> 3 NFLX 0.14444744
#> 4 GOOG 0.05068483
Whether you want to convert a data frame (or any time series) to a xts or zoo object, as in the answers above, or to any other time series (such as a ts object) the tsbox package makes coercion easy:
PRICE <- structure(list(
DATE = c(20070103L, 20070104L, 20070105L, 20070108L, 20070109L,
20070110L, 20070111L, 20070112L, 20070115L),
CLOSE = c(54.7, 54.77, 55.12, 54.87, 54.86, 54.27, 54.77, 55.36, 55.76)),
.Names = c("DATE", "CLOSE"), class = "data.frame",
row.names = c("1", "2", "3", "4", "5", "6", "7", "8", "9"))
library(tsbox)
ts_xts(PRICE)
#> [time]: 'DATE' [value]: 'CLOSE'
#> Loading required namespace: xts
#> Registered S3 method overwritten by 'xts':
#> method from
#> as.zoo.xts zoo
#> CLOSE
#> 2007-01-03 54.70
#> 2007-01-04 54.77
#> 2007-01-05 55.12
#> 2007-01-08 54.87
#> 2007-01-09 54.86
#> 2007-01-10 54.27
#> 2007-01-11 54.77
#> 2007-01-12 55.36
#> 2007-01-15 55.76
ts_ts(PRICE)
#> [time]: 'DATE' [value]: 'CLOSE'
#> Time Series:
#> Start = 2007.00547581401
#> End = 2007.0383306981
#> Frequency = 365.2425
#> [1] 54.70 54.77 55.12 NA NA 54.87 54.86 54.27 54.77 55.36 NA
#> [12] NA 55.76
This answer based on #Joshua_Ulrich's answer creates a time series from the built-in airquality dataset containing "Daily air quality measurements in New York, May to September 1973".
> head(airquality,3)
Ozone Solar.R Wind Temp Month Day
1 41 190 7.4 67 5 1
2 36 118 8.0 72 5 2
3 12 149 12.6 74 5 3
Convert Month and Day to a vector of class "Date"
airqualitydate = as.Date(sprintf("1973%02.0f%02.0f", airquality$Month, airquality$Day),
format="%Y%m%d")
Create the time series object
ts_airquality <- xts(airquality, airqualitydate)
head(ts_airquality, 3)
Ozone Solar.R Wind Temp Month Day
1973-05-01 41 190 7.4 67 5 1
1973-05-02 36 118 8.0 72 5 2
1973-05-03 12 149 12.6 74 5 3
Plot to illustrate the different output of the plot.xts() function. (compare to plot(airquality))
plot(ts_airquality$Ozone, main="Ozone (ppb)")
lines(ts_airquality$Temp, on=NA, main="Temperature (degrees F)")
Note, the base R ts() method is mostly suited for quarterly or yearly data.
As explained in an answer to "starting a daily time series in R":
"Time Series Object does not work well with creating daily time series. I will suggest you use the zoo library."
In particular the xts package is an extension to zoo.

Resources