Multi-Task Learning for Simultaneous Price, Volume, and Volatility Prediction
Pembelajaran pelbagai tugas (MTL) biasanya dijual dengan satu dakwaan: kongsikan encoder merentas sasaran yang berkorelasi dan tugas utama akan menjadi lebih baik. Dalam dagangan, sasaran yang berkorelasi itu jelas — pulangan, volume dan volatiliti terealisasi semuanya muncul daripada order flow yang sama — dan dakwaan itu hampir tidak pernah diuji. Soalan yang menarik bukan sama ada tugas-tugas itu berkaitan. Soalannya ialah sama ada gradient yang dikongsi selaras, dan apa yang berlaku pada fold apabila ia tidak selaras.
Artikel ini meletakkan dua perkara di tengah-tengah yang biasanya dianggap sebagai nota kaki dalam tulisan MTL:
- Pengimbangan loss ialah eksperimen, bukan perincian. Bobot tetap, pembobotan ketidakpastian Kendall dan GradNorm ialah tiga model yang berbeza. Jalankan ketiga-tiganya pada fold yang sama dan laporkan bobot yang dipelajari bersama metrik tugas utama bagi setiap satu.
- Negative transfer boleh diukur sebelum anda melihat metrik. Kesamaan kosinus antara gradient tugas pada encoder dikongsi memberitahu anda, semasa training, sama ada tugas tambahan menarik representasi ke arah yang dikehendaki tugas utama. Tandakan kosinus, kemudian periksa sama ada tandanya meramalkan hasil pada fold itu.
Segala-galanya yang lain dalam pipeline — proses volatiliti, training loop, kawalan kebocoran, protokol pengesahan — telah diliputi di tempat lain dalam blog ini dan dipautkan, bukannya diterbitkan semula.
Persediaan

Diberikan ciri input (OHLCV, penunjuk teknikal, order flow), terdapat tiga sasaran:
- Tugas 1 (utama): pulangan tempoh seterusnya
- Tugas 2 (tambahan): log volume tempoh seterusnya
- Tugas 3 (tambahan): volatiliti terealisasi tempoh seterusnya
Model pelbagai tugas menghasilkan ketiga-tiganya serentak, , dan risiko pelbagai tugas ialah jumlah berpemberat bagi risiko setiap tugas:
Keseluruhan artikel ini berkisar pada dan perkara yang dilakukan oleh gradient setiap tugas terhadap tugas lain.
Mengapa latihan bersama mungkin membantu, dalam satu perenggan. Tugas tambahan mengehadkan representasi dikongsi supaya ia menerangkan lebih daripada satu fenomena pasaran, yang menjadi kawalan kapasiti dan bias induktif pada masa yang sama; dan kerana volume serta volatiliti diperhatikan secara langsung sedangkan "expected return" tidak, head tambahan membekalkan isyarat gradient yang lebih bersih daripada head utama. Kes untuk satu model yang mengeluarkan banyak output dihujahkan dengan panjang — bersama machinery interpretability — dalam temporal fusion transformers untuk ramalan berbilang horizon, yang membuat hujah encoder dikongsi-banyak head yang sama untuk quantile berbilang horizon.
Seni bina secara ringkas
Hard parameter sharing: encoder dikongsi memberi makan kepada head khusus tugas , jadi . Inilah versi yang diukur di sini, kerana inilah versi yang konflik gradient pada ditakrifkan dengan baik.
Soft parameter sharing memberikan setiap tugas encoder sendiri dengan penalti coupling — lebih banyak parameter, lebih banyak fleksibiliti, dan tiada satu vektor parameter yang dikongsi untuk mengukur konflik. Cross-stitch networks berada di antaranya, mencampurkan ciri setiap tugas melalui matriks terpelajar pada setiap tahap. Kedua-duanya patut dicuba jika hard sharing menunjukkan konflik, dan kedua-duanya di luar skop pengukuran di bawah.
Eksperimen yang Penting: Tiga Skema Pengimbangan Loss

