CTA + センチメント複合戦略

概要

CTA(SMAクロスオーバー)トレンドフォロー戦略に、ゴールドレポートの全文センチメント分類を確認フィルタとして併用する複合戦略。さらにNSNバックナンバー記事のタイプ別センチメントスコアを日次確信度補強として統合し、ゴールドレポート(週次方向性)とバックナンバー(日次確信度)の複合シグナルを構築する。週次アウトオブサンプル評価(2022年2月〜2026年3月)により、各センチメントフィルタがCTAシグナルのヒット率とリターンを改善するかを検証した。なお、キーワードリストはドメイン知識に基づく固定リストであり、ローリングウィンドウによる再訓練は行っていない(事後的な再最適化なし)。テキストセンチメントの投資応用は先行研究でも有効性が示されている [1][2]。

戦略コンセプト

CTA(Commodity Trading Advisor)戦略はSMA短期/長期のクロスオーバーでトレンド方向を判定する [3][4]。しかしCTA単体ではレンジ相場でのダマシシグナルが発生しやすく、バックテストでもCTA=LONG かつ Sentiment=BEARISH の週はヒット率54.5%にとどまる。ゴールドレポートの週次センチメント(Bullish/Bearish/Neutral)をフィルタとして併用することで、トレンドとファンダメンタルの方向が一致する高確信度シグナルのみを抽出する。

データソース

データ

ソース

期間

用途

日足OHLCV

day_bars Parquet(GOLD)

2022〜2026

SMA計算・クロスオーバー判定

ゴールドレポートPDF

rpGLD*.md(全文)

2022/02〜2026/03(約210号)

センチメント分類(週次方向性)

NSNバックナンバー記事

afk*.md(約17,800本)

2021〜2026

タイプ別センチメント(日次確信度補強)

週次リターン

day_bars(週足)

2022〜2026

戦略パフォーマンス評価

シグナル生成ロジック

CTAシグナル(SMAクロスオーバー)

  • LONG: SMA(短期) > SMA(長期)

  • SHORT: SMA(短期) < SMA(長期)

  • NEUTRAL: SMA(短期) = SMA(長期)

毎週金曜日(またはその週最終営業日)の終値ベースで判定。

センチメントシグナル

ゴールドレポート全文(outlook_body + bullish_factors + bearish_factors)をキーワードベースで分類。19個のBullishキーワードと15個のBearishキーワードのスコア差に基づき、Bullish/Bearish/Neutralを判定する。

分類の詳細は NSNテキストセンチメント分析 のゴールドレポート全文センチメント分析を参照。

NSNバックナンバーセンチメント(日次確信度補強)

NSNバックナンバー記事(約17,800本)のセンチメントをキーワードベースで分類(Bullish/Neutral/Bearish)し、ISO週単位で全記事の平均スコア(-1.0〜+1.0)を算出する(週あたり最低3記事)。

バックナンバー記事のセンチメントは nsn_sentiment.pyparse_backnumber_articles() および aggregate_weekly_sentiment() を用いて週次スコアに集約し、ゴールドレポートの方向性判断を日次データで補強する確信度フィルタとして機能する。

時間軸の整合

月  火  水  木  金  土  日  │  月  火  水  木  金
────────────────────────────┼──────────────────
 レポート週(ISO week)      │  トレード週
                        ↑   │  ← 翌週リターンで評価
                     CTA判定 │
                        ↑   │
                   レポート発行│
  • ゴールドレポートは土曜日発行 → そのISO週の月曜日をキーとする

  • CTAシグナルは同週金曜日の終値で判定(前営業日へ遡及)

  • find_next_week_return() により翌週(トレード週)のリターンで評価

戦略バリアント

9つの戦略バリアントを比較評価する:

バリアント

エントリー条件

意図

CTA only

SMA(短期) > SMA(長期)

ベースライン(トレンドフォロー単体)

Sentiment only

レポート = Bullish

ベースライン(センチメント単体)

Combined

CTA=LONG AND Sentiment=BULLISH

複合フィルタ

High-confidence (≥2)

CTA=LONG AND Sentiment=BULLISH AND score_diff ≥ 2

高確信フィルタ

High-confidence (≥3)

