rangebar-eval-metrics について
rangebar-eval-metricsは、レンジバーデータで機械学習モデルを評価するためのリファレンスとスクリプトを提供します。バーの期間が一定でないことや自己相関を考慮した指標とレポート作成手順を含み、研究や検証に利用できます。
主な機能
- 01Sharpe比とリスク指標
- 02予測品質指標
- 03PSR、DSR、MinTRL検定
- 04フォールド別レポート生成
- 05指標スキーマの検証
- 06取引時間帯に応じた年率換算
活用シーン
- 01レンジバーデータ上のモデル評価
- 02Walk-Forward Optimizationのフォールド分析
- 03Sharpe比の統計的有意性検定
- 04評価レポートの生成
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ terrylica/ cc-skills --skill rangebar-eval-metricsインストール後、Claude Code で/rangebar-eval-metricsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
requirements.txtreferences/anti-patterns.mdcrypto-markets.mdevolution-log.mdmetrics-schema.mdml-prediction-quality.mdrisk-metrics.mdsharpe-formulas.mdsota-2025-2026.mdstructured-logging.mdtemporal-aggregation.mdworked-examples.mdscripts/compute_metrics.py詳細
レンジバー評価指標
最先端の指標を用いてレンジバー(価格ベースのサンプリング)データを評価するための、機械可読なリファレンスと計算スクリプトです。
このスキルを使用する場面
以下の場合にこのスキルを使用してください。
- レンジバーデータに対する ML モデルのパフォーマンスを評価する場合
- 非 IID のバー系列を用いてシャープレシオを計算する場合
- ウォークフォワード最適化の指標分析を実行する場合
- PSR、DSR、または MinTRL の統計的検定を計算する場合
- fold の結果から評価レポートを生成する場合
クイックスタート
# Compute metrics from predictions + actuals
python scripts/compute_metrics.py --predictions preds.npy --actuals actuals.npy --timestamps ts.npy
# Generate full evaluation report
python scripts/generate_report.py --results folds.jsonl --output report.md
指標の階層
| 階層 | 目的 | 指標 | 計算単位 |
|---|---|---|---|
| Primary(5) | リサーチ上の判断 | weekly_sharpe, hit_rate, cumulative_pnl, n_bars, positive_sharpe_rate | fold ごと+集計 |
| Secondary/Risk(5) | 追加のコンテキスト | max_drawdown, bar_sharpe, return_per_bar, profit_factor, cv_fold_returns | fold ごと |
| ML Quality(3) | 予測の健全性 | ic, prediction_autocorr, is_collapsed | fold ごと |
| Diagnostic(5) | 最終検証 | psr, dsr, autocorr_lag1, effective_n, binomial_pvalue | 集計のみ |
| Extended Risk(5) | 詳細なリスク分析 | var_95, cvar_95, omega_ratio, sortino_ratio, ulcer_index | fold ごと(任意) |
レンジバーに特別な扱いが必要な理由
レンジバーは、標準的な IID の前提を満たしません。
- 期間が一定でない:バーは時間ではなく、価格の動きに基づいて形成されます
- 自己相関:高ボラティリティの期間にはバーが集中し、時間的な相関が生じます
- 情報量が一定でない:ボラティリティが高いほどバーが増え、1 日あたりの情報量も増加します
標準的な解決策:シャープレシオの計算前に、_group_by_day() を用いて日次集計します。
参考資料
中核となるリファレンスファイル
| トピック | リファレンスファイル |
|---|---|
| シャープレシオの計算 | sharpe-formulas.md |
| リスク指標(VaR、Omega、Ulcer) | risk-metrics.md |
| ML 予測品質(IC、自己相関) | ml-prediction-quality.md |
| 暗号資産市場に関する考慮事項 | crypto-markets.md |
| 時間集計のルール | temporal-aggregation.md |
| 指標の JSON スキーマ | metrics-schema.md |
| アンチパターン(取引コスト) | anti-patterns.md |
| SOTA 2025-2026(SHAP、BOCPD など) | sota-2025-2026.md |
| 実例(BTC、EUR/USD) | worked-examples.md |
| 構造化ログ(NDJSON) | structured-logging.md |
関連スキル
| スキル | 関連性 |
|---|---|
| adaptive-wfo-epoch | WFE の計算に weekly_sharpe、psr、dsr を使用します |
依存関係
pip install -r requirements.txt
# Or: pip install numpy>=1.24 pandas>=2.0 scipy>=1.10
主な計算式
日次集計シャープレシオ(主要指標)
def weekly_sharpe(pnl: np.ndarray, timestamps: np.ndarray) -> float:
"""Sharpe with daily aggregation for range bars."""
daily_pnl = _group_by_day(pnl, timestamps) # Sum PnL per calendar day
if len(daily_pnl) < 2 or np.std(daily_pnl) == 0:
return 0.0
daily_sharpe = np.mean(daily_pnl) / np.std(daily_pnl)
# For crypto (7-day week): sqrt(7). For equities: sqrt(5)
return daily_sharpe * np.sqrt(7) # Crypto default
情報係数(予測品質)
from scipy.stats import spearmanr
def information_coefficient(predictions: np.ndarray, actuals: np.ndarray) -> float:
"""Spearman rank IC - captures magnitude alignment."""
ic, _ = spearmanr(predictions, actuals)
return ic # Range: [-1, 1]. >0.02 acceptable, >0.05 good, >0.10 excellent
確率的シャープレシオ(統計的検証)
from scipy.stats import norm
def psr(sharpe: float, se: float, benchmark: float = 0.0) -> float:
"""P(true Sharpe > benchmark)."""
return norm.cdf((sharpe - benchmark) / se)
年率換算係数
| 市場 | 日次 → 週次 | 日次 → 年次 | 理由 |
|---|---|---|---|
| 暗号資産(24/7) | sqrt(7) = 2.65 | sqrt(365) = 19.1 | 週あたり7取引日 |
| 株式 | sqrt(5) = 2.24 | sqrt(252) = 15.9 | 週あたり5取引日 |
暗号資産市場で sqrt(252) を使用しないでください。
重要:セッションフィルターによって年率換算が変わります
| 表示 | フィルター | days_per_week | 理由 |
|---|---|---|---|
| セッションフィルター適用(ロンドン〜NY) | 平日 08:00-16:00 | sqrt(5) | 株式と同様の取引 |
| 全バー(フィルターなし) | なし | sqrt(7) | 24/7の暗号資産全体 |
セッションフィルター適用データに sqrt(7) を使用すると、シャープレシオが約18%過大評価されます!
詳しい理由については、crypto-markets.md を参照してください。
2つの表示による指標
包括的な分析を行うには、両方の表示で指標を計算してください。
- セッションフィルター適用(ロンドン 08:00 から NY 16:00):主な戦略評価
- 全バー:レジーム検出、データ品質の診断
学術文献
| 概念 | 引用 |
|---|---|
| ディフレート・シャープレシオ | Bailey & López de Prado (2014) |
| 非正規性を考慮したシャープレシオの標準誤差 | Mertens (2002) |
| シャープレシオの統計 | Lo (2002) |
| オメガレシオ | Keating & Shadwick (2002) |
| アルサー指数 | Peter Martin (1987) |
判断基準
実行基準(研究)
go_criteria:
- positive_sharpe_rate > 0.55
- mean_weekly_sharpe > 0
- cv_fold_returns < 1.5
- mean_hit_rate > 0.50
公開基準
publication_criteria:
- binomial_pvalue < 0.05
- psr > 0.85
- dsr > 0.50 # If n_trials > 1
スクリプト
| スクリプト | 目的 |
|---|---|
scripts/compute_metrics.py | 予測値/実績値からすべての指標を計算します |
scripts/generate_report.py | フォールド結果から Markdown レポートを生成します |
scripts/validate_schema.py | 指標の JSON をスキーマに照らして検証します |
修正(2026-01-19 マルチエージェント監査)
以下の修正は、12のサブエージェントによる敵対的監査に基づいて適用されました。
| 問題 | 根本原因 | 修正 | 出典 |
|---|---|---|---|
weekly_sharpe=0 | 予測値が一定 | モデル崩壊の検出とアーキテクチャの修正 | model-expert |
IC=None | 予測値の分散がゼロ | 一定値の場合は1.0を返す(意味的に正しい) | model-expert |
prediction_autocorr=NaN | ゼロ除算 | std < 1e-10 をチェックし、1.0を返す | model-expert |
| アルサー指数のゼロ除算 | ピーク時のエクイティが0 | np.where(peak > 1e-10, ...) でチェック | risk-analyst |
| オメガレシオ/プロフィットファクターの信頼性不足 | サンプル数が少なすぎる | min_days パラメーター(デフォルト:5) | robustness-analyst |
| BiLSTM の平均値崩壊 | アーキテクチャが小さすぎる | hidden_size: 16→48、dropout: 0.5→0.3 | model-expert |
profit_factor=1.0 (n_bars=0) | 早期リターンの値が誤り | 比率を計算するデータがない場合は NaN を返す | risk-analyst |
モデル崩壊の検出
# ALWAYS check for model collapse after prediction
pred_std = np.std(predictions)
if pred_std < 1e-6:
logger.warning(
f"Constant predictions detected (std={pred_std:.2e}). "
"Model collapsed to mean - check architecture."
)
推奨する BiLSTM アーキテクチャ
# BEFORE (causes collapse on range bars)
HIDDEN_SIZE = 16
DROPOUT = 0.5
# AFTER (prevents collapse)
HIDDEN_SIZE = 48 # Triple capacity
DROPOUT = 0.3 # Less aggressive regularization
完全な実装の詳細については、リファレンスドキュメントを参照してください。
トラブルシューティング
| 問題 | 原因 | 解決策 |
|---|---|---|
| weekly_sharpe が 0 | 予測値が一定 | モデルの崩壊を確認し、hidden_size を増やします |
| IC が None を返す | 予測値の分散がゼロ | モデルが崩壊しています。アーキテクチャを確認します |
| prediction_autocorr が NaN | ゼロ除算 | 自己相関の計算で std < 1e-10 をチェックします |
| Ulcer Index の除算エラー | ピーク時の資産がゼロ | ガードを追加します:np.where(peak > 1e-10, ...) |
| profit_factor = 1.0 | 処理されたバーがない | n_bars が 0 の場合は NaN を返します |
| シャープレシオが 18% 過大 | データに対する年率換算が誤り | セッションでフィルタリングした場合は sqrt(5)、24/7 の場合は sqrt(7) を使用します |
| PSR/DSR が計算されない | scipy がない | インストールします:pip install scipy |
| タイムスタンプを解析できない | 形式が誤っている | datetime 文字列ではなく、Unix タイムスタンプを使用してください |
コメント
Markdown 対応