上篇文章,我們講了回測系統(tǒng)的總體架構。后續(xù)會逐步把每個核心組件拆解開來說明。本篇要講述的是數據獲取——***Datafeed***。為了安裝和理解系統(tǒng)簡單,我們不使用數據庫,而是直接以csv的形式存儲數據。
Datafeed需要傳入兩個參數,data_path是本地存儲目錄,source是指明下載數據的地方,默認是從quandl下載美股數據。
實現(xiàn)交易數據獲取,這里考慮最簡化用戶環(huán)境,暫不使用數據庫,直接按年保存至本地csv。
datafeed.py
```
class DataFeed(object):
? ? def __init__(self,data_path,source='quandl'):
? ? ? ? self.data_path = data_path
? ? ? ? self.source = source
```
實現(xiàn)獲取數據的接口是download_or_get_data,如果本地已存在,則直接讀取對應的csv; 如果沒有,則從云端下載。為了實現(xiàn)方便,我們把數據按年存儲,這樣,就算給定的回測周期不同,也有大量可以復用,不必從頭從云端下載。
```
def download_or_get_data(self,codes,from_year,to_year,authToken=None):
? ? ? ? #目錄是否存在,如果不存在,則創(chuàng)建
? ? ? ? if not os.path.exists(self.data_path):
? ? ? ? ? ? logger.info("Creating %s directory" % (self.data_path))
? ? ? ? ? ? os.mkdir(self.data_path)
? ? ? ? all = {}
? ? ? ? for code in codes:
? ? ? ? ? ? all_code = []
? ? ? ? ? ? for year in range(from_year, to_year + 1):
? ? ? ? ? ? ? ? all_code.append(self.__fetch_data(code,year))
? ? ? ? ? ? df_code = pd.concat(all_code, axis=0)
? ? ? ? ? ? all[code] = df_code.sort_index()
? ? ? ? self.data = all
? ? ? ? return all
```
__fetch_data是獲取一個code某一年的數據。如果本地存在該csv文件,則直接讀取,否則從云端下載。
```
def __fetch_data(self,code,year):
? ? ? ? fileName = os.path.join(self.data_path, "%s-%d-quandl.csv" % (code, year))
? ? ? ? if not os.path.exists(fileName):
? ? ? ? ? ? logger.info("Downloading %d to %s" % (year, fileName))
? ? ? ? ? ? if self.source == 'quandl':
? ? ? ? ? ? ? ? self.__fetch_from_quanl(code,year,fileName)
? ? ? ? df = pd.read_csv(fileName).copy()
? ? ? ? df.index = df['Date']
? ? ? ? return df
```
__fetch_from_quanl實現(xiàn)從quanl下載對應code的交易數據,code可以美股代碼,比如AAPL,AMZN等。
```
def __fetch_from_quanl(self,code,year,file_name,authToken=None):
? ? ? ? download_daily_bars('WIKI', code, year, file_name, authToken)
```
后續(xù)可以擴展加上A股,BTC等數據源。