Mesa — 經濟模型模擬工具

在設計金融服務時,有時候會需要跑些模擬測試套用不同的參數來確認自己所預想的服務會不會虧錢以及用來探索自己可能沒注意到的環節。經過一番搜尋之後發現 mesa 這個由 Python 撰寫的工具很適合用在這樣的模擬。

mesa 是一個 Python 撰寫的函式庫,內建了一些模擬測試會需要的工具例如說數據蒐集、排程管理以及視覺化繪圖整合等等,整合這些工具可以讓模擬時更快速的可以蒐集與展現模擬結果。比如說我們今天要做一個類似 uniswap 的兌幣服務時,我們就可以利用 mesa 進行模擬實驗,得出下面這樣的模擬結果:

image

圖中比較平整的曲線是模擬中的市場價格曲線,另外一條則是 Uniswap 一部分參與者用隨機的方式買賣,另外占總數 10% 的套利者用於將 Uniswap 中的價格與市場價格同步的模擬結果。

Uniswap

簡介一下 Uniswap,他是一套沒有掛單簿 (Order Book) 的去中心化交易平台,任何人都可以透過提供一對貨幣(如 DAI + ETH)到 Uniswap 上放到代幣池裡面讓其他人交易,並且從中獲取交易手續費。價格的制訂也很簡單,比如說這個池子有 100 ETH 跟 20000 DAI,如果 Alice 想用 50 DAI 來買 ETH,這樣他會得到多少 ETH 則用以下的公式得出: (100 + x)(20000 + y) = 100 * 20000

只要把 50 DAI 帶入 y 求出 x 即可。計算後 x 是 -0.249,這就是 Alice 用 50 DAI 可以買到的 ETH 數量,所以可以說 ETH 的價格是 200.5 DAI/ETH。當交易成立後 Uniswap 就會把 ETH 匯給 Alice,這樣因為池子裡面的比例改變了,所以 ETH 的價格就會相對應的提高一些。

從這邊看來,Uniswap 上面的價格其實不見得跟外面交易所的價格一樣,畢竟他價格的調整方式很簡單。但實際上使用 Uniswap 的價格會跟外面的交易所差不多,主因是不管 Uniswap 上面的價格為何,套利者發現價差之後,利益就會驅使他們在 Uniswap 上面交易,直到價格跟外面的市場價格接近到沒有套利空間為止。

比如說外面市場價格 ETH 是 200 DAI/ETH,但 Uniswap 上面的價格公式得出來是 100 DAI/ETH,套利者就會進來爆買 ETH 直到接近市場價格為止。這也就是為什麼這麼簡單的數學公式卻可以做到無掛單簿的交易平台的原因。

如果我今天要模擬 Uniswap 這樣的機制要有多少比例的套利者在系統當中才可以維持價格跟市價差不多,我們就可以透過 mesa 這套模擬工具來做到。

Mesa

Mesa 是一套 Agent based model 工具,提供了上述一些基本的工具,把系統運作的邏輯寫入後就可以開始跑模擬測試了。Mesa 有兩個關鍵的類別:

  • agent: 系統裡面獨立的個體,在我們的例子裏面就是交易者 (trader)
  • model: 整個模擬的模型,裏面包含了負責調配 agent 執行順序的 scheduler 以及 agent 本身,同時也有 DataCollector 可以蒐集資料。

mesa 執行的時候類似回合制,model 執行一個回合時,每個 agent 都會被呼叫做一次動作,至於 agent 執行的順序則是透過 scheduler 調配,執行時則是呼叫 model.step() 以及 agent.step()

Trader

首先我們先繼承 mesa.Agent 建立一個 Trader 類別,並且給他初始的 ETH 與 DAI 讓他可以到 Uniswap 上交易,初始化時同時給一個 is_arbitrageur 的屬性,如果為 True 代表他知道市場的價格,輪到他交易時他就會觀察市場價格來套利。如果是 False 就代表他不知道市場價格,就會隨意地買 0-10 ETH 或買 0-100 ETH。

step() 是每次輪到這個 agent 動作時會執行的函式。

Uniswap

接著我們建立另外一個 Agent Uniswap 用於處理 trader 來的交易。另外每一輪到 Uniswap 執行 step() 時,我們簡易的用 math.sin() 模擬出一個實際市場上的價格,這樣套利者就可以看實際價格決定他要買還賣來套利。trade() 則是給 trader 用來交易 Uniswap 中的 ETH 或 DAI,完成後就跟 trader 用 transfer() 來交換貨幣。

這樣系統中的兩種 Agent 就寫好了,接下來要利用 model 把這些東西放到模擬系統中。

Model

Model 是用來把建立系統中的 agent,排程他們如何執行以及蒐集資料的地方。我們這邊建立了兩種 reporter 分別是針對 model 的資料蒐集以及 agent 的資料蒐集,Model 這邊會蒐集每輪的現在的價格以及市場價格,Agent 則是蒐集每輪的 ETH 以及 DAI 的數量資訊。

Model 中的 step() 相同的也是每個回合會執行的函式,而呼叫 self.schedule.step() 時則會依照 schedule 的設定來決定執行 agent.step() 的順序,在這邊我們使用亂數執行順序。

全部都完成後,我們就可以執行模擬看看結果,這邊用了 100 個 trader, 其中有 10 個套利者,初始在 uniswap 裡面有 100000 個 DAI 跟 10000 個 ETH 進行模擬。

執行上面的程式後就會跳出一個視窗上面顯示這次的模擬結果。

另外 Mesa 還有提供 BatchRunner 以及其他視覺化的模擬工具,可以再跑多輪不同參數的結果後再繪製到同一個圖表中比對,比如說 Uniswap 的例子就可以用 10%, 20%, 30% 的套利者來看跟市場價格的差異。如果你在開發的系統會需要模擬不同參與者在不同條件下的模擬結果,可以透過 mesa 這樣的工具來模擬結果來設計參數。

下面的連結是本文中使用的範例源碼。

yurenju/uniswap-mesa


讀者回函
讀完本文之後有什麼建議或回饋嗎?請按此在 Twitter 上面分享此文並且提及我,或是透過寄送電子郵件分享你的看法 😎