CTA=LONG AND Sentiment=BULLISH AND score_diff ≥ 3

最高確信フィルタ

CTA filtered by Bearish

CTA=LONG AND Sentiment=BEARISH

フィルタが除外した週のパフォーマンス

Enhanced Combined

Combined AND nsn_score > 0

NSNバックナンバー日次確信度で補強

Enhanced High-confidence (≥2)

High-confidence (≥2) AND nsn_score > 0

NSN補強 + スコア確信度

Enhanced High-confidence (≥3)

High-confidence (≥3) AND nsn_score > 0

NSN補強 + 最高確信度

スコア確信度(score_diff)

センチメント分類で算出されるスコア差(bullish_score - bearish_score)を確信度として活用する。スコア差が大きいほど、センチメント判定の確信度が高い。

以下はセンチメント分類全体(全レポート約210号、CTA条件なし)におけるスコア差別の的中率であり、バックテスト期間(85週)とは異なるデータセットである:

スコア差閾値

シグナル数

的中率

≥ 1

108

68.5%

≥ 2

80

72.5%

≥ 3

55

76.4%

≥ 4

29

82.8%

注意: 閾値を上げるとシグナル数が大幅に減少し(≥4で29回)、ヒット率の統計的信頼性が低下する点に留意が必要。

WeeklySignalsentiment_score フィールドにスコア差を格納し、閾値によるフィルタリングを可能にする。

バックテスト結果

デフォルトパラメータ(SMA 20/60)

85週のアウトオブサンプル評価期間での結果:

戦略

N

Hit%

Avg%

Total%

Sharpe

MaxDD%

PF

CTA only

67

68.7%

+1.034%

+69.28%

2.46

-8.98%

2.53

Sentiment only

64

68.8%

+1.162%

+74.39%

2.72

-8.98%

2.85

Combined

48

70.8%

+1.147%

+55.07%

2.50

-8.98%

2.63

High-confidence (≥2)

40

75.0%

+1.477%

+59.08%

3.10

-8.17%

3.35

High-confidence (≥3)

30

76.7%

+1.563%

+46.90%

3.72

-5.49%

4.15

CTA+Bearish(除外分)

11

54.5%

+0.803%

+8.83%

2.20

-4.57%

2.05

Enhanced Combined

40

75.0%

+1.475%

+59.00%

3.17

-8.98%

3.41

Enhanced (≥2)

34

79.4%

+1.794%

+60.99%

3.74

-8.17%

4.35

Enhanced (≥3)

25

80.0%

+1.912%

+47.80%

4.71

-3.37%

6.31

  • Sharpe Ratio: 年率換算(mean / std × √52)。Enhanced (≥3) 4.71 が全戦略中最高

  • MaxDD: 累積リターンのピークからの最大下落。Enhanced (≥3) -3.37%はCombined -8.98%から約62%縮小

  • PF (Profit Factor): 総利益 / 総損失。Enhanced (≥3) 6.31 が全戦略中最高

数値の解釈に関する注意: Enhanced (≥3) の Sharpe 4.71 / PF 6.31 は N=25 の小サンプルから算出されており、ブートストラップ95%信頼区間は Sharpe [2.1, 7.3] と広い。また、検証期間が金の歴史的上昇相場と一致しているため、これらの高い数値にはブルマーケット効果が含まれる。「常にLONG」ベースラインでも Hit率67.1%・平均+1.047% のリターンが得られることを踏まえ、戦略固有のエッジとして解釈すべきは超過パフォーマンス部分のみである。

主要な発見:

  • Combined戦略はCTA単体よりヒット率+2.1ptPF+0.10改善

  • センチメントフィルタが除外した11週はヒット率54.5%・PF 2.05と低く、フィルタの有効性を裏付ける

  • Sharpe/PFともにSentiment onlyが最高性能だが、CombinedはCTA単体(67回)からダマシを19回除外しており、シグナルの質的改善を示す

  • NSN補強で全指標改善: Combined → Enhanced Combined でHit率+4.2pt、Sharpe+0.67、PF+0.78

  • Enhanced (≥3) が最高性能: Hit率80.0%、Sharpe 4.71、PF 6.31。3つの信号源(CTA + ゴールドレポート + バックナンバー)が同方向を示すシグナルのみを抽出

  • 高確信度帯ほどNSN補強効果が大: Enhanced (≥3) はCombined比でHit率+9.2pt、PF+3.68の改善

