深圳融克迪特科技有限公司 Logo,金融科技,量化交易,软件开发

深圳融克迪特科技有限公司

RONG CREDIT TECHNOLOGY CO., LTD.

基础入门

【vectorbt 系列 第3讲】计算5日均线

本讲在最小回测数据上生成第一列 5 日均线,围绕滚动窗口、前几行空值、手工核验和结果解读展开。目标是让入门者先把最基础的指标计算看懂,为后续买卖信号和向量化回测打下中间层。

2026-04-23 智铨研究 阅读时长 8 分钟

目录

  1. 本节目标
  2. 为什么第 3 讲先选 5 日均线
  3. 沿用第 2 讲的最小回测表
  4. 四步算出第一列 5 日均线
  5. 先按时间顺序确认输入
  6. 执行 5 日均线计算
  7. 把价格和均线并排看
  8. 观察前 4 行空值
  9. 确认均线列真的可用
  10. 新列存在
  11. 前 4 行为空
  12. 第 5 行开始有值
  13. 均线列不是全空
  14. 均线为什么看起来“不对”
  15. 前几行是 NaN
  16. 均线列全空
  17. 结果和手算不一致
  18. 哪些情况仍然算完成本讲
  19. 写一个最小均线函数
  20. 完成标准
  21. 手工核一行均线结果
  22. 为什么第 3 讲还没有直接调用回测
  23. 看均线结果时,建议重点盯住哪几类现象
  24. 第 3 讲和 pandas 的关系是什么
  25. 这一步对下一讲买入信号意味着什么
  26. 一个更完整但仍然简单的检查片段
  27. 系列衔接
  28. 风险揭示与免责声明

1. 本节目标

本讲要完成的动作非常清楚:在第 2 讲已经整理好的最小回测数据上,计算第一列 5 日均线,并理解滚动窗口在向量化回测里意味着什么。如果第 2 讲解决的是“输入表长什么样”,那第 3 讲解决的就是“如何在这张表上得到第一列可解释指标”。

学完这一讲后,你可以直接完成下面几件事:

  1. 知道 5 日均线依赖哪一列输入。
  2. 会用 pandas 或 vectorbt 相关对象生成均线列。
  3. 理解前几行空值为什么是正常现象。

这是 vectorbt 入门短课里第一次真正从“数据准备”走向“指标计算”。

2. 为什么第 3 讲先选 5 日均线

5 日均线是最适合入门向量化思路的第一步指标,因为它:

  1. 逻辑直观,不需要额外金融背景。
  2. 只依赖收盘价,输入足够简单。
  3. 一旦算出来,就能立刻用于后面构造买入、卖出信号。

换句话说,它不是最复杂的指标,但它正好处在“足够简单,又能带动后面几讲”的位置上。

3. 沿用第 2 讲的最小回测表

import pandas as pd

work_df = single_df.copy()
work_df['close'] = pd.to_numeric(work_df['close'], errors='coerce')
print(work_df.head())

这一步的核心,是再次确认 close 已经是一列真正可计算的数值列。因为如果输入都没整理好,均线结果再漂亮也不可信。

4. 四步算出第一列 5 日均线

这一讲只做一件事:让第一列均线稳定落到表上。四步顺下来,输入、计算和解释关系都会清楚很多。

5. 先按时间顺序确认输入

print(work_df[['date', 'close']].head())
print(work_df[['date', 'close']].tail())

入门阶段一定要先确认顺序。滚动窗口计算对顺序非常敏感,如果表不是按时间从早到晚排好,后面得到的均线虽然有数字,但业务意义是错的。

6. 执行 5 日均线计算

work_df['ma_5'] = work_df['close'].rolling(window=5).mean()

这一行就是本讲最核心的动作。它把当前行及前 4 行的收盘价做平均,并把结果放进一列新的指标列里。

7. 把价格和均线并排看

print(work_df[['date', 'close', 'ma_5']].head(10))

后面你会拿 closema_5 做信号判断,所以现在就应该把两列放在一起看,而不是只孤立地盯着均线列。

8. 观察前 4 行空值

print(work_df['ma_5'].head(6))

窗口长度为 5,前 4 行没有足够历史样本,出现空值是正确表现。这一步必须看清楚,因为后面构造信号时,前几行自然也会受到影响。

9. 确认均线列真的可用

均线列是否可用,核心看窗口规律有没有正常体现出来,而不是只看有没有生成一列数字。

10. 新列存在

assert 'ma_5' in work_df.columns

11. 前 4 行为空

assert work_df['ma_5'].head(4).isna().all()

12. 第 5 行开始有值

assert pd.notna(work_df.loc[4, 'ma_5'])

13. 均线列不是全空

assert work_df['ma_5'].notna().sum() > 0

14. 均线为什么看起来“不对”

下面这些现象第一次看到时很容易误判成报错,其实大多都属于滚动窗口的正常表现。

15. 前几行是 NaN

这是正常的滚动窗口行为,不是错误。

16. 均线列全空

这通常意味着 close 列没有被正确转成数值,或者表里的有效样本行数小于 5。

17. 结果和手算不一致

先检查排序,再检查取的是否真是 close 列。多数情况下,问题不是 rolling 本身,而是输入顺序或字段取错了。

18. 哪些情况仍然算完成本讲

  1. 你可以把列名叫成 ma5ma_5 或别的清晰名字。
  2. 你可以先用 pandas 算均线,不必强求本讲就一定用 vectorbt 封装指标。
  3. 前 4 行为空值不算失败,反而是本讲必须理解的一部分。
  4. 你暂时不构造信号也没关系,本讲核心只是把均线列稳定生成。