Loss naif sensitif terhadap skala. Jika loss pulangan sekitar dan loss volume sekitar , volume menguasai gradient dan head pulangan kebuluran. Tiga respons:
Bobot tetap. Tetapkan selepas menyeragamkan setiap sasaran. Baseline yang jujur — jika ia menang, skema adaptif hanyalah upacara.
Pembobotan ketidakpastian (Kendall et al., 2018). Pelajari skala hingar homoskedastik bagi setiap tugas:
Tugas dengan ketidakpastian tinggi mendapat bobot lebih rendah secara automatik; sebutan menghalang penyelesaian remeh . Perhatikan bahawa ini ialah alat pembobotan loss semasa latihan, bukan selang ramalan — untuk ketidakpastian yang benar-benar boleh digunakan bagi menentukan saiz kedudukan, lihat conformal prediction.
GradNorm (Chen et al., 2018). Seimbangkan magnitud gradient dan bukannya skala loss. Setiap langkah: kira dan min , kira kadar latihan relatif , dan kemas kini . Semua tugas kemudian berlatih pada kadar yang setanding tanpa mengira skala loss.
Kod khusus MTL ialah head, forward yang mengembalikan senarai, dan pengagregatan loss. Stack Linear/BatchNorm/ReLU/Dropout, boilerplate Adam/cosine/clip dan epoch loop ialah corak standard yang ditunjukkan dalam DeepLOB dan ditiadakan di sini.
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 mempunyai parameter, jadi ia mesti dimasukkan ke dalam optimizer bersama model: optim.Adam(list(model.parameters()) + list(uw.parameters()), ...). Terlupa perkara ini ialah cara paling biasa untuk "menjalankan uncertainty weighting" tetapi secara senyap menjalankan bobot tetap.
Perkara yang perlu dilaporkan
Bagi setiap skema, pada setiap fold: bobot akhir tugas yang dipelajari, metrik tugas utama dan — kerana skema pembobotan ialah pilihan model — berapa banyak skema yang dibandingkan sebelum memilih satu.
| Skema | Metrik tugas utama vs single-task | |||
|---|---|---|---|---|
| Tetap () | 1.00 | 1.00 | 1.00 | — |
| Pembobotan ketidakpastian | — | — | — | — |
| GradNorm | — | — | — | — |
Tiga skema didarab dengan beberapa fold sudah menjadi carian model kecil. Sebarang penambahbaikan yang dilaporkan di sini perlu bertahan daripada pembetulan multiple-testing yang diterangkan dalam deflated Sharpe dan multiple testing sebelum ia membawa makna.
Negative Transfer: Tandakan Gradient

Inilah bahagian yang patut dikekalkan. Negative transfer berlaku apabila tugas tambahan menjadikan tugas utama lebih teruk, dan ia mempunyai diagnostik langsung: sudut antara gradient tugas dalam ruang parameter dikongsi.
Ukur pada encoder dikongsi sahaja — head adalah khusus tugas mengikut pembinaan dan sentiasa "bersetuju" secara remeh.
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:]
}
Panggil ini pada batch held-out pada cadence tetap sepanjang latihan, bukan sekali pada penghujung. Satu pasangan boleh bermula selaras dan menyimpang apabila encoder menjadi khusus; satu angka pada akhir latihan menyembunyikan perkara itu.
Penemuan yang perlu dicari — dan diterbitkan dalam apa jua keadaan:
| Pasangan | cos sim, latihan awal | cos sim, latihan lewat | MTL membantu tugas utama? |
|---|---|---|---|
| return ↔ volume | — | — | — |
| return ↔ volatility | — | — | — |
| volume ↔ volatility | — | — | — |
Jika gradient volume dan volatiliti selaras antara satu sama lain manakala kedua-duanya bercanggah dengan gradient return, kesimpulan yang betul ialah dua tugas tambahan itu membentuk blok koheren yang tidak termasuk tugas return — dan pembaikannya ialah pengelompokan tugas, bukan kapasiti yang lebih besar. Apabila konflik itu nyata, ubat standard ialah PCGrad (Yu et al., 2020), yang mengunjurkan setiap gradient bercanggah ke satah normal gradient yang lain; CAGrad (Liu et al., 2021), yang mencari arah penurunan yang tidak memudaratkan mana-mana tugas; atau menggugurkan tugas tambahan sepenuhnya.
Perhatikan perkara yang sengaja tiada: plot t-SNE representasi dikongsi yang diwarnakan mengikut nilai sasaran. Ia hiasan — nombor kosinus di atas mengatakan segala yang ingin ditunjukkan oleh embedding, dan mengatakannya sebagai nombor.
Protokol Pengesahan

