見出し画像

第8章 ml4tワークフロー 第2節: ベクトル化バックテスト

はじめに

第8章ではml4tのワークフローについて学びます。(今後第一節にもっと詳しく書きたいと思います。)

フロー解説

・データを取得(Market: OHLCVやdepth等の市場データ, Fundamental: ファンダメンタルデータ, Alternative:オルタナティブ(その他)データ)
・時間を調整する。(データによって頻度が違うので、同じ時刻でどういう値をしているのかについて見ていく。)
・ファクター&特徴量エンジニアリング
・機械学習モデル(モデルの定義、パラメーターチューニング、交差検定)
・予測(リスクファクター、価格とリターン、共分散)
以下実務
・資産選定(ルールベース、モデルベース、ベットサイズ)
・ポートフォリオ最適化(アセットアロケーション、セクター比重、リスクリターンプロファイル)
・ターゲットポートフォリオ
・注文
・執行
・ライブ

画像1


ベクトル化バックテスト(Vectorized Backtesting)とは?

ベクトル化バックテストは最も基本的な戦略の評価方法です。シグナルベクトルを目標在庫量として、投資期間のリターンから損益を計算します。

インポートと設定

import warnings
warnings.filterwarnings('ignore')
from pathlib import Path
from time import time
import datetime

import numpy as np
import pandas as pd
import pandas_datareader.data as web

from scipy.stats import spearmanr

import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter
import seaborn as sns
sns.set_style('whitegrid')
np.random.seed(42)

データの読み込み

DATA_DIR = Path('..', 'data')
data = pd.read_hdf('00_data/backtest.h5', 'data')
data.info()
'''
<class 'pandas.core.frame.DataFrame'>
MultiIndex: 190451 entries, ('AAL', Timestamp('2014-12-09 00:00:00')) to ('YUM', Timestamp('2017-11-30 00:00:00'))
Data columns (total 6 columns):
#   Column     Non-Null Count   Dtype  
---  ------     --------------   -----  
0   predicted  74054 non-null   float64
1   open       190451 non-null  float64
2   high       190451 non-null  float64
3   low        190451 non-null  float64
4   close      190451 non-null  float64
5   volume     190451 non-null  float64
dtypes: float64(6)
memory usage: 10.4+ MB
'''

ここのデータセットは00_data/data_prep.pyを実行する必要があります。

S&P500 ベンチマーク

sp500 = web.DataReader('SP500', 'fred', '2014', '2018').pct_change()
sp500.info()
'''
<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 1044 entries, 2014-01-01 to 2018-01-01
Data columns (total 1 columns):
#   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
0   SP500   1042 non-null   float64
dtypes: float64(1)
memory usage: 16.3 KB
'''

フォワードリターンの計算

daily_returns = data.open.unstack('ticker').sort_index().pct_change()
daily_returns.info()
'''
<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 751 entries, 2014-12-09 to 2017-11-30
Columns: 257 entries, AAL to YUM
dtypes: float64(257)
memory usage: 1.5 MB
'''
fwd_returns = daily_returns.shift(-1)

シグナルの生成

predictions = data.predicted.unstack('ticker')
predictions.info()
'''
<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 751 entries, 2014-12-09 to 2017-04-14
Columns: 257 entries, AAL to YUM
dtypes: float64(257)
memory usage: 1.5 MB
'''
N_LONG = N_SHORT = 15
long_signals = ((predictions
               .where(predictions > 0)
               .rank(axis=1, ascending=False) > N_LONG)
               .astype(int))
short_signals = ((predictions
                 .where(predictions < 0)
                 .rank(axis=1) > N_SHORT)
                .astype(int))

ポートフォリオリターンの計算

long_returns = long_signals.mul(fwd_returns).mean(axis=1)
short_returns = short_signals.mul(-fwd_returns).mean(axis=1)
strategy = long_returns.add(short_returns).to_frame('Strategy')

結果のプロット

fig, axes = plt.subplots(ncols=2, figsize=(14,5))
strategy.join(sp500).add(1).cumprod().sub(1).plot(ax=axes[0], title='Cumulative Return')
sns.distplot(strategy.dropna(), ax=axes[1], hist=False, label='Strategy')
sns.distplot(sp500, ax=axes[1], hist=False, label='SP500')
axes[1].set_title('Daily Standard Deviation')
axes[0].yaxis.set_major_formatter(FuncFormatter(lambda y, _: '{:.0%}'.format(y))) 
axes[1].xaxis.set_major_formatter(FuncFormatter(lambda y, _: '{:.0%}'.format(y))) 
sns.despine()
fig.tight_layout();

画像2

res = strategy.join(sp500).dropna()

画像3






















この記事が気に入ったらサポートをしてみませんか?

コメントを投稿するには、 ログイン または 会員登録 をする必要があります。
金融市場定量分析用ブログです。 本人は蟲柱である胡蝶しのぶの弟子で、花の呼吸の使い手です。
第8章 ml4tワークフロー 第2節: ベクトル化バックテスト|カナヲ定量分析