四大免费数据源代码实测

前两篇讲了为什么自建技术选型。 本文直接上代码,实测对比四个数据源。


1. 快速上手

python 复制代码
# === AKShare ===
pip install akshare
import akshare as ak
df = ak.stock_zh_a_hist(symbol='000001', period='daily', adjust='qfq')
# 返回:日期、开盘、收盘、最高、最低、成交量、成交额、振幅、涨跌幅、涨跌额、换手率

# === Tushare ===
pip install tushare
import tushare as ts
ts.set_token('your_token_here')
pro = ts.pro_api()
df = pro.daily(ts_code='000001.SZ', start_date='20240101', end_date='20241231')
# 返回:ts_code, trade_date, open, high, low, close, pre_close, change, pct_chg, vol, amount

# === yfinance ===
pip install yfinance
import yfinance as yf
df = yf.Ticker('000001.SZ').history(period='1y')
# 返回:Open, High, Low, Close, Volume, Dividends, Stock Splits

# === Baostock ===
pip install baostock
import baostock as bs
bs.login()
rs = bs.query_history_k_data_plus('sz.000001',
    'date,open,high,low,close,volume', start_date='2024-01-01', end_date='2024-12-31')
df = rs.get_data()
bs.logout()

2. 数据质量实测

以平安银行 000001 为样本,对比 2025-01-02 日线数据:

python 复制代码
import akshare as ak
import tushare as ts
import yfinance as yf
import baostock as bs

# 基准数据(东方财富网页端手工验证)
benchmark = {'open': 11.25, 'high': 11.42, 'low': 11.02, 'close': 11.38}

def test_accuracy(name, data):
    errors = {}
    for field in ['open', 'high', 'low', 'close']:
        diff = abs(data[field] - benchmark[field])
        errors[field] = f'{diff:.2f}'
    return errors

# AKShare
ak_df = ak.stock_zh_a_hist(symbol='000001', period='daily', start_date='20250102', end_date='20250102')
ak_data = {'open': ak_df['开盘'].iloc[0], 'high': ak_df['最高'].iloc[0],
           'low': ak_df['最低'].iloc[0], 'close': ak_df['收盘'].iloc[0]}
print('AKShare:', test_accuracy('AKShare', ak_data))
# 输出:误差全为 0.00

# yfinance
yf_df = yf.Ticker('000001.SZ').history(start='2025-01-02', end='2025-01-03')
yf_data = {'open': yf_df['Open'].iloc[0], 'high': yf_df['High'].iloc[0],
           'low': yf_df['Low'].iloc[0], 'close': yf_df['Close'].iloc[0]}
print('yfinance:', test_accuracy('yfinance', yf_data))
# 输出:±0.01-0.02 偏差(Yahoo 使用自有数据源)

结论:AKShare、Tushare、Baostock 与东方财富一致。yfinance 有 ±0.01 的系统偏差。


3. 更新时效

python 复制代码
from datetime import datetime
import akshare as ak

# 检测当日数据是否已更新
today = datetime.now().strftime('%Y%m%d')
df = ak.stock_zh_a_hist(symbol='000001', period='daily', start_date=today, end_date=today)

if len(df) > 0:
    print(f'✅ {today} 日线已更新')
else:
    print(f'⏳ {today} 日线尚未更新(通常在15:30后)')
数据源 当日可用时间 盘中数据
AKShare 15:30 ✅ 有实时接口
Tushare 16:00+ ❌ 免费版
yfinance 18:00+
Baostock 次日上午

4. AKShare 防封 IP 方案

python 复制代码
import time
import random
import akshare as ak
import psycopg2
from datetime import datetime, timedelta

def safe_fetch(symbol, max_retries=3):
    """带退避重试的安全拉取"""
    for attempt in range(max_retries):
        try:
            df = ak.stock_zh_a_hist(
                symbol=symbol, period='daily',
                start_date='20200101', end_date=datetime.now().strftime('%Y%m%d'),
                adjust='qfq'  # 前复权
            )
            return df
        except Exception as e:
            wait = random.uniform(3, 8) * (attempt + 1)
            print(f'⚠️ {symbol} 失败 (attempt {attempt+1}): {e}')
            print(f'   等待 {wait:.0f} 秒重试...')
            time.sleep(wait)
    print(f'❌ {symbol} 3次重试全部失败,跳过')
    return None

