signal-classification — скилл для Claude Code: ML-классификаторы
Скилл строит ML-классификаторы торговых сигналов на XGBoost и LightGBM: метки, walk-forward валидация, SHAP и подбор порога.
npx skills add agiprolabs/claude-trading-skills --skill signal-classification -a claude-codeЧто делает signal-classification
Скилл закрывает весь путь от разметки до оценки: считает форвардную доходность, ставит метки up/down и выбрасывает нейтральную зону, обучает XGBoost или LightGBM на каждом окне и собирает прогнозы вне выборки. Walk-forward здесь главное — обычная кросс-валидация перемешивает данные и подсовывает модели будущее, поэтому окна идут по времени с зазором-эмбарго, равным горизонту прогноза.
Внутри есть готовые функции: create_binary_labels для меток, walk_forward_splits для окон, пример обучения XGBClassifier и калибровка вероятностей через CalibratedClassifierCV с изотоническим методом. Для разбора предсказаний подключён SHAP — shap.TreeExplainer даёт и глобальную важность признаков, и объяснение отдельного прогноза. Справочники лежат в references/validation_methods.md и references/model_guide.md.
Сырые вероятности бустинга откалиброваны плохо: 0.7 на выходе не значит 70% попаданий, так что без калибровки порог подбирать рано. Мультиклассовая схема режет выборку на классы, и авторы советуют брать её только при 1000+ примерах на класс — иначе модель просто нечему учиться. Нужны xgboost или lightgbm, scikit-learn и shap в окружении.
Какие задачи решает
- разметить форвардную доходность на up/down и выкинуть нейтральную зону
- разбить историю на walk-forward окна с зазором против утечки меток
- обучить XGBoost или LightGBM на табличных признаках без нормализации
- откалибровать вероятности модели перед подбором порога
- объяснить через SHAP, какие признаки тянут конкретный прогноз
Примеры запросов агенту
- собери метки по форвардной доходности с горизонтом 24 бара и порогом 1%
- прогони walk-forward валидацию с окном обучения 720 баров и зазором 24
- построй SHAP summary plot по топ-15 признакам для обученной модели
Как установить signal-classification
1Через Skills CLI (Vercel)
npx skills add agiprolabs/claude-trading-skills --skill signal-classification -a claude-code2Вручную: положить файлы
~/.claude/skills/signal-classification/SKILL.mdПапка скилла целиком; для одного проекта — .claude/skills/signal-classification/
1Через Skills CLI (Vercel)
npx skills add agiprolabs/claude-trading-skills --skill signal-classification -a codex2Вручную: положить файлы
.agents/skills/signal-classification/SKILL.mdДля всех проектов — ~/.agents/skills/
1Через Skills CLI (Vercel)
npx skills add agiprolabs/claude-trading-skills --skill signal-classification -a cursor2Вручную: положить файлы
.cursor/skills/signal-classification/SKILL.mdCursor читает и .agents/skills/, и .claude/skills/
1GitHub CLI
gh skill install agiprolabs/claude-trading-skills signal-classification2Вручную: положить файлы
.github/skills/signal-classification/SKILL.md1Через Skills CLI (Vercel)
npx skills add agiprolabs/claude-trading-skills --skill signal-classification -a gemini-cli2Командой платформы
gemini skills install https://github.com/agiprolabs/claude-trading-skills --path skills/signal-classificationВручную: положить файлы
.devin/skills/signal-classification/SKILL.mdСтарый путь .windsurf/skills/ тоже читается
Через Skills CLI (Vercel)
npx skills add agiprolabs/claude-trading-skills --skill signal-classification -a opencodeClaude.ai
Упакуйте папку в zip и загрузите в Settings → Capabilities → Skills
По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов
Вопросы о signal-classification
Как установить signal-classification в Claude?
Выполните npx skills add agiprolabs/claude-trading-skills --skill signal-classification -a claude-code. Скилл окажется в ~/.claude/skills/signal-classification/SKILL.md.
Что делает signal-classification?
Собирает пайплайн классификатора торговых сигналов: метки из форвардной доходности, обучение XGBoost или LightGBM, walk-forward валидация, SHAP-важность признаков и оптимизация порога.
Зачем калибровать вероятности перед подбором порога?
Сырые вероятности XGBoost и LightGBM не откалиброваны, поэтому 0.7 не означает 70% верных сигналов. Изотоническая калибровка через CalibratedClassifierCV приводит их к реальным частотам.
Исходный текст
SKILL.md · MIT
---
name: signal-classification
description: ML trading signal classifiers using XGBoost and LightGBM with walk-forward validation, SHAP feature importance, and threshold optimization
---
# Signal Classification
Predict whether an asset's price will move up or down over a forward horizon using supervised machine learning classifiers. This skill covers the full pipeline: label creation, model training, walk-forward validation, feature importance analysis, and threshold optimization for trading applications.
## Why Tree-Based Models Dominate Trading ML
XGBoost and LightGBM are the workhorses of quantitative trading ML for good reason:
- **Non-linear relationships**: Financial features interact in complex, non-linear ways that trees capture naturally
- **Robust to feature scale**: No need to normalize or standardize inputs — trees split on rank order
- **Built-in feature importance**: Understand which features drive predictions without separate analysis
- **Fast training and inference**: Train on thousands of samples in seconds, predict in microseconds
- **Handle missing values**: Native support for NaN without imputation hacks
- **Regularization built in**: max_depth, min_child_weight, subsample all prevent overfitting
Linear models and deep learning have their place, but for tabular trading features with fewer than 100k samples, gradient-boosted trees consistently outperform alternatives.
## Classification Types
### Binary Classification
The simplest and most common setup. Predict whether forward returns exceed a threshold:
- **Up signal**: forward return > +1%
- **Down signal**: forward return < -1%
- **Neutral (excluded)**: -1% to +1% — drop these from training to create cleaner labels
```python
import numpy as np
def create_binary_labels(
prices: np.ndarray, horizon: int = 24, threshold: float = 0.01
) -> np.ndarray:
"""Create binary labels from forward returns.
Args:
prices: Array of prices.
horizon: Forward return lookback in bars.
threshold: Minimum return magnitude for a label.
Returns:
Array of labels: 1 (up), 0 (down), NaN (neutral).
"""
fwd_returns = np.roll(prices, -horizon) / prices - 1
fwd_returns[-horizon:] = np.nan
labels = np.where(fwd_returns > threshold, 1,
np.where(fwd_returns < -threshold, 0, np.nan))
return labels
```
### Multi-Class Classification
Three classes for finer signal granularity:
| Class | Condition | Typical threshold |
|-------|-----------|-------------------|
| Strong Up | fwd_return > +2% | High confidence long |
| Mild Up | +0.5% to +2% | Moderate confidence |
| Down | fwd_return < -0.5% | Avoid / short |
Multi-class reduces per-class sample size. Use only with large datasets (1000+ samples per class).
### Probability Calibration
Raw model probabilities from XGBoost/LightGBM are not well-calibrated. A predicted 0.7 probability does not mean 70% chance of being correct. Use calibration to fix this:
```python
from sklearn.calibration import CalibratedClassifierCV
calibrated = CalibratedClassifierCV(base_model, cv=5, method="isotonic")
calibrated.fit(X_train, y_train)
probs = calibrated.predict_proba(X_test)[:, 1]
```
Isotonic calibration works better than Platt scaling for tree models.
## Walk-Forward Validation
**This is the single most important concept in trading ML.** Standard cross-validation randomly shuffles data, which creates lookahead bias. Walk-forward validation respects time ordering.
### How It Works
```
Window 1: [===TRAIN===][GAP][=TEST=]
Window 2: [===TRAIN===][GAP][=TEST=]
Window 3: [===TRAIN===][GAP][=TEST=]
Window 4: [===TRAIN===][GAP][=TEST=]
```
Each window:
1. Train on past N bars
2. Skip a gap (embargo) equal to the forward return horizon
3. Predict on next M bars
4. Record out-of-sample predictions
5. Slide forward and repeat
### Typical Parameters
| Parameter | Value | Rationale |
|-----------|-------|-----------|
| Train window | 30 days (720 hourly bars) | Enough data to learn, recent enough to be relevant |
| Test window | 7 days (168 hourly bars) | Enough predictions for statistical significance |
| Step size | 1 day (24 bars) | Overlap test windows for more data points |
| Gap (embargo) | Same as forward horizon | Prevents label leakage |
### Walk-Forward Implementation
```python
from typing import Iterator
def walk_forward_splits(
n_samples: int,
train_size: int = 720,
test_size: int = 168,
step_size: int = 24,
gap: int = 24,
) -> Iterator[tuple[np.ndarray, np.ndarray]]:
"""Generate walk-forward train/test index splits.
Args:
n_samples: Total number of samples.
train_size: Number of training samples per window.
test_size: Number of test samples per window.
step_size: Step between successive windows.
gap: Gap between train end and test start.
Yields:
Tuples of (train_indices, test_indices).
"""
start = 0
while start + train_size + gap + test_size <= n_samples:
train_idx = np.arange(start, start + train_size)
test_start = start + train_size + gap
test_idx = np.arange(test_start, test_start + test_size)
yield train_idx, test_idx
start += step_size
```
See `references/validation_methods.md` for purged CV, CPCV, and evaluation metrics.
## Model Training Pipeline
### Full Pipeline Overview
1. **Feature engineering** — compute technical indicators, on-chain metrics, volume features (see `feature-engineering` skill)
2. **Label creation** — forward returns with threshold, drop neutral zone
3. **Walk-forward split** — time-ordered train/test windows with gap
4. **Train model** — XGBoost or LightGBM on each training window
5. **Predict on test** — generate out-of-sample probability predictions
6. **Aggregate predictions** — concatenate all out-of-sample results
7. **Evaluate** — accuracy, precision, recall, F1, AUC, profit factor
### Quick Training Example
```python
from xgboost import XGBClassifier
model = XGBClassifier(
n_estimators=200,
max_depth=4,
learning_rate=0.05,
subsample=0.8,
colsample_bytree=0.8,
eval_metric="logloss",
use_label_encoder=False,
random_state=42,
)
model.fit(
X_train, y_train,
eval_set=[(X_val, y_val)],
verbose=False,
)
probabilities = model.predict_proba(X_test)[:, 1]
```
See `references/model_guide.md` for parameter recommendations and tuning.
## SHAP Feature Importance
SHAP (SHapley Additive exPlanations) provides the gold standard for understanding model predictions.
### Global Feature Importance
Which features matter most across all predictions:
```python
import shap
explainer = shap.TreeExplainer(model)
shap_values = explainer.shap_values(X_test)
# Summary plot (top 15 features)
shap.summary_plot(shap_values, X_test, max_display=15)
```
### Local Explanations
Why a specific prediction was made:
```python
# Explain a single prediction
shap.force_plot(explainer.expected_value, shap_values[0], X_test.iloc[0])
```
### Temporal Feature Importance
Track how feature importance drifts over walk-forward windows. If a feature's importance drops significantly, the market regime may have shifted.
## Threshold Optimization
The default 0.5 probability threshold is almost never optimal for trading.
### Why Not 0.5?
- Class imbalance: if 60% of labels are "up", a 0.5 threshold is too aggressive
- Trading costs: marginal signals (0.51 probability) rarely cover transaction costs
- Asymmetric payoffs: precision matters more than recall for trading
### Optimize for Profit Factor
```python
def optimize_threshold(
probabilities: np.ndarray,
returns: np.ndarray,
thresholds: np.ndarray | None = None,
) -> tuple[float, float]:
"""Find threshold that maximizes profit factor.
Args:
probabilities: Model predicted probabilities.
returns: Actual forward returns.
thresholds: Thresholds to search over.
Returns:
Tuple of (best_threshold, best_profit_factor).
"""
if thresholds is None:
thresholds = np.arange(0.50, 0.85, 0.01)
best_threshold, best_pf = 0.5, 0.0
for t in thresholds:
signals = probabilities >= t
if signals.sum() < 10:
continue
signal_returns = returns[signals]
wins = signal_returns[signal_returns > 0].sum()
losses = abs(signal_returns[signal_returns < 0].sum())
pf = wins / losses if losses > 0 else 0.0
if pf > best_pf:
best_pf = pf
best_threshold = t
return best_threshold, best_pf
```
Typical finding: optimal threshold is 0.60-0.75 for crypto trading signals.
## Crypto-Specific Considerations
### Short Training Windows
Crypto market regimes change fast. A model trained on 6 months of data may perform worse than one trained on 30 days. Use shorter training windows and retrain frequently.
### Class Imbalance
Most time periods are "flat" (returns within the neutral zone). Strategies to handle this:
- **Drop neutral zone**: only train on clear up/down labels
- **Undersample majority class**: `scale_pos_weight` in XGBoost
- **SMOTE**: synthetic minority oversampling (use cautiously — can introduce lookahead)
- **Adjust threshold**: raise the probability threshold to compensate
### Transaction Costs
A model with 55% accuracy sounds good, but after 0.5% round-trip costs (slippage + fees), many signals become unprofitable. Always evaluate signals net of costs:
```python
net_return = gross_return - 0.005 # 50 bps round-trip
```
### Feature Decay
Features lose predictive power over time as more participants discover and trade on them. Monitor rolling performance and retrain when metrics degrade.
## Integration with Other Skills
| Skill | Integration |
|-------|-------------|
| `feature-engineering` | Compute input features for the classifier |
| `vectorbt` | Backtest trading strategies from ML signals |
| `regime-detection` | Train separate models per regime, or use regime as a feature |
| `position-sizing` | Size positions based on classifier confidence |
| `risk-management` | Apply portfolio-level risk limits to ML-generated signals |
## Files
### References
- `references/model_guide.md` — XGBoost and LightGBM parameter guide, tuning, and ensembling
- `references/validation_methods.md` — Walk-forward, purged CV, CPCV, and evaluation metrics
### Scripts
- `scripts/train_classifier.py` — Train a signal classifier with walk-forward validation and feature importance
- `scripts/walk_forward_backtest.py` — Backtest ML signals vs buy-and-hold with walk-forward validation
## Dependencies
```bash
# Core (required)
uv pip install pandas numpy scikit-learn
# Optional (recommended)
uv pip install xgboost lightgbm shap
```
## Key Takeaways
1. **Walk-forward validation is non-negotiable** — random CV will give you wildly inflated results
2. **Optimize threshold for profit factor**, not accuracy — a high-precision, low-recall model beats a high-accuracy one
3. **Short training windows** for crypto — 30 days beats 6 months in most regimes
4. **Monitor feature decay** — retrain when rolling metrics drop below baseline
5. **Always evaluate net of costs** — a 55% accurate model may be unprofitable after fees
6. **SHAP over raw feature importance** — SHAP gives consistent, theoretically grounded explanations
© agiprolabs · MIT · agiprolabs/claude-trading-skills