首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Python 实现均线策略:从代码到回测

Python 实现均线策略:从代码到回测

原创
作者头像
gavin1024
发布2026-09-20 15:53:22
发布2026-09-20 15:53:22
1340
举报

用 Python 实现一个完整的均线策略并做回测,需要走完六个环节:加载并清洗数据、计算均线与生成信号、构建带持仓逻辑的回测流程、计入滑点和手续费等真实成本、计算关键绩效指标(累计收益、最大回撤、夏普比率)、以及可视化结果。相比只算收益的简化版,一个"规范"的回测会尽量贴近真实交易,才能给出更可信的判断。本文在双均线策略的基础上,带你写出一套更完整、更严谨的回测代码,并讲清楚每一步为什么这么做。

一、从"能跑"到"可信"的一步

如果你已经写过最简单的双均线策略,那这篇是它的进阶版。上一步我们让策略"能跑起来",但那是个简化模型——没算成本、没算回撤,收益数字有点"虚"。这篇我们要让回测从"能跑"变成"可信"

区别在哪?一个可信的回测,会尽量还原真实交易的环境:考虑滑点和手续费、正确处理持仓、算出完整的绩效指标。只有这样,回测结果才有参考价值,而不是自欺欺人的漂亮曲线。下面我们一步步把这套更严谨的回测搭起来。

二、第一步:加载并清洗数据

老规矩,从数据开始。这一步除了读取,还要做基本的清洗和检查。

代码语言:python
复制
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

df = pd.read_csv("stock_data.csv", parse_dates=["date"])
df = df.sort_values("date").reset_index(drop=True)

# 基本清洗:去掉缺失、去掉重复
df = df.dropna(subset=["close"]).drop_duplicates(subset=["date"])

print("数据条数:", len(df))

数据质量是回测可信的前提,脏数据会直接污染结果,务必先检查干净。

三、第二步:计算均线并生成信号

计算快慢均线,并生成持仓信号。这里的关键是用前一日信号决定当日持仓,避免未来函数。

代码语言:python
复制
df["ma_fast"] = df["close"].rolling(5).mean()
df["ma_slow"] = df["close"].rolling(20).mean()

# 快线在慢线上方持有(1),否则空仓(0)
df["signal"] = np.where(df["ma_fast"] > df["ma_slow"], 1, 0)

# 关键:用前一天的信号作为今天的实际持仓,避免未来函数
df["position"] = df["signal"].shift(1).fillna(0)

shift(1) 这一步是回测严谨性的核心之一,很多新手就栽在用了"今天才知道的信息去赚今天的钱"。

四、第三步:计入滑点和手续费

这是让回测贴近真实的关键一步,也是简化版最缺的部分。每次买卖都会产生成本,我们在持仓发生变化(即发生交易)时扣掉这部分成本。

代码语言:python
复制
df["return"] = df["close"].pct_change().fillna(0)

# 交易成本设定(示例):手续费+滑点合计单边 0.1%
cost_rate = 0.001

# 持仓变化的地方就是发生了交易
df["trade"] = df["position"].diff().abs().fillna(0)

# 策略每日收益 = 持仓 × 当日收益 - 当日交易成本
df["strategy_return"] = df["position"] * df["return"] - df["trade"] * cost_rate

别小看这 0.1%,如果策略交易频繁,成本累积起来会显著拉低收益。很多"回测赚钱、实盘亏钱"的策略,问题就出在没算成本。

五、第四步:计算累计收益与最大回撤

有了每日策略收益,计算累计净值曲线,并算出最重要的风险指标——最大回撤。

代码语言:python
复制
# 累计净值
df["cum_strategy"] = (1 + df["strategy_return"]).cumprod()
df["cum_market"] = (1 + df["return"]).cumprod()

# 计算最大回撤
cummax = df["cum_strategy"].cummax()
drawdown = (df["cum_strategy"] - cummax) / cummax
max_drawdown = drawdown.min()

