让我们考虑可以在此处下载的Yahoo财务数据: https://finance.yahoo.com/quote/BTC-USD/history?period1=1325372400&period2=1548025200&interval=1d&filter=history&frequency=1d
您可以使用以下方法读取数据:
yahoo <- read.csv("~/Downloads/yahoo.BTC-USD.daily.csv",
na.strings=c("NA","NaN", " "))
这是结果数据框:
> head(yahoo)
Date Open High Low Close Volume
1 2011-12-31 4.25 5.00 4.20 4.72 596240
2 2012-01-01 4.72 5.50 4.62 5.27 553045
3 2012-01-02 5.27 5.47 4.80 5.22 360357
4 2012-01-03 5.22 5.29 4.65 4.88 619170
5 2012-01-04 4.88 5.70 4.75 5.57 688717
6 2012-01-05 5.57 7.22 5.57 6.95 1130623
这些是每日蜡烛,即每一行代表一个交易日。
我想做两件事:
将此数据帧汇总到例如每周数据,将7行分组在一起:
对于给定的音量阈值,将该数据帧聚合为几乎等体积的序列:每个音量阈值我都会有一行。
这是我使用for循环想到的:
第1点:
aggregate.candles <- function(x, candles) {
Date <- candles$Date[x[1]]
Open <- candles$Open[x[1]]
High <- max(candles$High[x])
Low <- min(candles$Low[x])
Close <- candles$Close[tail(x, 1)]
Volume <- sum(candles$Volume[x])
return(data.frame(Date, Open, High, Low, Close, Volume))
}
require(zoo)
yahoo.weekly <- as.data.frame(rollapply(seq_along(yahoo$Open), FUN = aggregate.candles, candles = yahoo, width = 7, by = 7))
这就像一种魅力,但是如果您有改进之处,我将非常高兴。使用聚合函数不能做点什么吗?还是用tidyverse包装让它看起来更干净?
现在对于第2点,如果没有for循环,我找不到解决方法:
aggregate.volume <- function(candles, threshold) {
Open <- c()
High <- c()
Low <- c()
Close <- c()
Volume <- c()
tmpOpen <- -1
tmpHigh <- 0
tmpLow <- .Machine$double.xmax
tmpClose <- 0
tmpVolume <- 0
for (i in seq_along(candles$Open)) {
tmpVolume <- tmpVolume + candles$Volume[i]
if (tmpVolume < threshold) {
if (tmpOpen == -1)
tmpOpen <- candles$Open[i]
tmpHigh <- max(tmpHigh, candles$High[i])
tmpLow <- min(tmpLow, candles$Low[i])
tmpClose <- candles$Close[[i]]
} else {
Open <- c(Open, tmpOpen)
Close <- c(Close, tmpClose)
High <- c(High, tmpHigh)
Low <- c(Low, tmpLow)
Volume <- c(Volume, tmpVolume)
tmpOpen <- -1
tmpHigh <- 0
tmpLow <- .Machine$double.xmax
tmpClose <- 0
tmpVolume <- 0
}
}
return(data.frame(Open, High, Low, Close, Volume))
}
yahoo.volume.10m <- aggregate.volume(yahoo, threshold = 1e8)
是否有更优雅/更有效的方法(使用聚合函数或tidyverse / dplyr)?
我问效率,因为这可以在更大的数据集(例如一分钟的蜡烛)上完成。
答案 0 :(得分:1)
要使用group by
中的tidyverse
,我们首先将Date进行突变以创建分组变量
library(tidyverse)
library(lubridate)
yahoo <- as.tibble(read.csv("~/Downloads/BTC-USD.csv", na.strings=c("NA","NaN", " ")))
yahoo <- yahoo[order(yahoo$Date),]
yahoo.weekly <- yahoo %>%
mutate(week = isoweek(Date), year = isoyear(Date)) %>%
group_by(year, week) %>%
summarise("Open" = first(Open), "High" = max(High), "Low" = min(Low), "Close" = last(Close), "Volume" = sum(Volume))
cumsum_group <- function(x, threshold){
cumsum <- 0
groups <- rep(0, length(x))
for (i in 1:length(x)){
cumsum <- cumsum + x[i]
if(cumsum >= threshold & i<length(x)){
i <- i+1
groups[i] <- 1
cumsum <- 0
}
}
cumsum(groups)+1
}
yahoo.volume.10m <- yahoo %>%
mutate(group = cumsum_group(Volume, threshold = 1e8)) %>%
group_by(group) %>%
summarise("Open" = first(Open), "High" = max(High), "Low" = min(Low), "Close" = last(Close), "Volume" = sum(Volume))
cumsum_group
在此创建ID,以将其分组到特定阈值。不幸的是,我也不能考虑阈值“问题”的总和的变化。