Multi-Task Learning for Simultaneous Price, Volume, and Volatility Prediction
Multitasking-Lernen (MTL) wird normalerweise mit der Behauptung verkauft: Teilen Sie einen Encoder über korrelierte Ziele hinweg und die primäre Aufgabe wird besser. Beim Handel sind die korrelierten Ziele offensichtlich – Rendite, Volumen und realisierte Volatilität fallen alle aus demselben Auftragsfluss – und diese Behauptung wird fast nie überprüft. Die interessante Frage ist nicht, ob die Aufgaben miteinander zusammenhängen. Es geht darum, ob die gemeinsamen Farbverläufe übereinstimmen und was an den Falten passiert, wo sie nicht übereinstimmen.
In diesem Artikel stehen zwei Dinge im Mittelpunkt, die in den meisten MTL-Aufsätzen als Fußnoten behandelt werden:
- Verlustausgleich ist ein Experiment, kein Detail. Feste Gewichte, Kendall-Unsicherheitsgewichtung und GradNorm sind drei verschiedene Modelle. Führen Sie alle drei auf den gleichen Falten aus und geben Sie die gelernten Gewichtungen zusammen mit der Metrik für die primäre Aufgabe für jede an.
- Negative Übertragung ist messbar, bevor Sie die Metrik sehen. Die Kosinusähnlichkeit zwischen Aufgabengradienten auf dem gemeinsam genutzten Encoder sagt Ihnen während des Trainings, ob die Hilfsaufgaben die Darstellung dorthin ziehen, wohin die primäre Aufgabe gehen möchte. Unterzeichnen Sie den Kosinus und prüfen Sie dann, ob das Vorzeichen das Ergebnis dieser Falte vorhersagte.
Alles andere in der Pipeline – der Volatilitätsprozess, die Trainingsschleife, die Leckkontrollen, das Validierungsprotokoll – wird bereits an anderer Stelle in diesem Blog behandelt und verlinkt, anstatt erneut abgeleitet zu werden.
Einrichtung

Gegebene Eingabefunktionen (OHLCV, technische Indikatoren, Auftragsfluss), drei Ziele:
- Aufgabe 1 (primär): Rückkehr in die nächste Periode
- Aufgabe 2 (Hilfsaufgabe): Protokollvolumen der nächsten Periode
- Aufgabe 3 (Hilfsaufgabe): Realisierte Volatilität der nächsten Periode
Ein Multitask-Modell erzeugt alle drei gleichzeitig, , und das Multitask-Risiko ist eine gewichtete Summe der Risiken pro Task:
Im ganzen Artikel geht es um die und darüber, was die Farbverläufe pro Aufgabe miteinander machen.
Warum gemeinsames Training hilfreich sein könnte, in einem Absatz. Hilfsaufgaben schränken die gemeinsame Darstellung ein, um mehr als ein Marktphänomen zu erklären, das gleichzeitig eine Kapazitätskontrolle und eine induktive Verzerrung darstellt; Und da Volumen und Volatilität direkt beobachtet werden, die „erwartete Rendite“ jedoch nicht, liefern die Hilfsköpfe ein klareres Gradientensignal als der Primärkopf. Der Fall, dass ein Modell viele Ausgaben aussendet, wird – mit der angeschlossenen Interpretierbarkeitsmaschinerie – ausführlich in Temporal Fusion Transformers for Multi-Horizon Forecasting dargelegt, was das gleiche Shared-Encoder-Many-Heads-Argument für Multi-Horizon-Quantile vorschlägt.
Architektur, kurz
Harte Parameterfreigabe: ein gemeinsam genutzter Encoder füttert aufgabenspezifische Köpfe , Also . Dies ist die hier gemessene Version, da es sich um die Version handelt, bei der ein Farbverlaufskonflikt auftritt ist wohldefiniert.
Soft Parameter Sharing gibt jeder Aufgabe einen eigenen Encoder mit einer Kopplungsstrafe – mehr Parameter, mehr Flexibilität und kein einzelner gemeinsamer Parametervektor, an dem Konflikte gemessen werden könnten. Kreuzstichnetzwerke liegen dazwischen und mischen Funktionen pro Aufgabe durch eine erlernte Matrix auf jeder Ebene. Es lohnt sich, beides auszuprobieren, wenn beim Hard Sharing Konflikte auftreten, und beide außerhalb des Rahmens der folgenden Messung liegen.
Das Experiment, das zählt: Drei Verlustausgleichssysteme

