株のシステムトレードをしよう - 1から始める株自動取引システムの作り方

株式をコンピュータに売買させる仕組みを少しずつ作っていきます。できあがってから公開ではなく、書いたら途中でも記事として即掲載して、後から固定ページにして体裁を整える方式で進めていきます。

戦略:前日比x%以下で買い、前日比y%以上で売り その2

昨日は大まかな戦略の方針を定めた。

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

(C) 2020 dogwood008 禁無断転載 不許複製 Reprinting, reproducing are prohibited.