Machine Learning in Trading Strategy Design › Unsupervised Learning for Market Structure

Michael BrenndoerferJanuary 3, 20268 min read
Quantitative FinanceAll chapters
Part 13 of 15Machine Learning and Alternative Data
Chapter 70Machine Learning in Trading Strategy Design › Unsupervised Learning for Market Structure
Reading section 8 of 14 · Unsupervised Learning for Market Structure · 8 minSection 8 of 14 · 8 min

Book contents

Section 8 of 14 · 8 min read

Machine Learning in Trading Strategy Design › Unsupervised Learning for Market StructureOne section · Sections in this chapter8 / 14 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

Not all valuable patterns require labeled data. Unsupervised learning techniques discover hidden structure in market data without being told what to look for. These methods excel at grouping similar assets, identifying regime changes, and detecting anomalies that signal risk or opportunity. The absence of labels forces these algorithms to find patterns based on the intrinsic structure of the data, often revealing relationships that wouldn't be apparent from traditional analysis.

Clustering for Portfolio Construction

Hierarchical clustering and k-means provide data-driven alternatives to traditional sector classifications. Standard industry categories, like GICS sectors or NAICS codes, group companies based on what they do. But for portfolio construction, what matters is how assets behave together in the market, their return correlations and factor exposures. Two tech companies in the same GICS sector might have very different risk profiles if one is a growth stock sensitive to interest rates while the other is a mature value play.

Assets grouped by return covariance patterns may reveal economic relationships that standard industry categories miss. A cloud computing company might cluster more closely with commercial real estate (both sensitive to business investment cycles) than with social media companies (more dependent on advertising spending). By letting the data determine groupings, clustering can identify these unexpected but economically meaningful relationships:

In[36]:
Code
import numpy as np
import pandas as pd

# Generate synthetic multi-asset returns with cluster structure
np.random.seed(42)
n_assets = 30
n_days = 252

# Create factor returns
tech_factor = np.random.normal(0.0005, 0.015, n_days)
value_factor = np.random.normal(0.0003, 0.012, n_days)
defensive_factor = np.random.normal(0.0002, 0.008, n_days)
market_factor = np.random.normal(0.0003, 0.01, n_days)

# Assign assets to clusters with varying factor exposures
asset_returns = np.zeros((n_days, n_assets))
cluster_assignments_true = []

for i in range(n_assets):
    if i < 10:  # Tech-like assets
        asset_returns[:, i] = (
            0.8 * tech_factor
            + 0.5 * market_factor
            + np.random.normal(0, 0.01, n_days)
        )
        cluster_assignments_true.append(0)
    elif i < 20:  # Value-like assets
        asset_returns[:, i] = (
            0.7 * value_factor
            + 0.6 * market_factor
            + np.random.normal(0, 0.012, n_days)
        )
        cluster_assignments_true.append(1)
    else:  # Defensive assets
        asset_returns[:, i] = (
            0.9 * defensive_factor
            + 0.3 * market_factor
            + np.random.normal(0, 0.006, n_days)
        )
        cluster_assignments_true.append(2)

returns_df = pd.DataFrame(
    asset_returns, columns=[f"Asset_{i}" for i in range(n_assets)]
)

# Calculate correlation matrix
corr_matrix = returns_df.corr()
In[37]:
Code
from scipy.cluster.hierarchy import linkage
from scipy.spatial.distance import squareform
from sklearn.cluster import KMeans

# Perform hierarchical clustering on correlation distance
# Convert correlation to distance: d = sqrt(0.5 * (1 - corr))
distance_matrix = np.sqrt(0.5 * (1 - corr_matrix))

# Hierarchical clustering
linkage_matrix = linkage(squareform(distance_matrix), method="ward")

# K-means on return features (using covariance-based features)
cov_features = corr_matrix.values  # Use correlation profile as features
kmeans = KMeans(n_clusters=3, random_state=42, n_init=10)
cluster_labels = kmeans.fit_predict(cov_features)
Out[38]:
Visualization
Hierarchical clustering dendrogram for 30 synthetic assets, with merge distance on the y-axis and asset labels A0 through A29 on the x-axis.
Dendrogram from hierarchical clustering of 30 synthetic assets based on return correlations. The tree structure illustrates the proximity of assets within tech, value, and defensive groups, and gives a data-driven basis for portfolio diversification.
Out[39]:
Visualization
Correlation heatmap for 30 assets reordered by hierarchical-cluster membership, with red blocks indicating high within-cluster correlations and blue indicating negative correlations.
Correlation matrix reordered by cluster membership. The block-diagonal structure highlights groups of highly correlated assets (red blocks) separated by lower correlations.
In[40]:
Code
from sklearn.metrics import adjusted_rand_score

