《打造自己的套利机器人》课程的辅助课。第 15 课用 z-score 判断两枚币何时偏离。这里用十个数字来说明它。
关于一列数字的三个问题
拿十天里你的公交车晚点的分钟数举例:10、12、11、13、9、12、11、10、12、30。
- 什么是典型值?均值(平均数):把所有数相加,再除以数量。
- 它们的变化有多大?标准差:到均值的典型距离。
- 今天是否异常?z-score:一个数距离均值有多少个标准差。
手算和代码中的步骤
import statistics
data = [10, 12, 11, 13, 9, 12, 11, 10, 12, 30]
mean = sum(data) / len(data)
print("mean", mean)
dev = [(x - mean) ** 2 for x in data]
var = sum(dev) / len(data)
print("variance", round(var, 2), "stdev", round(var ** 0.5, 2), "check", round(statistics.pstdev(data), 2))
for x in (11, 30):
print(x, "z =", round((x - mean) / var ** 0.5, 2))
mean 13.0
variance 33.4 stdev 5.78
11 z = -0.35
30 z = 2.94
逐步来看:
- 均值是 130 / 10 = 13。
- 对每个值,先取它到均值的距离,再平方。这样负数和正数不会抵消,较大的距离也会被更重地计入。把这些平方取平均,就是方差 33.4。
- 方差的平方根是标准差:5.78。
statistics.pstdev这一行给出的数相同,是一次核对。 - z-score 是(值 − 均值)/ 标准差。11 分钟这一天的 z = −0.35,接近正常。30 分钟这一天的 z = 2.94,远离正常。
一个异常值会改变一切
去掉 30 后重新计算其余九天:均值会变成 11.11,标准差会变成 1.2。现在 30 的 z-score 是 15.8,一个很大的数。当异常那天包含在列表里时,均值和离散程度都会增大,30 看上去只是有点异常(2.94)。对包含异常值的窗口取平均,会稍微掩盖它。第 15 课的窗口是最近的 100 个值,它特意不包括今天。
经验法则
对于自然界中的许多事物,大约 95 个值(共 100 个)位于均值的 2 个标准差内。因此,z-score 高于 2 或低于 −2 的情况,在 100 天中只会出现几天,这就是机器人把它当作信号的原因。真实市场的尾部比这个规则所说的更厚,所以保留这个信号,也要加上止损。
练习
- 运行代码。把 30 改成 14。均值和标准差会发生什么变化?
- 写一列你自己的十个数字,例如通勤时间或每天的步数,然后手算最后一个数字的 z-score。
- 为什么要把距离平方,而不是直接把它们相加?
回到课程:第 15 课(配对交易)。