Takehana Lab

System Trading : MultiCharts, TradingView, Python, R

tidyquantによるバックテスト(パラメーター最適化)

前回の記事の続きです。 takehana13.hateblo.jp

今回はバックテストデータをパラメータの値ごとに分析することを考えます。まずストラテジー全体を関数化します。

strategy_ema <- function(data, n){
  term1 <- data %>% group_by(symbol) %>%
    tq_mutate(select = adjusted,
              mutate_fun = EMA, n = n,
              col_rename = "ema")
  term2 <- term1 %>% tq_mutate(select = adjusted,
                               mutate_fun = ROC,
                               col_rename = "roc")
  term3 <- term2 %>% mutate(sig = lag(if_else(adjusted > ema, 1, -1)),
                            ret = roc * sig)
  term4 <- term3 %>% drop_na %>% mutate(eq = cumsum(ret)) %>% 
    select(symbol, date, eq)
  }

次に複数のパラメータをベクトル化してストラテジー関数に渡しpurrr::map()します。

param <- seq(10, 50, by = 10)
opt_ret <- param %>% map(~strategy_ema(FANG, .x))
opt_ret <- opt_ret %>% set_names(str_c("param", seq_len(5)))
opt_ret <- opt_ret %>% bind_rows(.id = "param")

最後に結果をプロットします。

opt_ret %>% filter(symbol == "FB") %>% 
  ggplot(aes(x = date, y = eq, colour = param)) +
  geom_line() +
  theme_tq() +
  geom_hline(yintercept = 0, colour = "darkgray") +
  scale_color_tq()

f:id:takehana13:20190928144708p:plain

この結果を見るとema(10)のリターンが極端に低いことが分かります。

また同様のコードで他の銘柄のパフォーマンスも確認できます。

f:id:takehana13:20190928145820p:plain

グーグルのパフォーマンスはFacebookものよりもパラメータの違いによる影響が顕著ではありません。

tidyquantでバックテスト

Rでデータ操作と言えばTidyverseですが、RでQuantsと言えばQuantmodでしたが、最近の人はtidyquantなのでしょうか?

時系列操作というジャンルではtsibbleも便利なので難しいところですね。

今回はtidyquantを使って単純なストラテジーのバックテスト例を書いてみます。

ライブラリを読み込んで組み込みデータを確認します。

require(tidyquant)
require(tidyverse)
data(FANG)

FANG %>% select(symbol, date, adjusted) %>% 
  ggplot(aes(x = date, y = adjusted, colour = symbol)) +
  geom_line() +
  theme_tq() +
  scale_color_tq() +
  facet_wrap(.~symbol, scale = "free")

f:id:takehana13:20190928145224p:plain

バックテストに使用するインジケータEMA(20)を計算します。

term1 <- FANG %>% group_by(symbol) %>%
  tq_mutate(select = adjusted,
            mutate_fun = EMA, n = 20,
            col_rename = "ema")

計算したEMAを可視化します。少し見にくいかもしれませんが、赤線がMAです。

term1 %>% ggplot(aes(date, adjusted)) +
  geom_line() +
  geom_line(aes(date, ema), color = "red") +
  facet_wrap(.~symbol, scale = "free") +
  theme_tq()

f:id:takehana13:20190928144010p:plain

リターン計算に使うROC(Rate Of Change)をデータに追加します。

term2 <- term1 %>% tq_mutate(select = adjusted,
                             mutate_fun = ROC,
                             col_rename = "roc")

シグナルとリターンを計算します。ここではclose > emaのときロングでなければショートとしています。

シグナルの発生から発注までの間に1期分ラグが発生するので注意が必要です。

EasyLanguage的に言えばbuy next bar at market;ということです。

term3 <- term2 %>% mutate(sig = lag(if_else(adjusted > ema, 1, -1)),
                          ret = roc * sig)

時系列収益率の推移を確認します。

term3 %>% select(symbol, date, ret) %>% drop_na %>% 
  ggplot(aes(x = date, y = ret, colour = symbol)) +
  geom_point(alpha = .3) +
  scale_color_tq() +
  theme_tq()

f:id:takehana13:20190928145108p:plain

累積リターンを可視化します。

term3 %>% drop_na %>% mutate(eq = cumsum(ret)) %>% 
  select(symbol, date, eq) %>% 
  ggplot(aes(x = date,y = eq, colour = symbol)) +
  geom_line()+
  theme_tq()+
  scale_color_tq()+
  geom_hline(colour = "darkgray", yintercept = 0)

f:id:takehana13:20190928145035p:plain

もっと複雑なストラテジーも簡単にテストできます。またコスト計算やポートフォリオリターンについての分析も必要です。

後日それらについても記事を書きます。