单根 K 线内的循环
使用自己的循环计算移动平均,并与现成函数比较。
执行器负责遍历整组 K 线,但单根 K 线内部也可能需要重复操作,例如把最近五个收盘价相加。这时可以使用循环。
for 与 range
for offset in range(5):
total += close[offset]range(5) 依次将 0、1、2、3、4 赋给循环变量 offset,不包括 5。每个值都会让缩进行执行一次。
因此,close[offset] 先表示当前收盘价,再表示之前一、二、三、四根的收盘价,恰好五个值。
循环前需要将 total 清零。它是当前 K 线计算的中间结果,不是跨 K 线保存的计数器。
range(1, 5) 给出的序列是 1、2、3、4。包含起点,不包含终点。不写起点时从零开始。
手写移动平均
创建 manual_average.py:
"""
@pyne edge
"""
from pynecore.lib import close, color, input, plot, script, ta
@script.indicator("Manual Average Check", overlay=False)
def main(
length: int = input.int(5, title="Length", minval=1, maxval=100),
):
total = 0.0
for offset in range(length):
total += close[offset]
manual_average = total / length
builtin_average = ta.sma(close, length)
difference = manual_average - builtin_average
plot(difference, "Difference", color=color.blue)在演示数据上运行。线条表示自写平均值与内置 SMA 的差。预热后应在零附近,或因数值表示精度而极接近零。

这里不画两条重叠线,因为微小差异不容易看出。直接显示差值更容易判断计算是否一致。
一次执行做了什么?
长度为五时,顺序如下:
- 将
total设为零。 - 循环累加当前和前四个收盘价。
- 将总和除以五。
- 同时计算内置 SMA,并与自写结果求差。
- 为差值线绘制一个点。
随后执行器进入下一根 K 线。total 重新归零,循环相加的是新 K 线对应的五个值。
如果把 total 改成 Persistent,下一根就会从上一总和继续。每根都往旧结果再加五个数,这就不再是当前窗口的平均值。
缺少历史值时
最初四根 K 线中,五元素窗口至少缺一个收盘价。总和中的 na 会让自写平均值也缺失。内置五期 SMA 同样到第五根才有效。
本书演示数据的所有收盘价均有效。如果数据中段也有缺失,ta.sma 对缺失值的处理可能不同于简单按 K 线偏移求和。所以本例在指定数据上检查。
要重复多少次?
百根窗口意味着每根 K 线执行一百次加法。两千根数据就是二十万次循环步骤。
内置 ta.sma 的用途,就是通过执行器为常见任务设计的计算来完成这项工作。本例的自写循环用于理解和比较。如果现成函数满足需求,就使用它。
循环终点必须明确且有限。输入的最大值也限制了用户每根 K 线能请求多少计算。
break 与 continue
break 终止循环。continue 跳过当前步骤剩余部分,直接进入下一步。
在平均窗口中要谨慎使用。如果只相加三个值就停止,就不能像包含五个值那样仍除以五。跳过步骤会改变计算含义。
自己试一试
把长度设为三。在某根 K 线处,写出循环中的偏移量和对应三个价格。然后修改程序,以叠加模式绘制自写平均和内置平均,便于与差值结果比较。
参考答案
三个偏移是 0、1、2。装饰器使用 overlay=True,计算后添加:
plot(manual_average, "Manual average", color=color.blue, linewidth=2)
plot(builtin_average, "Built-in average", color=color.orange)从这个视图移除差值绘图。零附近的线与价格水平的平均线共用刻度时不好阅读。可以另存原来的差值面板版本以供检查。
识别窗口错位
思考将循环改成 range(1, length + 1) 会怎样。元素数仍为五,但当前 K 线被排除,五根之前的值被纳入。这就变成上一根 K 线的平均窗口,而非当前窗口。