MA期間パラメータ感度分析

6つのSMA短期/長期の組合せでバックテストを実施:

SMA

CTA Hit

CTA Sharpe

CTA PF

Comb N

Comb Hit

Comb Sharpe

Comb PF

Comb MaxDD%

5/20

67.2%

2.33

2.52

46

69.6%

2.42

2.66

-10.53%

10/30

66.7%

2.16

2.36

46

69.6%

2.19

2.46

-8.98%

10/50

67.2%

2.71

2.81

48

68.8%

2.56

2.74

-8.98%

20/60

68.7%

2.46

2.53

48

70.8%

2.50

2.63

-8.98%

30/90

69.4%

2.72

2.75

55

70.9%

2.83

2.94

-8.98%

20/100

68.9%

2.68

2.74

56

71.4%

2.83

2.96

-8.98%

感度分析の結論:

  1. 全パラメータでCombined > CTA only: ヒット率・Sharpe・PFすべてで改善。フィルタ効果はパラメータに依存しない頑健な結果

  2. 長期MAほど高性能: SMA30/90とSMA20/100がSharpe 2.83・PF 2.94-2.96で最高

  3. 短期MAの課題: SMA5/20はMaxDD -10.53%と他より大きく、ノイズ感度が高い

  4. 推奨パラメータ: SMA20/60(バランス型)またはSMA20/100(Sharpe/PF重視)

センチメント単体の一貫性

センチメントシグナルはMA期間に依存しない(ゴールドレポートベース)ため、全パラメータ組合せで同一:

  • シグナル数: 64

  • ヒット率: 68.8%

  • 平均リターン: +1.162%

  • 累積リターン: +74.39%

実装

モジュール構成

src/market_analysis/gold_report_outlook.py
├── SentimentClassification       # センチメント分類結果(label + score_diff)
└── classify_gold_outlook_fulltext()  # 全文センチメント分類(スコア差付き)

src/market_analysis/nsn_sentiment.py
├── classify_sentiment()          # バックナンバー記事センチメント分類
└── aggregate_weekly_sentiment()  # 週次センチメントスコア集約

src/market_analysis/backtest_cta_sentiment.py
├── WeeklySignal                  # 週次シグナル(sentiment_score + nsn_sentiment_score)
├── generate_weekly_signals()     # 週次CTA+センチメントシグナル生成(NSN対応)
├── run_cta_sentiment_backtest()  # 9バリアント比較バックテスト(NSN補強含む)
└── run_ma_sensitivity()          # MAパラメータ感度分析

src/market_analysis/backtest_cta_position.py
├── PositionTrade                 # ポジションベーストレード(entry/exit日・価格・保有週数)
├── PositionBacktestResult        # バックテスト結果(trades + metrics + サマリ)
├── PositionMode                  # イグジットモード(STRICT / LENIENT)
├── get_monday_open_prices()      # 月曜始値取得(祝日時は翌営業日)
└── run_position_backtest()       # ポジションベースバックテスト(Strict/Lenient × 全バリアント)

使用例

from pathlib import Path
from market_analysis.loader import create_connection
from market_analysis.backtest_cta_sentiment import (
    run_cta_sentiment_backtest,
    run_ma_sensitivity,
)

con = create_connection()
pdfs_dir = Path("nsn_data/reports/gold_report/pdfs")
articles_dir = Path("nsn_data/news/overseas_financial_news_backnumber/articles")

# デフォルトパラメータでバックテスト(NSNバックナンバー補強付き)
result = run_cta_sentiment_backtest(con, pdfs_dir, articles_dir=articles_dir)
print(f"Combined hit rate: {result.combined.hit_rate}%")

# NSN補強バリアントの結果
for entry in result.enhanced:
    print(f"Enhanced (score_diff ≥ {entry.min_score_diff}): "
          f"N={entry.metrics.n_signals}, "
          f"Hit={entry.metrics.hit_rate}%")

