交易工具

币安 API 拉历史 K 线 怎么避免漏数据

2026-04-23 · 6 分钟阅读

用 API 拉历史 K 线做回测要分页要去重本文给出标准范式。

回测策略需要历史 K 线。先在 币安官网 创建只读 API Key,APP 用 币安官方APP(iOS 见 iOS安装教程)。

接口

GET /api/v3/klines
参数: symbol, interval, startTime, endTime, limit

limit 最大 1000 条。

一次性拉全部历史

不可能。limit 限制 1000 条。需要分页。

分页范式

import time
all_klines = []
end = int(time.time() * 1000)
start = end - 365 * 24 * 3600 * 1000  # 1 年

while start < end:
    klines = client.get_klines(
        symbol='BTCUSDT',
        interval='1h',
        startTime=start,
        limit=1000
    )
    if not klines:
        break
    all_klines.extend(klines)
    start = klines[-1][0] + 1  # 下一批从最后一根 + 1ms 开始
    time.sleep(0.5)  # 限速保护

去重

边界 K 线可能重复。每批末尾 + 1ms 避免。

或者:

import pandas as pd
df = pd.DataFrame(all_klines)
df = df.drop_duplicates(subset=[0])  # 时间戳去重

K 线格式

每条 K 线是数组:

[
  open_time,    # 开盘时间戳 ms
  open,         # 开盘价
  high,         # 最高
  low,          # 最低
  close,        # 收盘
  volume,       # 成交量
  close_time,   # 收盘时间戳
  quote_volume, # 报价币种成交额
  trades,       # 成交笔数
  taker_buy_base,
  taker_buy_quote,
  ignore
]

转 DataFrame

df = pd.DataFrame(all_klines, columns=[
    'open_time','open','high','low','close','volume',
    'close_time','quote_volume','trades',
    'taker_buy_base','taker_buy_quote','ignore'
])
df['open_time'] = pd.to_datetime(df['open_time'], unit='ms')
df.set_index('open_time', inplace=True)
df = df.astype({'open': float, 'high': float, 'low': float, 'close': float, 'volume': float})

之后能用 pandas / numpy / 各种回测库。

周期与数据量

周期 1 年 K 线数
1m 525600
5m 105120
15m 35040
1h 8760
4h 2190
1d 365

按 1000 条/批拉:

  • 1m 1 年 = 526 次请求 = 4-5 分钟
  • 1h 1 年 = 9 次请求 = 几秒

多币种并发

import concurrent.futures
symbols = ['BTCUSDT', 'ETHUSDT', 'SOLUSDT']

def fetch(s):
    return get_history(s, '1h', 365)

with concurrent.futures.ThreadPoolExecutor(max_workers=3) as ex:
    results = list(ex.map(fetch, symbols))

并发但不要超过 weight 上限。

公开 vs 鉴权

历史 K 线是公开数据,不需要 API Key 也能拉:

import requests
url = 'https://api.binance.com/api/v3/klines'
params = {'symbol': 'BTCUSDT', 'interval': '1h', 'limit': 1000}
r = requests.get(url, params=params)

但鉴权(带 Key)能享受更高 weight 上限。

完整年度数据

币安提供历史数据下载(zip CSV 包),可以一次性下载好几年的数据:

  • data.binance.vision/

按月、按 K 线类型。比 API 拉快很多。

持续更新

回测后实盘需要持续更新最新 K 线。两种方式:

1. 定时拉

每分钟拉最近 5 根 K 线,更新本地。

2. WebSocket

订阅 K 线 WS:

wss://stream.binance.com:9443/ws/btcusdt@kline_1h

每根 K 线更新即时推送。

WS 适合实时;REST 适合历史补充。

数据质量

注意:

  • 网络抖动可能漏一批
  • 时间戳要校对(毫秒不是秒)
  • 未收盘 K 线(最近一根)会变化

回测时排除最近一根未收盘 K 线。

持久化

拉到的数据存:

  • CSV:简单
  • Parquet:高效压缩
  • SQLite:查询方便
  • DuckDB:分析快
  • 时序数据库:海量数据

中等量用 Parquet。

衍生品历史

合约 K 线接口:

  • U 本位:/fapi/v1/klines
  • 币本位:/dapi/v1/klines

参数和返回格式与现货 v3 一致。

资金费率历史

GET /fapi/v1/fundingRate?symbol=BTCUSDT&limit=1000

每 8 小时一条。最多 1000 条 = 333 天。

常见问题

问:拉历史会被限速吗? 答:会。注意 sleep。

问:能拉所有币种吗? 答:能。但有些已下架的币历史保留有限。

问:1m K 线占内存多大? 答:1 年 ≈ 50MB(CSV)。多币累计很大。

问:回测能模拟滑点吗? 答:需要自己加滑点模型。币安数据不带。

问:历史数据可以商用吗? 答:用于自己策略 OK。重新公开发布需看条款。

延伸阅读

历史 K 线是回测的燃料。学会拉数据 + 去重 + 持久化,量化策略已经成功一半。