Pengukuran di atas tidak bernilai di bawah protokol yang cuai, dan MTL menjadikan perangkap biasa lebih teruk kerana terdapat tiga sasaran untuk dibocorkan dan bukannya satu.
Data sebenar, bukan simulator. Sasaran mesti datang daripada data OHLCV/trade sebenar. GARCH toy yang dikodkan keras menghasilkan volatiliti yang berkorelasi dengan pulangan secara binaan, dan itulah tepat perkara yang sedang diuji — eksperimen akan mengukur penjana itu sendiri. Jika anda mahukan proses volatiliti yang dipasang, ramalan volatiliti GARCH untuk kripto memasang GARCH(1,1) melalui maximum likelihood pada BTC/ETH sebenar dan mengesahkan residual yang distandardkan, manakala GARCH tidak simetri dan kesan leverage menerangkan mengapa simulator respons simetri Gaussian tersalah menyatakan volatiliti kripto sejak awal. Data sintetik hanya boleh dipertahankan apabila ia memberikan ground truth terkawal — korelasi tugas yang diketahui dan ditetapkan pengarang yang cuba anda pulihkan — dan itu ialah eksperimen yang berbeza daripada eksperimen di sini.
Scaler dipasang pada train sahaja. Pasang feature scaler dan ketiga-tiga target scaler di dalam setiap fold latihan dan gunakannya pada pengesahan; fit_transform global sebelum pemisahan membocorkan momen test set ke dalam latihan. Kegagalan tepat ini disenaraikan dalam taksonomi look-ahead bias.
Fold walk-forward yang dipurge dan di-embargo. Satu chronological split 80/20 tidak dapat membezakan penambahbaikan MTL daripada kesan fold — itulah keseluruhan hujah walk-forward optimization, yang menunjukkan tiga split menghasilkan tiga kesimpulan. Guna semula generator expanding-window purged_walk_forward daripada pemodelan spread dengan machine learning: ia menggugurkan gap sebanyak horizon baris pada kedua-dua sisi setiap sempadan, yang penting di sini kerana window volatiliti terealisasi yang bertindih bocor merentasi sempadan walaupun sasaran return tidak.
Baseline klasik. Rangkaian MTL yang mengatasi tiga rangkaian single-task tidak membuktikan apa-apa jika model gradient-boosting atau ridge bagi setiap sasaran mengatasi keempat-empatnya. Pasang satu model bagi setiap sasaran dengan LightGBM atau ridge pada fold dan ciri yang sama, dan laporkan dalam jadual yang sama.
| Model | Metrik tugas utama | Nota |
|---|---|---|
| Ridge, setiap sasaran | — | Baseline klasik |
| LightGBM, setiap sasaran | — | Baseline klasik |
| MLP single-task, setiap sasaran | — | Tiga rangkaian berasingan |
| MTL, skema loss terbaik | — | Satu rangkaian, tiga head |
Apa yang Menjadikan MTL Berbaloi di Sini

Syarat apabila MTL sepatutnya menang, dinyatakan sebagai hipotesis untuk diperiksa terhadap fold di atas dan bukannya sebagai senarai semak:
- Label tambahan lebih bersih daripada label utama. Volume diperhatikan secara langsung; "expected return" tidak. Jika head return kebanyakannya menyesuaikan hingar, isyarat gradient daripada head tambahan ialah satu-satunya bahagian objective yang dirumuskan dengan baik.
- Data latihan terhad berbanding kapasiti encoder, jadi constraint tambahan benar-benar melakukan kerja regularisasi dan bukannya sekadar bersaing untuk parameter.
- Latency inferens penting dan satu forward pass mengatasi tiga.
Dan hujah menentangnya, yang sama-sama boleh diuji: jika nilai cos_sim(return, ·) berterusan negatif, encoder dikongsi ditarik menjauhi tugas utama dan head tambahan ialah cukai, bukan regularizer.
Kesimpulan

Pulangan, volume dan volatiliti datang daripada microstructure yang sama, jadi representasi dikongsi ialah prior yang munasabah — tetapi prior bukan hasil. Dua perkara yang benar-benar boleh ditetapkan oleh setup ini ialah skema pengimbangan loss yang disukai data (dengan bobot yang dipelajari dilaporkan, bukan hanya pemenang dinamakan) dan sama ada gradient tugas pada encoder dikongsi selaras, diukur sepanjang latihan dan bukannya diandaikan hanya kerana sasaran berkorelasi.
Jika fold walk-forward yang dipurge menunjukkan rangkaian MTL gagal mengatasi model gradient-boosting bagi setiap sasaran, itulah penemuannya dan ia diterbitkan sedemikian — templatnya ialah hasil negatif yang jujur. Keputusan negatif tentang negative transfer masih merupakan hasil tentang negative transfer.
Pengarang
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.