# 高確信フィルタ(score_diff ≥ 2)の結果
for entry in result.high_confidence:
    print(f"score_diff ≥ {entry.min_score_diff}: "
          f"N={entry.metrics.n_signals}, "
          f"Hit={entry.metrics.hit_rate}%")

# パラメータ感度分析
sensitivity = run_ma_sensitivity(con, pdfs_dir, articles_dir=articles_dir)
for entry in sensitivity.entries:
    bt = entry.backtest
    print(f"SMA {entry.short_window}/{entry.long_window}: "
          f"Combined {bt.combined.hit_rate}%")

統計的検定

信頼区間

各戦略バリアントのHit率およびSharpe Ratioに95%信頼区間を付与し、点推定値の不確実性を定量化する。

Hit率の信頼区間(Clopper-Pearson法)

二項分布の正確信頼区間(Clopper-Pearson法)を用いる。Wald近似と異なり、小標本(N<30)でも保守的で信頼性の高い区間を返す。

戦略

N

Hit%

95% CI

CTA only

67

68.7%

[56.2%, 79.6%]

Sentiment only

64

68.8%

[55.9%, 79.8%]

Combined

48

70.8%

[55.9%, 83.0%]

High-confidence (≥3)

30

76.7%

[57.7%, 90.1%]

Enhanced (≥3)

25

80.0%

[59.3%, 93.2%]

解釈: Enhanced (≥3) のHit率80.0%は、95%信頼区間が[59.3%, 93.2%]と広い。N=25ではランダム(50%)を上回ることは示せるが、精度の高い点推定には不十分。

Sharpe Ratioの信頼区間(ブートストラップ法)

1,000回のリサンプリングによるブートストラップ・パーセンタイル法で95%信頼区間を算出する。Sharpe Ratioは正規分布を仮定できないため、ノンパラメトリックな手法が適切である。

戦略

Sharpe

95% CI

CTA only

2.46

[1.5, 3.4]

Combined

2.50

[1.4, 3.6]

Enhanced (≥3)

4.71

[2.1, 7.3]

注意: ブートストラップCIはシード固定(seed=42)で再現性を確保。

戦略間の有意差検定

Combined vs CTA only のHit率差について、二項比率のz検定を実施する。複数戦略ペアの同時比較にはHolm法による多重比較補正を適用し、補正後p値を報告する。

比較

Hit率差

Raw p値

Holm補正後 p値

有意 (α=0.05)

Combined vs CTA only

+2.1pt

Enhanced (≥3) vs CTA only

+11.3pt

Enhanced (≥3) vs Combined

+9.2pt

注意: p値はバックテスト実行時に動的に算出される。上表の「—」はプレースホルダ。

実装

StrategyMetrics に以下のフィールドを追加:

  • hit_rate_ci_lower / hit_rate_ci_upper: Hit率の95%信頼区間(Clopper-Pearson法)

  • sharpe_ci_lower / sharpe_ci_upper: Sharpe Ratioの95%ブートストラップ信頼区間

CTASentimentResult に以下を追加:

  • statistical_tests: 戦略間の有意差検定結果(Holm補正後p値を含む)

from market_analysis.backtest_cta_sentiment import run_cta_sentiment_backtest

result = run_cta_sentiment_backtest(con, pdfs_dir, articles_dir=articles_dir)

# Hit率の信頼区間
print(f"Combined Hit率: {result.combined.hit_rate}% "
      f"[{result.combined.hit_rate_ci_lower}%, {result.combined.hit_rate_ci_upper}%]")

# Sharpe Ratioの信頼区間
print(f"Combined Sharpe: {result.combined.sharpe_ratio} "
      f"[{result.combined.sharpe_ci_lower}, {result.combined.sharpe_ci_upper}]")

# 戦略間検定
for test in result.statistical_tests:
    print(f"{test.strategy_a} vs {test.strategy_b}: "
          f"p={test.corrected_p_value:.4f} ({'*' if test.significant else 'n.s.'})")

ベースライン比較とブルマーケットバイアス定量化

背景

