【我們為什麼挑選這篇文章】從比特幣被發明至今,已有無數自稱專家的人出面,跟大家解釋何謂比特幣,未來發展如何,但這些論述往往缺乏數據的背書,難以驗證。
本文手把手的教大家如何使用 python 建立數據、驗證與觀察「到底什麼是比特幣」,從數字角度讓你真正理解比特幣!(責任編輯:林厚勳)
作者:Patrick Triest
編譯:Katherine Hou、林海、Shan LIU、高寧、Yawei
關於數位加密貨幣(如:比特幣和以太坊)的文章鋪天蓋地,數百個自詡專家的作者各自發表著他們對比特幣未來的猜想。而用來支持他們觀點的這些分析中強有力的數據和統計學基礎卻乏善可陳。
這篇文章的目的是簡單介紹「如何用 Python 來分析數位加密貨幣」。我們將用簡單的 Python 代碼來檢索、分析和可視化不同的數位貨幣數據。在這個過程中,我們將揭露一個有趣的趨勢:這些不穩定的市場是如何運作的,它們又是如何發展的。
這不是一篇解釋數位加密貨幣是什麼的科普文,也不是一篇講哪個貨幣會升值、哪個會貶值的觀點性文章。相反,在這篇教程中,我們所關心的只是獲取原始數據,並揭示隱藏在數字中的故事。
步驟1 – 配置你的數據實驗室
包含執行結果的 notebook 完整版本可以在這裡下載。
步驟1.1 – 安裝 Anaconda
安裝這個項目所需的所有相關環境,最簡單的辦法就是用Anaconda。它是一個打包的Python數據科學生態系統和依賴管理器。
推薦使用下面的官方安裝指南來安裝 Anaconda:https://www.continuum.io/downloads
如果你是一個高階用戶,而你不需要使用 Anaconda,那也完全沒有問題。我會假設你在安裝必須的依賴環境時不需要幫助,你可以直接跳到第二部分。
步驟1.2 – 建立一個 Anaconda 項目環境
當 Anaconda 安裝完成後,我們需要創建一個新的環境來管理我們的依賴包。執行 conda create –name cryptocurrency-analysis python=3 來為我們的項目創建一個新的 Anaconda 環境。接下來,執行source activate cryptocurrency-analysis ( Linux/macOS 系統) 或者 activate cryptocurrency-analysis (Windows 系統) 來啟用這個環境。
最後,執行 conda install numpy pandas nb_conda jupyter plotly quandl 來為這個環境安裝所需的依賴包。完成這些需要幾分鐘的時間。
為什麼要用環境?如果你打算在你的電腦上執行很多Python項目,那麼分開不同項目的依賴包(軟件庫和包)來避免衝突是很有幫助的。
Ananconda會為每一個項目的依賴包創建一個特殊的環境目錄,使得所有包都能妥善地被管理和區分。
步驟1.3 – 啟動一個交互的Jupyter Notebook
當環境和依賴包都安裝好之後,執行 jupyter notebook 來啟動 iPython 內核,然後用你的瀏覽器訪問http://localhost:8888/ 。創建一個新的Python notebook,確保它使用的內核是Python [conda env:cryptocurrency-analysis]。
步驟1.4 – 導入依賴包
當你打開了一個空的Jupyter notebook,我們要做的第一件事就是導入所需的依賴包。
import os import numpy as np import pandas as pd import pickle import quandl from datetime import datetime
我們還要導入Plotly來啟用離線模式。
import plotly.offline as py import plotly.graph_objs as go import plotly.figure_factory as ff py.init_notebook_mode(connected=True)
步驟2 – 獲得比特幣的價格數據
一切就緒,我們可以開始獲取要分析的數據了。首先,我們要用Quandl的免費比特幣接口來獲得比特幣的價格數據。
步驟2.1 – 編寫Quandl幫助函數
為了方便數據獲取,我們要編寫一個函數來下載和同步來自Quandl(https://www.quandl.com/ 號稱金融數據界的維基百科)的數據。
def get_quandl_data(quandl_id): ”’Download and cache Quandl dataseries”’ cache_path = ‘{}.pkl’.format(quandl_id).replace(‘/’,’-‘) try: f = open(cache_path, ‘rb’) df = pickle.load(f) print(‘Loaded {} from cache’.format(quandl_id)) except (OSError, IOError) as e: print(‘Downloading {} from Quandl’.format(quandl_id)) df = quandl.get(quandl_id, returns=”pandas”) df.to_pickle(cache_path) print(‘Cached {} at {}’.format(quandl_id, cache_path)) return df
我們用pickle來序列化,把下載的數據存成文件,這樣代碼就不會在每次執行的時候重新下載同樣的數據。這個函數將返回Pandas數據框(Dataframe)格式的數據。如果你對數據框不太熟悉,你可以把它想成是強大的電子表格。
步驟2.2 – 抓取 Kraken 交易所定價數據
我們首先來獲取 Kraken 比特幣交易所的歷史比特幣匯率。
# Pull Kraken BTC price exchange data btc_usd_price_kraken = get_quandl_data(‘BCHARTS/KRAKENUSD’)
我們可以用 head() 方法來查看數據框的前五行。
btc_usd_price_kraken.head()
接下來,我們要做一個簡單的圖表,以此來快速地通過可視化的方法驗證數據基本正確。
# Chart the BTC pricing data btc_trace = go.Scatter(x=btc_usd_price_kraken.index, y=btc_usd_price_kraken[‘Weighted Price’]) py.iplot([btc_trace])
這裡,我們用Plotly 來完成可視化部分。相對於使用一些更成熟的Python數據可視化庫,例如 Matplotlib ,用 Plotly 是一個不那麼傳統的選擇,但我認為Plotly是一個不錯的選擇,因為它可以調用 D3.js的充分交互式圖表。這些圖表有非常漂亮的默認設置,易於探索,而且非常方便嵌入到網頁中。
我們可以將生成的圖表與公開可用的比特幣價格圖表(如Coinbase上的圖表)進行比較,作為一個快速的完整性檢查,驗證下載的數據是否合理。
步驟2.3 從更多的比特幣交易所抓取價格數據
你可能已經注意到,上面的數據集中存在數據缺失現象--特別是在 2014 年末和2016 年初。在 Kraken 交易所的數據集中,這種數據缺失情況尤為明顯。我們當然不希望這些數據會影響到我們對價格的全面分析。
比特幣交易所的特點是,供需關係決定比特幣的價格。因而,沒有哪個交易的價格所能夠成為市場的「主流價格」。為瞭解決這個問題,以及剛剛提到的數據缺失問題(可能是由於技術性斷電和數據的差錯),我們將從三家主要的比特幣交易所抓取數據,進而計算出平均的比特幣價格指數。
首先,我們把各個交易所的數據下載到到由字典類型的數據框中。
# Pull pricing data for 3 more BTC exchanges exchanges=[‘COINBASE’,’BITSTAMP’,’ITBIT’]exchange_data={}exchange_data[‘KRAKEN’]=btc_usd_price_kraken for exchange in exchanges:exchange_code=’BCHARTS/{}USD’.format(exchange)btc_exchange_df=get_quandl_data(exchange_code)exchange_data[exchange]=btc_exchange_df
步驟2.4 將所有價格數據整合到單一數據框之中
接下來,我們將要定義一個簡單的函數,把各個數據框中共有的列合併為一個新的組合數據框。
def merge_dfs_on_column(dataframes, labels, col):”’Merge a single column of each dataframe into a new combined dataframe”’series_dict={} for index in range(len(dataframes)):series_dict[labels[index]]=dataframes[index][col]return pd.DataFrame(series_dict)
現在,基於各個數據集的「加權價格」列,把所有的數據框整合到一起。
# Merge the BTC price dataseries’ into a single dataframebtc_usd_datasets=merge_dfs_on_column(list(exchange_data.values()), list(exchange_data.keys()),’Weighted Price’)
最後,可以使用「tail()」方法,查看合併後數據的最後五行,以確保數據整合成功。
btc_usd_datasets.tail()
看起來,這些數據符合我們的預期:數據範圍大致相同,只是基於各個交易所的供求關係而略有不同。
步驟2.5 價格數據的可視化
從邏輯上來說,下一步就是通過可視化,將這些數據進行比對。為此,我們需要先定義一個輔助函數,通過提供單行命令使用數據製作圖表。
def df_scatter(df, title,seperate_y_axis=False,y_axis_label=”, scale=’linear’,initial_hide=False):”’Generate a scatter plot of the entire dataframe”’label_arr= list(df)series_arr= list(map(lambda col:df[col],label_arr)) layout =go.Layout(title=title, legend=dict(orientation=”h”), xaxis=dict(type=’date’), yaxis=dict(title=y_axis_label, showticklabels=notseperate_y_axis, type=scale))y_axis_config=dict(overlaying=’y’, showticklabels=False, type=scale ) visibility =’visible’ifinitial_hide: visibility =’legendonly’# Form Trace For Each Seriestrace_arr=[]for index, series in enumerate(series_arr): trace =go.Scatter(x=series.index, y=series, name=label_arr[index], visible=visibility)# Add seperate axis for the seriesif seperate_y_axis: trace[‘yaxis’]=’y{}’.format(index +1) layout[‘yaxis{}’.format(index +1)]=y_axis_configtrace_arr.append(trace) fig =go.Figure(data=trace_arr, layout=layout)py.iplot(fig)
為簡便起見,我不會過多探討這個輔助函數的工作原理。如果想瞭解更多,請查看Pandas 和 Plotly的說明文件。
現在,我們就可以輕鬆製作比特幣價格數據的圖形了!
# Plot all of the BTC exchange pricesdf_scatter(btc_usd_datasets,’Bitcoin Price (USD) By Exchange’)
步驟2.6 清理並加總價格數據
從以上圖形中可以看到,儘管這四個系列數據遵循大致相同的路徑,但其中還是有一些不規則的變化,我們將設法清除這些異常變化。
在2012-2017年的時間段中,我們知道比特幣的價格從來沒有等於零的時候,所以我們先去除數據框中所有的零值。
# Remove “0” valuesbtc_usd_datasets.replace(0,np.nan,inplace=True)
在重新構建數據框之後,我們可以看到更加清晰的圖形,沒有缺失數據的情況了。
# Plot the revised dataframedf_scatter(btc_usd_datasets,’Bitcoin Price (USD) By Exchange’)
我們現在可以計算一個新的列:所有交易所的比特幣日平均價格。
# Calculate the average BTC price as a new columnbtc_usd_datasets[‘avg_btc_price_usd’]=btc_usd_datasets.mean(axis=1)
新的一列就是比特幣的價格指數!我們再把它畫出來,以核對該數據看起來是否有問題。
# Plot the average BTC pricebtc_trace=go.Scatter(x=btc_usd_datasets.index, y=btc_usd_datasets[‘avg_btc_price_usd’])py.iplot([btc_trace])
太好了,看起來確實沒有問題。稍後,我們將繼續使用這個加總的價格序列數據,以便能夠確定其他數位貨幣與美元之間的兌換匯率。
步驟3 獲取山寨幣(Altcoins)價格
現在,我們已經有了比特幣價格的時間序列數據了。接下來我們來看看非比特幣的數位加密貨幣的一些數據,一般是指山寨幣(Altcoins)。
步驟3.1 定義Poloniex交易所的API輔助函數
我們將使用Poloniex API來獲取數位加密貨幣交易的數據訊息。我們定義了兩個輔助函數來獲取山寨幣的相關數據,這兩個函數主要是通過這個API下載和緩存JSON數據。
首先,我們定義函數 get_json_data,它將從給定的URL中下載和緩存JSON數據。
defget_json_data(json_url,cache_path):”’Download and cache JSON data, return as a dataframe.”’try: f = open(cache_path,’rb’)df=pickle.load(f)print(‘Loaded {} from cache’.format(json_url))except(OSError,IOError) as e:print(‘Downloading {}’.format(json_url))df=pd.read_json(json_url)df.to_pickle(cache_path)print(‘Cached {} at {}’.format(json_url,cache_path))return df
然後,我們定義一個新的函數,該函數將產生Poloniex API的HTTP請求,並調用剛剛定義的get_json_data函數,以保存調用的數據結果。
base_polo_url=’https://poloniex.com/public?command=returnChartData¤cyPair={}&start={}&end={}&period={}’start_date=datetime.strptime(‘2015-01-01′,’%Y-%m-%d’)# get data from the start of 2015end_date=datetime.now()# up until todaypediod=86400# pull daily data (86,400 seconds per day)def get_crypto_data(poloniex_pair):”’Retrieve cryptocurrency data from poloniex”’json_url=base_polo_url.format(poloniex_pair,start_date.timestamp(),end_date.timestamp(),pediod)data_df=get_json_data(json_url,poloniex_pair)data_df=data_df.set_index(‘date’)return data_df
上述函數將抽取加密貨幣配對字符代碼(比如「BTC_ETH」),並返回包含兩種貨幣歷史兌換匯率的數據框。
步驟3.2 從Poloniex下載交易數據
絕大多數山寨幣都無法使用美元直接購買,個人要想獲取這些電子貨幣,通常都得先買比特幣,再根據加密貨幣兌換匯率,兌換成山寨幣。因而,我們就得下載每一種加密貨幣兌換比特幣的兌換匯率,然後再使用現有比特幣價格數據轉換成美元。
我們會下載9種排名靠前的加密貨幣交易數據:Ethereum,Litecoin,Ripple,Ethereum Classic,Stellar,Dash,Siacoin,Monero,和NEM。
altcoins=[‘ETH’,’LTC’,’XRP’,’ETC’,’STR’,’DASH’,’SC’,’XMR’,’XEM’]altcoin_data={} for altcoin in altcoins:coinpair=’BTC_{}’.format(altcoin)crypto_price_df=get_crypto_data(coinpair)altcoin_data[altcoin]=crypto_price_df
現在,我們有了包含9個數據框的字典,每種都包含山寨幣與比特幣之間的歷史日平均價格數據。
我們可以通過Ethereum價格表格的最後幾行,來判定數據是否可用。
altcoin_data[‘ETH’].tail()
步驟3.3 – 統一貨幣單位:美元
現在,我們可以將BTC-山寨幣匯率數據與我們的比特幣價格指數結合,來直接計算每一個山寨幣的歷史價格(單位:美元)。
# Calculate USD Price as a new column in each altcoin dataframe for altcoin in altcoin_data.keys(): altcoin_data[altcoin][‘price_usd’] = altcoin_data[altcoin][‘weightedAverage’] * btc_usd_datasets[‘avg_btc_price_usd’]
此處,我們為每一個山寨幣的數據框新增一列存儲其相應的美元價格。
接著,我們可以重新使用之前定義的函數merge_dfs_on_column,來建立一個合併的數據框,整合每種電子貨幣的美元價格。
# Merge USD price of each altcoin into single dataframe combined_df = merge_dfs_on_column(list(altcoin_data.values()), list(altcoin_data.keys()), ‘price_usd’)
就是如此簡單!
現在讓我們同時把比特幣價格作為最後一欄添加到合併後的數據框中。
# Add BTC price to the dataframe combined_df[‘BTC’] = btc_usd_datasets[‘avg_btc_price_usd’]
現在我們有一個唯一的數據框,它包含了我們正在驗證的十種電子貨幣的每日美元價格。
我們重新調用之前的函數df_scatter,以圖表形式展現全部山寨幣的相應價格。
# Chart all of the altocoin prices df_scatter(combined_df, ‘Cryptocurrency Prices (USD)’, seperate_y_axis=False, y_axis_label=’Coin Value (USD)’, scale=’log’)
看起來不錯!這張圖為我們展現了每一種貨幣兌換匯率在過去幾年的變化情況的一個全貌。
在這裡我們使用了對數規格的y軸,在同一繪圖上比較所有貨幣。你也可以嘗試其他不同的參數值(例如scale=’linear’),可以從不同視角理解數據。
步驟3.4- 執行相關性分析
你可能注意到電子貨幣的匯率看上去似乎是相關的,儘管他們的貨幣價值相差很大,而且波動性很高。尤其是從2017年4月的迅猛上漲開始,甚至很多的小波動似乎都與整個市場的波動同步出現。
當然,有數據支撐的結論比依據圖像而產生的直覺更有說服力。
我們可以利用Pandas corr()函數來驗證上述的相關性假設。該檢驗手段為數據框的每一欄計算了其對應另一欄的皮爾森相關係數。
8/22/2017修訂說明-這部分的修改是為了在計算相關係數時使用每日回報率而不是價格的絕對值。
基於一個非穩態時間序列(例如原始的價格數據)直接計算可能會導致相關性係數的偏差。針對此問題,我們的解決方案是使用pct_change()方法,將數據框中的每一個的價格絕對值轉化為相應的日回報率。
首先,我們來計算2016年的相關係數。
# Calculate the pearson correlation coefficients for cryptocurrencies in 2016 combined_df_2016 = combined_df[combined_df.index.year == 2016] combined_df_2016.pct_change().corr(method=’pearson’)
上面這張圖顯示的都是相關係數。係數接近1或-1,分別意味著這一序列是強正相關的,或逆相關的,相關係數趨近於0則說明相應對象並不相關,他們的波動是相互獨立的。
為了更可視化的展示結果,我們創建了一個新的可視化的幫助函數。
def correlation_heatmap(df, title, absolute_bounds=True): ”’Plot a correlation heatmap for the entire dataframe”’ heatmap = go.Heatmap( z=df.corr(method=’pearson’).as_matrix(), x=df.columns, y=df.columns, colorbar=dict(title=’Pearson Coefficient’), ) layout = go.Layout(title=title) if absolute_bounds: heatmap[‘zmax’] = 1.0 heatmap[‘zmin’] = -1.0 fig = go.Figure(data=[heatmap], layout=layout) py.iplot(fig) correlation_heatmap(combined_df_2016.pct_change(), “Cryptocurrency Correlations in 2016”)

圖示為2016年的電子貨幣相關係數。
此處,深紅色的數值代表強相關性(每一種貨幣顯然是與其自身高度相關的),深藍色的數值表示強逆相關性。所有介於中間的顏色-淺藍/橙/灰/茶色-其數值代表不同程度的弱相關或不相關。
這張圖表說明了什麼呢?關鍵在於,它說明了不同的數位加密貨幣價格在2016年間的波動情況,幾乎沒有統計上的顯著相關性。
現在,為了驗證我們的假設-電子貨幣在近幾個月的相關性增強,接下來,我們將使用從2017年開始的數據來重複同樣的測試。
combined_df_2017 = combined_df[combined_df.index.year == 2017] combined_df_2017.pct_change().corr(method=’pearson’)
上圖似乎顯示了更強的相關性。但這些數據可以單獨作為投資決策的依據嗎?答案是否定的。
然而值得注意得是,在這張圖上幾乎所有的電子貨幣相互之間都變得相關性更強了。
correlation_heatmap(combined_df_2017.pct_change(), “Cryptocurrency Correlations in 2017”)
圖:2017年的電子貨幣相關性
這是不是相當有趣呢?
為什麼?
好問題!其實,我也不是很確定 ……
我的第一反應是,對沖基金最近開始公開在電子貨幣市場交易(TO 編按:請參考這篇和這篇)。這些基金持有遠超於普通交易人的大量資本,當一支基金如果在多種加密貨幣間對衝自己的投入資本,然後根據獨立變量(比如說股票市場)對每一種貨幣使用相似的交易策略。如果從這個角度來看,出現這種越來越強的相關性趨勢是合理的。
更深度的理解XRP和STR
例如,從上圖中可以很明顯看出 XRP(Ripple的代幣)是與其他電子貨幣相關性最低的。但這裡有一個值得注意的例外是 STR(Stellar的代幣,官方名字是”Lumens”),與XRP有強相關關係(相關係數:0.62)。
有趣的是,Stellar 和 Ripple 是非常相似的金融科技平台,他們都旨在減少銀行間跨國轉賬時的繁瑣步驟。
可想而知,考慮到區塊鏈服務使用代幣的相似性,一些大玩家以及對沖基金可能會對他們在 Stellar 和 Ripple 上的投資使用相似的交易戰略。這可能就是為什麼 XRP 相比其他電子貨幣,與 STR 有更強相關性的原因。
現在,到你了!
然而,這一解釋在很大程度上是推測性的,可能你會做的更好。基於我們已經奠定的基礎,你有成百上千條不同的方法可以繼續探索數據中蘊藏的故事。
可以考慮從以下思路入手:
- 為整個分析添加更多加密貨幣的數據
- 調整相關性分析的時間範圍和顆粒度,以得到優化的或粗粒度的趨勢視圖。
- 從交易量或區塊鏈數據挖掘集中尋找趨勢。相較於原始的價格數據,如果你想預測未來價格波動,你可以更需要買/賣量的比率數據。
- 在股票、商品、法定貨幣上加入價格數據來決定他們當中哪一項與電子貨幣具有相關性(但是,別忘了那句老話「相關不蘊含因果」)
- 使用Event Registry, GDELT,以及Google Trends來量化圍繞著特定電子貨幣的「熱詞」數量。
- 利用數據訓練一個預測性機器學習模型,來預測明日價格。如果你有更大的雄心壯志,你甚至可以考慮嘗試用循環神經網絡(RNN)進行上述訓練。
- 利用你的分析來創建一個自動化的交易機器人,通過對應的應用編程接口(API),應用在例如「Poloniex」或「Coinbase」的交易網站上。請小心:一個性能欠佳的機器人可以輕易地讓你的資產瞬間灰飛煙滅。
關於比特幣,以及對於加密貨幣總體而言,最好的部分是它們的去中心化本質,這使得它比任何其他資產都自由、民主。可以將你的分析開源共享,參與到社區中,或者寫一篇博客!
希望你現在已經掌握了自行分析所需的技能,以及在未來讀到任何投機性的加密貨幣的文章時,進行辯證思考的能力,尤其是那些沒有數據支撐的預測。
感謝你的閱讀,關於這一教程,如果你有任何看法、建議或批評指正,請在下方留言。如果你發現代碼如果有問題,也可以在 Github 倉庫中新建一個問題(issue)。
原文連結:https://blog.patricktriest.com/analyzing-cryptocurrencies-python/
(本文經合作夥伴 大數據文摘 授權轉載,並同意 TechOrange 編寫導讀與修訂標題,原文標題為 〈 手把手| 用Python代碼建個數據實驗室,順利入坑比特幣 〉。)
看完想知道更多比特幣?來,這邊請
比特幣真正的價值:應該要拿來拯救世界,而不是拿來炒作投資
比特幣漲破 30 萬台幣又大跌 15%,劍橋研究員:比特幣有可能引發下一次金融危機!
世界一半的比特幣出自中國,現在政府直接斷電不給挖,是要礦工們去跳樓嗎?