首页 > 解决方案 > r 在绘制日内数据时如何从 x 轴中删除工作日的非工作时间(以及周末和节假日)

问题描述

在 R 中,我在 5 分钟绘制了一些盘中价格数据。间隔,因此需要修改 x 轴以删除市场关闭的时间段,即周一至周五下午 4 点至上午 9 点,节假日除外。

我使用包 bdscale 最接近实现这一点,它不是专门设计用于删除工作日的下班时间,但可以做到这一点。

这是一个可重复的示例,尽管它需要一个 alpha vantage API 密钥(它是免费的)。

library(tidyquant)
library(alphavantager)
library(bdscale)
library(scales)

this_ts <- "SPY"
av_api_key("YOUR_KEY_HERE")
df_ohlcv <- this_ts %>%
  tq_get(get = "alphavantager", av_fun = "TIME_SERIES_INTRADAY", interval = "5min")
df_ohlcv$p <- rowSums(df_ohlcv[, c(3:5)]) / 3
df <- df_ohlcv[, c("timestamp", "p")]
gg <- ggplot(df, aes(x = timestamp, y = p))
gg <- gg + geom_line()
gg <- gg + scale_x_bd(business.dates = df$timestamp, labels = date_format("%a\n%b %d\n%H:%M"))
gg

这个

如您所见,生成的图删除了下班后的时间段,但 x 轴标签却被弄乱了。此外,背景中的灰色面板很不稳定。也许使用 bdscale 以外的东西会更好?帮助表示赞赏。

编辑:

> dput(df)
structure(list(timestamp = structure(c(1563286500, 1563286800, 
1563287100, 1563287400, 1563287700, 1563288000, 1563288300, 1563288600, 
1563288900, 1563289200, 1563289500, 1563289800, 1563290100, 1563290400, 
1563290700, 1563291000, 1563291300, 1563291600, 1563291900, 1563292200, 
1563292500, 1563292800, 1563356100, 1563356400, 1563356700, 1563357000, 
1563357300, 1563357600, 1563357900, 1563358200, 1563358500, 1563358800, 
1563359100, 1563359400, 1563359700, 1563360000, 1563360300, 1563360600, 
1563360900, 1563361200, 1563361500, 1563361800, 1563362100, 1563362400, 
1563362700, 1563363000, 1563363300, 1563363600, 1563363900, 1563364200, 
1563364500, 1563364800, 1563365100, 1563365400, 1563365700, 1563366000, 
1563366300, 1563366600, 1563366900, 1563367200, 1563367500, 1563367800, 
1563368100, 1563368400, 1563368700, 1563369000, 1563369300, 1563369600, 
1563369900, 1563370200, 1563370500, 1563370800, 1563371100, 1563371400, 
1563371700, 1563372000, 1563372300, 1563372600, 1563372900, 1563373200, 
1563373500, 1563373800, 1563374100, 1563374400, 1563374700, 1563375000, 
1563375300, 1563375600, 1563375900, 1563376200, 1563376500, 1563376800, 
1563377100, 1563377400, 1563377700, 1563378000, 1563378300, 1563378600, 
1563378900, 1563379200), class = c("POSIXct", "POSIXt"), tzone = "UTC"), 
    p = c(299.738333333333, 299.628333333333, 299.616666666667, 
    299.633333333333, 299.556666666667, 299.658333333333, 299.805, 
    299.843333333333, 299.913333333333, 299.843333333333, 299.844, 
    299.935, 299.963333333333, 300.003333333333, 300.016666666667, 
    299.924333333333, 299.92, 299.985, 300.046666666667, 299.958333333333, 
    299.95, 299.846666666667, 299.77, 299.78, 299.753333333333, 
    299.563333333333, 299.626666666667, 299.598333333333, 299.585, 
    299.43, 299.256666666667, 299.1333, 299.13, 299.096666666667, 
    299.046633333333, 299.063333333333, 298.804333333333, 298.59, 
    298.45, 298.598333333333, 298.763333333333, 298.776333333333, 
    298.893333333333, 298.875, 298.915, 298.844966666667, 298.83, 
    298.86, 299.036666666667, 299.129033333333, 299.203333333333, 
    299.136633333333, 299.058333333333, 299.038333333333, 298.873, 
    298.856666666667, 298.8373, 298.846666666667, 298.863333333333, 
    298.938333333333, 298.970033333333, 298.88, 298.912266666667, 
    298.95, 298.903333333333, 298.871666666667, 298.86, 298.8, 
    298.805666666667, 298.843966666667, 298.886533333333, 298.9178, 
    299.028333333333, 299.015, 298.986666666667, 298.973333333333, 
    298.818466666667, 298.708166666667, 298.548333333333, 298.543333333333, 
    298.613333333333, 298.66, 298.716666666667, 298.753333333333, 
    298.7, 298.693333333333, 298.6067, 298.586, 298.388333333333, 
    298.458333333333, 298.613333333333, 298.6254, 298.45, 298.245, 
    298.335, 298.361666666667, 298.273333333333, 298.258333333333, 
    298.266666666667, 298.027566666667)), .Names = c("timestamp", 
"p"), row.names = c(NA, -100L), class = c("tbl_df", "tbl", "data.frame"
))

