相場環境(トレンド・レンジ)別にバックテスト結果を分ける

同じ売買ルールでも、トレンド相場とレンジ相場では成績が逆になることがあります。バックテストの結果をエントリー時の相場環境ごとに分けると、その戦略がどの相場で稼ぎ、どの相場で負けているのかが分かります。この記事では、相場環境の判定方法と、分けるときの落とし穴をまとめます。

合計の成績だけでは分からないこと

ある戦略の損益が-2%だったとします。これは「どこでも少しずつ負ける戦略」かもしれませんし、「トレンドでは大きく勝ち、レンジでそれ以上に負ける戦略」かもしれません。2つは合計が同じでも、次に試すことがまったく違います。

後者なら、戦略そのものを捨てる必要はありません。レンジを避ける条件を加える、レンジ用の別ルールと組み合わせる、といった改善の余地があります。前者なら、ルールの考え方から見直すことになります。

例:ブレイクアウトを相場ごとに流した結果

Hawk Backtesterのデモで、直近40本の高値・安値を抜けたら入るブレイクアウトを、合成データの相場の種類だけ変えて流しました。データは乱数で作った合成データ(1時間足1,500本)で、実際の相場の成績ではありません。

相場損益勝率
トレンド+10.20%48%
レンジ-6.10%23%
急変動-4.73%27%
ミックス-2.29%29%

ブレイクアウトがトレンドに強く、レンジに弱いのは教科書どおりです。ただ、ミックス相場の-2.29%だけを見ていたら、この偏りには気づけません。自分の戦略がどの相場でどう負けているかは、実際に分けてみるまで分かりませんでした。

エントリー時の相場別の成績
デモの「相場別の成績」。エントリーした時点の相場で取引を分けて集計します(合成データ)。

相場環境の判定方法

実データには「この足はトレンド」という正解ラベルがありません。自分で判定のルールを決める必要があります。よく使われるのは次の3つです。

ADXでトレンドの強さを見る

ADX(平均方向性指数)は、方向を問わずトレンドの強さを表す指標です。ADXが25以上ならトレンド、20未満ならレンジ、というように閾値で分けます。上昇か下降かは、+DIと-DIのどちらが大きいかで判定します。閾値の25や20は慣習的な値で、銘柄や時間足によって合う値は変わります。

移動平均の傾きで方向を見る

たとえば50本移動平均の、直近10本での変化率を使います。一定以上の上向きなら上昇トレンド、下向きなら下降トレンド、その間ならレンジとします。判定が分かりやすく、自分で検算しやすい方法です。

ボラティリティの水準で分ける

ATRや一定期間のリターンの標準偏差を、過去の分布と比べます。たとえば過去1年の中で上位10%に入るボラティリティの時期を「急変動」とします。トレンドかレンジかとは別の軸なので、上の2つと組み合わせて使えます。

# 例:エントリー時点の相場を判定する(未来のデータを使わない)
ma = close.rolling(50).mean()
slope = ma.pct_change(10) * 100          # 50本MAの直近10本での変化率(%)
vol = close.pct_change().rolling(20).std()
vol_rank = vol.rolling(24 * 250).rank(pct=True)   # 過去の分布での位置

def regime_at(i):
    if vol_rank.iloc[i] > 0.9:
        return "shock"
    if slope.iloc[i] > 0.3:
        return "up"
    if slope.iloc[i] < -0.3:
        return "down"
    return "range"

# 各トレードに、エントリーした足の判定を付ける
trades["regime"] = [regime_at(t.entry_index) for t in trades.itertuples()]

閾値(0.3%や上位10%)は例です。自分の銘柄・時間足で、判定結果をチャートに重ねて見て、違和感がないかを確かめてから使ってください。

「エントリー時」で分ける理由

相場で分けるときは、トレードが始まった時点の判定を使います。保有中に相場が変わることはよくありますが、戦略が判断に使えるのはエントリーした時点の情報だけです。エントリー時の相場で分けておけば、「この相場のときは入らない」という条件にそのまま置き換えられます。

相場で分けるときの落とし穴

未来のデータで判定してしまう

一番多い失敗は、判定に未来のデータが混ざることです。たとえば「その後50本で価格が5%以上動いた区間をトレンドとする」という判定は、後から見ればきれいですが、エントリーした時点では分かりません。この判定で「トレンドのときだけ入る」と条件を付けると、実際には使えない情報で成績を良く見せてしまいます。中心化した移動平均や、期間全体で計算した平均・標準偏差も同じ問題を持ちます。

1つの相場あたりの取引数が少ない

全体で60回の取引も、4つの相場に分けると1つあたり15回前後になります。急変動の時期は短いので、数回しかないこともあります。数件の大きな勝ち負けで結果がひっくり返るので、件数の少ない相場の結果は参考程度に見てください。Hawk Backtesterのデモでは、取引が3件未満の相場はヒントの判定に使いません。

判定ルールに合わせて戦略を調整しすぎる

相場の判定ルールそのものもパラメータです。閾値を細かく変えて一番成績の良い組み合わせを選ぶと、その期間に合わせすぎた結果になります。考え方は過剰最適化を避ける方法と同じです。

分けたあとに何をするか

  • 負けている相場を避ける条件を加える:たとえばADXが20未満のときはブレイクアウトに入らない。加えたあと、別の期間でも効くかを確かめます。
  • 負け方を相場ごとに見る:レンジでの負けが「一度は含み益だった負け」なのか「最初から逆行した負け」なのかで、直す場所が変わります。見分け方はMFE・MAEの解説にあります。
  • 別の期間・銘柄で同じ傾向が出るか確かめる:1つの期間だけの偏りは、偶然のこともあります。
相場による成績の偏りを示す改善のヒント
デモでは、相場ごとの偏りを「改善のヒント」として自動で出します(合成データ)。

Hawk Backtesterのデモは合成データを使うため、相場の種類が正解として分かっています。判定のずれに悩まずに「相場で分けると何が見えるか」を確かめられるので、まず考え方をつかむのに向いています。自分のデータで試す場合は、上のような判定ルールを自分で決めることになります。

よくある質問

トレンドとレンジを判定する一番良い指標はどれですか?

どれか1つが常に優れているわけではありません。ADXは方向を問わない強さ、移動平均の傾きは方向、ボラティリティは値動きの大きさを見ています。何を知りたいかで選び、判定結果をチャートに重ねて目で確かめるのが確実です。

相場ごとに別のパラメータを使ってもよいですか?

使えますが、パラメータの数が増えるほど過去のデータに合わせやすくなります。相場ごとに分けたあとの取引数が十分にあるか、別の期間でも同じ結論になるかを確かめてください。

バックテストで相場別に勝っていれば、今後も勝てますか?

分かりません。バックテストは過去のデータでの振る舞いを調べるもので、将来の成績を保証するものではありません。相場別の分析は、戦略の性格を理解するための道具として使ってください。