60倍回報! AI工程師用OpenAI建立了一個比特幣自動交易工具(附詳細做法)
炒股的人都知道,天天盯著大盤做決策不僅讓人勞神,還讓人禿頭。所以一堆頂級的數學家開始用數學的手段進行股市預測。
加密貨幣市場也一樣,而且加密貨幣市場波動更加頻繁,更加劇烈。對於這個問題,國外加密貨幣開發者 Adam King 提出了一種新的解決思路。
結合人工智慧在預測方面得天獨厚的優勢, Adam 提出了使用深度強化學習構建加密貨幣自動交易程式,同時,這位小哥還做出了一個能夠真正交易比特幣的展示模型,他是怎麼做到的?這個自動交易程式又能達到怎樣的效果呢?讓我們在文中一探究竟。
在本文中,我們將使用深度強化學習建立一個加密貨幣自動交易智慧體(agent),並訓練它通過交易比特幣盈利。
為了避免重複造輪子,在本篇教程中我們將使用人工智慧研究機構 OpenAI 開發的程式包。
目前人工智慧在很多領域都已經超過了人類,從最初谷歌 DeepMind 團隊開發的 AlphaGo 戰勝圍棋世界冠軍李世石,到後來師出同門的 AlphaStar 在星際爭霸中以 10:1 的大比分戰勝兩位職業玩家。近日,OpenAI 團隊的 OpenAI Five 在 Dota2 遊戲中以 2:0 的比分將世界冠軍 OG 斬於馬下。
谷歌 DeepMind 團隊星際爭霸人工智慧產品 AlphaStar 的訓練過程
人工智慧給我們帶來了很多激動人心的結果,雖然我們不會構建像 AlphaGo 這樣令人印象深刻的產品,但在日常的比特幣交易中實現盈利也非易事。
因此,與其冒著脫髮的風險苦苦探索比特幣幣價的規律,何不讓人工智慧來一展身手?
在本文中,我們將通過人工智慧技術完成一下三個嘗試:
- 為我們的智慧體(agent)建立一個測試強化學習的 gym 環境; 以一種簡單、優雅的方式視覺化我們的測試環境; 訓練我們的智慧體,讓它學習到能獲益的比特幣交易策略。
這裡有些操作可能會比較麻煩,就比如說從頭開始構建 gym 測試環境並將測試環境視覺化,不過不要擔心,我會仔細介紹這些細節,跟上我的節奏就好。
程式庫安裝
在本教程中,我們將使用 Zielak 提供的 Kaggle 資料集。如果你想要這些資料,你可以在我的 Github 倉庫中下載 .csv 資料檔案。
首先,我們來匯入所有必要的 Python 程式庫。如果你的電腦上還沒有安裝這些程式庫,你可以使用 pip install 命令進行安裝。
接下來,我們建立一個比特幣交易環境的類。我們需要向其中傳入一個 pandas 資料幀,一個用於指示智慧體在每一個時間步長( time step )需要分析前幾個時間步長資料的回顧視窗大小( lookback_window_size ),以及可選的智慧體賬戶初始餘額( initial_balance )。
程式碼中我們將手續費( commission )設定為每筆交易的 0.075% ,也就是加密貨幣期貨交易所 Bitmex 當前的費率,同時,我們將序列執行( serial )引數預設為否( false ),這意味著在預設情況下我們的資料幀將以隨機的形式遍歷各個片段。
除此之外,我們還在資料幀上分別呼叫了刪除非數字(NaN,Not A Number)所在行的 dropna 函式以及在刪除了資料之後重新設定資料幀索引的 reset_index 函式。
程式碼中 action_space (操作空間)的第一個數字表示可選的 3 個選項,即買入,賣出或持有,第二個數字表示所操作的比例,最小單位是 10% ,也就是說這個數字中的 1,2,3 分別代表 10%,20%,30% 。當選擇買入操作時,具體買入的比特幣數量將是第二個數字( amount )乘以當前賬戶的比特幣餘額( self.balance )。對於賣出操作,具體賣出的比特幣數量也是第二個數字( amount )乘以當前賬戶的比特幣餘額( self.balance )。
當然了,如果選擇持有操作,那麼就不會買賣賬戶中的比特幣,因而第二個數字就沒有了意義。
我們的 observation_space(觀察空間)被定義為 0 到 1 之間的連續浮點數集,它的大小為( 10,回顧視窗大小( lookback_window_size ) + 1)。這裡的 + 1 操作是考慮到了當前這一時間步長的操作。對於視窗中的每一步,我們都將觀察它的收盤價位置價值( OHCLV ),我們在那時的資產總價值、買入或賣出的比特幣數量、以及我們在買入或賣出這些比特幣時花費的美元數。
接下來,我們需要編寫重新設定( reset )函式來初始化比特幣交易環境。
程式碼中我們使用了重新設定會話控制( self._reset_session )函式和下一次資料觀察( self._next_observation )函式,不過這些函式都還沒有被定義,接下來我們來定義它們。
交易會話控制
交易會話控制( session )是比特幣交易環境中的一個重要組成部分。如果我們將這個智慧體部署到外部,我們可能永遠都不會一次讓它執行幾個月的時間。出於這個原因,我們將在資料幀引數( self.df )中限制智慧體能夠連續看到的資料幀數量。
在我們的重新設定會話控制( _reset_session )函式中,我們首先將當前的時間步長( current_step )重新設定為 0 。接下來,我們將剩餘時間步長( steps_left )設定為 1 到最大交易會話控制數( MAX_TRADING_SESSION )之間的隨機數,當然了,最大交易會話控制數需要在檔案的頂部定義。
接下來,如果需要連續遍歷資料幀,那就應該設定遍歷所有的資料幀,否則我們需要在資料幀引數( self.df )中設定一個隨機的資料幀起始位置( frame_start ),並建立一個名為啟用資料幀( active_df )的新資料幀,它是資料幀( self.df )從起始位置( frame_start )到起始位置 + 剩餘時間步長( frame_start + steps_left )這些連續幀組成的切片。
使用資料幀切片帶來的一個重要影響就是,智慧體將獲得更多獨一無二的資料,以便進行長時間的訓練。舉個例子,如果我們只是按順序來遍歷資料幀(即按資料幀 0 到最後一幀(len(df))的順序),那麼我們就只有資料幀個數這麼多的唯一資料點。我們的觀察空間在每一個時間步長只能觀察區區幾個狀態。
但是,通過隨機遍歷資料幀的切片,我們有效地結合了原始資料集上每一個時間點的賬戶餘額,交易資料以及當前比特幣價格,從而創造出了更多獨一無二的資料點。接下來我們通過一個例子來說明一下。
我們的智慧體在每個時間步長中都有三種選擇:買入,賣出或持有。對於這三種選擇中的每一種,都還需指定操作比特幣的數量,如操作當前比特幣餘額的 10%,20%,或是 100% 。這意味著我們的智慧體在每個時間步長中都有 30 種不同的選擇(當然了,對於持有操作,這 10 種選擇的效果是一樣的),而它從中選出最好的一個。
回到我們隨機切片後的比特幣交易環境。在第 10 個時間步長中,我們的智慧體可以處於資料幀內的任何資料幀長度(len(df))時間步長。考慮到每個時間步長智慧體可以做 30 種選擇,這意味著在任意 10 個時間步長的間隔時間中,該智慧體可以經歷資料幀長度(len(df))的 30 次方種可能的唯一狀態。
雖然這樣的操作可能會給大型資料集帶來相當大的噪聲,但我相信這是一把雙刃劍,這樣我們的智慧體也會從有限的資料量中學到更多。不過,對於測試資料集,我們仍將按順序來遍歷,這樣做更貼近於“實時”的交易資料,因而可以更好更精確地檢測我們的智慧體。
比特幣交易智慧體都學到了些什麼
為了更好地瞭解智慧體所看到並學習到的特徵,我們需要將比特幣交易環境的觀察空間視覺化。就比如說,下面是使用 OpenCV 視覺化渲染後的觀察空間。
OpenCV 視覺化渲染後的觀察空間
影象中的每一行都代表我們觀察空間( observation_space )中的一行。 前4行類似於頻率的紅線代表了 OHCL 資料,下方的橙色和黃色的點代表著數量 ,再下方這個起伏不定的藍色長條是智慧體所擁有資產的總價值,而下方顏色較淺的點代則表智慧體的交易。
如果你眯著眼睛看這張圖,你就可以看到一個 K 線圖,下面有著代表數量的指示條以及一個顯示交易歷史的類似於莫爾斯電碼的介面。 看起來我們的智慧體應該能夠在觀察空間( observation_space )的資料中學到一些東西 。在這裡,我們將定義下一次觀察( _next_observation )函式,在這個函式中我們要將觀察到的資料縮放到 0 到 1 之間。
重要的一點是, 僅僅縮放智慧體到目前為止所觀察到的資料,以避免出現前視偏 差( Look-ahead bias,前視偏差是指在策略的開發中,採取了未來的一些資訊,而這些資訊在實盤操作中是基本上不可能得到的)。
編寫步驟
現在我們已經設定好了觀察空間,是時候編寫我們的操作步驟( step )函數了,這個函式可以指導智慧體的行為。
每當當前交易時段的剩餘操作步驟( self.steps_left )等於 0 時,我們將賣出所持有的所有比特幣並呼叫重新設定會話控制( _reset_session )函式。
否則,我們將智慧體的獎勵( reward )設定為當前所持有資產的總價值,如果智慧體的資金用完了,則只會將完成( done )設定為真( True )。
其實,採取行動的過程十分簡單,也就只有三步:
第一步,獲取當前的比特幣價格( current_price );
第二步,確定該買入賣出還是持有,以及所要操作的份額;
第三步,就是真實買入或賣出這些比特幣。現在我們來編寫採取行動( _take_action )函式,以便於測試我們的比特幣交易智慧體。
最後,在這個函式中,我們將交易新增到交易記錄引數( self.trades )中,並更新我們的資產總價值和賬戶交易歷史。
到這裡,我們的智慧體就可以啟動新環境,在新環境中學習比特幣交易的特徵,並採取行動以獲得收益。是時候讓比特幣交易智慧體一展身手了。
檢視比特幣交易智慧體的交易記錄
上文中說到了,我們需要將智慧體的學習和決策過程視覺化。當然了,僅僅使用最簡單的方法,在智慧體每次決策後輸出智慧體所持有資產的總價值(print(self.net_worth))也不是不可以,不過這樣做就少了很多的樂趣。因此,我們決定繪製一個簡單的比特幣價格資料 K 線圖,其中包含數量欄和我們資產總價值的單獨圖表。
在程式碼中,我們需要定義一個用來視覺化的資產交易圖( StockTradingGraph )函式,在函式的初始化過程中,我們需要呼叫 python 視覺化程式庫 matplotlib.pyplot ,並指出每一個需要視覺化的資料。
為了更好地展現資料,在視覺化方法中我們需要匯入 Python 時間日期( datetime )處理模組,在資料上標註出人類可讀的日期和時間。
在匯入完成後,我們需要使用將時間戳轉換為世界統一時間 UTC 的 utcfromtimestamp 函式,將每個時間戳轉化為 UTC 時間, 然後用計算機時間函式( strftime )將這個 UTC 時間按照“ 年 - 月 - 日 小時:分鐘 ”的格式展現出來 。
到這裡,視覺化函式的各個部分都已編寫完成,回到比特幣交易環境,我們現在可以彙總出一個視覺化( render )函式來顯示圖形。
ok了!我們現在可以看到智慧體正在交易比特幣。
使用 Matplotlab 程式庫視覺化後的智慧體交易比特幣資料
圖中綠色的豎線代表智慧體在買入比特幣,紅色的豎線代表智慧體在賣出比特幣。右上角的白色方框是智慧體所持有資產的總價值,在其下方的白色方框是當前比特幣的價格。
這裡容我自戀一下,我認為這個視覺化的效果簡單而又不失優雅。現在,是時候訓練我們的比特幣交易智慧體了,看看它能幫我們賺到多少錢!
訓練比特幣交易智慧體
由於我們訓練智慧體時使用的是時間序列資料,因此在交叉驗證方面我們並沒有太多的選擇。
就拿一種常見的交叉驗證形式: k-fold(k組)交叉驗證來舉例,在 k-fold 交叉驗證中,你需要將資料拆分成 k 個相等的分組,將每一個分組分別做一次測試組,其餘的 k-1 組資料用作訓練組。
然而,時間序列資料與時間有著高度的依賴性,這意味著後面出現的資料高度依賴於先前出現的資料。所以在這種情況下 k-fold 將不起作用,因為這樣會讓我們的智慧體提前知道未來的資料,即使盈利了我們也不知道是得益於智慧體精準的預測還是因為智慧體作弊了。
當應用於時間序列資料時,大多數其他的交叉驗證策略也都存在著同樣的缺陷。因此,我們只需在完整資料幀中給定一個分界點,前一部分的資料用作訓練集,其餘的資料用作測試集。
接下來,由於我們的比特幣交易環境被設定為僅處理單個數據幀,因此我們需要建立兩個比特幣交易環境,一個用於訓練資料,一個用於測試資料。
到這裡,我們就可以訓練模型了。如下面的程式碼所示,我們只需要在比特幣交易環境中建立智慧體,然後呼叫 model.learn 命令開始訓練。
在這裡,我們會使用機器學習框架 tensorflow 的視覺化工具 tensorboard ,從而我們可以輕鬆地視覺化 tensorflow 的資料流圖並檢視有關我們智慧體的一些量化指標。
比如說,下圖展示了智慧體在經過 200000 個時間步長後的盈利:
看起來我們的智慧體都獲得了很多的收益!最好的一個智慧體在 200,000 個時間步長後資產總價值提升了 1000 倍,而其餘的智慧體資產總價值平均提升了 30 倍以上!
不過,就在這時,我意識到比特幣交易環境中存在一個錯誤......在修復了該錯誤之後,這是新的收益圖:
正如你所看到的,我們的一些智慧體做得很好,而有一些則表現很差。 總的來說,表現良好的智慧體最多能夠實現資產總價值提升 10 倍甚至 60 倍 。
我必須承認,所有這些智慧體都是在虛擬的比特幣交易環境中訓練和測試的,所以將這個比特幣交易智慧體直接應用於比特幣區塊鏈上還為時尚早。 但是至少這個結果告訴我們,使用人工智慧來進行加密貨幣交易決策這條路是行得通的 。
接下來,讓我們在比特幣交易測試環境中測試智慧體,在測試環境中我們將使用智慧體以前從未見過的全新資料,看看這些智慧體是否學到了比特幣的交易策略。
結果顯示,我們訓練出來的比特幣交易智慧體在新的測試環境中爭相走向破產
這也並不意外,因為我們還有很多的工作要做。 僅僅通過簡單地將模型從當前的近端策略優化( Proximal Policy Optimization , PPO2 )智慧體切換到 stable-baseline 程式庫中的 A2C ( Advantage Actor-Critic )就可以大大提高我們在此資料集上的效能 。
同時,我們也可以更新獎勵函式,激勵那些資產總價值不斷增加的操作,防止有些比特幣交易智慧體在資產總價值達到高位時就消極怠工。
僅僅做出這兩個改動就可以大幅度提高比特幣交易智慧體在當前資料集上的效能,正如下圖所示,最終我們在資料全新的測試環境上成功實現了盈利。
除此之外,我們還可以做得更好。為了提升這些比特幣交易智慧體的準確度,我們可以優化超引數並訓練智慧體更長的時間。是時候給你的顯示卡(深度學習程式碼執行在顯示卡之上)一點壓力了!
如果你想繼續優化,這裡可以給你提供些思路,你可以使用貝葉斯優化來在問題空間上尋找最佳的超引數,並使用顯示卡的 CUDA 運算平臺優化訓練環境和測試環境。
結論
在本教程中,我們使用深度強化學習從零開始建立了一個能夠獲得收益的比特幣交易智慧體。
具體而言,我們完成了以下的任務:
- 使用 OpenAI 團隊開發的用於測試強化學習演算法的工具包 gym 從零開始建立了一個比特幣交易環境;
- 使用 Python 視覺化程式庫 Matplotlib 將比特幣交易環境視覺化;
- 使用簡單的交叉驗證對我們的比特幣交易智慧體進行了訓練和測試;
- 雖然還有很多的工作需要完成,但現在我們已經可以看到成功的曙光。
雖然最後我們的比特幣交易智慧體在資料全新的測試環境中還不能保證總是盈利,但我們已經離成功不遠了。
作者 | Adam King
譯者 | Guoxi
責編 | Aholiab
出品 | 區塊鏈大本營(blockchain_camp)