先備知識:對數,或機器人為什麼相加而不是相乘

套利課程的短篇零基礎課。對數如何處理一串匯率,為什麼對數總和會取代乘積,以及如何理解負號。附有可手動核對輸出的簡短 Python 程式碼。

課程「建立自己的套利機器人」的輔助課。第 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 以下。對數總和會變成什麼?
  2. 手算:三筆兌換的匯率為 1.02、1.03 和 0.95。先相乘,再用計算機相加對數,最後比較。
  3. 為什麼恰好等於 1 的匯率不會影響一條路徑的總長度?

下一篇:圖的輔助課(arbitrage-prereq-2-graphs)。