You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

R语言调用Binance API填充数据框的方式是否高效规范?

关于Binance API批量获取K线数据的实现规范与效率优化咨询

我尝试通过Binance API获取BTCUSDT的1分钟开盘价,该API单次请求最多返回1500根K线。所需数据的时间范围为2019-09-09至2023-03-15。作为自学开发者,未来会频繁使用此类方法,因此想确认当前实现方式是否规范高效。目前我的实现需要发起1231次请求,整个过程耗时约15分钟,以下是我的R实现代码:

library(httr)
library(magrittr)
library(xts)

base_url <- "https://fapi.binance.com"
path1 <- "/fapi/v1/klines?symbol=BTCUSDT&interval=1m&startTime="
path2 <- "&limit=1500"
fxn <- get("GET")

## Total hours
total_hours = as.integer(as.Date("2023-03-15") - as.Date("2019-09-09")) * 24

## API requests needed
requests =  (total_hours * 60) / 1500

## Available data starts 2019-09-09
startTime = (as.numeric(as.POSIXct("2019-09-09 00:00:00 EST", origin = "1970-01-01")) * 1000)

## Create data frame of opening prices
prices = data.frame(matrix(ncol = 1))
colnames(prices) = "Open"

## Fill prices data frame
for(i in 1:requests){
  url <- paste0(base_url, path1, startTime, path2)
  call <- fxn(url)
  response <- content(call)
  prices %<>% add_row(Open = as.double(sapply(response, "[[", 2)))
  startTime = startTime + (1500*60000)
  
  print(i)
}

现有实现的问题与优化方向

1. 时间处理的准确性问题

  • 用as.Date计算天数转小时的方式,会忽略结束日期当天的分钟级数据,应该用完整的POSIXct时间戳计算总分钟数,避免数据遗漏或多算。
  • Binance API统一使用UTC时间,代码中用EST时区可能导致时间偏移,建议全程用UTC处理时间戳,消除时区转换误差。

2. 数据拼接效率低下

  • 循环中反复调用add_row扩展数据框,每次都会复制整个数据对象,数据量越大耗时越明显。建议预先用列表收集每批结果,最后一次性合并,效率会大幅提升。

3. 缺失错误处理机制

  • 没有处理API请求失败的情况(比如网络波动、限流触发),一旦某次请求出错,整个循环会直接中断,之前的数据也可能丢失。需要添加错误捕获和重试逻辑。

4. API请求的合理性优化

  • Binance API有请求频率限制,串行请求如果过于密集容易触发限流,建议每次请求后添加0.1-0.5秒的延迟;也可以尝试并行请求,但需严格控制并发数不超过API限制。
  • 可以通过endTime参数明确指定每批请求的结束时间,避免因服务器数据缺失导致的时间偏移,保证数据连续性。

优化后的示例代码

library(httr)
library(magrittr)
library(xts)

# 基础配置
base_url <- "https://fapi.binance.com"
symbol <- "BTCUSDT"
interval <- "1m"
limit <- 1500
start_time_str <- "2019-09-09 00:00:00 UTC"
end_time_str <- "2023-03-15 23:59:59 UTC"

# 转换为Binance要求的毫秒级时间戳
start_time <- as.numeric(as.POSIXct(start_time_str)) * 1000
end_time <- as.numeric(as.POSIXct(end_time_str)) * 1000

# 计算总请求次数(向上取整避免遗漏最后一批数据)
total_minutes <- (end_time - start_time) / 60000
requests <- ceiling(total_minutes / limit)

# 初始化列表存储每批结果(比循环拼接数据框高效)
price_list <- vector("list", length = requests)

# 循环请求数据
for(i in 1:requests){
  # 计算当前请求的结束时间(不超过总结束时间)
  current_end <- min(start_time + limit * 60000, end_time)
  url <- paste0(base_url, "/fapi/v1/klines?symbol=", symbol, "&interval=", interval,
                "&startTime=", start_time, "&endTime=", current_end, "&limit=", limit)
  
  # 带重试的请求逻辑
  tryCatch({
    response <- GET(url)
    stop_for_status(response) # 检查HTTP状态码,非200则抛出错误
    data <- content(response)
    # 提取开盘价并转换为数值类型
    price_list[[i]] <- as.double(sapply(data, "[[", 2))
    cat("完成请求", i, "/", requests, "\n")
  }, error = function(e){
    cat("请求", i, "失败:", e$message, ",1秒后重试...\n")
    Sys.sleep(1)
    i <- i - 1 # 重新执行当前请求
  })
  
  # 更新下一次请求的起始时间
  start_time <- current_end + 60000 # 下一分钟的起始时间
  Sys.sleep(0.2) # 避免触发API限流
}

# 合并所有结果为数据框
prices <- data.frame(Open = unlist(price_list))

内容的提问来源于stack exchange,提问作者bernresearch

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 11:13:23