量化交易入门:用Python搭建第一个策略回测

📈 “用数据说话,让代码交易。”

🤔 为什么我开始研究量化交易

作为一个程序员,我对投资理财一直有个执念:能不能用技术手段,让投资更理性、更系统化?

2024年底,A股市场的大幅波动让我意识到:

  • 情绪化交易是亏钱的主因
  • 人工盯盘效率太低
  • 历史数据里可能藏着规律

于是,我开始了量化交易的学习之旅。

🎯 量化交易是什么

简单理解:用数学模型和计算机程序来执行交易决策

量化 vs 主观交易

维度 主观交易 量化交易
决策依据 感觉、新闻、经验 数据、模型、规则
情绪影响 大(恐惧、贪婪) 小(机械执行)
执行效率 人工,慢 自动化,毫秒级
可复制性 容易
风险控制 依赖纪律 可以程序化止损

量化交易的核心流程

1
数据获取 → 策略开发 → 回测验证 → 模拟交易 → 实盘交易

🛠️ 技术栈选择

为什么选 Python?

  • ✅ 生态完善(pandas、numpy、backtrader)
  • ✅ 学习曲线平缓
  • ✅ 社区活跃,文档丰富
  • ✅ 可以对接各种数据源

回测框架对比

框架 特点 适合
Backtrader 功能全面,文档好 新手入门 ✅
Zipline Quantopian出品 美股为主
vn.py 国产,功能强 国内实盘
聚宽/米筐 在线平台 不想搭环境

我选了 Backtrader,因为:

  1. 文档详细,社区活跃
  2. 支持A股数据
  3. 学习资料多

🚀 搭建开发环境

安装依赖

1
pip install backtrader pandas numpy matplotlib akshare

数据获取:使用 AKShare

AKShare 是免费的开源财经数据接口库,非常适合入门。

1
2
3
4
5
6
7
8
9
10
11
import akshare as ak

# 获取贵州茅台历史数据
df = ak.stock_zh_a_hist(
symbol="600519",
period="daily",
start_date="20230101",
end_date="20241231"
)

print(df.head())

输出:

1
2
3
         日期    开盘    收盘    最高    最低    成交量
0 2023-01-03 1725.0 1728.0 1733.0 1721.0 12345
1 2023-01-04 1730.0 1735.0 1740.0 1728.0 23456

💡 第一个策略:双均线策略

策略逻辑

最简单的趋势跟踪策略

  • 短期均线上穿长期均线 → 买入(金叉)
  • 短期均线下穿长期均线 → 卖出(死叉)

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import backtrader as bt
import akshare as ak
import pandas as pd
from datetime import datetime

# ============ 策略定义 ============
class DualMAStrategy(bt.Strategy):
"""双均线策略"""

params = (
('short_period', 10), # 短期均线周期
('long_period', 30), # 长期均线周期
)

def __init__(self):
# 计算两条均线
self.short_ma = bt.indicators.SMA(
self.data.close, period=self.params.short_period
)
self.long_ma = bt.indicators.SMA(
self.data.close, period=self.params.long_period
)

# 交叉信号
self.crossover = bt.indicators.CrossOver(
self.short_ma, self.long_ma
)

def next(self):
# 当前没有持仓
if not self.position:
# 金叉信号,买入
if self.crossover > 0:
self.buy()
print(f'{self.data.datetime.date(0)} BUY: {self.data.close[0]:.2f}')

# 当前有持仓
else:
# 死叉信号,卖出
if self.crossover < 0:
self.sell()
print(f'{self.data.datetime.date(0)} SELL: {self.data.close[0]:.2f}')

# ============ 数据准备 ============
def get_data(symbol='600519', start='20230101', end='20241231'):
"""获取A股数据"""
df = ak.stock_zh_a_hist(
symbol=symbol,
period="daily",
start_date=start,
end_date=end
)

# 重命名列以匹配Backtrader格式
df = df.rename(columns={
'日期': 'date',
'开盘': 'open',
'收盘': 'close',
'最高': 'high',
'最低': 'low',
'成交量': 'volume'
})

# 转换日期格式
df['date'] = pd.to_datetime(df['date'])
df.set_index('date', inplace=True)

return df

# ============ 回测执行 ============
def run_backtest():
# 创建Cerebro引擎
cerebro = bt.Cerebro()

# 添加策略
cerebro.addstrategy(DualMAStrategy)

# 获取数据
df = get_data('600519') # 贵州茅台

# 创建数据源
data = bt.feeds.PandasData(
dataname=df,
datetime=None, # 使用索引作为日期
open='open',
high='high',
low='low',
close='close',
volume='volume'
)

cerebro.adddata(data)

# 设置初始资金
cerebro.broker.setcash(100000.0)

# 设置佣金(万三)
cerebro.broker.setcommission(commission=0.0003)