19. 写一个最小均线函数

import pandas as pd

def add_ma5(df: pd.DataFrame) -> pd.DataFrame:
    out = df.copy()
    out['close'] = pd.to_numeric(out['close'], errors='coerce')
    out['ma_5'] = out['close'].rolling(window=5).mean()
    return out

work_df = add_ma5(single_df)
print(work_df[['date', 'close', 'ma_5']].head(10))

20. 完成标准

如果你现在已经能稳定地把 close 列变成一列 ma_5,并能解释前几行空值为什么出现,那第 3 讲就过关了。

21. 手工核一行均线结果

和 AkShare 那边一样,vectorbt 入门阶段最有效的验证方式之一,就是手工核对第一条完整均线值。因为当 window=5 时,第 5 行会第一次得到有效结果,非常适合作为检查点。

first_window = work_df.loc[0:4, 'close']
print(first_window.tolist())
print('手工均值 =', first_window.mean())
print('程序 ma_5 =', work_df.loc[4, 'ma_5'])

只要这两者一致,你对滚动计算的信任就会明显提升。对新手来说,这种“亲手核一行”的体验特别重要,因为它能打破一种常见误解:以为回测和指标计算都是黑盒,自己只能照着抄代码。其实不是。至少在第 3 讲这个层面,均线完全是你能逐行解释清楚的。

22. 为什么第 3 讲还没有直接调用回测

vectorbt 是为了回测服务的,但第 3 讲仍然故意停在“先把指标列算稳”。原因很务实。如果你还没看清 closema_5 的关系,就直接把两列送进后面的入场出场逻辑,一旦结果奇怪,你几乎无法判断是信号错了还是均线本身就没准备好。

所以第 3 讲的真正作用,是在回测前建立一个中间层:

  1. 你知道输入列是什么。
  2. 你知道衍生列是怎么来的。
  3. 你知道前几行为什么为空。
  4. 你知道哪一行开始这个指标才具备解释意义。

后面一旦继续做买入、卖出或回测,你就不再是“直接把 API 堆起来”,而是在一个自己看得懂的中间层之上继续推进。

23. 看均线结果时,建议重点盯住哪几类现象

第 3 讲不要求你做复杂统计,但建议你至少观察下面这些现象:

  1. 均线比原始价格更平滑。
  2. 价格快速变化时,均线反应会慢半拍。
  3. 前 4 行因为窗口不足而为空。
  4. 如果价格持续上升,均线也会逐步跟上,但斜率通常更缓。

你可以直接把最近几行拉出来看:

print(work_df[['date', 'close', 'ma_5']].tail(8))

这一步对后面构造信号尤其重要。因为信号说到底,就是在观察价格和均线之间发生了什么关系。如果你现在连这两列并排时在表达什么都还没看清,后面信号列就会变成一串难以解释的真假值。

24. 第 3 讲和 pandas 的关系是什么

虽然我们当前是 vectorbt 入门短课,但第 3 讲依然用 pandas 的 rolling() 来做第一列均线。这并不矛盾,反而很合理。原因在于:vectorbt 的优势在于后续把指标、信号和回测链起来;而入门阶段先用 pandas 把最基础的窗口计算看清楚,理解成本最低。

等你后面走到更复杂的批量参数比较、指标工厂或组合评估时,再更深入用 vectorbt 的封装能力,会更顺手。第 3 讲当前的定位不是“展示框架最强能力”,而是“先让你把一个基础指标彻底弄明白”。

25. 这一步对下一讲买入信号意味着什么

下一讲要做的事,其实已经被第 3 讲准备好了。因为买入信号最常见的一种写法,就是拿 closema_5 直接比较。也就是说,第 4 讲不是凭空新增一块逻辑,而是在第 3 讲已经得到的这两列上做布尔判断。所以第 3 讲只要做得扎实,后面的信号课会轻松很多;反过来,如果第 3 讲只是“勉强跑通”,第 4 讲开始你就会被真假值和空值一起困住。

26. 一个更完整但仍然简单的检查片段

print(work_df[['date', 'close', 'ma_5']].head(10))
print('前4行是否为空:', work_df['ma_5'].head(4).isna().all())
print('第5行是否有值:', pd.notna(work_df.loc[4, 'ma_5']))
print('最后3行:')
print(work_df[['date', 'close', 'ma_5']].tail(3))

把这一段固定下来,你后面每次换窗口、换样本时都可以拿来快速验证。

27. 系列衔接

本讲是《vectorbt回测入门短课》的第 3/8 讲,当前主题是《计算5日均线》。

上一讲:第 2 讲《准备最小回测数据》。

下一讲:第 4 讲《构造买入信号》。

后续安排:第 5 讲《构造卖出信号》;第 6 讲《跑第一轮向量化回测》。

28. 风险揭示与免责声明

风险揭示与免责声明

本页面内容仅用于量化研究与技术交流,旨在展示研究方法与流程,不构成对任何金融产品、证券或衍生品的要约、招揽、推荐或保证。

本文所涉历史数据、回测结果与示例参数不代表未来表现,也不应作为投资决策依据。

市场存在波动、流动性与执行偏差等不确定性,任何策略均可能出现收益波动或阶段性失效。

读者应结合自身风险承受能力进行独立判断,并在必要时咨询持牌专业机构意见。