← Volver a los artículos
August 15, 2026
5 min de lectura

Multi-Task Learning for Simultaneous Price, Volume, and Volatility Prediction

Multi-Task Learning for Simultaneous Price, Volume, and Volatility Prediction
#deep-learning
#multi-task
#shared-representation
#prediction
#auxiliary

El aprendizaje multitarea (MTL) generalmente se vende con una afirmación: comparta un codificador entre objetivos correlacionados y la tarea principal mejorará. En el comercio, los objetivos correlacionados son obvios (los rendimientos, el volumen y la volatilidad observada caen todos fuera del mismo flujo de órdenes) y la afirmación casi nunca se prueba. La pregunta interesante no es si las tareas están relacionadas. Se trata de si los gradientes compartidos concuerdan y qué sucede en los pliegues donde no lo hacen.

Este artículo centra dos cosas que la mayoría de los artículos de MTL tratan como notas a pie de página:

  1. El equilibrio de pérdidas es un experimento, no un detalle. Las ponderaciones fijas, la ponderación de incertidumbre de Kendall y GradNorm son tres modelos diferentes. Ejecute los tres en los mismos pliegues e informe los pesos aprendidos junto con la métrica de la tarea principal para cada uno.
  2. La transferencia negativa se puede medir antes de ver la métrica. La similitud del coseno entre los gradientes de tareas en el codificador compartido le indica, durante el entrenamiento, si las tareas auxiliares están llevando la representación a algún lugar al que la tarea principal quiere ir. Firma los cosenos y luego verifica si el signo predijo el resultado en ese pliegue.

Todo lo demás en proceso (el proceso de volatilidad, el ciclo de capacitación, los controles de fugas, el protocolo de validación) ya se trata en otras partes de este blog y está vinculado en lugar de derivarse nuevamente.

Configuración

Tres objetivos de mercado que surgen de una representación latente compartida

Características de entrada dadas xRd\mathbf{x} \in \mathbb{R}^d (OHLCV, indicadores técnicos, flujo de pedidos), tres objetivos:

  • Tarea 1 (primaria): retorno del próximo período y(1)=rt+1y^{(1)} = r_{t+1}
  • Tarea 2 (auxiliar): volumen de registro del siguiente período y(2)=logVt+1y^{(2)} = \log V_{t+1}
  • Tarea 3 (auxiliar): volatilidad realizada en el próximo período y(3)=σt+1y^{(3)} = \sigma_{t+1}

Un modelo multitarea produce las tres simultáneamente, y^=fθ(x)\hat{\mathbf{y}} = f_\theta(\mathbf{x}), y el riesgo de múltiples tareas es una suma ponderada de los riesgos por tarea:

RMTL(θ)=k=1KwkE[(k)(fθ(k)(x),y(k))]\mathcal{R}_{\text{MTL}}(\theta) = \sum_{k=1}^{K} w_k \cdot \mathbb{E}\bigl[\ell^{(k)}(f_\theta^{(k)}(\mathbf{x}), y^{(k)})\bigr]

Todo el artículo trata sobre el wkw_k y sobre lo que los gradientes por tarea se hacen entre sí.

Por qué la capacitación conjunta podría ayudar, en un párrafo. Las tareas auxiliares limitan la representación compartida para explicar más de un fenómeno de mercado, lo cual es un control de capacidad y un sesgo inductivo al mismo tiempo; y debido a que el volumen y la volatilidad se observan directamente mientras que el "retorno esperado" no, los cabezales auxiliares proporcionan una señal de gradiente más limpia que el cabezal primario. El argumento a favor de un modelo que emite muchos resultados se discute extensamente, con la maquinaria de interpretabilidad adjunta, en transformadores de fusión temporal para pronósticos de múltiples horizontes, que presenta el mismo argumento de codificador compartido de muchas cabezas para cuantiles de múltiples horizontes.

Arquitectura, brevemente

Compartir parámetros de forma estricta: un codificador compartido gϕg_\phi alimenta KK jefes de tareas específicas hψkh_{\psi_k}, entonces y^(k)=hψk(gϕ(x))\hat{y}^{(k)} = h_{\psi_k}(g_\phi(\mathbf{x})). Esta es la versión medida aquí, porque es la versión en la que el gradiente entra en conflicto. ϕ\phi está bien definido.