バックテスト期間中の金は歴史的な上昇相場であり、常にLONG(ベースライン)でもHit率67.1%、平均+1.047%のリターンを示す。LONGバイアスの戦略は市場環境の恩恵を大きく受けており、戦略固有のエッジとブルマーケット効果の分離が必要である。

常にLONGベースライン

全対象週で無条件にLONGした場合のパフォーマンス(always_long)を基準として、各戦略の超過パフォーマンスを評価する。

指標

Always LONG

CTA only

Combined

Enhanced (≥3)

N

85

67

48

25

Hit%

Sharpe

PF

注意: 上表の「—」はバックテスト実行時に動的に算出される。

ランダムフィルタベースライン

各戦略のシグナル数Nと同数の週をランダムに選択し、1,000回のモンテカルロシミュレーションでHit率・Sharpe・PFの分布を構築する。戦略の実績値がランダム選択の分布のどこに位置するかをp値で評価する。

from market_analysis.backtest_cta_sentiment import run_cta_sentiment_backtest

result = run_cta_sentiment_backtest(con, pdfs_dir, articles_dir=articles_dir)

# ベースライン比較の取得
for comp in result.baseline_comparisons:
    print(f"{comp.strategy_name}: "
          f"超過Hit率={comp.excess_hit_rate:+.1f}pt, "
          f"p={comp.random_baseline.p_value_hit_rate:.4f}")

相対パフォーマンス指標

各戦略のAlways LONGベースラインに対する超過パフォーマンスを算出する:

  • 超過Hit率 = 戦略Hit率 - ベースラインHit率(パーセンテージポイント)

  • 超過Sharpe = 戦略Sharpe - ベースラインSharpe

期間別パフォーマンス分解

年別のパフォーマンスを分解し、上昇期と相対的弱期を分離して評価する。2024年前半(プラス率56%、相対的に弱い期間)での性能を個別報告する。

Note: 四半期別分解はデータ期間が約85週(約1.6年)と限られており、四半期あたり約13週のサンプルでは統計的に不安定なため、現時点では省略している。データ蓄積に伴い将来的に追加を検討する。

# 期間別分解の取得
for breakdown in result.period_breakdowns:
    print(f"{breakdown.period_label}: "
          f"N={breakdown.metrics.n_signals}, "
          f"Hit={breakdown.metrics.hit_rate}%")

ベースライン比較の実装

CTASentimentResult に以下を追加:

  • always_long: 全週LONGのベースラインメトリクス

  • baseline_comparisons: 各戦略のベースライン比較結果(超過Hit率・Sharpe + ランダムベースラインp値)

  • period_breakdowns: Always LONGの期間別パフォーマンス分解

@dataclass(frozen=True)
class RandomBaselineResult:
    n_simulations: int
    mean_hit_rate: float
    mean_sharpe: float
    mean_profit_factor: float
    p_value_hit_rate: float
    p_value_sharpe: float
    p_value_profit_factor: float

@dataclass(frozen=True)
class BaselineComparison:
    strategy_name: str
    strategy_metrics: StrategyMetrics
    baseline_metrics: StrategyMetrics
    excess_hit_rate: float
    excess_sharpe: float
    random_baseline: RandomBaselineResult

@dataclass(frozen=True)
class PeriodBreakdown:
    period_label: str
    metrics: StrategyMetrics

ポジションベースバックテスト

概要

週次独立モデルでは各週を個別のトレードとして評価するが、実際の運用ではシグナルが継続する限りポジションを保持し続けるのが合理的である。ポジションベースモデルでは、シグナル確定(土曜レポート)後の翌月曜寄りでエントリー/イグジットを行い、連続シグナル期間を1トレードとして評価する。

週次独立モデルとの主な違い

項目

週次独立モデル

ポジションベースモデル

価格基準

週足close-to-close

月曜始値(open)

トレード単位

毎週個別評価

連続シグナル期間を1トレード

取引回数

シグナル発生週数と同数

シグナル反転時のみ

Sharpe年率化

√52(週次)

√(52 / 平均保有週数)(トレード単位)

月曜始値の取得ルール

日足OHLCVから月曜日の始値を取得する。月曜のデータが存在しない場合は火曜→水曜→…と翌営業日を探索する。北辰物産は祝日取引実施日が設定されているため、多くの祝日ではデータが存在する。祝日カレンダーや祝日判定ロジックは実装しない。

