前回の振り返り
前回は基礎的な戦略 TestStrategy
を作成した。
how-to-make-stock-trading-system.dogwood008.com
今回の内容
今回は昨日作成した戦略を使用した、バックテストを実行してみる。
バックテストの実行
実行すると、下記のような出力を得られるだろう。
$ docker-compose up Starting stock-trading-system_app_1 ... done Attaching to stock-trading-system_app_1 app_1 | Starting Portfolio Value: 100000.00 app_1 | 2000-01-03, Close, 26.27 app_1 | 2000-01-04, Close, 23.95 (中略) app_1 | 2000-12-28, Close, 27.63 app_1 | 2000-12-29, Close, 25.85 app_1 | Final Portfolio Value: 100000.00 stock-trading-system_app_1 exited with code 0
これと、 TestStrategy
を見比べて、動作の流れを説明する。
# 以下引用: mementum, "Quickstart Guide - Backtrader", # "https://www.backtrader.com/docu/quickstart/quickstart/#our-first-strategy", # アクセス日:2020年10月29日, 日本語のコメント部は著者による # Create a Stratey ここから売買戦略だが、まだ基本的には何かを参照して売買を決めるような戦略は作らない class TestStrategy(bt.Strategy): def log(self, txt, dt=None): ''' Logging function for this strategy''' dt = dt or self.datas[0].datetime.date(0) print('%s, %s' % (dt.isoformat(), txt)) def __init__(self): # Keep a reference to the "close" line in the data[0] dataseries self.dataclose = self.datas[0].close # `self.dataclose` に今着目しているローソク足の終値を代入する # 「今」とは、バックテスト中では1営業日ずつ進むその年月日を指す def next(self): # Simply log the closing price of the series from the reference self.log('Close, %.2f' % self.dataclose[0])
ローソク足(ティック)が1進む、つまり着目している年月日が1営業日進むと、そのたびに next(self)
が呼ばれる。 next(self)
からは self.log(~)
を呼んでいるので、ログが記録される。
ここで、前回書いたとおり、 print()
によるログよりも logger
を使ったログ出力の方が望ましいので、その部分を変えていこう。修正には次の記事を参考にする。
ついでに、 private
扱いにしたいメソッドや変数は、プレフィクスとして _
を付けておく1。
# main.py を修正 (前略) # ログ用 from logging import getLogger, StreamHandler, Formatter, DEBUG # Create a Stratey class TestStrategyWithLogger(bt.Strategy): def _log(self, txt, dt=None): ''' Logging function for this strategy ''' dt = dt or self.datas[0].datetime.date(0) self._logger.debug('%s, %s' % (dt.isoformat(), txt)) def __init__(self): # Keep a reference to the "close" line in the data[0] dataseries self._dataclose = self.datas[0].close self._logger = getLogger(__name__) self.handler = StreamHandler() self.handler.setLevel(DEBUG) self._logger.setLevel(DEBUG) self._logger.addHandler(self.handler) self._logger.propagate = False self.handler.setFormatter( Formatter('[%(levelname)s] %(message)s')) def next(self): # Simply log the closing price of the series from the reference self._log('Close, %.2f' % self._dataclose[0]) if __name__ == '__main__': (中略) # Add a strategy IN_DEVELOPMENT = True # このフラグにより、ログレベルを切り替えることで、本番ではWARN以上のみをログに出すようにする。 # フラグの切り替えは、環境変数で行う事が望ましいが今は一旦先送りする。 loglevel = DEBUG if IN_DEVELOPMENT else WARN cerebro.addstrategy(TestStrategyWithLogger, loglevel) (後略)
これにより、 IN_DEVELOPMENT
定数の状態により、ログレベルを変更することができるようになった。つまり、本番はより重要なログのみを出力するようにし、開発中はデバッグ用のログを出力することができるようになったということである。
実際に実行してみよう。
# IN_DEVELOPMENT = True のとき $ docker-compose up Starting stock-trading-system_app_1 ... done Attaching to stock-trading-system_app_1 app_1 | [DEBUG] 2000-01-03, Close, 26.27 app_1 | [DEBUG] 2000-01-04, Close, 23.95 app_1 | [DEBUG] 2000-01-05, Close, 22.68 (中略) app_1 | [DEBUG] 2000-12-27, Close, 27.30 app_1 | [DEBUG] 2000-12-28, Close, 27.63 app_1 | [DEBUG] 2000-12-29, Close, 25.85 app_1 | Starting Portfolio Value: 100000.00 app_1 | Final Portfolio Value: 100000.00 stock-trading-system_app_1 exited with code 0
# IN_DEVELOPMENT = False のとき $ docker-compose up Starting stock-trading-system_app_1 ... done Attaching to stock-trading-system_app_1 app_1 | Starting Portfolio Value: 100000.00 app_1 | Final Portfolio Value: 100000.00 stock-trading-system_app_1 exited with code 0
どうだろうか。下の「 IN_DEVELOPMENT
= False
のとき」には、WARN以上のログのみが出力されている(=DEBUGはレベルが低いため、出力がスキップされる)ため、出力がシンプルになっているのがわかる。
次回は実際に前日とのローソク足を比較するロジックを実装する。
-
Pythonにはprivate変数・メソッドという概念が無いようである。プレフィクスは慣習として付けるに留まるので、インスタンスの外から見える。↩