共计 2720 个字符,预计需要花费 7 分钟才能阅读完成。
1. A 股量化现状与数据困境
刚接触 A 股量化的开发者常会遇到这样的场景:好不容易写好了策略代码,却发现历史数据获取要么收费高昂,要么接口不稳定。相比美股成熟的量化生态,A 股市场存在几个典型痛点:

- 数据孤岛问题:核心数据分散在各券商、交易所、第三方平台
- 非标数据格式:不同来源的复权方式、字段命名差异显著
- 更新延迟:免费源常有 15 分钟以上的行情延迟
我曾尝试过多个数据源,直到发现 AKShare 这个宝藏库——一个免费、开源的金融数据接口库,特别适合个人开发者低成本启动。
2. 数据源横向对比
先看几个主流数据源的特性对比(以股票基础数据为例):
| 特性 | AKShare | Tushare Pro | Wind | 聚源 |
|---|---|---|---|---|
| 费用 | 免费 | 分级收费 | 年费制 | 按量计费 |
| 更新频率 | 实时 | 15 分钟延迟 | 实时 | 实时 |
| 历史数据深度 | 10 年 + | 20 年 + | 完整 | 完整 |
| 接口稳定性 | ★★★☆ | ★★★★ | ★★★★★ | ★★★★ |
AKShare 的核心优势 在于:
- 完全规避了商业 API 的鉴权复杂性问题
- 通过
requests_html直接抓取权威源数据,避免二次加工 - 支持银行间市场、期货、期权等泛金融数据
3. 实战四部曲
3.1 环境准备
安装只需要一行命令(建议使用虚拟环境):
pip install akshare pandas backtrader
3.2 数据获取实战
以获取贵州茅台 (600519) 的日线数据为例:
import akshare as ak
# 获取后复权数据
def get_stock_data(stock_code):
try:
df = ak.stock_zh_a_daily(
symbol=stock_code,
adjust="hfq" # hfq 后复权, qfq 前复权, none 不复权
)
# 处理停牌日(AKShare 已自动过滤)df = df[df["volume"] > 0]
# 标准化字段名以兼容 Backtrader
df.rename(columns={
"date": "datetime",
"open": "open",
"high": "high",
"low": "low",
"close": "close",
"volume": "volume"
}, inplace=True)
df["datetime"] = pd.to_datetime(df["datetime"])
df.set_index("datetime", inplace=True)
return df
except Exception as e:
print(f"数据获取异常: {e}")
return None
# 示例调用
mt_data = get_stock_data("sh600519")
print(mt_data.tail(3))
关键点说明:
– 复权处理直接影响策略回测结果,通常用后复权 (hfq) 做长期回测
– AKShare 返回的 DataFrame 需要转换为 Backtrader 要求的格式
– 建议添加重试机制应对网络波动
3.3 双均线策略实现
接下来用 Backtrader 实现经典的双均线策略:
import backtrader as bt
class DualMAStrategy(bt.Strategy):
params = (('fast_period', 10),
('slow_period', 30),
)
def __init__(self):
# 计算两条均线
self.fast_ma = bt.indicators.SMA(
self.data.close,
period=self.p.fast_period
)
self.slow_ma = bt.indicators.SMA(
self.data.close,
period=self.p.slow_period
)
self.crossover = bt.indicators.CrossOver(
self.fast_ma,
self.slow_ma
)
def next(self):
if not self.position: # 没有持仓
if self.crossover > 0: # 金叉
self.buy(size=100) # 买入 100 股
elif self.crossover < 0: # 死叉
self.close() # 平仓
# 回测引擎配置
def run_backtest(data):
cerebro = bt.Cerebro()
# 加载数据
data_feed = bt.feeds.PandasData(dataname=data)
cerebro.adddata(data_feed)
# 添加策略
cerebro.addstrategy(DualMAStrategy)
# 设置初始资金
cerebro.broker.setcash(100000.0)
# 运行回测
print('初始资金: %.2f' % cerebro.broker.getvalue())
cerebro.run()
print('最终资金: %.2f' % cerebro.broker.getvalue())
# 可视化(需要安装 matplotlib)cerebro.plot(style='candlestick')
# 执行回测
run_backtest(mt_data)
3.4 生产环境优化
实际部署时需要特别注意:
- 限流应对:
- AKShare 默认没有严格限流,但频繁请求可能触发源站反爬
-
建议添加随机延时:
import random, time time.sleep(random.uniform(0.5, 1.5)) -
数据缓存:
- 使用
pickle或feather格式本地存储历史数据 -
实现增量更新逻辑:
if os.path.exists("cache.pkl"): old_df = pd.read_pickle("cache.pkl") new_df = get_stock_data("sh600519") updated_df = pd.concat([old_df, new_df]).drop_duplicates() -
回测陷阱:
- 避免使用未来数据(比如在当天交易前访问当天的收盘价)
- 滑点模拟:Backtrader 内置
cerebro.broker.set_slippage_perc(0.001) - 手续费设置:
cerebro.broker.setcommission(commission=0.0005)# 万 5
4. 延伸思考
完成基础策略后,建议尝试以下进阶方向:
1. 如何将策略扩展为多股票轮动组合?
2. 除了双均线,哪些因子在 A 股市场具有持续 alpha?
3. 怎样验证策略在熊市 / 牛市中的表现差异?
量化开发就像搭积木——从 AKShare 获取数据是地基,Backtrader 提供搭建工具,而真正的艺术在于策略逻辑的设计。希望这篇指南能帮你少走弯路,快速验证自己的交易想法。在实际操作中如果遇到问题,建议多查看 AKShare 的 GitHub Issues 区,很多坑已经有现成的解决方案。
正文完
