ml4t-feature-families · git:20260528.303089e · 2026-05-28 · sha256 875567a8de6066f7
ml4t-feature-families git:20260528.303089eA
Immutable. This exact content is served forever at /api/v1/blob/875567a8de6066f7.
---
name: ml4t-feature-families
description: "Five families of financial features — momentum, mean-reversion, volatility, carry, and value. Use when designing a feature set to ensure coverage across complementary market dynamics."
when_to_use: "Use when designing a diversified feature set for alpha models"
dependencies: []
metadata:
book_chapters: "8"
library: "ml4t-engineer"
paths: ["**/*feature*.py", "**/*label*.py", "**/*barrier*.py", "**/*store*.py", "**/*horizon*.py", "**/*meta_label*.py", "**/*microstructure*.py", "**/*regime*.py", "**/*selection*.py"]
---
# Feature Families
A model trained on six momentum variants learns one signal six ways. Diversifying across feature families — each driven by a different economic mechanism — produces more robust predictions.
## The Problem
Feature sets dominated by a single family (e.g., all momentum) are highly correlated internally. The model wastes capacity learning redundant information and becomes fragile when that one mechanism stops working. A momentum crash wipes out all signal simultaneously.
## The Pattern
### WRONG
```python
import polars as pl
# All momentum variants — same family, correlated, fragile
features = df.with_columns(
mom_5d=pl.col("close").pct_change(5).over("symbol"),
mom_21d=pl.col("close").pct_change(21).over("symbol"),
mom_63d=pl.col("close").pct_change(63).over("symbol"),
mom_126d=pl.col("close").pct_change(126).over("symbol"),
mom_252d=pl.col("close").pct_change(252).over("symbol"),
)
```
### CORRECT
```python
import polars as pl
import numpy as np
# One representative from each family — diverse signals
features = df.sort("symbol", "timestamp").with_columns(
# Momentum: trend-following
momentum_63d=pl.col("close").pct_change(63).over("symbol"),
# Mean-reversion: deviation from moving average
mean_rev_z=(pl.col("close") - pl.col("close").rolling_mean(20).over("symbol"))
/ pl.col("close").rolling_std(20).over("symbol"),
# Volatility: risk regime
realized_vol=pl.col("returns").rolling_std(21).over("symbol") * np.sqrt(252),
# Carry: yield/cost signal (example: dividend yield or funding rate)
carry_proxy=pl.col("dividend_yield"),
# Value: fundamental anchor
pe_ratio=pl.col("pe_ratio"),
)
```
## The Five Families
| Family | Mechanism | Typical Horizon | Example Features |
|--------|-----------|-----------------|------------------|
| Momentum | Trend continuation | 1-12 months | Price return, risk-adjusted return, MACD |
| Mean-reversion | Overreaction snap-back | 1-5 days | RSI, z-score vs MA, Bollinger %B |
| Volatility | Risk regime | 5-60 days | Realized vol, GARCH forecast, VIX ratio |
| Carry | Yield differential | Ongoing | Dividend yield, funding rate, roll yield |
| Value | Fundamental anchor | Months-years | P/E, P/B, EV/EBITDA |
## Diversity Diagnostic
```python
# Check inter-family correlation — should be low
corr = features.select(feature_cols).to_pandas().corr()
avg_cross_family = corr.abs().mean().mean() # Target: < 0.3
```
## Guardrails
- **Max 2-3 features per family** in initial models — add more only if IC justifies it
- **Cross-family correlation < 0.3** on average — higher means redundancy
- **Each feature needs an economic hypothesis** — if you cannot explain *why* it predicts, it may be noise
- **Not all families apply to all assets**: carry is irrelevant for assets without yield
## Production Implementation
`ml4t-engineer` provides a catalog of 120+ features organized by registry
category. The mapping to economic families is approximate, so carry and value
signals often remain external features in research code.
```python
from ml4t.engineer import compute_features, feature_catalog
# Browse registry categories
feature_catalog.list(category="momentum")
feature_catalog.list(category="volatility")
# Compute a diversified set from current registry names
features = compute_features(data, [
"mom", "rsi", "realized_volatility", "garman_klass_volatility",
])
```
## Checklist
- [ ] Features span at least 3 of the 5 families
- [ ] No single family contributes more than 40% of total features
- [ ] Cross-family correlation checked (target < 0.3)
- [ ] Each feature has a stated economic hypothesis
- [ ] Family coverage documented in feature config