用 R 获取中国国债到期收益率曲线数据
楚新元 / 2021-08-18
这里直接给出代码如下,读者自行体验。
get_cnbond_yield = function(from, to) {
# 规范化日期格式
from = lubridate::ymd(from)
to = lubridate::ymd(to)
# 参数检查,参数输入错误后给出必要的提示
test_internet = curl::has_internet()
if (!test_internet) {
stop('没有发现网络链接...')
}
if (is.na(from) | is.na(to)) {
stop('输入的起止日期参数必须是包含年月日的字符。')
}
if (to < from) {
stop('发现期初日期 > 期末日期,你把两者弄混了吗?')
}
if (to > Sys.Date()) {
stop('输入的期末日期不能大于当前日期。')
}
if (from < "2006-03-01") {
stop('数据库不包含2006年3月1日之前的数据。')
}
# 生成起止时间段完整的日期向量
dates = seq.Date(from = from, to = to, by = "day")
# 生成每一天的数据下载地址
url = paste0(
"http://yield.chinabond.com.cn/cbweb-mn/yc/downBzqxDetail?ycDefIds=2c9081e50a2f9606010a3068cae70001&&zblx=txy&&workTime=",
dates,
"&&dxbj=0&&qxlx=0,&&yqqxN=N&&yqqxK=K&&wrjxCBFlag=0&&locale=zh_CN"
)
# 批量下载数据到data文件夹下
if (!dir.exists("data")) dir.create("data")
purrr::pwalk(
list(
url = url,
mode = "wb",
quiet = TRUE,
destfile = paste0("./data/", dates, ".xlsx")
),
download.file
)
# 批量读取非空.xlsx文件后合并成一个数据框
data_list = fs::dir_ls(path = "./data", glob = "*.xlsx")
data_list = data_list[file.info(data_list)$size > 3235]
names(data_list) = data_list
df = purrr::map_dfr(
data_list,
readxl::read_xlsx,
.id = "Date"
)
fs::dir_delete("data") # 删除data文件夹
# 必要的数据清洗加工
df[, 2] = NULL
colnames(df)[2:3] = c("Term", "Rate")
df$Rate = as.numeric(df$Rate)
df$Date = gsub("./data/", "", df$Date)
df$Date = gsub(".xlsx", "", df$Date)
df$Term[df$Term == 0] = "1D"
df$Term[df$Term == 0.08] = "1M"
df$Term[df$Term == 0.17] = "2M"
df$Term[df$Term == 0.25] = "3M"
df$Term[df$Term == 0.5] = "6M"
df$Term[df$Term == 0.75] = "9M"
df$Term[df$Term ==1] = "1Y"
df$Term[df$Term ==2] = "2Y"
df$Term[df$Term ==3] = "3Y"
df$Term[df$Term ==5] = "5Y"
df$Term[df$Term ==7] = "7Y"
df$Term[df$Term ==10] = "10Y"
df$Term[df$Term ==15] = "15Y"
df$Term[df$Term ==20] = "20Y"
df$Term[df$Term ==30] = "30Y"
df$Term[df$Term ==40] = "40Y"
df$Term[df$Term ==50] = "50Y"
result = tidyr::pivot_wider(
data = df,
names_from = Term,
values_from = Rate
)
# 导出数据到Excel文件中
writexl::write_xlsx(result, "result.xlsx")
}