ari = adjusted_rand_score(cluster_assignments_true, cluster_labels)
Out[41]:
Console
Clustering Quality:
  Adjusted Rand Index: 1.000 (1.0 = perfect match with true clusters)

Cluster Composition:
  Cluster 0: 10 assets - ['A10', 'A11', 'A12', 'A13', 'A14']...
  Cluster 1: 10 assets - ['A20', 'A21', 'A22', 'A23', 'A24']...
  Cluster 2: 10 assets - ['A0', 'A1', 'A2', 'A3', 'A4']...

The clustering identifies natural groupings in the data that can inform portfolio construction. The dendrogram on the left shows the hierarchical structure of asset relationships: assets that merge at lower heights are more similar, while those that only join at the top of the tree are quite different. The correlation heatmap on the right, reordered by cluster membership, reveals the block structure that clustering uncovers. Within each block (cluster), correlations are high, indicating that these assets move together. Between blocks, correlations are lower, creating diversification potential across clusters.

Rather than using arbitrary sector classifications that may not reflect current market dynamics, you can build diversified portfolios by selecting assets from different clusters. This approach diversifies risk exposures according to observed asset behavior rather than sector labels. When correlations change (as they often do during market stress), the clusters can be recomputed to maintain effective diversification.

Anomaly Detection for Risk Management

Unsupervised anomaly detection identifies unusual market behavior that might signal emerging risks or trading opportunities. The logic is that normal market conditions, while noisy, exhibit statistical regularities. When these regularities break down, when volatility spikes unexpectedly, when correlations shift dramatically, when the distribution of returns changes character, something unusual is happening. Detecting these anomalies early can help traders manage risk or capitalize on dislocations.

Isolation forests and autoencoders are particularly effective for high-dimensional financial data. Isolation forests work by recursively partitioning data; points that can be isolated quickly (with few partitions) are anomalous because they're far from the dense regions where most data lies. This approach is computationally efficient and doesn't require assumptions about the distribution of normal data:

In[42]:
Code
from sklearn.ensemble import IsolationForest


def detect_market_anomalies(returns_df, contamination=0.05):
    """
    Detect anomalous market conditions using Isolation Forest.

    Parameters:

    - returns_df: DataFrame of asset returns
    - contamination: Expected proportion of anomalies

    Returns:

    - anomaly_scores: Lower = more anomalous
    - anomaly_labels: -1 for anomalies, 1 for normal
    """
    # Create cross-sectional features for each day
    daily_features = pd.DataFrame(index=returns_df.index)
    daily_features["cross_sectional_mean"] = returns_df.mean(axis=1)
    daily_features["cross_sectional_std"] = returns_df.std(axis=1)
    daily_features["cross_sectional_skew"] = returns_df.skew(axis=1)
    daily_features["pct_positive"] = (returns_df > 0).mean(axis=1)
    daily_features["dispersion"] = returns_df.max(axis=1) - returns_df.min(
        axis=1
    )

    # Isolation Forest
    iso_forest = IsolationForest(contamination=contamination, random_state=42)
    anomaly_labels = iso_forest.fit_predict(daily_features)
    anomaly_scores = iso_forest.decision_function(daily_features)

    return daily_features, anomaly_scores, anomaly_labels


daily_features, anomaly_scores, anomaly_labels = detect_market_anomalies(
    returns_df
)
Out[43]:
Visualization
Scatter plot of cross-sectional volatility versus dispersion with anomalies highlighted in red.
Anomaly detection in the volatility-dispersion plane using an Isolation Forest. Normal market behavior (blue) clusters in a central region, while anomalies (red) appear as outliers with extreme volatility or dispersion, signaling potential market dislocations or data errors.
Out[44]:
Visualization
Line chart of Isolation Forest anomaly scores over trading days with detected anomalies highlighted as red scatter points below the threshold line.
Time series of anomaly scores generated by the Isolation Forest. Sharp dips below the red dashed threshold line indicate statistically significant anomalies, flagging potential market dislocations or data quality issues that require risk management attention.

The visualization highlights how the model isolates days with extreme cross-sectional properties. Normal market behavior (blue points) clusters in a characteristic region of the volatility-dispersion space. Anomalous days (red points) appear in unusual locations: perhaps extremely high volatility with moderate dispersion (a correlated sell-off), or moderate volatility with extreme dispersion (a sector rotation with some stocks surging while others crash). Each anomaly pattern tells a different story about what's happening in the market.

Anomaly detection serves multiple purposes in trading. It can identify potential market dislocations that create trading opportunities, since unusual conditions often precede mean-reversion. It can flag unusual portfolio behavior that warrants risk review, alerting managers when their positions are experiencing statistically unusual moves. And it can detect data quality issues before they corrupt model inputs, catching feed errors or stale prices that might otherwise trigger erroneous trades.