# 添加分析器
cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='sharpe')
cerebro.addanalyzer(bt.analyzers.DrawDown, _name='drawdown')
cerebro.addanalyzer(bt.analyzers.Returns, _name='returns')

# 运行前打印资金
print(f'初始资金: {cerebro.broker.getvalue():.2f}')

# 运行回测
results = cerebro.run()

# 打印结果
print(f'最终资金: {cerebro.broker.getvalue():.2f}')
print(f'收益率: {(cerebro.broker.getvalue()/100000 - 1)*100:.2f}%')

# 打印分析结果
strat = results[0]
print(f"\n夏普比率: {strat.analyzers.sharpe.get_analysis()['sharperatio']:.3f}")
print(f"最大回撤: {strat.analyzers.drawdown.get_analysis()['max']['drawdown']:.2f}%")

# 绘制图表
cerebro.plot(style='candlestick')

if __name__ == '__main__':
run_backtest()

📊 回测结果分析

贵州茅台(2023-2024)回测结果

指标 数值 说明
初始资金 100,000元 -
最终资金 108,450元 -
收益率 +8.45% 2年
年化收益 ~4.1% 不算高
夏普比率 0.85 风险调整后收益尚可
最大回撤 -15.2% 需要忍耐的浮亏
交易次数 23次 频率适中

结果解读

优点

  • ✅ 策略有效,跑赢了活期存款
  • ✅ 自动化执行,无需盯盘
  • ✅ 有明确的买卖信号

缺点

  • ❌ 收益不算高(4.1%年化)
  • ❌ 最大回撤15%,需要心理素质
  • ❌ 震荡市会反复打脸(假信号)

🎯 策略优化思路

1. 加入过滤条件

1
2
3
4
5
def next(self):
# 只在长期趋势向上时交易
if self.data.close > self.long_ma:
if not self.position and self.crossover > 0:
self.buy()

2. 加入止损

1
2
3
4
5
6
7
8
9
def __init__(self):
self.order = None

def notify_order(self, order):
if order.status in [order.Completed]:
if order.isbuy():
# 买入后设置止损(下跌5%)
self.sell(exectype=bt.Order.Stop,
price=order.executed.price * 0.95)

3. 多因子策略

结合RSI、MACD等指标,减少假信号:

1
2
3
4
5
6
# RSI过滤
self.rsi = bt.indicators.RSI(self.data.close)

# 只在RSI 30-70之间交易(避免超买超卖)
if 30 < self.rsi < 70:
# 执行交易逻辑

⚠️ 新手避坑指南

坑1:过度拟合

问题:策略在历史数据上表现完美,实盘却亏钱。

原因:参数调得太多,适应了历史噪音而非真实规律。

解决

  • 用70%数据训练,30%数据测试
  • 参数不要调太细
  • 多品种、多时间段验证

坑2:忽视交易成本

问题:回测没算滑点和手续费,实盘收益大打折扣。

解决

1
2
3
# 设置 realistic 的佣金和滑点
cerebro.broker.setcommission(commission=0.0003) # 万3佣金
cerebro.broker.set_slippage_perc(0.0001) # 万1滑点

坑3:未来函数

问题:用了”未来”的数据做决策(比如用当天的收盘价决定当天买入)。

解决:时刻检查逻辑,确保只用当前和过去的数据。

坑4:幸存者偏差

问题:只测了表现好的股票,忽略了那些退市或暴跌的。

解决

  • 随机选择测试标的
  • 包含不同行业、不同市值的股票

🚀 下一步学习计划

短期(1-3个月)

  • 学习更多技术指标(RSI、MACD、布林带)
  • 实现多因子选股策略
  • 加入仓位管理(凯利公式、波动率控制)

中期(3-6个月)

  • 学习统计套利策略(配对交易)
  • 了解机器学习在量化中的应用
  • 搭建模拟交易环境

长期(6-12个月)

  • 接入实盘交易接口
  • 建立完整的风控体系
  • 开发多策略组合

📚 推荐学习资源

书籍

  1. 《Python金融大数据分析》 - Yves Hilpisch
  2. 《量化投资:策略与技术》 - 丁鹏
  3. 《海龟交易法则》 - Curtis Faith

网站

GitHub项目


💭 写在最后

量化交易不是”躺着赚钱”的圣杯,而是:用系统化的方法,在不确定的市场中寻找统计优势

我的第一个双均线策略收益不高,但它让我理解了:

  • 策略需要回测验证
  • 风险控制和收益同样重要
  • 纪律比聪明更重要

“量化交易是科学也是艺术,技术是基础,心态是核心。”

希望这篇入门指南对你有帮助。如果你也在学习量化,欢迎交流!

风险提示:本文仅供学习交流,不构成投资建议。市场有风险,投资需谨慎。


写于 2025年3月10日 | 量化学习第3个月