标签: rggplot2quantmod

解决方案


我不确定是否有一种简单的解决方案可以在不将比例转换为离散比例的情况下以您想要的方式更改休息时间。

这样做的缺点是你失去了灵活设置休息时间的能力scale_x_datetime。为了解决这个问题,我给出了一些示例,说明如何通过更改数据框来设置一些方便的中断,如下例所示。我还将时间戳列转换为用于离散刻度的字符。

我假设,由于您正在获取市场时间的数据,因此市场时间已经由数据中的时间戳列定义。这样可以避免定义不包括假期等的自定义比例。

# convert to character column and set up handy columns for making breaks
df <- df %>%
      mutate(timestamp_chr = as.character(df$timestamp),
             day = lubridate::day(timestamp),
             hour = lubridate::hour(timestamp),
             minute = lubridate::minute(timestamp),
             new_day = if_else(day != lag(day) | is.na(lag(day)), 1, 0))


df

# # A tibble: 100 x 7
#    timestamp              p    day  hour minute timestamp_chr       new_day
#    <dttm>              <dbl> <int> <int>  <int> <chr>                 <dbl>
# 1  2019-07-16 14:15:00  300.    16    14     15 2019-07-16 14:15:00       1
# 2  2019-07-16 14:20:00  300.    16    14     20 2019-07-16 14:20:00       0
# 3  2019-07-16 14:25:00  300.    16    14     25 2019-07-16 14:25:00       0
# 4  2019-07-16 14:30:00  300.    16    14     30 2019-07-16 14:30:00       0
# 5  2019-07-16 14:35:00  300.    16    14     35 2019-07-16 14:35:00       0
# 6  2019-07-16 14:40:00  300.    16    14     40 2019-07-16 14:40:00       0
# 7  2019-07-16 14:45:00  300.    16    14     45 2019-07-16 14:45:00       0
# 8  2019-07-16 14:50:00  300.    16    14     50 2019-07-16 14:50:00       0
# 9  2019-07-16 14:55:00  300.    16    14     55 2019-07-16 14:55:00       0
# 10 2019-07-16 15:00:00  300.    16    15      0 2019-07-16 15:00:00       0
# # … with 90 more rows


# breaks equally spaced
my_breaks <-df$timestamp_chr[seq.int(1,length(df$timestamp_chr) , by = 10)]


ggplot(df, aes(x = timestamp_chr, y = p, group = 1)) +  
  geom_line() +
  scale_x_discrete(breaks = my_breaks) +
  theme(axis.text.x = element_text(angle = 90))

在此处输入图像描述

在上面的示例中,我使用了等间距的中断,但您也可以指定,例如:

# breaks on the hour
my_breaks <- df[df$minute == 0,]$timestamp_chr


# breaks at start of each new day
my_breaks <- df[df$new_day == 1,]$timestamp_chr

推荐阅读