迅投社区发布稿:《散户量化工具箱①:用 Python 跑通你的第一个双均线回测(附全套代码)》
写策略的第一课,不是选股,不是择时,是亲手跑通一个回测。今天把全套代码贴出来,在沪深300 十一年真实数据上跑,结果如实公开——包括它跑不赢买入持有这个扎心事实。
一、数据获取(baostock,免费)
import baostock as bs
import pandas as pd
bs.login()
rs = bs.query_history_k_data_plus(
'sh.000300', 'date,open,high,low,close,volume',
start_date='2015-01-01', end_date='2026-09-01',
frequency='d', adjustflag='3')
rows = []
while rs.error_code == '0' and rs.next():
rows.append(rs.get_row_data())
df = pd.DataFrame(rows, columns=rs.fields)
bs.logout()
实测 5000+ 交易日约 3.3 秒。注意当日数据 19:00 后才更新。
二、策略:5 日线上穿 20 日线买,下穿卖
df['pct'] = df['close'].pct_change().fillna(0)
df['ma_f'] = df['close'].rolling(5).mean()
df['ma_s'] = df['close'].rolling(20).mean()
df = df.dropna(subset=['ma_s']).copy()
raw = (df['ma_f'] > df['ma_s']).astype(int) # 1=持仓 0=空仓
pos = raw.shift(1).fillna(0) # ★ T日信号,T+1才执行
trades = pos.diff().abs().fillna(0) # 调仓记换手
nav = (1 + pos * df['pct'] - trades * 0.001).cumprod() # 含单边千1成本
shift(1) 是全段代码的命门:信号由收盘价算出,当天不可能按收盘价成交。少这一行,回测好看一半,也假一半。
三、结果(沪深300,2015→2026)
- 双均线(零成本):年化 1.61%,回撤 −31.6%
- 双均线(单边千1):年化 −0.07%,回撤 −36.5%
- 买入持有:年化 2.40%,回撤 −46.7%
- 十一年共交易 94 次(188 次单边)
教科书第一策略,跑不赢买入持有。
四、三个发现
- 均线策略死于震荡:A 股近年震荡占比高,金叉死叉反复打脸。策略没有好坏,只有适应的市场环境。
- 成本是新手最大盲区:94 笔交易,零成本 1.6%,千1成本归零。
- 回撤仍有 36%:择时只是比扛单(−47%)好,不是保险箱。
五、这个回测真正的价值
学的不是策略,是检验闭环:数据 → 信号 → 严格执行 → 计入成本 → 客观统计。跑通一次,下次看到「年化 50% 神器」你会本能问三句:数据真实吗?执行严格吗?成本算了吗?
进阶篇(防坑三件套:参数网格/样本外/成本压测、凯利公式仓位实测)已在本系列后续文章,欢迎跟更。
本文仅供量化学习,不构成投资建议。历史回测不代表未来表现。
更多量化工程实操内容,欢迎关注公众号「晋盈投资」(不荐股、不承诺收益)。 |