← Torna agli articoli
August 15, 2026
5 min di lettura

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

L'apprendimento multi-task (MTL) viene solitamente venduto con un'asserzione: condividi un codificatore tra obiettivi correlati e l'attività principale migliorerà. Nel trading gli obiettivi correlati sono ovvi – rendimenti, volume e volatilità realizzata rientrano tutti nello stesso flusso di ordini – e l’affermazione non viene quasi mai verificata. La domanda interessante non è se i compiti siano correlati. Dipende se i gradienti condivisi sono d'accordo e cosa succede nelle pieghe in cui non lo sono.

Questo articolo mette al centro due cose che la maggior parte degli articoli su MTL trattano come note a piè di pagina:

  1. Il bilanciamento delle perdite è l'esperimento, non un dettaglio. I pesi fissi, la ponderazione dell'incertezza di Kendall e GradNorm sono tre modelli diversi. Eseguili tutti e tre sulle stesse pieghe e riporta i pesi appresi insieme alla metrica dell'attività principale per ciascuno.
  2. Il trasferimento negativo è misurabile prima di visualizzare la metrica. La somiglianza del coseno tra i gradienti delle attività sul codificatore condiviso indica, durante l'addestramento, se le attività ausiliarie stanno trascinando la rappresentazione da qualche parte in cui l'attività primaria vuole andare. Firma i coseni, quindi controlla se il segno prevedeva il risultato su quella piega.

Tutto il resto in cantiere – il processo di volatilità, il ciclo di formazione, i controlli delle perdite, il protocollo di validazione – è già trattato altrove su questo blog ed è collegato anziché derivato nuovamente.

Configurazione

Tre target di mercato che emergono da una rappresentazione latente condivisa

Date le caratteristiche di input xRd\mathbf{x} \in \mathbb{R}^d (OHLCV, indicatori tecnici, flusso degli ordini), tre obiettivi:

  • Attività 1 (primaria): rendimento del periodo successivo y(1)=rt+1y^{(1)} = r_{t+1}
  • Attività 2 (ausiliaria): volume del registro del periodo successivo y(2)=logVt+1y^{(2)} = \log V_{t+1}
  • Task 3 (ausiliario): volatilità realizzata nel periodo successivo y(3)=σt+1y^{(3)} = \sigma_{t+1}

Un modello multi-task li produce tutti e tre contemporaneamente, y^=fθ(x)\hat{\mathbf{y}} = f_\theta(\mathbf{x})e il rischio multi-task è una somma ponderata dei rischi per attività:

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]

L'intero articolo riguarda il wkw_k e sull'effetto reciproco dei gradienti per attività.

Perché la formazione congiunta potrebbe aiutare, in un paragrafo. I compiti ausiliari costringono la rappresentanza condivisa a spiegare più di un fenomeno di mercato, che è allo stesso tempo un controllo della capacità e un pregiudizio induttivo; e poiché il volume e la volatilità vengono osservati direttamente mentre il "rendimento atteso" non lo è, le testine ausiliarie forniscono un segnale del gradiente più pulito rispetto alla testina primaria. Il caso di un modello che emette molti output è discusso a lungo - con il meccanismo di interpretabilità allegato - in trasformatori di fusione temporale per previsioni multi-orizzonte, che utilizza lo stesso argomento del codificatore condiviso a molte teste per i quantili multi-orizzonte.

Architettura, in breve

Condivisione hardware dei parametri: un codificatore condiviso gϕg_\phi feed KK capi con compiti specifici hψkh_{\psi_k}, COSÌ y^(k)=hψk(gϕ(x))\hat{y}^{(k)} = h_{\psi_k}(g_\phi(\mathbf{x})). Questa è la versione misurata qui, perché è la versione in cui il gradiente è in conflitto ϕ\phi è ben definito.

Condivisione software dei parametri assegna a ciascuna attività il proprio codificatore con una penalità di accoppiamento λkjϕkϕj2\lambda \sum_{k \neq j} \|\phi_k - \phi_j\|^2 — più parametri, più flessibilità e nessun unico vettore di parametri condivisi su cui misurare il conflitto. Le reti a punto croce si trovano nel mezzo, mescolando le funzionalità per attività attraverso una matrice appresa αkj\alpha_{kj} ad ogni livello. Vale la pena provarli entrambi se la condivisione difficile mostra conflitti ed entrambi esulano dall'ambito della misurazione seguente.

L'esperimento che conta: tre schemi di bilanciamento delle perdite

Gradienti di attività concorrenti bilanciati attorno a un nucleo neurale condiviso

La perdita ingenua L=kwkL(k)\mathcal{L} = \sum_k w_k \mathcal{L}^{(k)} è sensibile alla scala. Se la perdita di rendimento vive in giro 0.010.01 e perdita di volume intorno 1.01.0, il volume possiede il gradiente e la testa di ritorno muore di fame. Tre risposte:

