昨日は大まかな戦略の方針を定めた。
how-to-make-stock-trading-system.dogwood008.com
この方針に従って実装を進めていく。まだ完成はしていないが、戦略の部分だけ途中経過を公開する。
import backtrader as bt from logging import getLogger, StreamHandler, Formatter, DEBUG, INFO if USE_BOKEH: from backtrader_plotting import Bokeh from backtrader_plotting.schemes import Tradimo # for jupyter if 'PercentageBuySellStrategyWithLogger' in globals(): del PercentageBuySellStrategyWithLogger # Create a Stratey class PercentageBuySellStrategyWithLogger(bt.Strategy): params = ( ('default_unit_size', 100), # デフォルトの単元株の株数 ('buy_under_percentage', 5), # 前日終値と比較し本日始値が▲x%の場合に買い注文 ('sell_under_percentage', 5), # 前日終値と比較し本日始値がy%の場合に売り注文 ('min_order_price', 10 * 10000), # 最低購入金額(円) ('max_order_price', 50 * 10000), # 最高購入金額(円) ('smaperiod', 5), ) 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, loglevel): # Keep a reference to the "close" line in the data[0] dataseries self._dataclose = self.datas[0].close self._dataadjclose = self.datas[0].adjclose self._datavolume = self.datas[0].volume self._logger = getLogger(__name__) self.handler = StreamHandler() self.handler.setLevel(loglevel) self._logger.setLevel(loglevel) self._logger.addHandler(self.handler) self._logger.propagate = False self.handler.setFormatter( Formatter('[%(levelname)s] %(message)s')) self.sma = bt.indicators.SimpleMovingAverage( self.datas[0], period=self.params.smaperiod) def _log(self, txt, loglevel=INFO, dt=None): ''' Logging function for this strategy ''' dt = dt or self.datas[0].datetime.date(0) self._logger.log(loglevel, '%s, %s' % (dt.isoformat(), txt)) def _debug(self, txt, dt=None): self._log(txt, DEBUG, dt) def _info(self, txt, dt=None): self._log(txt, INFO, dt) def size(self) -> int: # TODO: min_order_price <= 購入金額 <= max_order_price になるように調整して返す return self.p.default_unit_size def next(self): open_today = self._dataclose[0] close_yesterday = self._dataclose[-1] if close_yesterday * (100.0 - self.p.buy_under_percentage) / 100.0 <= open_today: size = self.size() self._info('BUY CREATE @{price:.2f}, #{unit:4d}'.format(price=open_today, unit=size)) self.buy(size=size, price=open_today, exectype=bt.Order.Limit, valid=bt.Order.DAY) if close_yesterday * (100.0 - self.p.buy_under_percentage) / 100.0 <= open_today: size = None # 自動的に建玉全数が指定される self._info('CLOSE (SELL) CREATE @{price:.2f}, #all'.format(price=open_today)) self.close(size=size, price=open_today, exectype=bt.Order.Limit, valid=bt.Order.DAY) if USE_BOKEH: del PercentageBuySellStrategyWithLogger from percentage_buy_sell_strategy_with_logger import PercentageBuySellStrategyWithLogger