【戦略検証】Pythonで投資ストラテジーの検証を行えるスクリプト

プログラミングコード

今日は、Pythonで特定の投資ストラテジーのバックテストを行うために使えるBaseStrategyクラスなるものを実装したので、それを記していきます。

トマトソース

追記2022/03/22:おそらく私の独自のスクリプトを用いるよりも、既存ライブラリを用いたほうが爆速でバックテストができるのでそちらを使うことをお勧めします。

トマトソースのWEB開発
目次

BaseStrategyクラス

BaseStrategyクラスでは、投資ストラテジーのバックテストに必要な処理を汎用的に使えるようにまとめています。(まだ課題あり)

ポイントとしては、処理の記述が面倒くさいバックテストの部分を汎用化しているので、ストラテジーをバックテストする際にラクに行えます。

コードはGitHub Gistに公開しているので、そちらでご覧いただけます。

Gist
base_strategy.py GitHub Gist: instantly share code, notes, and snippets.

BaseStrategyの使い方

使い方はシンプルです。

BaseStrategyの使い方
  1. ストラテジークラスを作成し、継承する
  2. バックテストをしたいタイミングでクラスを使う

といった感じで使えます。

BaseStrategyを使ったサンプルコード

BaseStrategyクラスを継承したパターンは以下の通りです。

import pandas as pd
import numpy as np
import talib as ta
from strategy.base.base_strategy import BaseStrategy

class SimpleMAStrategy(BaseStrategy):

    def __init__(self, sma_length, initial_capital, force_stop):
        super().__init__(initial_capital, force_stop)
        self.sma_length = sma_length

    def prepare(self, data=None, multiplier=1):
        super().prepare()
        df = data.copy()
        # - 終値が移動平均線をX*MA以上を下回ったらLong
        # - 終値が移動平均線をX*MA以上を上回ったらShort
        df["MA"] = ta.SMA(df["close"], self.sma_length)

        # Entry logic
        df["long_entry_signal"] = np.where(-df["close"] + df["MA"] > df["MA"]*multiplier,  1, 0)
        df["long_entry_at"] = np.where(df["long_entry_signal"], df["close"].shift(-1), 0) # long at next close price when long signal occurs
        df["short_entry_signal"] = np.where(df["close"] - df["MA"] > df["MA"]*multiplier,  1, 0)
        df["short_entry_at"] = np.where(df["short_entry_signal"], df["close"].shift(-1), 0) # short at next close price when short signal occurs

        # Exit logic
        df["long_exit_signal"] = np.where(df["close"] > df["MA"],  1, 0) # short at next close price when short signal occurs
        df["long_exit_at"] = np.where(df["long_exit_signal"], df["close"].shift(-1), 0)
        df["short_exit_signal"] = np.where(df["close"] < df["MA"],  1, 0) # long at next close price when long signal occurs
        df["short_exit_at"] = np.where(df["short_exit_signal"], df["close"].shift(-1), 0)

        return df

#使う場合
strategy = SimpleMAStrategy(initial_capital=1000, force_stop=0.1)
processed = strategy.prepare(data, multiplier=2)
result = strategy.simulate(processed)

必要箇所でBaseStrategyクラスを呼び出す場合は以下の通りです。

import pandas as pd
import numpy as np
import talib as ta
from strategy.base.base_strategy import BaseStrategy

strategy = BaseStrategy(initial_capital=1000, force_stop=0.1)
already_processed = pd.read_csv("processed_data.csv") 
result = strategy.simulate(already_processed)
トマトソース

上記2種類の方法でご活用いただけますが、継承することを想定して作成しました。

BaseStrategyメソッドの内容

BaseStrategyクラスの内容としては、いくつかありますが一番重要なのはsimulateメソッドです。

これを用いれば、加工済みのデータを使ってトレード戦略のシュミレーションが行えます。

注意としては、ロングポジションを保持している場合は、ショートポジションを実行しないようになっています。

トマトソース

なので、両建ては行えない状態です。必要な場合は、ロジックの改良が必要になります。

加工済みのデータに必要なもの

コードを見ていただければわかるかと思いますが、simulateメソッドでバックテストを行うには以下の情報が必要になります。

必要なデータ
  1. long_entry_signal:買いエントリーシグナル(0, 1)
  2. long_exit_signal:買い手仕舞いシグナル(0, 1)
  3. long_entry_at:買いエントリー価格(float64)
  4. long_exit_at:買い手仕舞い価格(float64)
  5. short_entry_signal:空売りエントリーシグナル(0, 1)
  6. short_exit_signal:空売り手仕舞いシグナル(0, 1)
  7. short_entry_at:空売りエントリー価格(float64)
  8. short_exit_at:空売り手仕舞い価格(float64)

上記のデータを持ったDataFrameをsimulateメソッドに渡してください。

オプションとして

BaseStrategyのオプションとして、初期資金(initial capital)と強制ストップ(force_stop)の設定を行なえます。

読んで字のごとくですが、バックテストを行う際の初期資金と強制ストップ(初期資金からの損失の許容ライン)をクラスのインスタンス化時に渡して使えます。

所感・ディスカッション

BaseStrategyクラスの改善ポイントはいくつかあります。

BaseStrategyの改善点
  1. リファクタ(ドキュメントやリーダビリティ向上)
  2. iterrows()の処理が遅いので、別処理に置き換える
  3. 他の汎用メソッドを実装
  4. バグの有無確認(基本的なテストは完了済み)
トマトソース

上記については、随時対応していこうと思います。

まとめ

今回は自身で作成した投資ストラテジーのバックテストに使えるクラスを紹介しました。

軽く調べてもあまり出てこなかったので、自分で作ってみました。

個々のロジックが間違うと正確にバックテストできないので、少し苦労しましたが、良い経験となりました。

もし、バックテストのコードの作成に苦労されている、探されている方のお役に立てれば幸いです。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次