Horizon ships four pure-Python research modules inspired by Lopez de Prado’s Advances in Financial Machine Learning. Use them standalone for offline analysis or drop their pipeline functions into hz.run() for live monitoring.
Meta-Labeling
Triple-barrier labeling: primary model gives direction, meta-label model decides sizing.
Feature Importance
MDA, SFI, and clustered MDA with purged cross-validation to prevent leakage.
Alpha Decay
Track information coefficient over time, estimate half-life, detect dying edges.
PnL Attribution
Break down returns by market, time period, and factor exposure.
A two-model framework. The primary model predicts direction (+1 long, -1 short). The meta-label model then decides whether to act on that signal (1) or abstain (0), using a triple-barrier method: profit-taking, stop-loss, and a vertical (time) barrier.This separation lets you use a high-recall primary model (catches most opportunities) and a high-precision meta-label model (filters out bad trades), which is far more effective than trying to build a single model that does both.
Copy
from horizon.meta_label import compute_meta_labels, meta_label_pipeline
Compute meta-labels from primary model signals using triple barriers.For each primary signal, scans forward from the signal index and applies three barriers:
Profit-taking (PT): Return exceeds vol * pt_sl[0] in the direction of the primary signal. Meta-label = 1 (act).
Stop-loss (SL): Return exceeds vol * pt_sl[1] against the primary signal. Meta-label = 0 (abstain).
Vertical barrier: max_holding bars elapse with no barrier hit. Meta-label = 1 if cumulative return > 0, else 0.
Pipeline function for hz.run(). Reads the primary model’s signal from ctx.params, maintains a rolling buffer of price observations, and injects meta-label decisions.
Model-agnostic feature importance methods with purged cross-validation. Standard k-fold CV leaks information in time-series data because adjacent samples are correlated. Purged CV removes training samples within a configurable gap of each test fold, preventing look-ahead bias.All methods accept a generic score_fn(X_train, y_train, X_test, y_test) -> float so they work with any model (sklearn, xgboost, a simple function, etc.).
Copy
from horizon.feature_importance import ( mda_importance, sfi_importance, clustered_mda, FeatureImportance,)
Mean Decrease Accuracy (permutation importance). For each CV fold, computes a baseline test score, then shuffles each feature column individually and re-scores. Importance = mean decrease in score caused by shuffling.
Copy
def my_scorer(X_train, y_train, X_test, y_test): from collections import Counter majority = Counter(y_train).most_common(1)[0][0] return sum(1 for y in y_test if y == majority) / len(y_test)results = mda_importance( score_fn=my_scorer, X=feature_matrix, y=labels, feature_names=["momentum", "vol", "spread", "imbalance"], n_splits=5, purge_gap=10, seed=42,)for fi in results: print(f"{fi.feature}: {fi.importance:.4f} +/- {fi.std:.4f}")
Single Feature Importance (AFML Ch. 8.6). Trains the model on each feature individually and evaluates via cross-validation. The importance of a feature is its cross-validated score when used as the sole predictor.
Clustered Feature Importance (AFML Ch. 8.7). Groups features by correlation using agglomerative clustering (distance = 1 - |correlation|), then permutes entire clusters at once.When one feature in a correlated group is shuffled, the model can compensate by using the remaining correlated features. Shuffling the entire cluster eliminates this substitution effect, giving a more accurate picture of the group’s true importance.
Copy
results = clustered_mda( score_fn=my_scorer, X=feature_matrix, y=labels, feature_names=["momentum", "vol", "spread", "imbalance"], n_clusters=2, n_splits=5, seed=42,)# Each result.feature contains comma-separated names of features in the clusterfor fi in results: print(f"Cluster [{fi.feature}]: {fi.importance:.4f} +/- {fi.std:.4f}")
List of FeatureImportance, one per cluster. The feature field contains comma-separated names of features in that cluster. Sorted by importance descending.
Feature name (or comma-separated cluster names for clustered_mda).
importance
float
Mean importance score (higher = more important).
std
float
Standard deviation of importance across folds.
MDA can understate the importance of correlated features. If your feature set has groups of highly correlated predictors (e.g., multiple momentum lookbacks), use clustered_mda instead.
Monitor whether your trading edge is dying. The AlphaDecayTracker computes rolling IC (Spearman rank correlation between predictions and outcomes), estimates half-life via AR(1) fit, and detects negative trend via linear regression on the IC series.
Copy
from horizon.alpha_decay import AlphaDecayTracker, alpha_decay_pipeline, AlphaDecayReport