El intercambio suave de parámetros le da a cada tarea su propio codificador con una penalización de acoplamiento λkjϕkϕj2\lambda \sum_{k \neq j} \|\phi_k - \phi_j\|^2 — más parámetros, más flexibilidad y ningún vector de parámetros compartido único para medir el conflicto. Redes de punto de cruz se ubican en el medio, mezclando características por tarea a través de una matriz aprendida αkj\alpha_{kj} en cada nivel. Vale la pena probar ambos si el intercambio intenso muestra conflicto, y ambos están fuera del alcance de la medición a continuación.

El experimento que importa: tres esquemas de equilibrio de pérdidas

Gradientes de tareas en competencia equilibrados alrededor de un núcleo neuronal compartido

La ingenua pérdida L=kwkL(k)\mathcal{L} = \sum_k w_k \mathcal{L}^{(k)} es sensible a la escala. Si la pérdida de retorno sigue viva 0.010.01 y pérdida de volumen alrededor 1.01.0, el volumen es dueño del gradiente y la cabeza de retorno muere de hambre. Tres respuestas:

Pesas fijas. Conjunto wk=1w_k = 1 después de estandarizar cada objetivo. La línea de base honesta: si gana, los esquemas de adaptación son una ceremonia.

Ponderación de la incertidumbre (Kendall et al., 2018). Aprenda una escala de ruido homocedástica σk\sigma_k por tarea:

LMTL=k=1K12σk2L(k)+logσk\mathcal{L}_{\text{MTL}} = \sum_{k=1}^{K} \frac{1}{2\sigma_k^2} \mathcal{L}^{(k)} + \log \sigma_k

Las tareas de alta incertidumbre se reducen automáticamente; el logσk\log \sigma_k término bloquea lo trivial σk\sigma_k \to \infty solución. Tenga en cuenta esto σk\sigma_k es un dispositivo para ponderar la pérdida de tiempo de entrenamiento, no un intervalo predictivo; para conocer la incertidumbre con la que realmente puede dimensionar una posición, consulte predicción conforme.

GradNorm (Chen et al., 2018). Gradiente de equilibrio magnitudes en lugar de escalas de pérdida. Cada paso: calcular Gk=ϕwkL(k)2G_k = \|\nabla_\phi w_k \mathcal{L}^{(k)}\|_2 y la media Gˉ\bar{G}, calcular la tasa de entrenamiento relativa r~k=L(k)(t)/L(k)(0)rˉ\tilde{r}_k = \frac{\mathcal{L}^{(k)}(t)/\mathcal{L}^{(k)}(0)}{\bar{r}}y actualizar wkwkηwwkkGkGˉr~kαw_k \leftarrow w_k - \eta_w \nabla_{w_k} \sum_k |G_k - \bar{G} \cdot \tilde{r}_k^\alpha|. Luego, todas las tareas se entrenan a ritmos comparables, independientemente de la escala de pérdidas.

El código específico de MTL son los encabezados, el avance de lista y la agregación de pérdidas. La pila Linear/BatchNorm/ReLU/Dropout, el texto estándar de Adam/coseno/clip y el bucle de época son el patrón estándar que se muestra en DeepLOB y se omiten aquí.

import torch
import torch.nn as nn


class MultiTaskTradingModel(nn.Module):
    """Hard parameter sharing: one encoder, K heads."""

    def __init__(self, encoder: nn.Module, repr_dim: int, n_tasks: int = 3):
        super().__init__()
        self.shared_encoder = encoder          # any MLP/CNN/GRU trunk
        self.task_heads = nn.ModuleList(
            nn.Linear(repr_dim, 1) for _ in range(n_tasks)
        )

    def forward(self, x):
        h = self.shared_encoder(x)
        return [head(h).squeeze(-1) for head in self.task_heads]

    def shared_repr(self, x):
        return self.shared_encoder(x)


class UncertaintyWeightedLoss(nn.Module):
    """Kendall et al. (2018) homoscedastic weighting."""

    def __init__(self, n_tasks: int = 3):
        super().__init__()
        self.log_vars = nn.Parameter(torch.zeros(n_tasks))  # log(sigma^2)

    def forward(self, losses: list) -> torch.Tensor:
        return sum(
            torch.exp(-self.log_vars[i]) * loss + self.log_vars[i]
            for i, loss in enumerate(losses)
        )

    def get_weights(self) -> list:
        with torch.no_grad():
            return [torch.exp(-lv).item() for lv in self.log_vars]