エントリー/イグジット条件

エントリー条件(全モード共通)

ノーポジション時に条件成立 → 翌月曜寄りでエントリー

バリアント

エントリー条件

CTA only

CTA=LONG

Combined

CTA=LONG AND Sentiment=BULLISH

High-confidence (≥N)

Combined AND score_diff ≥ N

Enhanced

Combined AND nsn_score > 0

Enhanced (≥N)

Enhanced AND score_diff ≥ N

イグジット条件: Strict vs Lenient

NEUTRAL/score_diff低下時のイグジット判断を2モードで比較する。Strictモードは条件が弱まった時点で即座に決済し、Lenientモードは明確な反転シグナルが出るまでホールドを継続する。

状況

Strict(即決済)

Lenient(ホールド継続)

CTA=SHORT

決済

決済

CTA=NEUTRAL

決済

決済

Sentiment=BEARISH

決済

決済

Sentiment=NEUTRAL

決済

ホールド

score_diff < エントリー閾値

決済

ホールド

score_diffのイグジット閾値はエントリーと同じ値を使用する(例: High-confidence ≥2 のエントリーが score_diff >= 2 なら、イグジットも score_diff < 2 で発火)。

エッジケースの処理

  • シグナル欠損週: ポジション保持中にセンチメントデータがない週はホールドを継続する(シグナル変化なしとみなす)

  • 実行価格なし: イグジット/エントリーシグナル発火だが翌月曜始値が存在しない場合、次の利用可能月曜始値まで執行を遅延する

  • 末尾オープンポジション: バックテスト期間末にポジションが残っている場合、データセット内の最終利用可能月曜始値で仮想クローズする

バックテスト結果

Strict vs Lenient 比較

SMA(20/60)、GOLD、NSN バックナンバー記事込みでの結果:

バリアント

モード

N trades

Hit%

Avg%

Total%

Sharpe

MaxDD%

PF

Avg Weeks

Max Weeks

CTA only

7

71.4

+12.05

+84.34

1.17

-0.73

65.24

9.6

27

Combined

Strict

13

46.2

+5.05

+65.64

1.26

-1.98

9.62

3.7

25

Combined

Lenient

11

54.5

+6.64

+73.01

1.10

-3.67

10.95

4.9

27

High-conf ≥2

Strict

15

66.7

+3.38

+50.73

2.65

-3.90

7.56

2.7

6

High-conf ≥2

Lenient

10

60.0

+7.59

+75.91

1.22

-1.98

19.03

4.8

27

High-conf ≥3

Strict

15

60.0

+1.27

+18.99

1.35

-8.38

2.08

2.0

5

High-conf ≥3

Lenient

9

66.7

+7.38

+66.39

1.39

-2.47

14.28

4.6

25

Enhanced

Strict

11

63.6

+6.16

+67.81

1.39

-1.98

13.24

3.9

25

Enhanced

Lenient

10

70.0

+7.46

+74.64

1.17

-3.09

13.86

5.0

27

Enhanced ≥2

Strict

12

75.0

+4.16

+49.95

2.91

-1.98

11.59

3.0

6

Enhanced ≥2

Lenient

8

75.0

+9.68

+77.40

1.31

-1.98

29.54

5.5

27

Enhanced ≥3

Strict

12

66.7

+1.62

+19.47

1.49

-8.38

2.24

2.2

5

Enhanced ≥3

Lenient

6

83.3

+10.76

+64.54

1.45

-1.98

33.57

6.2

25

CTA onlyはセンチメント条件を含まないため、Strict/Lenientで同一結果となる(モード欄「—」)。

Warning

ポジションベースモデルのトレード数(N=6〜15)は週次独立モデル(N=85)より大幅に少なく、Hit%・PF・Sharpe等の指標は統計的に不安定である。特にCTA only(N=7, PF=65.24)やEnhanced ≥3 Lenient(N=6, Hit%=83.3%)のように極端な値はサンプル数の制約による可能性が高い。

Note

