# Ml4t Feature Families

> 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.

- Skill: `ml4t/ml4t-feature-families` (Agent Skill)
- Install (CLI): `npx skillmds@latest add ml4t/ml4t-feature-families`
- Raw SKILL.md: https://api.skillmd.com/api/skills/ml4t/ml4t-feature-families/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: ml4t (https://skillmd.com/u/ml4t)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/ml4t/ml4t-feature-families

---

# 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