Pesi fissi. Impostato wk=1w_k = 1 dopo aver standardizzato ogni obiettivo. La linea di base onesta: se vince, gli schemi adattivi sono una cerimonia.

Ponderazione dell'incertezza (Kendall et al., 2018). Impara una scala di rumore omoschedastica σk\sigma_k per attività:

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

I compiti ad alta incertezza vengono automaticamente ridimensionati; IL logσk\log \sigma_k il termine blocca il banale σk\sigma_k \to \infty soluzione. Nota questo σk\sigma_k è un dispositivo di ponderazione della perdita in termini di tempo di addestramento, non un intervallo predittivo: per l'incertezza con cui puoi effettivamente dimensionare una posizione, vedi previsione conforme.

GradNorm (Chen et al., 2018). Gradiente di equilibrio grandezze anziché scale di perdita. Ogni passaggio: calcolo Gk=ϕwkL(k)2G_k = \|\nabla_\phi w_k \mathcal{L}^{(k)}\|_2 e la media Gˉ\bar{G}, calcolare il tasso di formazione relativo r~k=L(k)(t)/L(k)(0)rˉ\tilde{r}_k = \frac{\mathcal{L}^{(k)}(t)/\mathcal{L}^{(k)}(0)}{\bar{r}}e aggiornare 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|. Tutte le attività vengono quindi addestrate a ritmi comparabili, indipendentemente dalla scala delle perdite.

Il codice specifico di MTL è l'intestazione, il ritorno in avanti della lista e l'aggregazione delle perdite. Lo stack Linear/BatchNorm/ReLU/Dropout, il boilerplate Adam/cosine/clip e il ciclo epoch sono il modello standard mostrato in DeepLOB e vengono omessi qui.

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 ha parametri, quindi deve entrare nell'ottimizzatore insieme al modello: optim.Adam(list(model.parameters()) + list(uw.parameters()), ...). Dimenticare questo è il modo più comune per "eseguire la ponderazione dell'incertezza" e invece eseguire silenziosamente pesi fissi.

Cosa segnalare

Per ogni schema, su ogni piega: i pesi dell'attività finale appresi, la metrica del compito primario e, poiché uno schema di ponderazione è una scelta del modello, quanti schemi sono stati confrontati prima di sceglierne uno.

Schema wreturnw_{\text{return}} wvolumew_{\text{volume}} wvolw_{\text{vol}} Metrica dell'attività primaria vs attività singola
Fisso (wk=1w_k = 1) 1.00 1.00 1.00
Ponderazione dell'incertezza
GradNorm

Tre schemi per più pieghe sono già una piccola ricerca di modelli. Qualsiasi miglioramento riportato qui deve sopravvivere alla correzione dei test multipli descritta in Sharpe sgonfio e test multipli prima che abbia alcun significato.

Trasferimento negativo: firma i gradienti

Gradienti di attività allineati e in conflitto in una rappresentazione condivisa

Questa è la parte che vale la pena conservare. Il trasferimento negativo si verifica quando i compiti ausiliari peggiorano il compito primario e ha una diagnostica diretta: l'angolo tra i gradienti dei compiti nello spazio dei parametri condivisi.

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}

Misurato solo sull'encoder condiviso: le testine sono specifiche per il compito per costruzione e "concordano" sempre banalmente.

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:]
    }

Chiamatelo su un lotto sospeso a cadenza fissa durante l'allenamento, non una volta alla fine. Una coppia può iniziare allineata e divergere man mano che il codificatore si specializza; un unico numero di fine formazione lo nasconde.

La scoperta da cercare e da pubblicare in entrambi i casi:

Coppia cos sim, formazione iniziale cos sim, formazione tardiva MTL ha aiutato il compito primario?
ritorno ↔ volume
rendimento ↔ volatilità
volume ↔ volatilità

Se i gradienti di volume e volatilità concordano tra loro mentre entrambi sono in conflitto con il gradiente di rendimento, la conclusione corretta è che le due attività ausiliarie formano un blocco coerente a cui l’attività di restituzione non appartiene – e la soluzione è il raggruppamento delle attività, non una maggiore capacità. Quando il conflitto è reale, i rimedi standard sono PCGrad (Yu et al., 2020), che proietta ciascun gradiente conflittuale sul piano normale dell'altro; CAGrad (Liu et al., 2021), che ricerca una direzione di discesa che non pregiudichi alcun compito; o abbandonare completamente il compito ausiliario.

Si noti ciò che è deliberatamente assente: un grafico t-SNE della rappresentazione condivisa colorato in base al valore target. È decorativo: i numeri del coseno sopra dicono tutto ciò che l'incorporamento indicherebbe e lo dicono come numeri.

Protocollo di convalida

Finestre di convalida walk-forward separate lungo una sequenza temporale di ricerca

La misurazione di cui sopra è inutile con un protocollo approssimativo e MTL peggiora le solite trappole perché ci sono tre obiettivi da perdere invece di uno.

