【导语】上一篇我们用AKShare轻松拿到了股票日K数据,这一篇就进入实战环节!今天教大家做新手最易上手的“5日-20日均线交叉策略”——金叉(5日均线上穿20日均线)买入,死叉(5日均线下穿20日均线)卖出。全程带代码,跑完就能看到策略在历史数据中的收益,让你真正体验量化交易的闭环。
一、先搞懂:均线交叉策略为什么适合新手?
很多老股民都用过均线判断买卖点,均线交叉策略能成为量化入门首选,核心原因有两个:
- 逻辑简单易懂:5日均线代表短期趋势,20日均线代表中期趋势,金叉说明短期强势超过中期,是买入信号;死叉则相反,是卖出信号,不用复杂的数学模型。
- 数据要求低:只用上一篇获取的日K数据(开盘价、收盘价等)就能实现,无需额外找高阶数据,衔接性极强。
特别说明:本文是历史回测(用过去数据验证策略),不是实盘交易建议。实盘需结合实时行情、手续费等因素调整,新手先练回测再碰实盘。
二、策略回测前的3个核心准备
回测就像“模拟炒股”,要先明确规则和工具,避免结果失真。这三点提前搞清楚,代码跑起来更顺畅。
- 回测标的:延续上一篇的案例,用宁德时代(300750)2024年1月1日至2024年10月31日的日K数据,数据直接用AKShare实时获取,不用手动导入。
- 交易规则:① 不考虑涨跌停(回测简化);② 每次交易全仓买入/卖出(新手易理解);③ 手续费按万分之三计算(接近券商实际费率)。
- 核心指标:回测后重点看三个数据——总收益率(赚了多少)、交易次数(频繁与否)、最大回撤(最大亏损幅度,衡量风险)。
三、全程代码:从数据获取到回测结果输出
代码分为三部分:获取日K数据→计算均线与交易信号→回测收益。每一步都标了详细注释,上一篇的代码基础能直接复用,新手跟着复制就能跑。
完整代码(带注释)
import akshare as ak
import pandas as pd
import numpy as np
# ---------------------- 第一步:用AKShare获取宁德时代日K数据 ----------------------
# 延续上一篇的接口,获取2024年1-10月前复权数据
stock_df = ak.stock_zh_a_daily(
symbol="300750", # 宁德时代代码
start_date="2024-01-01",
end_date="2024-10-31",
adjust="qfq" # 前复权,匹配实盘成本
)
# 重置索引,把日期转为普通列
stock_df = stock_df.reset_index()
# 重命名列名(部分版本列名是英文,统一为中文方便新手)
stock_df.columns = ["日期", "开盘价", "最高价", "最低价", "收盘价", "成交量", "成交额"]
# ---------------------- 第二步:计算均线和交易信号 ----------------------
# 1. 计算5日均线和20日均线(用rolling函数滚动计算均值)
stock_df["5日均线"] = stock_df["收盘价"].rolling(window=5).mean() # window=5代表5天滚动
stock_df["20日均线"] = stock_df["收盘价"].rolling(window=20).mean()
# 2. 判断金叉和死叉信号(核心逻辑)
# 金叉:前一天5日均线<20日均线,当天5日均线>20日均线
stock_df["金叉信号"] = (stock_df["5日均线"].shift(1) < stock_df["20日均线"].shift(1)) & (stock_df["5日均线"] > stock_df["20日均线"])
# 死叉:前一天5日均线>20日均线,当天5日均线<20日均线
stock_df["死叉信号"] = (stock_df["5日均线"].shift(1) > stock_df["20日均线"].shift(1)) & (stock_df["5日均线"] < stock_df["20日均线"])
# 3. 标记交易信号(1=买入,0=无动作,-1=卖出)
stock_df["交易信号"] = 0
stock_df.loc[stock_df["金叉信号"], "交易信号"] = 1
stock_df.loc[stock_df["死叉信号"], "交易信号"] = -1
# ---------------------- 第三步:回测计算收益 ----------------------
# 1. 初始化回测参数
stock_df["持仓状态"] = 0 # 0=空仓,1=持仓
stock_df["单次收益"] = 0.0 # 每次交易的收益
cash = 100000 # 初始本金10万元
hold_shares = 0 # 持有股数
# 2. 遍历数据,执行交易逻辑
for i in range(len(stock_df)):
date = stock_df.loc[i, "日期"]
close_price = stock_df.loc[i, "收盘价"]
signal = stock_df.loc[i, "交易信号"]
# 买入逻辑:金叉信号且空仓
if signal == 1 and stock_df.loc[i, "持仓状态"] == 0:
hold_shares = cash // close_price # 全仓买入(取整数股)
cash = cash - hold_shares * close_price # 扣除买入金额
stock_df.loc[i, "持仓状态"] = 1
print(f"{date} 发出买入信号,买入价格{close_price}元,持有{hold_shares}股,剩余现金{cash:.2f}元")
# 卖出逻辑:死叉信号且持仓
elif signal == -1 and stock_df.loc[i, "持仓状态"] == 1:
cash = cash + hold_shares * close_price # 卖出获得现金
stock_df.loc[i, "单次收益"] = (close_price - stock_df.loc[i-1, "收盘价"]) * hold_shares # 计算单次收益
hold_shares = 0 # 清空持仓
stock_df.loc[i, "持仓状态"] = 0
print(f"{date} 发出卖出信号,卖出价格{close_price}元,单次收益{stock_df.loc[i, '单次收益']:.2f}元,总现金{cash:.2f}元")
# 延续前一天持仓状态
if i > 0:
stock_df.loc[i, "持仓状态"] = stock_df.loc[i-1, "持仓状态"]
# 3. 计算最终回测结果
final_cash = cash + hold_shares * stock_df.iloc[-1, stock_df.columns.get_loc("收盘价")] # 最终现金=剩余现金+持仓市值
total_return = (final_cash - 100000) / 100000 * 100 # 总收益率
trade_count = stock_df["交易信号"].abs().sum() # 交易次数(买入+卖出)
# 计算最大回撤(简化版:持仓期间从最高点到最低点的跌幅)
stock_df["持仓市值"] = stock_df["持仓状态"] * (hold_shares * stock_df["收盘价"] + cash)
if stock_df["持仓市值"].max() > 0:
max_drawdown = (stock_df["持仓市值"].max() - stock_df["持仓市值"].min()) / stock_df["持仓市值"].max() * 100
else:
max_drawdown = 0
# 输出最终结果
print("\n==================== 回测结果汇总 ====================")
print(f"初始本金:100000元")
print(f"最终资金:{final_cash:.2f}元")
print(f"总收益率:{total_return:.2f}%")
print(f"交易次数:{trade_count}次")
print(f"最大回撤:{max_drawdown:.2f}%")
print("======================================================")
四、代码运行后:关键结果怎么看?
把代码复制到PyCharm运行,会输出两部分内容,新手重点关注这几点:
1. 逐笔交易记录
代码会打印每次买卖的时间、价格和金额,比如:
2024-01-15 发出买入信号,买入价格180.50元,持有554股,剩余现金1230.00元 2024-02-20 发出卖出信号,卖出价格195.30元,单次收益8210.00元,总现金108426.20元
通过这些记录能清晰看到每笔交易的盈亏,判断信号是否及时。
2. 核心回测指标
最终汇总的三个指标是关键,以宁德时代2024年数据为例(实际结果以代码运行为准):
- 总收益率:如果结果是15.2%,说明策略在这段时间跑赢了不少理财产品;如果是负数,就要分析是策略问题还是市场整体下跌。
- 交易次数:正常情况下,均线策略交易次数不会太多(每月1-2次),如果频繁买卖(比如每月5次以上),可能是短期波动导致假信号,需要优化。
- 最大回撤:如果最大回撤是8%,意味着策略运行中最多亏过8%,新手要判断这个风险是否能接受。
五、新手必学:策略优化的3个小技巧
跑回测后发现收益不理想?不用急着否定策略,这三个简单优化方法能提升效果,新手也能操作:
1. 调整均线周期
如果假信号太多,可把短期均线换成10日,中期换成30日,过滤掉部分短期波动。修改代码中这两行的“window”参数即可:
stock_df["10日均线"] = stock_df["收盘价"].rolling(window=10).mean()
stock_df["30日均线"] = stock_df["收盘价"].rolling(window=30).mean()
2. 增加过滤条件
只看均线交叉容易被骗线,可加上“股价站上60日均线”作为附加条件(确保中期趋势向上),修改买入信号逻辑:
# 新增60日均线
stock_df["60日均线"] = stock_df["收盘价"].rolling(window=60).mean()
# 金叉信号+股价站上60日均线
stock_df["金叉信号"] = (stock_df["5日均线"].shift(1) < stock_df["20日均线"].shift(1)) & (stock_df["5日均线"] > stock_df["20日均线"]) & (stock_df["收盘价"] > stock_df["60日均线"])
3. 分散投资标的
单只股票风险高,可把策略应用到沪深300成分股上,筛选出同时发出金叉信号的股票组合买入。用上一篇学的AKShare接口,用“ak.stock_zh_index_component("000300")”就能获取沪深300成分股代码。
六、下一篇预告:策略可视化,用图表看懂收益走势
光看数字不够直观,下一篇我们教大家用matplotlib画图,把“股价+均线+买卖点+收益曲线”画在同一张图上,策略效果一目了然。还会教大家如何导出回测报告,方便后续分析。
【互动】你跑出来的宁德时代均线策略收益率是多少?评论区晒出你的结果,抽3人送《量化策略优化手册》,帮你进一步提升收益!