課程「建立自己的套利機器人」的輔助課。第 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)。