Dati reali, non un simulatore. Gli obiettivi devono provenire da dati OHLCV/commerciali effettivi. Un giocattolo GARCH codificato genera volatilità che è correlata ai rendimenti per costruzione, che è esattamente l'oggetto del test: l'esperimento misurerebbe il proprio generatore. Se desideri un processo di volatilità adattato, Previsione della volatilità GARCH per criptovalute adatta GARCH(1,1) con la massima verosimiglianza su BTC/ETH reali e convalida i residui standardizzati, e GARCH asimmetrico e l'effetto leva spiega perché un simulatore di risposta simmetrica gaussiana in primo luogo, valuta erroneamente la volatilità delle criptovalute. I dati sintetici sono difendibili solo quando forniscono una verità di base controllata – una correlazione di attività nota e stabilita dall’autore che stai tentando di recuperare – che è un esperimento diverso da quello qui.

Gli scaler si adattano solo al training. Adatta lo scaler di funzionalità e tutti e tre gli scaler di destinazione all'interno di ciascuna piega di training e applicali alla convalida; un globale fit_transform prima di suddividere i momenti di test delle perdite nell'addestramento. Questo esatto fallimento è catalogato nella tassonomia del look-ahead bias.

Fold walk-forward eliminati ed embargati. Una suddivisione cronologica 80/20 non è in grado di distinguere un miglioramento MTL da un effetto fold: questo è l'intero argomento di ottimizzazione walk-forward, che mostra tre suddivisioni che producono tre conclusioni. Riutilizzare la finestra espandibile purged_walk_forward generatore da spread modeling con machine learning: colma un gap di horizon righe su entrambi i lati di ciascun confine, il che è importante in questo caso perché le finestre di volatilità realizzata sovrapposte fuoriescono attraverso il confine anche quando l’obiettivo di rendimento non lo fa.

Una linea di base classica. Una rete MTL che batte tre reti a compito singolo non ha dimostrato nulla se un modello di potenziamento del gradiente o di cresta per target batte tutti e quattro. Montare un modello per target con LightGBM o colmo sulle stesse pieghe e le stesse caratteristiche e riportarlo nella stessa tabella.

Modello Metrica dell'attività primaria Note
Cresta, per bersaglio Linea di base classica
LightGBM, per destinazione Linea di base classica
MLP a attività singola, per target Tre reti separate
MTL, miglior schema di perdita Una rete, tre teste

Cosa renderebbe MTL degno di nota qui

Una soglia decisionale misurata per la complessità del modello multi-tasking

Condizioni in base alle quali MTL dovrebbe vincere, espresse come ipotesi da verificare rispetto alle pieghe di cui sopra piuttosto che come una lista di controllo:

  • Le etichette ausiliarie sono più pulite dell'etichetta primaria. Il volume viene osservato direttamente; il "rendimento atteso" non lo è. Se la testa di ritorno presenta principalmente rumore di adattamento, il segnale del gradiente proveniente dalle teste ausiliarie è l'unica parte ben posizionata dell'obiettivo.
  • I dati di addestramento sono limitati rispetto alla capacità del codificatore, quindi il vincolo ausiliario svolge un vero lavoro di regolarizzazione anziché limitarsi a competere per i parametri.
  • La latenza di inferenza è importante e un passaggio in avanti batte tre.

E l'argomentazione contraria, altrettanto verificabile: se la misura cos_sim(return, ·) i valori sono persistentemente negativi, il codificatore condiviso viene allontanato dal compito primario e le teste ausiliarie sono una tassa, non un regolarizzatore.

Conclusione

Flussi di previsione armonizzati che si risolvono in una conclusione multi-task

Rendimenti, volume e volatilità provengono dalla stessa microstruttura, quindi una rappresentazione condivisa è un ragionevole valore a priori, ma un valore a priori non è un risultato. Le due cose che questa configurazione può effettivamente stabilire sono quale schema di bilanciamento delle perdite i dati preferiscono (con i pesi appresi riportati, non solo il nome del vincitore) e se i gradienti del compito sul codificatore condiviso concordano, misurati durante l'allenamento piuttosto che presupposti dal fatto che gli obiettivi sono correlati.

Se le pieghe walk-forward eliminate mostrano che la rete MTL non riesce a battere un modello di potenziamento del gradiente per target, questa è la scoperta e viene pubblicata come tale: il modello è il negativo onesto. Un risultato negativo su un trasferimento negativo è pur sempre un risultato su un trasferimento negativo.

Disclaimer: le informazioni fornite in questo articolo hanno solo scopo didattico e informativo e non costituiscono consulenza finanziaria, di investimento o di trading. Il trading di criptovalute comporta un rischio significativo di perdita.

Autori

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

Resta un Passo Avanti al Mercato

Iscriviti alla nostra newsletter per approfondimenti esclusivi sul trading con IA, analisi di mercato e aggiornamenti sulla piattaforma.

Rispettiamo la tua privacy. Annulla l'iscrizione in qualsiasi momento.