在满足动态条件的数据框中查找第一行
Find the first rows in a data frame which meet a dynamic condition
下面是一些示例代码:
library(quantmod)
library(dplyr)
stock.prices <- getSymbols(Symbols = 'AAPL', from = '2017-08-08', to = '2017-08-17', env = NULL)[,c(2,4)]
stock.dividends <- getDividends(Symbol = 'AAPL', from = '2017-08-08', to = '2017-08-17')
summary <- merge(stock.prices, stock.dividends)
summary <- data.frame(date=index(summary), coredata(summary))
summary <- mutate(summary, buy.price = ifelse(is.na(AAPL.div), NA, lag(AAPL.Close, 1)))
summary
它产生这个数据:
date AAPL.High AAPL.Close AAPL.div lag.buy.price
1 2017-08-08 161.83 160.08 NA NA
2 2017-08-09 161.27 161.06 NA NA
3 2017-08-10 160.00 155.32 0.63 161.06
4 2017-08-11 158.57 157.48 NA NA
5 2017-08-14 160.21 159.85 NA NA
6 2017-08-15 162.20 161.60 NA NA
7 2017-08-16 162.51 160.95 NA NA
我想像这样追加一列:
date AAPL.High AAPL.Close AAPL.div lag.buy.price sell.date
1 2017-08-08 161.83 160.08 NA NA NA
2 2017-08-09 161.27 161.06 NA NA NA
3 2017-08-10 160.00 155.32 0.63 161.06 2017-08-15
4 2017-08-11 158.57 157.48 NA NA NA
5 2017-08-14 160.21 159.85 NA NA NA
6 2017-08-15 162.20 161.60 NA NA NA
7 2017-08-16 162.51 160.95 NA NA NA
这找到了我可以卖出以达到收支平衡的第一个日期...我在 2017-08-09 购买了股票,以便有资格在第二天获得股息。我支付每股 161.06 美元。收到股息后,我现在想以 >= 161.06 的价格卖出。 2017-08-15是我第一天可以做这个
我可以运行一个for循环来实现这个,但它看起来相当粗糙和低效。
有没有办法使用 dplyr 生成 'sell.date' 列?
这应该让你到达那里:
library(quantmod)
library(tidyverse)
stock.prices <- getSymbols(Symbols = 'AAPL', from = '2017-08-08', to = '2017-08-17', env = NULL)[,c(2,4)]
stock.dividends <- getDividends(Symbol = 'AAPL', from = '2017-08-08', to = '2017-08-17')
summary <- merge(stock.prices, stock.dividends) %>%
as_tibble() %>%
rownames_to_column('date') %>%
coredata() %>%
mutate(buy.price = ifelse(is.na(AAPL.div), NA, lag(AAPL.Close, 1)))
new_summary <- summary %>%
rownames_to_column() %>%
mutate(rowname = as.numeric(rowname),
sell.date = map2_chr(rowname, buy.price, function(row, buy){
if(is.na(row) | is.na(buy)){
NA
}else{
data <- summary %>%
mutate(lt_buy = AAPL.High >= buy) %>%
filter(lt_buy == T, rowname > row)
min(data$date)
}
}))
首先,您需要将行号附加到数据框。然后,您应该使用 purrr::map
来迭代数据(我将您的 library(dplyr)
更改为 library(tidyverse)
以获得 purrr
)。 purrr::map2
接受两个向量输入(在本例中是 data.frame
的两列——我冒昧地切换到 tibble
)并在这些输入上运行一个函数。我在那里写的匿名函数过滤了您的摘要 tibble
超出输入日期的日期和高于购买价格的价格。然后 returns 满足该标准的最短日期。
我还对您的数据设置进行了一些更改,以便它使用管链和更多 tidy
类型的结构。
希望对您有所帮助!
df[is.na(df$AAPL.div),'AAPL.div'] <- 0
sell.date <-
with(df, {
bought <- date > as.Date('2017-08-09')
date[which.max(bought & (AAPL.Close + cumsum(AAPL.div*bought)) > 161.06)]})
sell.date
#[1] "2017-08-15"
将其添加为列
df$sell.date <- ifelse(is.na(df$lag.buy.price), NA, sell.date)
df
# date AAPL.High AAPL.Close AAPL.div lag.buy.price sell.date
# 1: 2017-08-08 161.83 160.08 0.00 NA <NA>
# 2: 2017-08-09 161.27 161.06 0.00 NA <NA>
# 3: 2017-08-10 160.00 155.32 0.63 161.06 2017-08-15
# 4: 2017-08-11 158.57 157.48 0.00 NA <NA>
# 5: 2017-08-14 160.21 159.85 0.00 NA <NA>
# 6: 2017-08-15 162.20 161.60 0.00 NA <NA>
# 7: 2017-08-16 162.51 160.95 0.00 NA <NA>
使用的数据
library(data.table)
df <- fread("
a date AAPL.High AAPL.Close AAPL.div lag.buy.price
1 2017-08-08 161.83 160.08 NA NA
2 2017-08-09 161.27 161.06 NA NA
3 2017-08-10 160.00 155.32 0.63 161.06
4 2017-08-11 158.57 157.48 NA NA
5 2017-08-14 160.21 159.85 NA NA
6 2017-08-15 162.20 161.60 NA NA
7 2017-08-16 162.51 160.95 NA NA
")[, -1]
这个解决方案并非完全没有 for 循环,但我猜你的意思是一个循环来比较每个值(该部分在此处矢量化)。以防万一您有多个股息,您会发现需要这个循环:
summary$sell.date<-as.Date(rep(NA,7))
for(i in 1:length(which(!is.na(summary$buy.price))))
summary$sell.date[which(!is.na(summary$buy.price))[i]]<- summary[c(rep(FALSE,which(!is.na(summary$buy.price))[i]-1),(summary[which(!is.na(summary$buy.price))[i]:nrow(summary),"AAPL.High"]>summary[!is.na(summary$buy.price),"buy.price"][i])),"date"][1]
它产生以下结果:
date AAPL.High AAPL.Close AAPL.div buy.price sell.date
1 2017-08-08 161.83 160.08 NA NA <NA>
2 2017-08-09 161.27 161.06 NA NA <NA>
3 2017-08-10 160.00 155.32 0.63 161.06 2017-08-15
4 2017-08-11 158.57 157.48 NA NA <NA>
5 2017-08-14 160.21 159.85 NA NA <NA>
6 2017-08-15 162.20 161.60 NA NA <NA>
7 2017-08-16 162.51 160.95 NA NA <NA>
下面是一些示例代码:
library(quantmod)
library(dplyr)
stock.prices <- getSymbols(Symbols = 'AAPL', from = '2017-08-08', to = '2017-08-17', env = NULL)[,c(2,4)]
stock.dividends <- getDividends(Symbol = 'AAPL', from = '2017-08-08', to = '2017-08-17')
summary <- merge(stock.prices, stock.dividends)
summary <- data.frame(date=index(summary), coredata(summary))
summary <- mutate(summary, buy.price = ifelse(is.na(AAPL.div), NA, lag(AAPL.Close, 1)))
summary
它产生这个数据:
date AAPL.High AAPL.Close AAPL.div lag.buy.price
1 2017-08-08 161.83 160.08 NA NA
2 2017-08-09 161.27 161.06 NA NA
3 2017-08-10 160.00 155.32 0.63 161.06
4 2017-08-11 158.57 157.48 NA NA
5 2017-08-14 160.21 159.85 NA NA
6 2017-08-15 162.20 161.60 NA NA
7 2017-08-16 162.51 160.95 NA NA
我想像这样追加一列:
date AAPL.High AAPL.Close AAPL.div lag.buy.price sell.date
1 2017-08-08 161.83 160.08 NA NA NA
2 2017-08-09 161.27 161.06 NA NA NA
3 2017-08-10 160.00 155.32 0.63 161.06 2017-08-15
4 2017-08-11 158.57 157.48 NA NA NA
5 2017-08-14 160.21 159.85 NA NA NA
6 2017-08-15 162.20 161.60 NA NA NA
7 2017-08-16 162.51 160.95 NA NA NA
这找到了我可以卖出以达到收支平衡的第一个日期...我在 2017-08-09 购买了股票,以便有资格在第二天获得股息。我支付每股 161.06 美元。收到股息后,我现在想以 >= 161.06 的价格卖出。 2017-08-15是我第一天可以做这个
我可以运行一个for循环来实现这个,但它看起来相当粗糙和低效。
有没有办法使用 dplyr 生成 'sell.date' 列?
这应该让你到达那里:
library(quantmod)
library(tidyverse)
stock.prices <- getSymbols(Symbols = 'AAPL', from = '2017-08-08', to = '2017-08-17', env = NULL)[,c(2,4)]
stock.dividends <- getDividends(Symbol = 'AAPL', from = '2017-08-08', to = '2017-08-17')
summary <- merge(stock.prices, stock.dividends) %>%
as_tibble() %>%
rownames_to_column('date') %>%
coredata() %>%
mutate(buy.price = ifelse(is.na(AAPL.div), NA, lag(AAPL.Close, 1)))
new_summary <- summary %>%
rownames_to_column() %>%
mutate(rowname = as.numeric(rowname),
sell.date = map2_chr(rowname, buy.price, function(row, buy){
if(is.na(row) | is.na(buy)){
NA
}else{
data <- summary %>%
mutate(lt_buy = AAPL.High >= buy) %>%
filter(lt_buy == T, rowname > row)
min(data$date)
}
}))
首先,您需要将行号附加到数据框。然后,您应该使用 purrr::map
来迭代数据(我将您的 library(dplyr)
更改为 library(tidyverse)
以获得 purrr
)。 purrr::map2
接受两个向量输入(在本例中是 data.frame
的两列——我冒昧地切换到 tibble
)并在这些输入上运行一个函数。我在那里写的匿名函数过滤了您的摘要 tibble
超出输入日期的日期和高于购买价格的价格。然后 returns 满足该标准的最短日期。
我还对您的数据设置进行了一些更改,以便它使用管链和更多 tidy
类型的结构。
希望对您有所帮助!
df[is.na(df$AAPL.div),'AAPL.div'] <- 0
sell.date <-
with(df, {
bought <- date > as.Date('2017-08-09')
date[which.max(bought & (AAPL.Close + cumsum(AAPL.div*bought)) > 161.06)]})
sell.date
#[1] "2017-08-15"
将其添加为列
df$sell.date <- ifelse(is.na(df$lag.buy.price), NA, sell.date)
df
# date AAPL.High AAPL.Close AAPL.div lag.buy.price sell.date
# 1: 2017-08-08 161.83 160.08 0.00 NA <NA>
# 2: 2017-08-09 161.27 161.06 0.00 NA <NA>
# 3: 2017-08-10 160.00 155.32 0.63 161.06 2017-08-15
# 4: 2017-08-11 158.57 157.48 0.00 NA <NA>
# 5: 2017-08-14 160.21 159.85 0.00 NA <NA>
# 6: 2017-08-15 162.20 161.60 0.00 NA <NA>
# 7: 2017-08-16 162.51 160.95 0.00 NA <NA>
使用的数据
library(data.table)
df <- fread("
a date AAPL.High AAPL.Close AAPL.div lag.buy.price
1 2017-08-08 161.83 160.08 NA NA
2 2017-08-09 161.27 161.06 NA NA
3 2017-08-10 160.00 155.32 0.63 161.06
4 2017-08-11 158.57 157.48 NA NA
5 2017-08-14 160.21 159.85 NA NA
6 2017-08-15 162.20 161.60 NA NA
7 2017-08-16 162.51 160.95 NA NA
")[, -1]
这个解决方案并非完全没有 for 循环,但我猜你的意思是一个循环来比较每个值(该部分在此处矢量化)。以防万一您有多个股息,您会发现需要这个循环:
summary$sell.date<-as.Date(rep(NA,7))
for(i in 1:length(which(!is.na(summary$buy.price))))
summary$sell.date[which(!is.na(summary$buy.price))[i]]<- summary[c(rep(FALSE,which(!is.na(summary$buy.price))[i]-1),(summary[which(!is.na(summary$buy.price))[i]:nrow(summary),"AAPL.High"]>summary[!is.na(summary$buy.price),"buy.price"][i])),"date"][1]
它产生以下结果:
date AAPL.High AAPL.Close AAPL.div buy.price sell.date
1 2017-08-08 161.83 160.08 NA NA <NA>
2 2017-08-09 161.27 161.06 NA NA <NA>
3 2017-08-10 160.00 155.32 0.63 161.06 2017-08-15
4 2017-08-11 158.57 157.48 NA NA <NA>
5 2017-08-14 160.21 159.85 NA NA <NA>
6 2017-08-15 162.20 161.60 NA NA <NA>
7 2017-08-16 162.51 160.95 NA NA <NA>