昨日に引き続き戦略を作成していく。但し未だ完成していないので途中経過を添付する。
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_over_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._dataopen = self.datas[0].open self._datahigh = self.datas[0].high self._datalow = self.datas[0].low 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 notify_order(self, order): if order.status in [order.Submitted, order.Accepted]: return if order.status in [order.Completed]: if order.isbuy(): buy_or_sell = 'BUY' elif order.issell(): buy_or_sell = 'SELL' else: buy_or_sell = 'UNDEFINED' self._log('{b_s:%4s} EXECUTED, {price:07.2f}'.format( b_s=buy_or_sell, price=order.executed.price)) elif order.status in [order.Canceled, order.Margin, order.Rejected]: self._debug('Order Canceled/Margin/Rejected') elif order.status in [order.Expired]: self._debug('Expired: {b_s:s} ¥{sum:,d} (@{price:.2f} * {unit:4d})'.format( \ sum=int(order.price * order.size), b_s=order.ordtypename(), price=order.price, unit=order.size)) else: self._debug(order.getstatusname()) 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._dataopen[0] close_yesterday = self._dataclose[-1] if open_today * (100.0 - self.p.buy_under_percentage) / 100.0 <= close_yesterday: size = self.size() self._info('BUY CREATE @{price:.2f}, #{unit:4d}'.format(price=open_today, unit=size)) self._debug('(o, h, l, c) = ({o:}, {h:}, {l:}, {c:})'.format( o=self._dataopen[0], h=self._datahigh[0], l=self._datalow[0], c=self._dataclose[0])) self.buy(size=size, price=open_today, exectype=bt.Order.Stop, valid=bt.Order.DAY) elif close_yesterday * (100.0 + self.p.sell_over_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.Stop, valid=bt.Order.DAY) if USE_BOKEH: del PercentageBuySellStrategyWithLogger from percentage_buy_sell_strategy_with_logger import PercentageBuySellStrategyWithLogger