聖杯を求めて~新高値順張り戦略~

為替と学校の課題に忙しく、現物株の研究を全くしていなかったので久し振りにそれ関連の記事を書いてみる

昨日林則行氏が書いた「伝説のファンドマネージャーが教える株の公式」(ダイヤモンド社)という本を読んだ。アブダビ投資庁(?)のファンドマネージャーを勤めていたという名声は聞いたことがあったのだが、著書を読んだのは初めてだ。
内容はいいとも悪いとも言い難いところで、共感できることも多かったが、悪く言えば敢えて愚直な内容にして手に取る初心者を騙すような節も感じられた。
この本で最も強調されていたのが、「一定の期間内で新高値を記録した銘柄のみに注目して投資する」という投資手法であった。この考え方は自分も以前からトレードでよく活用していたのでとても共感できた。しかし実際にはどれぐらいの効力を発揮するトレード手法なのか、気になったので過去のデータで実際に検証してみることにした。

つまり新高値を形成した銘柄に順張りする戦略が所謂聖杯の候補の一つになり得るかを調べるのがこの記事の目的である。

分析対象:2022年現在日経225に組み込まれている全銘柄の2000年1月から2022年6月17日までの日足データ(現時点でyfinanceから取得できる全期間のデータ)
トレードルール:過去250営業日間の終値に対して新高値を付けた場合現物でエントリーし、終値が75日移動平均線を下回った時点でクローズ。エントリー時に手数料やスリッページなど1%程度の不利となる摩擦がある場合と理想的にない場合の双方を検証する。

実行したコードとその結果が以下の通りになる。

コード

code_list = [4151,4502,4503,4506,4507,4519,4523,4568,4578,6479,6501,6503,6504,6506,6645,6674,6701,6702,6703,6724,6752,6753,6758,6762,6770,6841,6857,6861,6902,6952,6954,6971,6976,6981,7735,7751,7752,8035,7201,7202,7203,7205,7211,7261,7267,7269,7270,7272,4543,4902,7731,7733,7762,9432,9433,9434,9613,9984,7186,8304,8306,8308,8309,8316,8331,8354,8355,8411,8253,8591,8697,8601,8604,8628,8630,8725,8750,8766,8795,1332,1333,2002,2269,2282,2501,2502,2503,2531,2801,2802,2871,2914,3086,3099,3382,8233,8252,8267,9983,2413,2432,3659,4324,4689,4704,4751,4755,6098,6178,7974,9602,9735,9766,1605,3101,3103,3401,3402,3861,3863,3405,3407,4004,4005,4021,4042,4043,4061,4063,4183,4188,4208,4452,4631,4901,4911,6988,5019,5020,5101,5108,5201,5202,5214,5232,5233,5301,5332,5333,5401,5406,5411,5541,3436,5703,5706,5707,5711,5713,5714,5801,5802,5803,2768,8001,8002,8015,8031,8053,8058,1721,1801,1802,1803,1808,1812,1925,1928,1963,5631,6103,6113,6301,6302,6305,6326,6361,6367,6471,6472,6473,7004,7011,7013,7003,7012,7832,7911,7912,7951,3289,8801,8802,8804,8830,9001,9005,9007,9008,9009,9020,9021,9022,9064,9147,9101,9104,9107,9202,9301,9501,9502,9503,9531,9532] #ここは手動で15分ぐらいがんばった、、

import numpy as np
import pandas as pd
import yfinance as yf
import matplotlib.pyplot as plt

profit_rate_list = list()

for code in code_list:
  tick = yf.Ticker(str(code) + '.T') #yfinanceのフォーマット
  history = tick.history(interval='1d', period='max')

  data = history['Close']
  mv = data.rolling(75).sum()/75
  data = pd.concat([data, mv], axis=1)
  data.columns = ['close', 'moving_average']
  if len(data) < 600:
    pass

  else:
    asset = 1000000 #元本
    position_flag = 0 #ポジションを持ってる判定に使う
    entry_price = 0 #約定価格

    for i in range(250, len(data)):
      if position_flag == 0:
        close_list = list(data['close'][i-250:i])
        if data.iat[i, 0] >= max(close_list):
          position_flag = 1
          entry_price = data.iat[i, 0]
          asset *= 0.99 #平均1%の摩擦があると仮定する。

      else:
        if data.iat[i, 0] <= data.iat[i, 1]:
          asset *= data.iat[i, 0]/entry_price
          position_flag = 0

        else:
          pass

    if asset < 0:
      pass

    else:
      profit_rate_list.append(asset/10000)
      print('---------------------------------')
      print('Code: ' + str(code))
      print('Profit rate(%): ' + str(round(asset/10000, 2)) + '%')

結果のグラフ。横軸が収益率(%)、縦軸がその収益率を取る銘柄数を表す。一つ目が摩擦がある場合、二つ目が摩擦がない場合の結果である。
>>

摩擦がある場合。平均値は137.4%、中央値は103.7%となった。
<
摩擦がない場合。平均値は167.4%、中央値は124.3%となった。
<<

摩擦が1%という厳しめの仮定をした場合でも、半数以上が元本割れを起こしていないので、よくある聖杯の中ではかなりマシな挙動をしている方であると言える。
ただし問題点としてはこの戦略がただホールドしていた場合に比べそれほど良い実績にはなっていないことで、例えばグラフの中に示される飛びぬけてパフォーマンスの高い銘柄はサイバーエージェントの1050%やソフトバンクの868%であるが、これらの会社は(ソフトバンクは一時的にバブルになっていたものの)2000年からの価格上昇はそれぞれ約12倍と10倍であり、戦略としては微妙なのではないか?と思う。
さらに言えば、N225自体も、2000年末の14000円台から見れば2022年6月現在の26000円台まで190%強、2000年初頭の19000円から見ても140%強伸びているため、やはり市場平均を大きく上回ることは出来ていないという結論になってしまう、、
テクニカルオンリーで雑に分析するとこのような結果となってしまうが、クローズする条件や高値として採用する期間の長さを変えたり、また財務情報の方にも一定の制約を付けることで市場平均に大きく勝てるのではないか?という検証をいずれやる気があるときにやりたいと思う。