Processus gaussiens pour la modélisation des prix non paramétriques
Fait partie de la série « Lignes de base Classic ML ».
Deux choses font qu'un processus gaussien mérite un article séparé sur ce blog, et aucune d'elles n'est "cela vous donne de l'incertitude".
Le premier est la conception du noyau. L’ensemble du biais inductif d’un médecin généraliste réside dans une seule fonction , et cette fonction est quelque chose que vous écrivez délibérément : à quel point le chemin est difficile, s'il se répète, si la répétition décroît. Rien d'autre dans la boîte à outils standard ne vous permet d'énoncer une hypothèse structurelle sur la dynamique du marché qui s'y conforme explicitement. La seconde est la vraisemblance marginale — un objectif de formation avec une pénalité de complexité dérivée du modèle lui-même, et non d'un ensemble retenu. Tous les autres articles de l'arc de surajustement sur ce blog (analyse de plateau, PBO, deflated Sharpe) existent parce que la régularisation de l'ensemble de validation est fragile lors de la recherche. Un médecin généraliste prétend ne pas en avoir besoin. Cette affirmation est testable, et la tester est plus intéressante qu’un autre didacticiel sur la taille de l’incertitude.
Sur l'incertitude elle-même : la variance postérieure du GP est structurelle – elle découle de la même inférence qui produit la moyenne, plutôt que d'être enroulée autour d'un modèle ajusté par la suite. C'est le vrai contraste avec la prédiction conforme, qui explique déjà sur ce blog pourquoi l'incertitude est la bonne entrée pour dimensionner une position et que faire avec un intervalle une fois que vous en avez un. Cet article ne réaffirme pas ce cas ; ça va après le modèle.
Ce qui suit est le noyau et la machinerie d'inférence, une implémentation de GPyTorch et - clairement indiqué à la fin - les mesures que cet article n'a pas encore.
Qu'est-ce qu'un processus gaussien ?
Les médecins généralistes apparaissent déjà sur ce blog en tant que substitut de l'optimisation bayésienne dans Optuna vs. coordinate descente, avec la même notation et la même mise en garde concernant la faible dimensionnalité. Ici, le GP est le modèle lui-même, ajusté aux données du marché plutôt qu'à une surface de recherche hyperparamétrique, le traitement va donc plus en profondeur.
Un processus gaussien est un ensemble de variables aléatoires dont un nombre fini a une distribution gaussienne conjointe. Il s'agit d'une distribution sur des fonctions, pas d'une distribution sur des paramètres.
Formellement, une fonction est tiré d'un GP si pour tout ensemble fini d'entrées :
où est la fonction moyenne et est la fonction de covariance (noyau). Nous écrivons cela de manière compacte sous la forme :
La fonction moyenne code une croyance antérieure sur le comportement moyen de . En trading, nous définissons généralement , codant l’hypothèse selon laquelle nous n’avons aucun biais directionnel préalable sur les rendements. Toute la structure va dans le noyau.
Pourquoi non paramétrique ?
Un modèle de régression linéaire avec 5 caractéristiques comporte 6 paramètres. Un réseau de neurones avec deux couches cachées de 64 unités en compte des milliers. Un GP n'a pas de nombre fixe de paramètres : la complexité du modèle augmente avec les données. Avec 10 observations, le GP définit une gaussienne à 10 dimensions. Avec 10 000 observations, il définit une gaussienne à 10 000 dimensions.
Cela ne veut pas dire que les généralistes n’ont pas d’hyperparamètres. La fonction noyau possède des hyperparamètres (échelles de longueur, amplitudes, périodicités) qui contrôlent les propriétés des fonctions tirées du prior. Mais la forme fonctionnelle elle-même n’est jamais figée. Le GP peut représenter n'importe quelle fonction continue, avec suffisamment de données et le bon noyau. C'est ce que signifie « non paramétrique » : le modèle n'est pas limité à une famille paramétrique comme les fonctions linéaires ou les polynômes.
Pour la modélisation financière, cela est précieux. Les marchés changent. La relation entre les caractéristiques et les rendements est non linéaire, non stationnaire et dépend du régime. Les modèles paramétriques imposent une structure qui peut ne pas correspondre à la réalité. Les médecins généralistes laissent parler les données.
Fonctions du noyau : encodage de la structure du marché
La fonction noyau est l'âme d'un processus gaussien. Il définit quelles fonctions sont probables a priori en spécifiant la covariance entre les valeurs de fonction à deux points d'entrée quelconques. Différents noyaux codent différentes hypothèses sur la régularité, la périodicité et le comportement à long terme.
Fonction de base radiale (RBF) / Exponentielle au carré
Le noyau RBF est le point de départ le plus courant :
où est la variance du signal (échelle de sortie) et est l'échelle de longueur. Les fonctions tirées d'un GP avec un noyau RBF sont infiniment différentiables – très fluides.
Interprétation du trading : L'échelle de longueur contrôle la distance entre deux points de données qui peuvent être tout en étant corrélés. Une échelle courte signifie que le modèle réagit aux modèles locaux ; une échelle longue signifie qu’elle capture les grandes tendances. La variance du signal contrôle l’amplitude de la fonction – quelle peut être l’ampleur des rendements prédits.
Problème pour la finance : Une douceur infinie est irréaliste. Les rendements financiers connaissent des sauts, des changements de régime et des discontinuités. Le noyau RBF peut surlisser ces caractéristiques, produisant des prédictions trop conservatrices à proximité de ruptures structurelles.
Noyau maternel
La classe Matern généralise le RBF en introduisant un paramètre de douceur :
où est la fonction de Bessel modifiée du deuxième type. Comme , le noyau Matern converge vers le RBF. Choix courants :
- : Equivalent au procédé Ornstein-Uhlenbeck. Les fonctions sont continues mais non différentiables – rugueuses, comme le mouvement brownien.
- : Les fonctions sont une fois différentiables. Un bon équilibre entre douceur et souplesse.
- : Les fonctions sont deux fois différenciables. Plus lisse que mais moins rigide que RBF.
Interprétation commerciale : La Matern- Le noyau est sans doute la meilleure valeur par défaut pour les séries temporelles financières. Il permet le genre de rugosité que présentent les trajectoires des prix réels sans être aussi irrégulier que . Cela concorde avec la littérature sur « la volatilité est approximative » (Gatheral, Jaisson et Rosenbaum, 2018), qui montre empiriquement que les trajectoires de volatilité ont des exposants de Hurst autour de , bien plus grossier que le mouvement brownien.
La principale preuve publiée démontrant que les noyaux de Matern battent les modèles de volatilité classiques est celle de Rizvi et al. (2017), qui rapportent un MSE environ 20 % meilleur qu'une marche aléatoire et 50 % meilleur que GARCH — sur les données quotidiennes de 2017 sur les paires de devises, pas sur la cryptographie, et non reproduites ici. Traitez-le comme une motivation pour essayer le noyau, pas comme une référence. L'ajustement GARCH(1,1) de ce blog sur les données quotidiennes réelles BTC, avec les diagnostics Ljung-Box et ARCH-LM, se trouve dans Prévision de volatilité GARCH pour crypto ; un face-à-face avec un Matern GP sur le même échantillon serait une comparaison honnête, et elle n'a pas été réalisée.
Noyau périodique
Les marchés financiers ont des schémas cycliques : courbes de volumes intrajournalières, effets jours de la semaine, flux de rééquilibrage mensuels, saisons de résultats trimestriels. Le noyau périodique capture les éléments suivants :
où est la période. Les fonctions tirées de ce noyau se répètent avec un point , modulé par l'échelle de longueur qui contrôle la rapidité avec laquelle la corrélation décroît au cours d'une période.
Interprétation commerciale : Définir (heures) pour capturer les tendances intrajournalières, ou (jours de bourse) pour la saisonnalité hebdomadaire. Contrairement aux fonctionnalités de Fourier, le noyau périodique ne suppose pas un nombre fixe d'harmoniques : le GP apprend la forme du cycle à partir des données.
Combinaison de noyaux : composition additive et multiplicative
Le véritable pouvoir des noyaux GP réside dans leur composition. Si et sont des noyaux valides, tout comme :
- Somme : — la fonction est la somme de composants indépendants (décomposition additive)
- Produit : — interactions entre composants (par exemple, comportement localement périodique)
Un noyau composite utile pour les rendements financiers :
Cela décompose le signal en :
- Une composante de tendance apériodique et non lisse (Matern-3/2)
- Une composante périodique dont l'amplitude décroît avec le temps (Periodic RBF)
Le produit crée un noyau localement périodique : le motif se répète, mais les répétitions distantes ont moins d'influence que les répétitions proches. Cela s’applique parfaitement à la saisonnalité financière, qui évolue au fil du temps à mesure que la microstructure du marché évolue.
Noyaux de mélange spectral
Pour une flexibilité maximale, le noyau de mélange spectral (SM) (Wilson & Adams, 2013) paramétrise la densité spectrale du noyau comme un mélange de gaussiennes :
où sont des poids de mélange, sont des variances spectrales, et sont des moyennes spectrales (fréquences). Par le théorème de Bochner, tout noyau stationnaire peut être représenté de cette façon. Le noyau SM peut découvrir simultanément des composantes périodiques, des tendances à long terme et des corrélations à court terme, le tout à partir de données.
Interprétation du trading : Le noyau SM est utile lorsque vous ne savez pas quels modèles existent dans les données. Il peut identifier des périodicités cachées dans les séries de rendements (par exemple, des cycles subtils de 4 heures sur les marchés de cryptographie pilotés par un rééquilibrage automatisé). L'inconvénient est davantage d'hyperparamètres et le risque de surapprentissage avec de petits ensembles de données.
Inférence postérieure : d'avant à la prédiction
Compte tenu des données de formation où et , le GP postérieur aux points de test a une solution de forme fermée. C’est le principal avantage informatique des généralistes par rapport à la plupart des modèles bayésiens.
Les équations postérieures
Laissez être le matrice de covariance de formation, être le matrice de covariance croisée, et être le tester la matrice de covariance. Le postérieur est :
où:
La moyenne postérieure est une combinaison linéaire des objectifs d'entraînement, pondérée par la similarité du noyau entre les points de test et d'entraînement. La covariance postérieure commence à partir de la covariance antérieure et soustrait les informations obtenues des données d'entraînement. Lorsque les données d'entraînement sont denses, la variance a posteriori est faible. Lorsque les données d'entraînement sont rares, la variance postérieure revient à la variance antérieure.
La vraisemblance marginale et l'affirmation qui mérite d'être testée
Les hyperparamètres du noyau (échelles de longueur, variances, niveau de bruit) sont apprises en maximisant la vraisemblance marginale log :
Le premier terme est un terme d’ajustement des données (pénalise les prédictions éloignées des observations). Le deuxième terme est une pénalité de complexité (pénalise les modèles trop flexibles, c'est-à-dire où la matrice du noyau a un déterminant important). Le troisième terme est une constante de normalisation.
C'est le rasoir automatique d'Occam, et c'est la chose la plus intéressante qu'un GP apporte à un pipeline commercial. La version forte de l'affirmation est qu'aucun ensemble de validation séparé n'est nécessaire pour la régularisation — la pénalité de complexité est à l'intérieur de l'objectif, de sorte que le modèle ne peut pas acheter gratuitement un ajustement avec flexibilité.
Cette affirmation mérite le scepticisme sur ce blog en particulier. Plateau Analysis montre qu'un score de validation sur un seul point est un mauvais critère de sélection et que la robustesse réside dans la forme du quartier ; PBO quantifie la fréquence à laquelle le gagnant de l'échantillon perd hors de l'échantillon ; deflated Sharpe prix en nombre d'essais. Une probabilité marginale est toujours un objectif dans l'échantillon maximisé sur — le facteur Occam pénalise la capacité du modèle, et non la sélection sur de nombreux noyaux ajustés. Si vous adaptez douze noyaux candidats et choisissez celui avec la meilleure probabilité marginale, vous êtes de retour dans le territoire des tests multiples et la logique de déflation s'applique inchangée. La version falsifiable : la sélection par vraisemblance marginale produit-elle un écart plus petit dans l'échantillon/hors échantillon que la sélection par ensemble de validation sur les mêmes données et la même famille de noyau ? Cela est mesurable et n’est pas mesuré ci-dessous.
La surface de vraisemblance marginale a également des optima locaux. Plusieurs redémarrages aléatoires ou une initialisation minutieuse sont importants - l'initialisation de l'échelle de longueur à la distance médiane par paire des entrées d'entraînement et de la variance du bruit à la variance de l'échantillon des cibles est un point de départ raisonnable.
Coût de calcul et évolutivité
Le goulot d’étranglement s’inverse , ce qui coûte dans le temps et en mémoire. Le mur cubique est déjà discuté sur ce blog dans l'autre sens : méthode de recherche vs coût d'évaluation disqualifie purement et simplement l'optimisation bayésienne basée sur GP lorsque l'objectif est bon marché, car le substitut coûte plus cher que les évaluations qu'il économise. L'arithmétique est la même ici ; l'application est différente. En tant que modèle adapté aux données du marché, le terme cubique n'est pas une disqualification mais un budget : il fixe un plafond strict à la fenêtre de formation.
Stratégies d'évolutivité pour les applications de trading :
-
GPs clairsemés (induisant des points). Remplacez le matrice avec un matrice où . Les points inducteurs sont des pseudo-entrées qui résument les données d’entraînement. La formulation SVGP (Stochastic Variational GP) de Hensman et al. (2013) permet une formation en mini-lots avec un coût par itération. GPyTorch le prend en charge nativement.
-
Interpolation structurée du noyau (SKI/KISS-GP). Exploite la structure de Kronecker et Toeplitz dans la matrice du noyau lorsque les entrées se trouvent sur une grille. Réduit le coût de où est la taille de la grille. Idéal pour les séries temporelles régulièrement échantillonnées (par exemple, barres d'une minute).
-
Généristes locaux sur fenêtres coulissantes. Former des médecins généralistes distincts sur les données récentes uniquement. C'est là que la contrainte spécifique au GP intervient : les noyaux standards sont stationnaires ( ne dépend que de ) et les marchés ne le sont pas, donc la réponse habituelle est une fenêtre glissante — mais la longueur de la fenêtre est délimitée au-dessus par , pas seulement par des statistiques. Walk-forward optimisation couvre les fenêtres ancrées et mobiles, les longueurs de train/test et la fréquence de réoptimisation en général ; pour un médecin généraliste, le dimensionnement de la fenêtre est une décision informatique autant que statistique, et une fenêtre ancrée (en constante croissance) n'est tout simplement pas disponible au-delà de quelques milliers de points sans approximation. Ce recadrage est la conséquence pratique : avec les médecins généralistes, vous n’avez pas le choix « d’utiliser tout l’historique ».
GP pour la prévision du retour : un cadre pratique
Conception des fonctionnalités : pourquoi 5 à 20 fonctionnalités, pas 500
La taxonomie générale des caractéristiques du ML des données de marché — déséquilibre du carnet d'ordres, pression comptable, VPIN, lambda de Kyle, caractéristiques de volatilité réalisée, codage temporel cyclique, signaux d'actifs croisés et de taux de financement — est déjà présentée dans [modélisation de propagation avec apprentissage automatique] (/fr/blog/post/spread-modeling-machine-learning) ; use that list.
Ce qui est spécifique au GP, c'est la taille de la liste. Les méthodes à noyau se dégradent dans les grandes dimensions : les distances se concentrent et un noyau stationnaire perd sa discrimination. La plage pratique pour un GP financier est de 5 à 20 entrées, et non les centaines qu'un arbre boosté par gradient mange volontiers. Le mécanisme qui permet de survivre est ARD (Automatic Relevance Determination) : donne à chaque dimension d'entrée sa propre échelle de longueur , et la formation de vraisemblance marginale pousse pour les dimensions qui ne transportent aucun signal, car une échelle de longueur infinie signifie que le noyau ignore cette coordonnée. La sélection des fonctionnalités devient un sous-produit de l'ajustement, et les connaissances acquises sont directement lisibles comme un classement de pertinence - ce qui le rend aussi falsifiable : ajustez le noyau composite sur de vraies barres, imprimez les échelles de longueur et voyez si les caractéristiques auxquelles vous croyez sont celles que le modèle conserve.
Dimensionnement des postes et abstention
The GP posterior gives directement, il tombe donc directement dans le filtre de dimensionnement du ratio de bord et de non-échange développé dans Conformal Prediction for Risk-Aware Position Sizing, avec la largeur de l'intervalle . La seule différence est la provenance : le GP produit la largeur à partir du modèle lui-même plutôt qu'à partir d'un ensemble d'étalonnage, elle varie donc en fonction de l'emplacement du point de test par rapport aux données d'entraînement plutôt qu'en fonction d'un quantile global de résidus passés.
Implémentation avec GPyTorch
GPyTorch est une bibliothèque basée sur PyTorch pour l'inférence GP évolutive. Il exploite l'accélération GPU, la différenciation automatique et les techniques modernes d'algèbre linéaire (gradients conjugués, décomposition de Lanczos) pour faire évoluer les GP au-delà du naïf. limite.
GP exact de base pour la prédiction de retour
import torch
import gpytorch
import numpy as np
from torch.utils.data import TensorDataset, DataLoader
class ExactGPModel(gpytorch.models.ExactGP):
"""Exact GP with a composite kernel for financial returns."""
def __init__(self, train_x, train_y, likelihood):
super().__init__(train_x, train_y, likelihood)
self.mean_module = gpytorch.means.ZeroMean()
self.covar_matern = gpytorch.kernels.ScaleKernel(
gpytorch.kernels.MaternKernel(nu=1.5, ard_num_dims=train_x.shape[1])
)
self.covar_periodic = gpytorch.kernels.ScaleKernel(
gpytorch.kernels.PeriodicKernel()
)
self.covar_rbf_decay = gpytorch.kernels.ScaleKernel(
gpytorch.kernels.RBFKernel()
)
def forward(self, x):
mean = self.mean_module(x)
covar = self.covar_matern(x) + self.covar_periodic(x) * self.covar_rbf_decay(x)
return gpytorch.distributions.MultivariateNormal(mean, covar)
ard_num_dims c'est ce qui permet les échelles de longueur par dimension discutées ci-dessus. Après la formation, model.covar_matern.base_kernel.lengthscale est le vecteur à lire.
Boucle d'entraînement
def train_gp(train_x, train_y, n_epochs=200, lr=0.05, device=None):
"""Train the GP by maximizing the marginal log-likelihood.
Returns the device alongside the model so that callers move test
tensors to the same place -- otherwise prediction crashes on GPU.
"""
if device is None:
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
train_x = train_x.to(device)
train_y = train_y.to(device)
likelihood = gpytorch.likelihoods.GaussianLikelihood().to(device)
model = ExactGPModel(train_x, train_y, likelihood).to(device)
model.train()
likelihood.train()
optimizer = torch.optim.Adam(model.parameters(), lr=lr)
mll = gpytorch.mlls.ExactMarginalLogLikelihood(likelihood, model)
losses = []
for epoch in range(n_epochs):
optimizer.zero_grad()
output = model(train_x)
loss = -mll(output, train_y)
loss.backward()
optimizer.step()
losses.append(loss.item())
if (epoch + 1) % 50 == 0:
noise = likelihood.noise.item()
print(
f"Epoch {epoch+1}/{n_epochs} | "
f"Loss: {loss.item():.4f} | "
f"Noise: {noise:.6f}"
)
return model, likelihood, device, losses
Prédiction avec incertitude
def predict_with_uncertainty(model, likelihood, test_x, device):
"""Generate predictions with uncertainty estimates."""
model.eval()
likelihood.eval()
test_x = test_x.to(device)
with torch.no_grad(), gpytorch.settings.fast_pred_var():
posterior = likelihood(model(test_x))
mean = posterior.mean
variance = posterior.variance
lower, upper = posterior.confidence_region() # 2-sigma bounds
return {
"mean": mean.cpu().numpy(),
"std": variance.sqrt().cpu().numpy(),
"lower_2sigma": lower.cpu().numpy(),
"upper_2sigma": upper.cpu().numpy(),
}
Le fast_pred_var() Le gestionnaire de contexte utilise l'algorithme LOVE (Lanczos Variance Estimates) pour calculer les variances prédictives dans temps au lieu de .
Pipeline de trading de bout en bout
Remarque sur le générateur de fonctionnalités ci-dessous : chaque statistique glissante doit être strictement rétrospective et la standardisation des entrées doit être adaptée uniquement à la tranche d'entraînement. Ce deuxième point n'est pas une hygiène générique - c'est précisément le canal de fuite de normalisation disséqué et mesuré dans la taxonomie des biais d'anticipation, qui rapporte l'inflation de Sharpe produite par chaque type de fuite. Un généraliste standardise ses apports par construction, c'est donc la fuite à laquelle il est le plus exposé.
import pandas as pd
def build_features(df: pd.DataFrame, lookback: int = 10) -> pd.DataFrame:
"""Build features for GP-based return prediction."""
features = pd.DataFrame(index=df.index)
for lag in range(1, lookback + 1):
features[f"ret_lag_{lag}"] = df["close"].pct_change().shift(lag)
ret = df["close"].pct_change()
features["vol_ratio"] = (
ret.rolling(10).std() / ret.rolling(50).std()
)
features["vol_zscore"] = (
(df["volume"] - df["volume"].rolling(50).mean())
/ df["volume"].rolling(50).std()
)
if "bid_vol" in df.columns and "ask_vol" in df.columns:
features["obi"] = (
(df["bid_vol"] - df["ask_vol"])
/ (df["bid_vol"] + df["ask_vol"])
)
if hasattr(df.index, "hour"):
hours = df.index.hour + df.index.minute / 60.0
features["time_sin"] = np.sin(2 * np.pi * hours / 24)
features["time_cos"] = np.cos(2 * np.pi * hours / 24)
features.dropna(inplace=True)
return features
def run_gp_strategy(
df: pd.DataFrame,
train_window: int = 500,
retrain_every: int = 50,
confidence_threshold: float = 1.0,
risk_fraction: float = 0.02,
max_leverage: float = 1.0,
):
"""Walk-forward GP trading strategy with uncertainty-based sizing."""
features = build_features(df)
returns = df["close"].pct_change().reindex(features.index)
target = returns.shift(-1) # predict next-bar return
mask = features.notna().all(axis=1) & target.notna()
features = features[mask]
target = target[mask]
positions = pd.Series(0.0, index=features.index)
predictions = pd.DataFrame(
index=features.index, columns=["mean", "std"], dtype=float
)
model = likelihood = device = None
x_mean = x_std = y_mean = y_std = None
for i in range(train_window, len(features)):
if model is None or (i - train_window) % retrain_every == 0:
train_x = torch.tensor(
features.iloc[i - train_window : i].values,
dtype=torch.float32,
)
train_y = torch.tensor(
target.iloc[i - train_window : i].values,
dtype=torch.float32,
)
x_mean, x_std = train_x.mean(0), train_x.std(0) + 1e-8
y_mean, y_std = train_y.mean(), train_y.std() + 1e-8
train_x_norm = (train_x - x_mean) / x_std
train_y_norm = (train_y - y_mean) / y_std
model, likelihood, device, _ = train_gp(
train_x_norm, train_y_norm, n_epochs=100
)
test_x = torch.tensor(
features.iloc[i : i + 1].values, dtype=torch.float32
)
test_x_norm = (test_x - x_mean) / x_std
pred = predict_with_uncertainty(model, likelihood, test_x_norm, device)
pred_mean = pred["mean"][0] * y_std.item() + y_mean.item()
pred_std = pred["std"][0] * y_std.item()
predictions.iloc[i] = [pred_mean, pred_std]
z_score = abs(pred_mean) / (pred_std + 1e-8)
if z_score > confidence_threshold:
size = min(z_score * risk_fraction, max_leverage)
positions.iloc[i] = np.sign(pred_mean) * size
strategy_returns = positions.shift(1) * returns
return strategy_returns, predictions, positions
Mise à l'échelle vers des ensembles de données plus grands avec des GP clairsemés
Lorsque la fenêtre d’entraînement dépasse quelques milliers de points, l’inférence exacte du GP devient lente. Passez à un GP clairsemé variationnel :
class SparseGPModel(gpytorch.models.ApproximateGP):
"""Sparse variational GP for large-scale return prediction."""
def __init__(self, inducing_points):
variational_distribution = (
gpytorch.variational.CholeskyVariationalDistribution(
inducing_points.size(0)
)
)
variational_strategy = (
gpytorch.variational.VariationalStrategy(
self,
inducing_points,
variational_distribution,
learn_inducing_locations=True,
)
)
super().__init__(variational_strategy)
self.mean_module = gpytorch.means.ZeroMean()
self.covar_module = gpytorch.kernels.ScaleKernel(
gpytorch.kernels.MaternKernel(nu=1.5)
)
def forward(self, x):
mean = self.mean_module(x)
covar = self.covar_module(x)
return gpytorch.distributions.MultivariateNormal(mean, covar)
def train_sparse_gp(train_x, train_y, n_inducing=128, n_epochs=50, batch_size=256):
"""Train sparse GP with mini-batch stochastic variational inference."""
indices = torch.randperm(train_x.size(0))[:n_inducing]
inducing_points = train_x[indices]
model = SparseGPModel(inducing_points)
likelihood = gpytorch.likelihoods.GaussianLikelihood()
model.train()
likelihood.train()
optimizer = torch.optim.Adam(
[{"params": model.parameters()}, {"params": likelihood.parameters()}],
lr=0.01,
)
mll = gpytorch.mlls.VariationalELBO(
likelihood, model, num_data=train_y.size(0)
)
dataset = TensorDataset(train_x, train_y)
loader = DataLoader(dataset, batch_size=batch_size, shuffle=True)
for epoch in range(n_epochs):
for x_batch, y_batch in loader:
optimizer.zero_grad()
output = model(x_batch)
loss = -mll(output, y_batch)
loss.backward()
optimizer.step()
return model, likelihood
Avec 128 points inducteurs, le coût par lot est — environ 4 millions d'opérations par lot. Cela gère facilement des ensembles de données de plus de 100 000 observations sur un seul GPU.
Deep Kernel Learning : le GP rencontre les réseaux de neurones
Lorsque l'espace d'entrée est de grande dimension ou que la relation entre les caractéristiques et les rendements est hautement non linéaire, un noyau simple peut avoir des difficultés. L'apprentissage profond du noyau (DKL) transmet les entrées via un réseau neuronal avant d'appliquer le noyau GP :
où est un réseau de neurones avec des paramètres et est un noyau standard (par exemple, Matern-3/2). Le réseau apprend une représentation de fonctionnalités où le noyau GP est le plus efficace. L'ensemble du modèle (paramètres de réseau et hyperparamètres du noyau) est formé de bout en bout en maximisant la vraisemblance marginale.
class DeepKernelGP(gpytorch.models.ExactGP):
"""GP with a neural network feature extractor."""
def __init__(self, train_x, train_y, likelihood, input_dim):
super().__init__(train_x, train_y, likelihood)
self.mean_module = gpytorch.means.ZeroMean()
self.feature_extractor = torch.nn.Sequential(
torch.nn.Linear(input_dim, 8),
torch.nn.ReLU(),
torch.nn.Linear(8, 4),
torch.nn.ReLU(),
torch.nn.Linear(4, 2),
)
self.covar_module = gpytorch.kernels.ScaleKernel(
gpytorch.kernels.MaternKernel(nu=1.5, ard_num_dims=2)
)
def forward(self, x):
features = self.feature_extractor(x)
mean = self.mean_module(features)
covar = self.covar_module(features)
return gpytorch.distributions.MultivariateNormal(mean, covar)
DKL combine l'apprentissage de la représentation des réseaux de neurones avec la quantification de l'incertitude des généralistes. La couche GP garantit que les prédictions éloignées des données d’entraînement présentent une grande incertitude – ce que les réseaux neuronaux standards ne parviennent pas à fournir. Notez également que DKL réintroduit exactement la flexibilité que la vraisemblance marginale était censée contrôler : le facteur Occam pénalise le noyau, mais le réseau devant lui a des milliers de paramètres libres et aucune pénalité de ce type.
Ludkovski et Risk (2025), Gaussian Process Models for Quantitative Finance, étudient DKL dans un contexte de finance quantitative plus large, y compris la tarification des options et l'optimisation du portefeuille ; ces résultats sont les leurs, sur leurs problèmes, et ne constituent pas une preuve de la prédiction du retour cryptographique.
Diagnostics et pièges
Calibrage
Un médecin généraliste bien calibré dispose d’intervalles prédictifs qui correspondent à la couverture empirique. La vérification est la même que celle utilisée dans prédiction conforme — qui couvre également la théorie selon laquelle la couverture marginale n'est pas une couverture conditionnelle, une limitation qui s'applique tout autant aux intervalles GP :
from scipy.stats import norm
def calibration_report(predictions, actuals):
"""Check if GP uncertainty is well-calibrated."""
z_scores = (actuals - predictions["mean"]) / (predictions["std"] + 1e-8)
for sigma in [1, 2, 3]:
expected_outside = 2 * (1 - norm.cdf(sigma))
actual_outside = (np.abs(z_scores) > sigma).mean()
print(
f"{sigma}-sigma | Expected outside: {expected_outside:.3f} | "
f"Actual outside: {actual_outside:.3f}"
)
Le dépassement attendu est de 0,317/0,046/0,003 à 1/2/3 sigma. Le nombre qui compte est ce que cela imprime sur une véritable marche en avant sur les barres cryptographiques, et ce tableau ne figure pas encore dans cet article. L'attente initiale est que le médecin généraliste est trop confiant - une probabilité gaussienne sur des rendements non stationnaires à queue large devrait mal se cacher à 3 sigma - mais "devrait" n'est pas une mesure.
Pièges restants
-
Mise à l'échelle d'entrée. Les échelles de longueur sont relatives à l'échelle d'entrée, donc une fonctionnalité s'étend et un à distance ne peut pas partager un message significatif ; ARD est ce qui sauve les plages hétérogènes, et la standardisation est ce qui rend l'initialisation d'ARD saine.
-
Surajustement de la vraisemblance marginale. Avec de nombreux hyperparamètres du noyau (en particulier les noyaux composites ou de mélange spectral), la vraisemblance marginale peut encore être surajustée. Utilisez des priors : un prior log-normal sur les échelles de longueur centrées sur la distance médiane par paire, un prior semi-normal sur les variances.
-
Conditionnement matriciel de covariance. peut devenir numériquement singulier lorsque le bruit est trop petit ou lorsque les points d'entraînement sont presque dupliqués. GPyTorch ajoute gigue en diagonale ; les données financières mal conditionnées nécessitent souvent davantage.
-
Biais d'anticipation. Couvert ci-dessus et, de manière détaillée, dans la taxonomie des biais d'anticipation.
Quand utiliser les généralistes par rapport à d'autres modèles
| Critère | Médecin généraliste | XGBoost | Réseau neuronal |
|---|---|---|---|
| Incertitude intégrée | Oui (structurel) | Non (nécessite une conformité/bootstrap) | Non (nécessite un abandon/ensemble MC) |
| Efficacité des données | Excellent (<1 000 échantillons) | * | * |
| Évolutivité | Mauvais exact, bon clairsemé | * | * |
| Non-linéarité | Dépend du noyau | * | * |
| Interprétabilité | Décomposition du noyau + échelles de longueur ARD | * | * |
| Non-stationnarité | Nécessite une fenêtre coulissante ou DKL | * | * |
* Pour les colonnes XGBoost et neural-network, reportez-vous aux comparaisons publiées plutôt qu'à une nouvelle affirmation ici : spread modeling with machine learning a le tableau gradient-boosting-vs-deep-learning pour les données tabulaires financières (seuils de taille des données, interprétabilité, adaptation du régime, latence) et fusion temporelle transformers a TFT contre LSTM contre vanilla Transformer.
Utilisez des médecins généralistes lorsque :
- Vous disposez d'ensembles de données petits à moyens (moins de ~ 10 000 observations par fenêtre de formation)
- Vous souhaitez une hypothèse structurelle explicite et inspectable sur le signal (tendance + saisonnalité + bruit)
- L'incertitude doit varier avec la distance par rapport aux données d'entraînement, pas seulement avec un quantile résiduel global
N'utilisez pas de médecins généralistes lorsque :
- Vous avez besoin d'une inférence inférieure à la milliseconde sur des millions d'observations
- La dimensionnalité d'entrée dépasse ~ 50
- Le signal vit dans des interactions complexes de fonctionnalités d'ordre élevé que les noyaux stationnaires ne peuvent pas représenter (DKL aide, au détriment de la propriété Occam)
Ce que cet article ne mesure pas encore
Tout ce qui précède est un modèle de machinerie. Rien de tout cela ne prouve qu’un médecin généraliste gagne de l’argent grâce à la cryptographie, et la norme de ce blog est que l’article comporte ses propres chiffres. Les échéances, dans l'ordre d'exécution :
- Échelles de longueur ARD sur de vraies barres BTCUSDT de 1 m. Ajustez le noyau composite, imprimez par fonctionnalité. Cela teste directement l'affirmation « ARD est une sélection de fonctionnalités intégrée » et produit un classement falsifiable par pertinence des fonctionnalités.
- Le tableau d'étalonnage d'une analyse progressive. Dépassement attendu par rapport au dépassement empirique à 1/2/3 sigma, énoncé clairement, y compris le cas où le médecin généraliste s'avère trop confiant.
- La stratégie basée sur la confiance, marche en avant, sur les cinq mêmes majors que le négatif honnête, dégonflée pour le nombre d'essais. Si elle échoue, elle s'inscrit dans cette série comme un autre résultat négatif.
- L'horloge murale courbe pour , exact par rapport à SVGP, de sorte que la section d'évolutivité repose sur un graphique au lieu d'une assertion.
Conclusion
L'argument en faveur des processus gaussiens dans le trading n'est pas « ils vous donnent des barres d'erreur » : la prédiction conforme vous donne des barres d'erreur avec moins d'hypothèses de distribution et une garantie de couverture que le GP n'a pas. Le cas est qu'un GP vous fait écrire votre hypothèse structurelle en tant que noyau, la compare à un objectif qui évalue sa propre complexité, puis vous indique laquelle de vos fonctionnalités il a réellement utilisée via les échelles de longueur ARD. C'est un modèle inhabituellement lisible.
Les coûts sont tout aussi concrets : une mise à l'échelle cubique qui plafonne votre fenêtre de formation, des hypothèses de stationnarité qu'une fenêtre déroulante ne répare que partiellement, une probabilité gaussienne que les retours à queue large seront violés et - une fois que vous aurez atteint l'apprentissage approfondi du noyau - la perte silencieuse de la propriété Occam qui a motivé la probabilité marginale en premier lieu. La question de savoir si ce qui reste est échangeable est une question empirique, et les quatre mesures énumérées ci-dessus permettraient d'y répondre.
Références
- Rasmussen, CE et Williams, CKI (2006). Processus gaussiens pour l'apprentissage automatique. Presse du MIT.
- Wilson, A. et Adams, R. (2013). Noyaux de processus gaussiens pour la découverte de modèles et l'extrapolation. ICML.
- Hensman, J., Fusi, N. et Lawrence, ND (2013). Processus gaussiens pour le Big Data. AUI.
- Gatheral, J., Jaisson, T. et Rosenbaum, M. (2018). La volatilité est rude. Finance quantitative, 18(6).
- Rizvi, SA, Roberts, SJ, Osborne, MA et Nyikosa, F. (2017). Une nouvelle approche pour prévoir la volatilité financière avec les enveloppes de processus gaussiennes. arXiv :1705.00891.
- Ludkovski, M., & Risk, J. (2025). Modèles de processus gaussiens pour la finance quantitative. Springer.
- Gardner, J.R., Pleiss, G., Bindel, D., Weinberger, K.Q. et Wilson, A.G. (2018). GPyTorch : Inférence de processus gaussien Blackbox Matrix-Matrix avec accélération GPU. NeurIPS.
Authors
Trading-systems engineer
Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.