Der naive Verlust ist maßstabsabhängig. Wenn die Rückflussdämpfung in der Nähe ist und Volumenverlust herum , das Volumen besitzt den Gradienten und die Rückförderhöhe verhungert. Drei Antworten:
Feste Gewichte. Set nach der Standardisierung jedes Ziels. Die ehrliche Grundlinie – wenn sie gewinnt, sind die adaptiven Schemata eine Zeremonie.
Unsicherheitsgewichtung (Kendall et al., 2018). Lernen Sie eine homoskedastische Rauschskala pro Aufgabe:
Aufgaben mit hoher Unsicherheit werden automatisch herabgestuft; Die Begriff blockiert das Triviale Lösung. Beachten Sie dies ist ein Verlustgewichtungsgerät für die Trainingszeit, kein Vorhersageintervall – Informationen zur Unsicherheit, mit der Sie tatsächlich eine Position dimensionieren können, finden Sie unter konforme Vorhersage.
GradNorm (Chen et al., 2018). Gleichgewichtsgradienten Größen statt Verlustskalen. Jeder Schritt: Berechnen und der Mittelwert , berechnen Sie die relative Trainingsrate , und aktualisieren . Alle Aufgaben werden dann unabhängig vom Verlustumfang mit vergleichbaren Raten trainiert.
Der MTL-spezifische Code besteht aus den Köpfen, dem List-Return-Forward und der Verlustaggregation. Der Linear/BatchNorm/ReLU/Dropout-Stack, die Adam/Cosine/Clip-Boilerplate und die Epochenschleife sind die in DeepLOB gezeigten Standardmuster und werden hier weggelassen.
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 verfügt über Parameter und muss daher zusammen mit dem Modell in den Optimierer eingefügt werden: optim.Adam(list(model.parameters()) + list(uw.parameters()), ...). Dies zu vergessen ist die häufigste Methode, „Unsicherheitsgewichtungen durchzuführen“ und stattdessen stillschweigend feste Gewichtungen auszuführen.
Was zu melden ist
Für jedes Schema, auf jeder Falte: die erlernten Gewichtungen der endgültigen Aufgabe, die Metrik der primären Aufgabe und – da es sich bei einem Gewichtungsschema um eine Modellauswahl handelt – wie viele Schemata verglichen wurden, bevor eines ausgewählt wurde.
| Schema | Metrik für primäre Aufgabe vs. Einzelaufgabe | |||
|---|---|---|---|---|
| Behoben () | 1,00 | 1,00 | 1,00 | — |
| Unsicherheitsgewichtung | — | — | — | — |
| GradNorm | — | — | — | — |
Drei Schemata mal mehrere Falten ist schon eine kleine Modellsuche. Jede hier gemeldete Verbesserung muss die in deflated Sharpe und multiple Tests beschriebene Korrektur mehrerer Tests überstehen, bevor sie etwas bedeutet.
Negative Übertragung: Signieren Sie die Farbverläufe

Das ist der Teil, den es wert ist, behalten zu werden. Von einer negativen Übertragung spricht man, wenn Hilfsaufgaben die Hauptaufgabe verschlechtern, und es gibt eine direkte Diagnose: den Winkel zwischen Aufgabengradienten im gemeinsamen Parameterraum.
Nur am gemeinsamen Encoder gemessen – die Köpfe sind konstruktionsbedingt aufgabenspezifisch und „stimmen“ immer trivial überein.
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:]
}
Rufen Sie dies während des Trainings in einer durchgehaltenen Gruppe mit einer festen Kadenz auf, nicht einmal am Ende. Ein Paar kann zunächst ausgerichtet sein und auseinanderlaufen, wenn sich der Encoder spezialisiert; Eine einzelne Abschlussnummer verbirgt dies.
Der Befund, nach dem man suchen und den man so oder so veröffentlichen sollte:
| Paar | cos sim, frühes Training | cos sim, spätes Training | MTL hat bei der Hauptaufgabe geholfen? |
|---|---|---|---|
| zurück ↔ Volumen | — | — | — |
| Rendite ↔ Volatilität | — | — | — |
| Volumen ↔ Volatilität | — | — | — |
Wenn Volumen- und Volatilitätsgradienten miteinander übereinstimmen, während beide mit dem Rückgabegradienten in Konflikt stehen, ist die richtige Schlussfolgerung, dass die beiden Hilfsaufgaben einen kohärenten Block bilden, zu dem die Rückgabeaufgabe nicht gehört – und die Lösung ist die Aufgabengruppierung, nicht mehr Kapazität. Wenn ein Konflikt real ist, sind die Standardlösungen PCGrad (Yu et al., 2020), das jeden widersprüchlichen Gradienten auf die Normalebene des anderen projiziert; CAGrad (Liu et al., 2021), das nach einer Abstiegsrichtung sucht, die keiner Aufgabe schadet; oder die Hilfsaufgabe ganz fallen lassen.
Beachten Sie, was bewusst fehlt: ein t-SNE-Diagramm der gemeinsamen Darstellung, gefärbt nach Zielwert. Es ist dekorativ – die Kosinuszahlen oben sagen alles aus, worauf die Einbettung hinweisen würde, und sie sagen es als Zahlen.
Validierungsprotokoll