Combined Hit%の低下について: CombinedのHit率46.2%(Strict)は週次独立モデルの70.8%から大幅に低下しているが、これはモデルの性質の違いに起因する。週次独立モデルは毎週独立にリターンを評価するのに対し、ポジションベースモデルでは複数週にまたがるトレード全体のリターンを1件として評価する。ポジション保有中の途中反落がトレード全体を負にすることがあり、Hit率が低下しても平均リターン(+5.05%)やTotal Return(+65.64%)は正を維持している。

Note

ポジションベースモデルのSharpe比は √(52 / 平均保有週数) で年率化しており、週次独立モデルの √52 とは計算方法が異なる。直接比較する際は年率化方法の違いに注意すること。

実資金シミュレーション

ポジションベースバックテストの各トレードに、証拠金制約付きVolatility Targetingベースのポジションサイジングを適用し、実際の円建て損益をシミュレーションする。

シミュレーション条件

  • 対象商品: 金ミニ(GOLD_MINI: tick_size=0.5, tick_value=50, 手数料=387円/往復)

  • ポジションサイジング: Volatility Targeting(sigma_target=0.15、実現Vol 20日)

  • 証拠金: JSCC AS-VaRパラメータ(BPL÷10)の週次時系列(2023年7月〜現在)

  • ポジションサイズ: min(Vol Target理論枚数, 証拠金上限枚数) を切り捨て

  • 資本更新: 各トレードのnet P&Lを逐次反映(複利効果)

Volatility Targetingはポートフォリオの年率ボラティリティが sigma_target に一致するよう、原資産の実現ボラティリティに応じてレバレッジを動的調整する手法である。シグナルベースの手仕舞いを採用する本戦略との親和性が高く、リスク管理 の実証比較において暫定推奨手法とされている。

使用方法

from pathlib import Path

from market_analysis.alternative_sizing import VolTargetSizer
from market_analysis.backtest_cta_position import run_position_backtest
from market_analysis.backtest_pnl_simulation import simulate_pnl_with_strategy
from market_analysis.margin_data import load_margin_parquet

# 1. ポジションベースバックテストを実行
pdfs_dir = Path("nsn_data/reports/gold_report/pdfs")
results = run_position_backtest(con, pdfs_dir)

# 2. 証拠金時系列を読み込み
margin_series = load_margin_parquet(Path("data/margin_gold.parquet"))

# 3. vol_map, price_map を日足データから構築
#    構築方法の詳細は backtest_sizing_comparison.run_sizing_comparison() を参照
#    vol_map: date -> 対数リターン20日RV年率化 (× √245)
#    price_map: date -> 日足終値
trades = results["combined_strict"].trades
sizer = VolTargetSizer(
    sigma_target=0.15,
    vol_map=vol_map,
    price_map=price_map,
    tick_size=0.5,
    tick_value=50.0,
)

# 4. P&Lシミュレーション実行
result = simulate_pnl_with_strategy(
    trades=trades,
    initial_capital=5_000_000,
    margin_series=margin_series,
    tick_size=0.5,
    tick_value=50.0,
    commission_rt=387.0,
    sizing_strategy=sizer,
)

価格データに関する注記

PositionTrade の価格は金標準(GOLD)の日足始値に基づく。金標準と金ミニは同じ円/g単位で価格相関0.9999だが(リスク管理 相関行列参照)、わずかな始値乖離が存在する。P&L計算式 (exit - entry) / 0.5 × 50 は金標準の価格差を金ミニの取引単位(標準の1/10)で正しく変換する。

資本効率

旧来の固定リスク率法(risk_rate=2%, stop=2×ATR(14))では理論最大レバレッジが0.34xに制約されていた。この課題を受けて設計された改良版ATR Baseline(alternative_sizingモジュール)との比較でも、Volatility Targeting(sigma=0.15, RV20)はさらに高い資本効率を達成している。

資本

ATR Baseline AvgLev

Vol Target (sigma=0.15, RV20) AvgLev

改善

500万円

0.73x

0.97x

+33%

800万円

0.77x

1.07x

+39%

1,000万円

0.81x

1.06x

+31%

Vol Targetingでは500万円の小口資本でもAvgLev 0.97xを達成し、現物投資と同等以上のエクスポージャーが得られる。資本別の推奨 sigma_target や詳細な感度分析は リスク管理 の「小口資本での運用」を参照。