print("策略累计收益:", round(df["cum_strategy"].iloc[-1], 4))
print("最大回撤:", round(max_drawdown * 100, 2), "%")

最大回撤告诉你这个策略最坏情况会让你亏多少,是判断"扛不扛得住"的关键指标,一定要看。

六、第五步:计算夏普比率

再算一个衡量"收益性价比"的指标——夏普比率,看看每承担一份风险换来多少回报。

代码语言:python
复制
# 简化的夏普比率(按日收益计算后年化,假设一年约 252 个交易日)
mean_ret = df["strategy_return"].mean()
std_ret = df["strategy_return"].std()

if std_ret != 0:
    sharpe = (mean_ret / std_ret) * np.sqrt(252)
else:
    sharpe = 0

print("夏普比率(年化):", round(sharpe, 2))

夏普比率越高,说明策略在同样风险下赚得越多,或同样收益下波动越小。它帮你避免只盯着收益率而忽略风险。

七、第六步:可视化回测结果

最后,把策略净值和基准做对比,画出来直观感受。

代码语言:python
复制
plt.figure(figsize=(12, 6))
plt.plot(df["date"], df["cum_market"], label="Buy & Hold")
plt.plot(df["date"], df["cum_strategy"], label="MA Strategy (with cost)")
plt.legend()
plt.title("MA Strategy Backtest")
plt.show()

这条计入了成本的策略曲线,比简化版真实得多,它才是你判断策略好坏的依据。

八、绩效指标解读

跑完回测,你手上有了一份体检报告。怎么读?看这张表:

指标

含义

怎么看

累计收益

策略最终赚了多少

和买入持有对比

最大回撤

最坏情况的跌幅

越小越好,问自己扛不扛得住

夏普比率

收益的性价比

越高越好

交易成本

滑点+手续费损耗

交易越频繁影响越大

记住:别只看累计收益一个数。一个收益高但回撤巨大的策略,可能远不如收益中等但走得稳的策略。四个指标合起来看,才是完整的判断。

九、几个务必牢记的提醒

  • 回测好不代表未来赚钱:历史不会简单重复,回测只是"取得实盘资格"。
  • 警惕过拟合:别为了让曲线好看反复调参数,那样实盘往往失灵。
  • 成本一定要算:不算滑点手续费的回测,都是纸上富贵。
  • 这是教学示例:均线策略是经典练手对象,不代表真实盈利能力。

当你的回测代码越来越完善、需要跑大量历史数据或让策略长期运行时,本地电脑可能就不够用了。这时可以把回测和策略程序放到腾讯云云服务器 CVM 上运行,利用云端的稳定性和算力,尤其适合需要 7×24 小时运转的场景。

结尾

用 Python 实现均线策略的完整回测,关键是从"能跑"迈向"可信"——正确处理持仓、计入真实成本、算全绩效指标。这套流程走通了,你就掌握了评价任何策略的基本方法。而看懂累计收益、最大回撤、夏普比率这几个指标,比追求一条漂亮曲线重要得多。

当你需要跑大规模回测或让策略长期运行时,稳定的运行环境很有帮助。腾讯云近期上线了量化交易专题活动,可以了解云服务器如何承载策略回测、数据抓取与自动化交易。

风险提示:本文仅为量化交易科普与技术分享,不构成任何投资建议。文中代码仅为教学示例,不代表任何真实策略效果。金融市场存在风险,任何交易策略都可能产生亏损,请结合自身情况谨慎决策。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 一、从"能跑"到"可信"的一步
  • 二、第一步:加载并清洗数据
  • 三、第二步:计算均线并生成信号
  • 四、第三步:计入滑点和手续费
  • 五、第四步:计算累计收益与最大回撤
  • 六、第五步:计算夏普比率
  • 七、第六步:可视化回测结果
  • 八、绩效指标解读
  • 九、几个务必牢记的提醒
  • 结尾
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档