UncertaintyWeightedLoss tiene parámetros, por lo que debe ingresar al optimizador junto con el modelo: optim.Adam(list(model.parameters()) + list(uw.parameters()), ...). Olvidar esto es la forma más común de "ejecutar ponderación de incertidumbre" y, en su lugar, ejecutar silenciosamente ponderaciones fijas.

Qué reportar

Para cada esquema, en cada pliegue: las ponderaciones de la tarea final aprendidas, la métrica de la tarea principal y, debido a que un esquema de ponderación es una elección de modelo, cuántos esquemas se compararon antes de elegir uno.

Esquema wreturnw_{\text{return}} wvolumew_{\text{volume}} wvolw_{\text{vol}} Métrica de tarea principal versus tarea única
Fijado (wk=1w_k = 1) 1,00 1,00 1,00
Ponderación de la incertidumbre
Norma de graduación

Tres esquemas multiplicados por varios pliegues ya es una pequeña búsqueda de modelos. Cualquier mejora reportada aquí tiene que sobrevivir a la corrección de pruebas múltiples descrita en Sharpe deflactado y pruebas múltiples antes de que signifique algo.

Transferencia Negativa: Firma los Degradados

Gradientes de tareas alineados y en conflicto en una representación compartida

Esta es la parte que vale la pena conservar. La transferencia negativa ocurre cuando las tareas auxiliares empeoran la tarea principal y tiene un diagnóstico directo: el ángulo entre los gradientes de la tarea en el espacio de parámetros compartido.

cos(ϕL(k),ϕL(j))<0    conflicting tasks\cos\bigl(\nabla_\phi \mathcal{L}^{(k)}, \nabla_\phi \mathcal{L}^{(j)}\bigr) < 0 \implies \text{conflicting tasks}

Medido únicamente en el codificador compartido: los cabezales son específicos de la tarea por construcción y siempre "están de acuerdo" trivialmente.

import torch.nn.functional as F


def shared_grad(model, x, y, task_idx, criterion=nn.MSELoss()):
    """Gradient of task `task_idx` w.r.t. the shared encoder, flattened."""
    model.zero_grad(set_to_none=True)
    loss = criterion(model(x)[task_idx], y)
    loss.backward()
    return torch.cat([
        p.grad.detach().flatten()
        for p in model.shared_encoder.parameters()
        if p.grad is not None
    ])


def task_conflict(model, x, y_by_task, task_names):
    """Pairwise cosine similarity between per-task shared-encoder gradients."""
    grads = {
        name: shared_grad(model, x, y_by_task[name], i)
        for i, name in enumerate(task_names)
    }
    return {
        (a, b): F.cosine_similarity(
            grads[a].unsqueeze(0), grads[b].unsqueeze(0)
        ).item()
        for i, a in enumerate(task_names)
        for b in task_names[i + 1:]
    }

Llame a esto en un lote retenido a una cadencia fija durante el entrenamiento, no una vez al final. Un par puede comenzar alineado y divergir a medida que el codificador se especializa; un único número de fin de formación lo oculta.

El hallazgo que hay que buscar y publicar de cualquier manera:

Par cos sim, formación temprana cos sim, entrenamiento tardío ¿MTL ayudó a la tarea principal?
volver ↔ volumen
rentabilidad ↔ volatilidad
volumen ↔ volatilidad

Si los gradientes de volumen y volatilidad concuerdan entre sí mientras ambos entran en conflicto con el gradiente de retorno, la conclusión correcta es que las dos tareas auxiliares forman un bloque coherente al que la tarea de retorno no pertenece, y la solución es agrupar las tareas, no más capacidad. Cuando el conflicto es real, las soluciones estándar son PCGrad (Yu et al., 2020), que proyecta cada gradiente en conflicto en el plano normal del otro; CAGrad (Liu et al., 2021), que busca una dirección de descenso que no perjudique ninguna tarea; o abandonar por completo la tarea auxiliar.

Tenga en cuenta lo que está deliberadamente ausente: un gráfico t-SNE de la representación compartida coloreado por el valor objetivo. Es decorativo: los números cosenos de arriba dicen todo lo que indicaría la incrustación, y lo dicen como números.

Protocolo de validación

Ventanas de validación de avance separadas a lo largo de una línea de tiempo de investigación

La medición anterior no tiene valor bajo un protocolo descuidado, y MTL empeora las trampas habituales porque hay tres objetivos para filtrar en lugar de uno.