他のポジションサイジング手法との比較

Volatility Targeting(推奨)に加え、ATR Baseline(旧手法)、Fixed Fractional(改良版)、戦略リスクベースの3手法を実装し比較評価を行っている。詳細な理論的背景と実証比較結果は リスク管理 の「代替ポジションサイジング手法」および「代替手法の実証比較」を参照。

全手法の一括比較

from market_analysis.backtest_sizing_comparison import run_sizing_comparison

rows = run_sizing_comparison(
    trades=trades,
    margin_series=margin_series,
    atr_map=atr_map,
    vol_maps={"rv20": vol_map},
    price_map=price_map,
    max_loss_map=max_loss_map,
    tick_size=0.5,
    tick_value=50.0,
    commission_rt=387.0,
    capital_levels=[5_000_000, 8_000_000, 10_000_000],
)

simulate_pnl_with_strategy()SizingStrategy プロトコルにより枚数決定ロジックを差し替え可能にしている。トレード反復・複利・ドローダウン追跡のロジックは共通。

制約事項

  • 証拠金データは2023年7月以降のみ利用可能(JSCC公開データの制約)

  • 証拠金の臨時変更(相場急変時)は反映されない(週次データのみ使用)

  • スリッページ・スプレッドコストは未考慮

リスクと注意事項

  1. ブルマーケットバイアス: 検証期間(2022年2月〜2026年3月)は金の歴史的な上昇相場と一致する。「常にLONG」ベースラインでもHit率67.1%・平均+1.047%のリターンが得られるため、LONGバイアスの戦略は市場環境の恩恵を大きく受けている。下落相場・レンジ相場での性能は未検証であり、戦略固有のエッジはベースライン超過分のみで評価すべきである

  2. サンプルサイズの限界: 85週(約1.6年)のデータであり、統計的有意性には限界がある。特にEnhanced (≥3) はN=25であり、Hit率80.0%の95%信頼区間は[59.3%, 93.2%]と広い。ランダム(50%)を上回ることは示せるが、精度の高い点推定には不十分である

  3. 多重比較による選択バイアス: 9バリアント × 6MAパラメータの計54条件を検証しており、最良の結果を報告することで過度に楽観的な評価となるリスクがある。Holm法による多重比較補正を適用しているが、バリアント設計自体の探索的性質は考慮されていない

  4. Sharpe/PFの過大評価リスク: Enhanced (≥3) の Sharpe 4.71 / PF 6.31 は小サンプル(N=25)由来のノイズとブルマーケット効果を含む。ブートストラップ95%信頼区間は Sharpe [2.1, 7.3] であり、真の値が2程度である可能性も排除できない

  5. 取引コスト未考慮: ヒット率・リターンは取引コスト控除前の数値

  6. 金ミニの流動性: GOLD_MINI(AC=0318)のスプレッドコストは別途考慮が必要

  7. レポート遅延リスク: ゴールドレポートの発行遅延時のシグナル欠落

  8. NSN配信タイミング: NSNバックナンバー記事の配信時刻について厳密な検証は未実施。週次集約(ISO週単位)のため日中の配信タイミングの影響は軽微と想定されるが、記事公開前のデータを参照していないことの完全な保証はない

  9. 過剰最適化の回避: 感度分析で全パラメータが同方向の改善を示しているため、パラメータ依存は低い

関連

参考文献

  • [1] Tetlock, P. C. (2007). “Giving Content to Investor Sentiment: The Role of Media in the Stock Market.” The Journal of Finance, 62(3), 1139-1168.

  • [2] Loughran, T. and McDonald, B. (2011). “When Is a Liability Not a Liability? Textual Analysis, Dictionaries, and 10-Ks.” The Journal of Finance, 66(1), 35-65.

  • [3] Moskowitz, T. J., Ooi, Y. H. and Pedersen, L. H. (2012). “Time Series Momentum.” Journal of Financial Economics, 104(2), 228-250.

  • [4] Hurst, B., Ooi, Y. H. and Pedersen, L. H. (2017). “A Century of Evidence on Trend-Following Investing.” AQR Capital Management.