backtrader数据基础
數據查看:
class TestStrategy(bt.Strategy):def __init__(self):# 打印數據集和數據集對應的名稱print("-------------self.datas-------------")print(self.datas)print("-------------self.data-------------")print(self.data._name, self.data) # 返回第一個導入的數據表格,縮寫形式print("-------------self.data0-------------")print(self.data0._name, self.data0) # 返回第一個導入的數據表格,縮寫形式print("-------------self.datas[0]-------------")print(self.datas[0]._name, self.datas[0]) # 返回第一個導入的數據表格,常規形式print("-------------self.datas[1]-------------")print(self.datas[1]._name, self.datas[1]) # 返回第二個導入的數據表格,常規形式print("-------------self.datas[-1]-------------")print(self.datas[-1]._name, self.datas[-1]) # 返回最后一個導入的數據表格print("-------------self.datas[-2]-------------")print(self.datas[-2]._name, self.datas[-2]) # 返回倒數第二個導入的數據表格 data1 = pd.read_csv('111.csv') cerebro = bt.Cerebro() st_date = datetime.datetime(2019,1,2) ed_date = datetime.datetime(2021,1,28) # 添加 600466.SH 的行情數據 datafeed1 = bt.feeds.PandasData(dataname=data1, fromdate=st_date, todate=ed_date) cerebro.adddata(datafeed1, name='600466.SH') # 添加 603228.SH 的行情數據 datafeed2 = bt.feeds.PandasData(dataname=data2, fromdate=st_date, todate=ed_date) cerebro.adddata(datafeed2, name='603228.SH') cerebro.addstrategy(TestStrategy) rasult = cerebro.run() # 訪問第一個數據集的 close 線 self.data.lines.close # 可省略 lines 簡寫成:self.data.close self.data.lines_close # 可省略 lines 簡寫成:self.data_close # 訪問第二個數據集的 open 線 self.data1.lines.close # 可省略 lines 簡寫成:self.data1.close self.data1.lines_close # 可省略 lines 簡寫成:self.data1_close # 注:只有從 self.datas 調用 line 時可以省略 lines,調用 indicators 中的 line 時不能省略獲取數據方法:
如果你能清楚的記住數據表格中每條線的位置,也可以通過索引位置(整數)來訪問,同樣支持簡寫形式:
1、完整形式:self.datas[X].lines[Y];
2、簡寫形式:self.dataX.lines[Y]、self.dataX_Y;
3、說明:X 對應單個數據表格在數據表格集合中的索引位置,Y 對應某條線在數據表格中的索引位置 。
class TestStrategy(bt.Strategy):def __init__(self):print("--------- 打印 self 策略本身的 lines ----------")print(self.lines.getlinealiases())print("--------- 打印 self.datas 第一個數據表格的 lines ----------")print(self.datas[0].lines.getlinealiases())# 計算第一個數據集的s收盤價的20日均線,返回一個 Data feedself.sma = bt.indicators.SimpleMovingAverage(self.datas[0].close, period=20)print("--------- 打印 indicators 對象的 lines ----------")print(self.sma.lines.getlinealiases())print("---------- 直接打印 indicators 對象的所有 lines -------------")print(self.sma.lines) print("---------- 直接打印 indicators 對象的第一條 lines -------------")print(self.sma.lines[0])def next(self):print('驗證索引位置為 6 的線是不是 datetime')print(bt.num2date(self.datas[0].lines[6][0]))# num2date() 作用是將數字形式的時間轉為 date 形式cerebro = bt.Cerebro() st_date = datetime.datetime(2019,1,2) ed_date = datetime.datetime(2021,1,28) datafeed1 = bt.feeds.PandasData(dataname=data1, fromdate=st_date, todate=ed_date) cerebro.adddata(datafeed1, name='600466.SH') datafeed2 = bt.feeds.PandasData(dataname=data2, fromdate=st_date, todate=ed_date) cerebro.adddata(datafeed2, name='603228.SH') cerebro.addstrategy(TestStrategy) rasult = cerebro.run()1、索引規則:索引位置編號結合了時間信息,
0 號位置永遠指向當前時間點的數據,
-1 號位置指向前一個時間點的數據,
然后依次回退 (backwards)-2、-3、-4、-5、......;
1 號位置指向下一天的數據,然后依次向前(forwards)2、3、4、......;
2、切片方法:get(ago=0, size=1) 函數,
其中 ago 對應數據點的索引位置,即從 ago 時間點開始往前取 size 個數據點。
默認情況下是取當前最新時點(ago=0)的那一個數據(size=1);
3、在編寫策略時,上面提到的對數據點的索引切片操作一般在 next() 函數中涉及較多,
而 __init__() 中涉及較少,
因為__init__() 中一般是對 一整條 line 進行操作(運算)。
__init__() 中:?
訪問的是整條 line,索引編號也是對整條 line 上所有數據點進行編號的,
所以 0 號位置對應導入的行情數據中最晚的那個時間點 2021-01-28,
然后依次 backwards;
1 號位置對應最早的那個時間點 2019-01-02,
然后依次 forwards ;
通過 get() 切片時,如果是從 ago=0 開始取,不會返回數據,從其他索引位置開始取,能返回數據 。
next() 中:
1、由于 next() 是按回測時間點依次循環運行的,
所以 next() 中數據點的索引位置是隨著回測依次推進而動態變化的:backwards 時對應回測過的、已處理過的那部分 line, forwards 時對應還未回測的那部分 line ;
2、在 next() 中,只要記住 0 是當前回測的時間點(今日),
然后站在當前時刻回首過往:-1 是昨日、-2 是前日,依次類推 ;或者站在當前時刻期盼未來:1 是明日、2 是明后日,以此類推 。
獲取 line 長度:
1、self.data0.buflen() 返回整條線的總長度,固定不變;
2、在 next() 中調用 len(self.data0),返回的是當前已處理(已回測)的數據長度,會隨著回測的推進動態增長。
DataFeeds 數據模塊
默認的導入方式
step1:調用 DataFeeds 模塊中的方法讀取數據;
step2:將讀取的數據傳給大腦。
# 讀取和導入 CSV 文件 data = bt.feeds.GenericCSVData(dataname='filename.csv', ...) cerebro.adddata(data, name='XXX') # 讀取和導入 dataframe 數據框 - 方式1 data = bt.feeds.PandasData(dataname=df, ...) cerebro.adddata(data, name='XXX') # 讀取和導入 dataframe 數據框 - 方式2 data = bt.feeds.PandasDirectData(dataname=df, ...) cerebro.adddata(data, name='XXX')# 以 GenericCSVData 為例進行參數說明(其他導入函數參數類似) bt.feeds.GenericCSVData(dataname='daily_price.csv', # 數據源,CSV文件名 或 Dataframe對象fromdate=st_date, # 讀取的起始時間todate=ed_date, # 讀取的結束時間nullvalue=0.0, # 缺失值填充dtformat=('%Y-%m-%d'), # 日期解析的格式# 下面是數據表格默認包含的 7 個指標,取值對應指標在 daily_price.csv 中的列索引位置datetime=0, # 告訴 GenericCSVData, datetime 在 daily_price.csv 文件的第1列high=3, low=4,open=2,close=5,volume=6,openinterest=-1) # 如果取值為 -1 , 告訴 GenericCSVData 該指標不存在?Backtrader 中的數據表格默認情況下包含 7 條 line,這 7 條 line 的位置也是固定的,
依次為 ('close', 'low', 'high', 'open', 'volume', 'openinterest', 'datetime') ,
那導入的數據表格必須包含這 7 個指標嗎?指標的排列順序也必須一致嗎?
當然不是!其實你只要告訴 GenericCSVData、PandasData 、PandasDirectData 這 7 個指標在數據源中位于第幾列,如果沒有這個指標,那就將位置設置為 -1?
(如果是dataframe, None 表示指標不存在,-1 表示按位置或名稱自動匹配指標),所以你要做的是讓 Backtrader 知道指標在數據源的哪個位置上 。?
自定義讀取函數
如果你覺得每次都要設置這么多參數來告知指標位置很麻煩,那你也可以重新自定義數據讀取函數,
自定義的方式就是繼承數據加載類 GenericCSVData、PandasData 再構建一個新的類,然后在新的類里統一設置參數:
?新增指標
在回測時,除了常規的高開低收成交量這些行情數據外,還會用到別的指標,
比如選股回測時會用到很多選股因子(PE、PB 、PCF、......),那這些數據又該如何添加進 Backtrader 的數據表格呢?
往 Backtrader 的數據表格里添加指標,就是給數據表格新增列,也就是給數據表格新增 line:
以導入 DataFrame 為例,
在繼承原始的數據讀取類 bt.feeds.PandasData 的基礎上
,設置 lines 屬性和 params 屬性,
新的 line 會按其在 lines 屬性中的順序依次添加進數據表格中,具體對照下面例子的輸出部分:
?
擴展PandasData類,加載更多列數據 #pandas的數據格式 from backtrader.feeds import PandasData class Addmoredata(PandasData):lines = ('turnover_rate','pe','pb',)params = (('turnover_rate',7),('pe',8),('pb',9),) 擴展GenericCSVData加載csv格式數據 from backtrader.feeds import GenericCSVData class AddCsvData(GenericCSVData):lines = ('turnover_rate','pe','pb',)params = (('turnover_rate',7),('pe',8),('pb',9),) import backtrader as bt from datetime import datetime class TestStrategy1(bt.Strategy):def log(self, txt, dt=None):dt = dt or self.datas[0].datetime.date(0)print('%s, %s' % (dt.isoformat(), txt))def next(self):self.log(f"換手率:{self.datas[0].turnover_rate[0]},\市凈率:{self.datas[0].pb[0]},市盈率:{self.datas[0].pe[0]}") cerebro = bt.Cerebro() cerebro.addstrategy(TestStrategy1) feed = Addmoredata(dataname = get_data('300002.SZ','20200420')) #如果是讀取csv數據使用下式 #feed = AddCsvData(dataname = 'test.csv',dtformat=('%Y-%m-%d')) cerebro.adddata(feed) cerebro.run() 多只股票數據加載測試: class TestStrategy2(bt.Strategy):def log(self, txt, dt=None):dt = dt or self.datas[0].datetime.date(0)print('%s, %s' % (dt.isoformat(), txt))def next(self):for data in self.datas:print(data._name)self.log(f"換手率:{data.turnover_rate[0]},\市凈率:{data.pb[0]},市盈率:{data.pe[0]}") cerebro = bt.Cerebro() cerebro.addstrategy(TestStrategy2) codes=['600862.SH','300326.SZ','300394.SZ'] #加載最近兩日交易數據 for code in codes:feed = Addmoredata(dataname = get_data(code,'20200506'),name=code)cerebro.adddata(feed) cerebro.run()總結
以上是生活随笔為你收集整理的backtrader数据基础的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: backtrader指标
- 下一篇: 超全Typora快速入门