Hi,
TTR/xts/quantmod maintainer here.
On Sun, Jan 5, 2025 at 10:58?AM Sparks, John <jspark4 at uic.edu>
wrote:>
> Hi,
>
> In looking at the documentation for the TTR library and particularly the
> example for calculating the ATR (average true range). The example shows
> how to calculate ATR for a file of a single stock.
>
> If I have multiple stocks in one file, isn't there a way to get the ATR
> for each of them? Or does one have to break out each stock and calculate
> the ATR separately using some sort of loop.
>
Yes, the TTR functions only work on a single stock at a time.
> In terms of a reproducible example, the file below contains open, high,
> low, close, etc. for AAPL and then MSFT.
>
Thanks for the reproducible data!
> If the ATR calculation were fully working, then there would be blanks for
> records 41 through 54 and then the ATR calculation would start up again.
>
> Guidance would be very much appreciated.
>
> --John Sparks
>
>
> Hist<-
> structure(list(symbol = c("AAPL", "AAPL",
"AAPL", "AAPL", "AAPL",
> "AAPL", "AAPL", "AAPL", "AAPL",
"AAPL", "AAPL", "AAPL", "AAPL",
> "AAPL", "AAPL", "AAPL", "AAPL",
"AAPL", "AAPL", "AAPL", "AAPL",
> "AAPL", "AAPL", "AAPL", "AAPL",
"AAPL", "AAPL", "AAPL", "AAPL",
> "AAPL", "AAPL", "AAPL", "AAPL",
"AAPL", "AAPL", "AAPL", "AAPL",
> "AAPL", "AAPL", "AAPL", "MSFT",
"MSFT", "MSFT", "MSFT", "MSFT",
> "MSFT", "MSFT", "MSFT", "MSFT",
"MSFT", "MSFT", "MSFT", "MSFT",
> "MSFT", "MSFT", "MSFT", "MSFT",
"MSFT", "MSFT", "MSFT", "MSFT",
> "MSFT", "MSFT", "MSFT", "MSFT",
"MSFT", "MSFT", "MSFT", "MSFT",
> "MSFT", "MSFT", "MSFT", "MSFT",
"MSFT", "MSFT", "MSFT", "MSFT",
> "MSFT", "MSFT", "MSFT"), date =
structure(c(20033, 20034, 20035,
> 20038, 20039, 20040, 20041, 20042, 20045, 20046, 20047, 20048,
> 20049, 20052, 20053, 20054, 20056, 20059, 20060, 20061, 20062,
> 20063, 20066, 20067, 20068, 20069, 20070, 20073, 20074, 20075,
> 20076, 20077, 20080, 20081, 20083, 20084, 20087, 20088, 20090,
> 20091, 20033, 20034, 20035, 20038, 20039, 20040, 20041, 20042,
> 20045, 20046, 20047, 20048, 20049, 20052, 20053, 20054, 20056,
> 20059, 20060, 20061, 20062, 20063, 20066, 20067, 20068, 20069,
> 20070, 20073, 20074, 20075, 20076, 20077, 20080, 20081, 20083,
> 20084, 20087, 20088, 20090, 20091), class = "Date"), open =
c(222.61,
> 224.63, 227.17, 225, 224.55, 224.01, 225.02, 226.4, 225.25, 226.98,
> 228.06, 228.88, 228.06, 231.46, 233.33, 234.47, 234.81, 237.27,
> 239.81, 242.87, 243.99, 242.91, 241.83, 246.89, 247.96, 246.89,
> 247.82, 247.99, 250.08, 252.16, 247.5, 248.04, 254.77, 255.49,
> 258.19, 257.83, 252.23, 252.44, 248.93, 243.36, 412.42, 421.28,
> 425.32, 422.52, 418.25, 421.64, 425, 419.82, 414.87, 413.11,
> 416.87, 419.5, 411.37, 418.38, 419.59, 425.11, 420.09, 421.57,
> 429.84, 433.03, 437.92, 442.3, 442.6, 444.39, 444.05, 449.11,
> 448.44, 447.27, 451.01, 451.32, 441.62, 433.11, 436.74, 434.65,
> 439.08, 434.6, 426.06, 426.1, 425.53, 421.08), high = c(226.07,
> 227.88, 228.66, 225.7, 225.59, 226.65, 228.87, 226.92, 229.74,
> 230.16, 229.93, 230.16, 230.72, 233.25, 235.57, 235.69, 237.81,
> 240.79, 242.76, 244.11, 244.54, 244.63, 247.24, 248.21, 250.8,
> 248.74, 249.29, 251.38, 253.83, 254.28, 252, 255, 255.65, 258.21,
> 260.1, 258.7, 253.5, 253.28, 249.1, 244.18, 420.45, 426.85, 426.5,
> 424.81, 424.44, 429.33, 428.17, 422.8, 418.4, 417.94, 417.29,
> 419.78, 417.4, 421.08, 429.04, 427.23, 424.88, 433, 432.47, 439.67,
> 444.66, 446.1, 448.33, 449.62, 450.35, 456.16, 451.43, 452.18,
> 455.29, 452.65, 443.18, 443.74, 437.65, 439.6, 440.94, 435.22,
> 427.55, 426.73, 426.07, 424.03), low = c(221.19, 224.57, 226.41,
> 221.5, 223.36, 222.76, 225, 224.27, 225.17, 226.66, 225.89, 225.71,
> 228.06, 229.74, 233.33, 233.81, 233.97, 237.16, 238.9, 241.25,
> 242.13, 242.08, 241.75, 245.34, 246.26, 245.68, 246.24, 247.65,
> 249.78, 247.74, 247.09, 245.69, 253.45, 255.29, 257.63, 253.06,
> 250.75, 249.43, 241.82, 241.89, 410.52, 419.88, 421.78, 416,
> 417.2, 418.21, 420, 413.64, 412.1, 411.55, 410.58, 410.29, 411.06,
> 414.85, 418.85, 422.02, 417.8, 421.31, 427.74, 432.63, 436.17,
> 441.77, 440.5, 441.6, 444.05, 449.11, 445.58, 445.28, 449.57,
> 437.02, 436.32, 428.63, 432.83, 434.19, 436.63, 426.35, 421.9,
> 420.66, 414.85, 419.54), close = c(222.72, 227.48, 226.96, 224.23,
> 224.23, 225.12, 228.22, 225, 228.02, 228.28, 229, 228.52, 229.87,
> 232.87, 235.06, 234.93, 237.33, 239.59, 242.65, 243.01, 243.04,
> 242.84, 246.75, 247.77, 246.49, 247.96, 248.13, 251.04, 253.48,
> 248.05, 249.79, 254.49, 255.27, 258.2, 259.02, 255.59, 252.2,
> 250.42, 243.85, 243.36, 420.18, 425.43, 422.54, 418.01, 423.03,
> 425.2, 426.89, 415, 415.76, 417.79, 415.49, 412.87, 417, 418.79,
> 427.99, 422.99, 423.46, 430.98, 431.2, 437.42, 442.62, 443.57,
> 446.02, 443.33, 448.99, 449.56, 447.27, 451.59, 454.46, 437.39,
> 437.03, 436.6, 435.25, 439.33, 438.11, 430.53, 424.83, 421.5,
> 418.58, 423.35), adjClose = c(222.48, 227.23, 226.96, 224.23,
> 224.23, 225.12, 228.22, 225, 228.02, 228.28, 229, 228.52, 229.87,
> 232.87, 235.06, 234.93, 237.33, 239.59, 242.65, 243.01, 243.04,
> 242.84, 246.75, 247.77, 246.49, 247.96, 248.13, 251.04, 253.48,
> 248.05, 249.79, 254.49, 255.27, 258.2, 259.02, 255.59, 252.2,
> 250.42, 243.85, 243.36, 419.34, 424.58, 421.7, 417.17, 422.18,
> 424.35, 426.04, 414.17, 414.93, 416.96, 414.66, 412.87, 417,
> 418.79, 427.99, 422.99, 423.46, 430.98, 431.2, 437.42, 442.62,
> 443.57, 446.02, 443.33, 448.99, 449.56, 447.27, 451.59, 454.46,
> 437.39, 437.03, 436.6, 435.25, 439.33, 438.11, 430.53, 424.83,
> 421.5, 418.58, 423.35)), class = "data.frame", row.names = c(NA,
> -80L))
>
> library(TTR)
> atr <- ATR(Hist[,c("high","low","close")],
n=14)
> atr
>
>
Here's a function that splits your data into a list by symbol, then
does the TTR calculation for each symbol and re-combines the result
into an object with the same structure as the input.
library(quantmod)
my_atr <- function(ohlc, n = 14, ...)
{
cn <- names(ohlc)
# get all the necessary columns
atr_cols <- c(which(grepl("date", cn, ignore.case = TRUE)),
has.HLC(ohlc, which = TRUE))
# find the symbol column
sym_col <- which(grepl("symbol", cn, ignore.case = TRUE))
# convert the input data.frame into a list of xts objects
# this ensures the data are correctly ordered by date
xts_list <- lapply(split(ohlc[, atr_cols], ohlc[, sym_col]), as.xts)
# calculate ATR for each symbol
atr_list <- lapply(xts_list, ATR, n = n, ...)
# convert the list results into data.frames
to_df <- function(nm) {
i <- atr_list[[nm]];
data.frame(symbol = nm, date = index(i), coredata(i))
}
atr_df <- lapply(names(atr_list), to_df)
# rbind all the list elements into a single data frame
do.call(rbind, atr_df)
}
Hope that helps.
--
Joshua Ulrich | about.me/joshuaulrich
FOSS Trading | www.fosstrading.com