quant_data · 数据工具箱
把"拉行情数据"这件事封装成函数,其他脚本 import 之后就能直接用。
安装 akshare:pip install akshare
依赖与基础导入
from datetime import datetime
import numpy as np
import pandas as pd
get_kline · A股日线
数据源自动兜底:akshare → baostock → 腾讯,谁通就用谁。
参数:symbol(默认 600519 贵州茅台)、start_date、end_date
函数定义与文档字符串
def get_kline(symbol="600519", start_date="20260101", end_date=None):
"""
拉取 A 股日线,返回一张表格,列名统一为:
open(开盘)high(最高)low(最低)close(收盘)volume(成交量)
数据源自动兜底:akshare -> baostock -> 腾讯,谁通就用谁。
symbol 是股票代码,默认贵州茅台 600519。
"""
import akshare as ak
import baostock as bs
import requests
日期处理与格式转换
if end_date is None:
end_date = datetime.now().strftime("%Y%m%d")
end_dash = f"{end_date[:4]}-{end_date[4:6]}-{end_date[6:]}"
start_dash = f"{start_date[:4]}-{start_date[4:6]}-{start_date[6:]}"
数据源 1:akshare(东财,免费、最常用)
try:
raw = ak.stock_zh_a_hist(
symbol=symbol,
period="daily",
start_date=start_date,
end_date=end_date,
adjust="qfq",
)
if raw is not None and len(raw) > 0:
df = pd.DataFrame({
"date": pd.to_datetime(raw["日期"]),
"open": raw["开盘"].astype(float),
"high": raw["最高"].astype(float),
"low": raw["最低"].astype(float),
"close": raw["收盘"].astype(float),
"volume": raw["成交量"].astype(float),
})
df = df.set_index("date")
print(f"[数据源] akshare 获取成功,共 {len(df)} 条")
return df
except Exception as e:
print(f"[数据源] akshare 不可用({type(e).__name__}),尝试 baostock...")
数据源 2:baostock(稳定,数据截至上一个交易日)
try:
bs_code = ("sh." if symbol.startswith("6") else "sz.") + symbol
bs.login()
rs = bs.query_history_k_data_plus(
bs_code,
"date,open,high,low,close,volume",
start_date=start_dash,
end_date=end_dash,
frequency="d",
adjustflag="2",
)
rows = []
while rs.error_code == "0" and rs.next():
rows.append(rs.get_row_data())
bs.logout()
if rows:
df = pd.DataFrame(rows, columns=["date", "open", "high", "low", "close", "volume"])
for c in ("open", "high", "low", "close", "volume"):
df[c] = pd.to_numeric(df[c])
df["date"] = pd.to_datetime(df["date"])
df = df.set_index("date")
print(f"[数据源] baostock 获取成功,共 {len(df)} 条")
return df
except Exception as e:
print(f"[数据源] baostock 不可用({type(e).__name__}),尝试腾讯...")
数据源 3:腾讯 ifzq(前复权,最多 1000 条)
try:
ten_code = ("sh" if symbol.startswith("6") else "sz") + symbol
url = "https://web.ifzq.gtimg.cn/appstock/app/fqkline/get"
r = requests.get(url, params={"param": f"{ten_code},day,,,1000,qfq"}, timeout=15)
kline = r.json()["data"][ten_code]
key = "qfqday" if "qfqday" in kline else "day"
rows = kline[key]
df = pd.DataFrame(rows, columns=["date", "open", "close", "high", "low", "volume"])
for c in ("open", "close", "high", "low", "volume"):
df[c] = pd.to_numeric(df[c])
df["date"] = pd.to_datetime(df["date"])
df = df.set_index("date")
print(f"[数据源] 腾讯 ifzq 获取成功,共 {len(df)} 条")
return df
except Exception as e:
print(f"[数据源] 腾讯也不可用({type(e).__name__})")
raise RuntimeError("所有 A 股数据源都不可用,请检查网络")
get_kline_crypto · 加密日线
数据源自动兜底:ccxt + OKX → 币安公开行情。
参数:symbol(默认 BTC/USDT)、limit(默认 1500)
函数定义与文档字符串
def get_kline_crypto(symbol="BTC/USDT", limit=1500):
"""
拉取加密市场日线,列名统一为 open/high/low/close/volume。
数据源自动兜底:ccxt + OKX(上期注册的交易所)-> 币安公开行情。
symbol 是交易对,默认 BTC/USDT。
"""
import ccxt
import requests
数据源 1:ccxt + OKX(上期注册的 API,可选)
try:
import os
api_key = os.getenv("OKX_API_KEY", "").strip()
secret = os.getenv("OKX_SECRET", "").strip()
password = os.getenv("OKX_PASSWORD", "").strip()
if api_key and secret and password:
ex = ccxt.okx({"apiKey": api_key, "secret": secret,
"password": password, "enableRateLimit": True,
"timeout": 30000})
else:
ex = ccxt.okx({"enableRateLimit": True, "timeout": 30000})
proxy = os.getenv("OKX_PROXY", "").strip()
if proxy:
ex.proxies = {"http": proxy, "https": proxy}
bars = ex.fetch_ohlcv(symbol, "1d", limit=limit)
if bars:
df = pd.DataFrame(bars, columns=["ts", "open", "high", "low", "close", "volume"])
df["date"] = pd.to_datetime(df["ts"], unit="ms")
df = df.set_index("date")
df = df.drop(columns=["ts"])
print(f"[数据源] OKX(ccxt) 获取成功,共 {len(df)} 条")
return df
except Exception as e:
print(f"[数据源] OKX 不可用({type(e).__name__}),尝试币安公开行情...")
数据源 2:币安公开行情(无需注册,直连稳定)
try:
base = symbol.replace("/", "")
url = "https://data-api.binance.vision/api/v3/klines"
r = requests.get(url, params={"symbol": base, "interval": "1d", "limit": limit},
timeout=20)
bars = r.json()
if isinstance(bars, list) and bars:
df = pd.DataFrame(bars, columns=[
"ts", "open", "high", "low", "close", "volume",
"close_ts", "quote_vol", "n", "taker_buy", "taker_buy_quote", "ignore",
])
df = df[["ts", "open", "high", "low", "close", "volume"]]
for c in ("open", "high", "low", "close", "volume"):
df[c] = pd.to_numeric(df[c])
df["date"] = pd.to_datetime(df["ts"], unit="ms")
df = df.set_index("date")
df = df.drop(columns=["ts"])
print(f"[数据源] 币安公开行情 获取成功,共 {len(df)} 条")
return df
except Exception as e:
print(f"[数据源] 币安也不可用({type(e).__name__})")
raise RuntimeError("所有加密数据源都不可用,请检查网络")
函数速览
get_kline · A股日线(三源兜底)
get_kline_crypto · 加密日线(双源兜底)
列名统一:open/high/low/close/volume
索引统一:date(datetime)
自动兜底:谁通就用谁
支持代理:OKX_PROXY 环境变量