《打造自己的套利机器人》课程的辅助课。第 5 到第 8 课会把汇率看作图,并使用 −log(rate)。本页从零开始说明原因。
问题:一串兑换需要相乘
你按 0.90 的汇率把美元换成欧元,按 0.88 把欧元换成英镑,再按 1.30 把英镑换回美元。每一步都会把你的资金乘上一个数。三步之后:1 × 0.90 × 0.88 × 1.30 = 1.0296。你赚了 2.96%。
对于三步来说,相乘没有问题。第 6 到第 8 课的算法是为另一件事设计的:它们沿着路径把数字相加(“最便宜的路径总和最小”)。我们需要一个把乘法变成加法的技巧。
这个技巧
对数(写作 log,这里指自然对数)是一个有特殊习惯的函数:
log(a × b) = log(a) + log(b)
输入相乘,输出相加。还需要知道两个事实:
- log(1) = 0。正好等于 1 的汇率(没有盈利,也没有亏损)会变成 0。
- 如果一个数大于 1,它的 log 为正;小于 1 时,它的 log 为负。
用上面的兑换链来验证:
import math
rates = [0.9, 0.88, 1.30]
prod = 1.0
for r in rates:
prod *= r
print("product", round(prod, 4))
logs = [math.log(r) for r in rates]
print("logs", [round(x, 4) for x in logs])
print("sum of logs", round(sum(logs), 4), "-> exp", round(math.exp(sum(logs)), 4))
print("negative logs sum", round(-sum(logs), 4))
输出:
product 1.0296
logs [-0.1054, -0.1278, 0.2624]
sum of logs 0.0292 -> exp 1.0296
negative logs sum -0.0292
对数之和是 0.0292。函数 exp 是 log 的反函数,exp(0.0292) 会还原为 1.0296,和直接相乘得到的答案相同。
为什么要有负号
寻路算法会寻找总和最小的路径。我们想找获利最多的环。获利意味着乘积大于 1,也就是对数之和大于 0。为了把“最大”变成“最小”,我们翻转符号:把每条路的长度设为 −log(rate)。
现在,总长度小于 0 的环就是盈利环。例子中的总长度是 −0.0292,小于 0,所以这个环能盈利,它正是第 6 课中的负环。
值得记住的几个小数字
- log(2) 是 0.6931,log(0.5) 是 −0.6931:翻倍和减半互为镜像。
- 变化很小时,log(1 + x) 接近 x。1% 的盈利,log(1.01),约为 0.0100(四舍五入后)。这就是小的对数值读起来像百分比的原因。
练习
- 运行代码。修改一个汇率,让乘积降到 1 以下。对数之和会变成什么?
- 手算:三笔兑换的汇率为 1.02、1.03 和 0.95。先相乘,再用计算器相加对数,最后比较。
- 为什么恰好等于 1 的汇率不会影响一条路径的总长度?
下一篇:图的辅助课(arbitrage-prereq-2-graphs)。