Datos reales, no un simulador. Los objetivos deben provenir de datos comerciales/OHLCV reales. Un juguete GARCH codificado genera volatilidad que se correlaciona con los rendimientos por construcción, que es precisamente lo que se está probando: el experimento estaría midiendo su propio generador. Si desea un proceso de volatilidad ajustado, Pronóstico de volatilidad GARCH para criptomonedas ajusta GARCH(1,1) por máxima probabilidad en BTC/ETH real y valida los residuos estandarizados, y GARCH asimétrico y el efecto de apalancamiento cubre por qué un simulador de respuesta simétrica gaussiana En primer lugar, tergiversa la volatilidad de las criptomonedas. Los datos sintéticos sólo son defendibles cuando proporcionan una verdad sobre el terreno controlada (una correlación de tareas conocida y establecida por el autor que se intenta recuperar), que es un experimento diferente al que se presenta aquí.

Los escaladores solo caben en el tren. Coloque el escalador de funciones y los tres escaladores de destino dentro de cada pliegue de entrenamiento y aplíquelos a la validación; un global fit_transform antes de dividir los momentos de prueba de fugas en entrenamiento. Esta falla exacta está catalogada en la taxonomía de sesgo de anticipación.

Pliegues de avance purgados y embargados. Una división cronológica 80/20 no puede distinguir una mejora de MTL de un efecto de pliegue; ese es todo el argumento de optimización de avance, que muestra tres divisiones que producen tres conclusiones. Reutilizar la ventana desplegable purged_walk_forward generador de modelado extendido con aprendizaje automático: elimina una brecha de horizon filas a ambos lados de cada límite, lo cual es importante aquí porque las ventanas superpuestas de volatilidad realizada se filtran a través del límite incluso cuando el objetivo de retorno no lo hace.

Una línea de base clásica. Una red MTL que supera a tres redes de tarea única no ha demostrado nada si un modelo de cresta o de aumento de gradiente por objetivo supera a los cuatro. Coloque un modelo por objetivo con LightGBM o cresta en los mismos pliegues y las mismas características, e infórmelo en la misma tabla.

Modelo Métrica de tarea principal Notas
Cresta, por objetivo Línea de base clásica
LightGBM, por objetivo Línea de base clásica
MLP de tarea única, por objetivo Tres redes separadas
MTL, el mejor esquema de pérdidas Una red, tres cabezas

¿Qué haría que MTL valga la pena aquí?

Un umbral de decisión medido para la complejidad del modelo multitarea

Condiciones bajo las cuales MTL debería ganar, expresadas como hipótesis para comparar con los pliegues anteriores en lugar de una lista de verificación:

  • Las etiquetas auxiliares son más limpias que la etiqueta principal. El volumen se observa directamente; El "retorno esperado" no lo es. Si el cabezal de retorno produce principalmente ruido de ajuste, la señal de gradiente de los cabezales auxiliares es la única parte bien colocada del objetivo.
  • Los datos de entrenamiento están limitados en relación con la capacidad del codificador, por lo que la restricción auxiliar realiza un trabajo de regularización real en lugar de simplemente competir por los parámetros.
  • La latencia de inferencia importa y un pase hacia adelante gana a tres.

Y el caso en contra, igualmente comprobable: si la medida cos_sim(return, ·) Los valores son persistentemente negativos, el codificador compartido se está alejando de la tarea principal y los cabezales auxiliares son un impuesto, no un regularizador.

Conclusión

Flujos de predicción armonizados que se resuelven en una conclusión multitarea

Los rendimientos, el volumen y la volatilidad provienen de la misma microestructura, por lo que una representación compartida es un previo razonable, pero un previo no es un resultado. Las dos cosas que esta configuración realmente puede establecer son qué esquema de equilibrio de pérdidas prefieren los datos (con los pesos aprendidos informados, no solo con el nombre del ganador) y si los gradientes de las tareas en el codificador compartido coinciden, medidos durante el entrenamiento en lugar de asumidos por el hecho de que los objetivos están correlacionados.

Si los pliegues de avance purgados muestran que la red MTL no logra superar un modelo de aumento de gradiente por objetivo, ese es el hallazgo y se publica como tal: la plantilla es el negativo honesto. Un resultado negativo sobre una transferencia negativa sigue siendo un resultado sobre una transferencia negativa.

blog.disclaimer

Authors

Eugen Soloviov
Eugen Soloviov

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.

Newsletter

Mantente a la vanguardia

Suscríbete a nuestro boletín para recibir información exclusiva sobre trading con IA, análisis de mercado y actualizaciones de la plataforma.

Respetamos tu privacidad. Puedes darte de baja en cualquier momento.