Die obige Messung ist unter einem schlampigen Protokoll wertlos, und MTL macht die üblichen Fallen noch schlimmer, weil es drei Ziele gibt, die durchgesickert sind, statt eines.
Echte Daten, kein Simulator. Die Ziele müssen aus tatsächlichen OHLCV-/Handelsdaten stammen. Ein fest codiertes GARCH-Spielzeug erzeugt Volatilität, die konstruktionsbedingt mit Renditen korreliert, was genau das ist, was getestet wird – das Experiment würde seinen eigenen Generator messen. Wenn Sie einen angepassten Volatilitätsprozess wünschen, passt GARCH-Volatilitätsprognose für Krypto GARCH(1,1) nach maximaler Wahrscheinlichkeit an reale BTC/ETH an und validiert die standardisierten Residuen, und asymmetrisches GARCH und der Leverage-Effekt erläutert, warum eine Gaußsche Funktion verwendet wird Der Symmetry-Response-Simulator gibt die Kryptovolatilität von vornherein falsch an. Synthetische Daten sind nur dann vertretbar, wenn sie eine kontrollierte Grundwahrheit liefern – eine bekannte, vom Autor festgelegte Aufgabenkorrelation, die Sie wiederherzustellen versuchen –, was ein anderes Experiment als das hier ist.
Skalierer passen nur auf den Zug. Platzieren Sie den Feature-Skalierer und alle drei Ziel-Skalierer in jeder Trainingsfalte und wenden Sie sie auf die Validierung an; ein globaler fit_transform Bevor Sie Lecks aufteilen, testen Sie Momente in das Training. Dieser genaue Fehler ist in der Look-Ahead-Bias-Taxonomie katalogisiert.
Gelöschte, mit einem Embargo belegte Walk-Forward-Falten. Eine 80/20-chronologische Aufteilung kann eine MTL-Verbesserung nicht von einem Fold-Effekt unterscheiden – das ist das gesamte Argument der Walk-Forward-Optimierung, das zeigt, dass drei Aufteilungen zu drei Schlussfolgerungen führen. Verwenden Sie das Erweiterungsfenster erneut purged_walk_forward Generator von Spread-Modellierung mit maschinellem Lernen: Es schließt eine Lücke von horizon Zeilen auf beiden Seiten jeder Grenze, was hier wichtig ist, da überlappende Fenster der realisierten Volatilität über die Grenze hinweg auslaufen, selbst wenn das Renditeziel dies nicht tut.
Eine klassische Grundlinie. Ein MTL-Netz, das drei Einzelaufgabennetze übertrifft, hat nichts bewiesen, wenn ein Gradientenverstärkungs- oder Ridge-Modell pro Ziel alle vier übertrifft. Passen Sie ein Modell pro Ziel mit LightGBM oder Grat an denselben Falten und denselben Merkmalen an und geben Sie es in derselben Tabelle an.
| Modell | Primäre Aufgabenmetrik | Notizen |
|---|---|---|
| Grat, pro Ziel | — | Klassische Grundlinie |
| LightGBM, pro Ziel | — | Klassische Grundlinie |
| Einzeltask-MLP, pro Ziel | — | Drei separate Netze |
| MTL, bestes Verlustschema | — | Ein Netz, drei Köpfe |
Was würde MTL hier lohnenswert machen?

Bedingungen, unter denen MTL gewinnen sollte, angegeben als Hypothesen zur Überprüfung anhand der oben genannten Falten und nicht als Checkliste:
- Hilfsetiketten sind sauberer als das Primäretikett. Das Volumen wird direkt beobachtet; „erwartete Rendite“ ist es nicht. Wenn der Rücklaufkopf größtenteils aus passendem Rauschen besteht, ist das Gradientensignal von den Hilfsköpfen der einzige gut positionierte Teil des Objektivs.
- Trainingsdaten sind im Verhältnis zur Encoderkapazität begrenzt, sodass die Hilfsbeschränkung echte Regularisierungsarbeit leistet und nicht nur um Parameter konkurriert. – Die Inferenzlatenz ist wichtig und ein Vorwärtspass schlägt drei.
Und der Fall dagegen, ebenso prüfbar: wenn das gemessen wird cos_sim(return, ·) Die Werte sind dauerhaft negativ, der gemeinsame Encoder wird von der primären Aufgabe abgezogen und die Hilfsköpfe sind eine Steuer, kein Regularisierer.
Fazit

Renditen, Volumen und Volatilität stammen aus derselben Mikrostruktur, daher ist eine gemeinsame Darstellung ein vernünftiger Prior – aber ein Prior ist kein Ergebnis. Die beiden Dinge, die dieses Setup tatsächlich feststellen kann, sind, welches Verlustausgleichsschema die Daten bevorzugen (mit den erlernten Gewichtungen werden berichtet, nicht nur der Gewinner genannt) und ob die Aufgabengradienten auf dem gemeinsam genutzten Encoder übereinstimmen, gemessen über das Training und nicht aufgrund der Tatsache, dass die Ziele korrelieren.
Wenn die bereinigten Walk-Forward-Falten zeigen, dass das MTL-Netz ein Gradienten-verstärkendes Modell pro Ziel nicht schlagen kann, ist das das Ergebnis und wird als solches veröffentlicht – die Vorlage ist das ehrliche Negativ. Ein negatives Ergebnis einer negativen Übertragung ist immer noch ein Ergebnis einer negativen Übertragung.
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.