def fetch_all_with_throttle(stock_list):
    """全量拉取 + 限速 + 本地缓存"""
    conn = psycopg2.connect('postgresql://trader:xxx@localhost:5432/quant')
    cur = conn.cursor()

    for i, symbol in enumerate(stock_list):
        # 1. 检查本地是否已有今日数据
        cur.execute("""
            SELECT 1 FROM kline_daily
            WHERE symbol = %s AND trade_date = CURRENT_DATE
        """, (symbol,))

        if cur.fetchone():
            print(f'[{i+1}/{len(stock_list)}] {symbol} ✅ 已有今日数据,跳过')
            continue

        # 2. 拉取 + 入库
        df = safe_fetch(symbol)
        if df is not None:
            for _, row in df.iterrows():
                cur.execute("""
                    INSERT INTO kline_daily (symbol, trade_date, open, high, low, close, volume)
                    VALUES (%s, %s, %s, %s, %s, %s, %s)
                    ON CONFLICT (symbol, trade_date) DO UPDATE SET
                        open=EXCLUDED.open, high=EXCLUDED.high, low=EXCLUDED.low,
                        close=EXCLUDED.close, volume=EXCLUDED.volume
                """, (symbol, row['日期'], row['开盘'], row['最高'], row['最低'], row['收盘'], row['成交量']))

            conn.commit()
            print(f'[{i+1}/{len(stock_list)}] {symbol} ✅ 拉取成功')

        # 3. 限速:随机间隔 0.5-1.5 秒
        time.sleep(random.uniform(0.5, 1.5))

    cur.close()
    conn.close()
    print('🎉 全量拉取完成')

# 使用
stock_list = ['000001', '000002', '000333', '600519', '601318']  # 示例
fetch_all_with_throttle(stock_list)

5. yfinance 美股 + A 股混用

python 复制代码
import yfinance as yf

# 美股
aapl = yf.Ticker('AAPL')
print(f"AAPL 市值: ${aapl.info['marketCap']:,}")
print(f"AAPL PE: {aapl.info['trailingPE']:.1f}")

# A 股(深交所 .SZ,上交所 .SS)
midea = yf.Ticker('000333.SZ')
print(f"\n美的集团最新价: ¥{midea.history(period='1d')['Close'].iloc[-1]:.2f}")

# 港股
tencent = yf.Ticker('0700.HK')
print(f"腾讯最新价: HK${tencent.history(period='1d')['Close'].iloc[-1]:.2f}")

# 加密货币
btc = yf.Ticker('BTC-USD')
print(f"比特币: ${btc.history(period='1d')['Close'].iloc[-1]:,.0f}")

6. 综合评分

AKShare Tushare yfinance Baostock
数据覆盖 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐
A股质量 ⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐
稳定性 ⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐
入门门槛 不用注册 要实名 不用注册 不用注册
代码量

7. 我的推荐

python 复制代码
# 生产环境(A股):Tushare 主力 + AKShare 补充
import tushare as ts  # 日线、复权、财务
import akshare as ak   # 资金流向、龙虎榜

# 美股:yfinance 一把梭
import yfinance as yf  # 全搞定

# 新手入门:AKShare + yfinance
import akshare as ak   # A股
import yfinance as yf  # 美股 + 全球
# 两个都不用注册,5分钟跑起来
相关推荐
用户5591357826319 小时前
Python + PostgreSQL + Docker 技术选型实战
产品
AskHarries2 天前
我如何从1000个产品里筛出方向
人工智能·产品·全栈
华洛3 天前
讲讲如何在传统产品中挖掘AI需求
javascript·产品经理·产品
小北的AI科技分享3 天前
产品管理:从概念到落地的全流程解析
产品··经理
字节逆旅6 天前
Marvis:腾讯悄悄搞了个 AI 桌面助手,有点意思
agent·产品
AskHarries6 天前
如何判断一个需求是真需求
人工智能·程序员·产品
全栈人月9 天前
技术人也要懂市场
产品
不简说9 天前
前端可视化打印设计器sv-print,一口气更新了30版
前端·源码·产品
可观测性用观测云14 天前
观测云产品更新 | Agent 监测、管理、APM等
产品