backtrader日志、日歷及resample


本文摘自https://blog.csdn.net/m0_46603114/article/details/107889583

日志功能

可以通過下面的代碼在backtrader中添加日志功能:

cerebro.addwriter(bt.WriterFile, out = 'log.csv', csv = True)
1
日志信息將被輸出到工作目錄下的log.csv文件中,輸出內容包括:

種子數據(Data Feeds)
策略數據(lines和參數)
指標和觀察者(Observer)數據(lines和參數)
分析數據(參數和分析結果數據)
交易日歷

交易日歷適用於以下場景:

由日線數據resample得到周線數據時,使用交易日歷可以准確識別每周的最后1根日線。
在策略的next()方法中打印一下內容

在輸出的每一行中,第一個日期為策略所使用的日期,第二個日期為當前日線的日期,第三個日期為當前月線的日期。
其中,第3行1月4日為星期五,應該出現第一根周線數據,但是輸出結果中卻沒有周線數據。第8行1月11日為周五,從1月7日至1月11日的5根日線可以合成1根周線,后面的周線數據也應該更新為1月11日,但是輸出結果卻是1月4日。
產生以上結果的原因是,backtrader把2019年1月1日當作了交易日,只是沒有讀入數據。這樣1月1日至4日,再加上7日共計5根日線,就在1月7日合成了第一根周線;同樣1月8日至11日,再加上14日共計5根日線,在1月14日合成了第二根周線。這顯然不是想要的結果。

解決上述問題的方案是,通過繼承bt.TradingCalendar定義新的日歷,然后在日歷中設定節假日。如以下代碼所示,將2019年1月1日添加到holidays列表中,然后在cerebro添加該日歷:

class AStockCalendar(bt.TradingCalendar):
params = dict(
holidays=[
datetime.date(2019, 1, 1),
],
open=datetime.time(9, 30),
close=datetime.time(15, 0),
)

cerebro.addcalendar(AStockCalendar())

當使用交易日歷時可以看到,在1月4日(星期五)合成了第一根周線,在1月11日(星期五)合成了第二根周線,得到了正確的結果。

同樣,可以把2019年的其他節假日都添加到holidays列表中,來實現整年的周線數據的正確合成。

日內分時數據resample合成日線數據時,使用交易日歷處理提前收盤的情況。
美股在感恩節后的第一天,會在下午1點休市,這樣如果不做處理,使用分鍾數據合成日線數據時就會出問題,可以通過添加以下日歷來解決:
class CustomCalendar(bt.TradingCalendar):
params = dict(
holidays=[
datetime.date(2016, 1, 1),
datetime.date(2016, 1, 18),
datetime.date(2016, 2, 15),
datetime.date(2016, 3, 25),
datetime.date(2016, 5, 30),
datetime.date(2016, 7, 4),
datetime.date(2016, 9, 5),
datetime.date(2016, 11, 24),
datetime.date(2016, 12, 26),
],
earlydays=[
(datetime.date(2016, 11, 25),
datetime.time(9, 30), datetime.time(13, ,0))
],
open=datetime.time(9, 30),
close=datetime.time(16, 0),
)

以2016年為例,日歷中設定了2016年的節假日,一般每日交易時間為9:30至16:00,11月25日的交易時間為9:30至13:00。

resample淺析

借助於日志功能,對resample功能進行簡單分析。這里以30分鍾數據為數據源,使用resample來合成60分鍾數據,同時加載已下載好的60分鍾數據用於對比resample結果,部分代碼如下:

data = load_data(stk_code, fromdate, todate, '30')
cerebro.adddata(data, name = stk_code + '_30m')
cerebro.resampledata(data, name = stk_code + '_30to60m', timeframe = bt.TimeFrame.Minutes, compression = 60)
data = load_data(stk_code, fromdate, todate, '60')
cerebro.adddata(data, name = stk_code + '_60m'

以加載2020年6月1日至4日平安銀行的數據為例,使用日志功能將結果輸出至log.csv中,部分結果如下:


標黃的D、L、T列分別表示加載的30分鍾時間標簽數據、由30分鍾數據合成的60分鍾時間標簽數據、加載的60分鍾時間標簽數據。
對比D列和T列可以發現,在加載的60分鍾數據中,6月1日首個時間點(10:00)數據為空,在時間點10:30出現第一個數據。在D列時間標簽變為11:00時,T列時間標簽仍為10:30。在D列時間標簽變為11:30時,T列時間標簽才變為11:30。這樣就保證了,在同時加載多個周期數據進行回測時,不會發生使用未來數據的情況。
對比D列和L列發現,resample結果未按預期得到10:30、11:30、14:00、15:00四個時段的60分鍾數據,而是得到10:00、11:00、12:00、14:00、15:00五個整點時間段的數據。筆者嘗試了調整函數resampledata()的bar2edge、rightedge、adjbartime、boundoff參數,也嘗試了使用交易日歷功能設置每日交易起止時間,均未能實現預期的resample結果。目前的解決方案是,在合成分鍾級數據時,不使用backtrader的resampledata()函數,而是先離線合成所需周期的數據,然后使用cerebro.adddata()加載合成的數據,再進行多周期策略的回測。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM