🎯 本章学习目标
欢迎来到量化交易的"弹药库"章节。如果把量化策略比作一辆赛车,那么数据就是它的燃料——没有燃料,再强的引擎也只能原地轰鸣。读完这一章,你将能够:
- 掌握至少5种免费金融数据源的获取方式,覆盖A股、美股、基金、加密货币等主要市场
- 理解不同数据源的优劣,知道在什么场景下该用哪个数据源
- 编写Python代码自动获取和清洗数据,把数据变成策略可用的"食材"
- 评估数据质量,识别缺失值、异常值等常见问题
- 与AI协作设计数据获取方案,让AI帮你写代码、找数据源、诊断问题
💬 一个真实的故事
小李是个量化新手,刚学完Python基础,兴致勃勃地想要回测一个"双均线金叉策略"。他打开Backtrader,写好策略逻辑,运行代码——结果报错了。原来,他根本没有数据。
他打开搜索引擎,输入"股票数据免费下载",结果跳出一堆广告:有的是收费的,有的需要注册复杂的API,有的数据格式乱七八糟。折腾了一整天,他终于从某个论坛下载了一份CSV文件,结果发现数据只到2022年,而且缺少成交量列。
小李气得差点放弃。他打开ChatGPT,问:"我需要一个免费的A股历史数据源,要求有日线数据,包含OHLCV,最好能直接用在Python里。"AI给了他三个选项:Tushare、AKShare和Yahoo Finance。半小时后,他已经拿到了贵州茅台从2010年至今的完整日线数据。
这个故事告诉我们:数据获取是量化交易的第一步,也是最让人头疼的一步。但有了AI的帮助,这个过程可以从"一天"缩短到"半小时"。
核心洞察:数据获取的本质不是"找数据",而是"建立一条从原始数据到策略引擎的自动化流水线"。一旦这条流水线搭好,后面的一切都会顺畅很多。
⚡ 核心知识:数据获取全景图
1. 为什么数据如此重要?
在量化交易的世界里,有一句话被反复提及:"Garbage in, garbage out"(垃圾进,垃圾出)。如果你的数据有错误、有缺失、有延迟,那么无论你的策略多么精妙,结果都可能是灾难性的。
数据质量问题的常见表现包括:价格跳空缺失(某些交易日没有数据)、复权错误(分红送股后价格没有正确调整)、时间戳混乱(不同数据源的时间格式不一致)、成交量异常(某天的成交量突然变成0或者巨大无比)。这些问题在回测中可能不明显,但一旦上实盘,就会让你付出真金白银的代价。
但好消息是,对于初学者来说,免费的金融数据已经足够支撑你学习和小规模研究。你不需要花几千块钱买Wind或者Bloomberg,先把手头能拿到的免费数据用好,才是正经事。
2. 免费数据源全景对比
下面的表格整理了目前最主流的免费金融数据源。你可以把它当成"数据采购指南",根据自己的需求对号入座。
| 数据源 | 覆盖市场 | 数据类型 | 获取方式 | 限制 | 推荐指数 |
| Tushare | A股、港股、美股、基金 | 日线、分钟线、财务数据 | Python API | 积分制,高频数据需付费 | ⭐⭐⭐⭐⭐ |
| AKShare | A股、期货、期权、宏观 | 日线、实时行情、基本面 | Python API | 部分接口不稳定 | ⭐⭐⭐⭐ |
| Yahoo Finance | 美股、港股、A股(ADR) | 日线、分钟线、财务数据 | yfinance库 | A股数据有延迟 | ⭐⭐⭐⭐ |
| JoinQuant(聚宽) | A股 | 日线、分钟线、财务数据 | 平台内置 | 需注册,数据不能导出 | ⭐⭐⭐ |
| Baostock | A股 | 日线、复权数据 | Python API | 数据更新较慢 | ⭐⭐⭐ |
| CCXT | 加密货币 | 现货、合约K线 | Python API | 各交易所限制不同 | ⭐⭐⭐⭐ |
3. 数据获取流程:从需求到落地
很多人在获取数据时犯的第一个错误是:上来就写代码。正确的流程应该是"先规划,后执行"。下面是一个标准化的数据获取流程,你可以把它当成 checklist 来用。
flowchart LR
A[明确数据需求] --> B[选择数据源]
B --> C[获取API密钥]
C --> D[下载数据]
D --> E[数据清洗]
E --> F[质量检查]
F --> G[存储数据]
G --> H[策略使用]
style A fill:#f97316,stroke:#fff,color:#fff
style H fill:#06b6d4,stroke:#fff,color:#fff
第一步:明确数据需求。你需要回答几个问题:我要交易什么市场?需要日线还是分钟线?需要哪些字段(开盘价、收盘价、成交量等)?数据要回溯到什么时候?这些问题决定了你选哪个数据源。
第二步:选择数据源。如果你做A股,首选Tushare或AKShare;如果你做美股,Yahoo Finance是最简单的;如果你做加密货币,CCXT几乎覆盖了所有主流交易所。
第三步:获取API密钥。大部分免费数据源都需要注册账号并获取API Token。这一步通常只需要5分钟,但很多人会卡在这里——别怕,AI可以一步步教你。
第四步:下载数据。用Python调用API,把数据拉取到本地。这里要注意频率限制,不要一股脑发太多请求,否则会被封IP。
第五步:数据清洗。这是最容易被忽视但最关键的步骤。你需要处理缺失值、调整复权价格、统一时间格式、去除异常值。
第六步:质量检查。用简单的统计方法检查数据是否合理。比如,检查是否有某天的收盘价为0,或者成交量突然暴增100倍。
第七步:存储数据。清洗后的数据要保存到合适的位置。对于小规模数据,CSV就够了;对于大规模数据,建议使用Parquet或HDF5格式。
4. 数据质量:免费数据的"坑"与"避坑指南"
免费数据虽然香,但也有一些常见的坑。作为一个负责任的量化学习者,你必须知道这些坑在哪里,以及如何避开它们。
- 前复权 vs 后复权 vs 不复权:很多新手直接用"不复权"数据回测,结果遇到股票分红送股,价格突然跳空,策略信号就全乱了。正确的做法是使用"前复权"数据做回测,但要知道前复权会改变历史价格,所以不能用来计算真实盈亏。
- 停牌日的处理:有些数据源会省略停牌日的数据,有些会用前一天的价格填充。这两种做法都会影响策略表现,你需要明确知道自己用的数据源是怎么处理的。
- 新股上市初期的数据:新股上市第一天通常涨跌幅限制不同,成交量也异常大。很多策略在新股上的表现都会失真,建议在回测时排除上市不满一年的股票。
- 时间戳不一致:有些数据源用北京时间,有些用UTC;有些收盘时间是15:00,有些是15:05。如果你同时用多个数据源,时间戳不一致会导致严重的数据错位。
🤖 与AI一起练习
练习1:让AI帮你选择数据源
Prompt模板:
我想做A股量化交易,策略是双均线交叉,需要日线数据(OHLCV),
时间范围是2020年至今。请推荐3个免费数据源,并对比它们的:
1. 数据覆盖范围
2. 获取难度
3. 数据质量
4. 使用限制
请以表格形式输出。
练习2:让AI帮你写数据获取代码
Prompt模板:
请用Python写一段代码,使用AKShare获取贵州茅台(600519)
从2020年1月1日到今天的日线数据,要求:
1. 包含前复权价格
2. 保存为CSV文件
3. 处理可能的缺失值
4. 添加一列"涨跌幅"
请给出完整可运行的代码,并逐行解释。
练习3:让AI诊断数据质量问题
Prompt模板:
我下载了一份股票数据,怀疑其中有质量问题。
请写一个Python函数,自动检测以下问题:
1. 缺失的交易日
2. 收盘价为0或负数的情况
3. 成交量异常(单日成交量超过均值10倍)
4. 涨跌幅超过±20%的情况(非ST股票)
函数应该返回问题清单和对应的行号。
🔧 动手实践:编写你的第一个数据获取脚本
光说不练假把式。下面是一段完整的Python代码,展示了如何用yfinance获取美股数据、用AKShare获取A股数据,并进行基础的数据清洗和质量检查。
import pandas as pd
import akshare as ak
import yfinance as yf
from datetime import datetime, timedelta
import numpy as np
# ==========================================
# 第一部分:获取A股数据(使用AKShare)
# ==========================================
def get_a_stock_data(stock_code, start_date, end_date):
"""
获取A股历史日线数据(前复权)
stock_code: 如 "600519"(贵州茅台)
"""
print(f"正在获取 {stock_code} 的数据...")
# 使用AKShare获取数据
df = ak.stock_zh_a_hist(
symbol=stock_code,
period="daily",
start_date=start_date.replace("-", ""),
end_date=end_date.replace("-", ""),
adjust="qfq" # qfq = 前复权
)
# 重命名列,统一格式
df.columns = ['date', 'open', 'close', 'high', 'low', 'volume',
'amount', 'amplitude', 'pct_change', 'change_amount', 'turnover']
# 转换日期格式
df['date'] = pd.to_datetime(df['date'])
df.set_index('date', inplace=True)
print(f"获取完成,共 {len(df)} 条记录")
return df
# 获取贵州茅台2020年至今的数据
maotai = get_a_stock_data("600519", "2020-01-01", "2024-12-31")
print(maotai.head())
# ==========================================
# 第二部分:获取美股数据(使用yfinance)
# ==========================================
def get_us_stock_data(ticker, period="5y"):
"""
获取美股历史数据
ticker: 如 "AAPL", "TSLA", "SPY"
"""
print(f"正在获取 {ticker} 的数据...")
stock = yf.Ticker(ticker)
df = stock.history(period=period)
# yfinance返回的列名已经是标准格式
# 只保留我们需要的列
df = df[['Open', 'High', 'Low', 'Close', 'Volume']]
df.columns = ['open', 'high', 'low', 'close', 'volume']
print(f"获取完成,共 {len(df)} 条记录")
return df
# 获取苹果公司5年数据
apple = get_us_stock_data("AAPL")
print(apple.head())
# ==========================================
# 第三部分:数据质量检查
# ==========================================
def check_data_quality(df, stock_name="Unknown"):
"""
检查数据质量,返回问题报告
"""
issues = []
# 1. 检查缺失值
missing = df.isnull().sum()
if missing.any():
issues.append(f"发现缺失值: \n{missing[missing > 0]}")
# 2. 检查零值或负值的价格
price_cols = ['open', 'high', 'low', 'close']
for col in price_cols:
if col in df.columns:
invalid = df[df[col] <= 0]
if len(invalid) > 0:
issues.append(f"{col} 有 {len(invalid)} 条非正值记录")
# 3. 检查成交量异常
if 'volume' in df.columns:
mean_vol = df['volume'].mean()
extreme = df[df['volume'] > mean_vol * 10]
if len(extreme) > 0:
issues.append(f"发现 {len(extreme)} 条成交量异常记录(超过均值10倍)")
# 4. 检查价格连续性(是否有跳空缺失)
if len(df) > 1:
# 计算相邻交易日的间隔
if isinstance(df.index, pd.DatetimeIndex):
gaps = df.index.to_series().diff().dt.days
# A股通常间隔1-3天(周末+节假日)
long_gaps = gaps[gaps > 5]
if len(long_gaps) > 0:
issues.append(f"发现 {len(long_gaps)} 个超过5天的数据缺口")
# 5. 检查涨跌幅异常
if 'close' in df.columns:
daily_return = df['close'].pct_change()
extreme_moves = daily_return[abs(daily_return) > 0.2]
if len(extreme_moves) > 0:
issues.append(f"发现 {len(extreme_moves)} 天涨跌幅超过20%")
# 输出报告
print(f"\n{'='*40}")
print(f"数据质量报告: {stock_name}")
print(f"{'='*40}")
print(f"总记录数: {len(df)}")
print(f"日期范围: {df.index[0]} 至 {df.index[-1]}")
print(f"发现问题数: {len(issues)}")
if issues:
for i, issue in enumerate(issues, 1):
print(f"\n问题 {i}: {issue}")
else:
print("\n数据质量良好,未发现明显问题!")
return len(issues) == 0
# 运行质量检查
check_data_quality(maotai, "贵州茅台(600519)")
check_data_quality(apple, "苹果(AAPL)")
# ==========================================
# 第四部分:保存数据
# ==========================================
def save_data(df, filename):
"""保存数据到CSV"""
df.to_csv(filename)
print(f"\n数据已保存至: {filename}")
save_data(maotai, "maotai_daily.csv")
save_data(apple, "apple_daily.csv")
print("\n✅ 全部完成!你现在可以用这些数据来运行策略了。")
运行这段代码,你会得到两个CSV文件,分别包含贵州茅台和苹果公司的历史日线数据。更重要的是,你建立了一套"获取-检查-保存"的标准化流程,以后每获取一个新数据,都可以复用这套流程。
交互式数据获取模拟器
在下面这个模拟器中,你可以体验不同参数对数据获取结果的影响。虽然它不会真的去下载数据,但可以帮助你理解各个参数的含义。
🤔 思考题
知识自测
1. 以下哪种情况最可能导致回测结果失真?
- A. 使用了前复权数据
- B. 使用了不包含停牌日的数据
- C. 使用了不复权数据进行长线回测
- D. 数据时间范围太短
答案是C。不复权数据在遇到分红送股时会出现价格跳空,导致均线等技术指标计算错误,从而使策略信号完全失真。前复权数据是回测的标准做法;停牌日缺失通常影响较小;数据时间范围短会降低统计显著性,但不会直接导致信号失真。
2. Tushare的积分制是什么意思?
- A. 积分越高,数据质量越好
- B. 积分是用来排名的,不影响使用
- C. 积分越高,可以访问的数据接口越多
- D. 积分需要花钱买,没有免费获取途径
答案是C。Tushare采用积分制来管理API访问权限:基础数据(日线行情)只需要很少积分或零积分;高频数据、财务数据等高级接口需要更多积分。积分可以通过注册、邀请好友、贡献代码等方式免费获取,不是必须购买的。
3. 如果你要同时回测A股和美股策略,最佳的数据获取方案是?
- A. 只用Tushare,因为它数据最全
- B. 只用Yahoo Finance,因为它最简单
- C. A股用AKShare/Tushare,美股用Yahoo Finance
- D. 手动从财经网站复制粘贴
答案是C。不同数据源有各自的优势领域:Tushare和AKShare在A股数据上最全面准确,Yahoo Finance在美股数据上最便捷。混合使用可以发挥各自优势。手动复制粘贴效率极低且容易出错,完全不可取。
深入思考
- 如果你发现某只股票在某一天的成交量为0,但价格有变化,可能是什么原因?应该如何处理?
- 为什么加密货币的数据获取比股票更复杂?交易所之间的价格差异会带来什么问题?
- 假设你有一份2015-2024年的数据,但发现2020年3月有一段数据缺失(正好是新冠崩盘期间),这对你的策略回测会有什么影响?
🚀 下一章预告
数据已经到手,但你真的会用AI来帮你处理数据吗?下一章《AI Prompt工程——如何让AI听懂你的交易逻辑》,我们将彻底告别"AI听不懂我说话"的困境。
你将学会:如何写出高质量的Prompt,让AI一次就生成你需要的代码;如何避免"差Prompt生成bug代码,好Prompt生成完美代码"的尴尬;以及一套实用的"量化Prompt模板库",以后每次写Prompt直接套模板就行。
如果你曾经对着AI输入"帮我写个量化策略",然后看着它生成一堆不知所云的代码发呆——下一章就是为你准备的。