← Kembali ke artikel
August 6, 2026
5 menit baca

Proses Gaussian untuk Pemodelan Harga Non-Parametrik

Proses Gaussian untuk Pemodelan Harga Non-Parametrik
#bayesian
#gaussian-process
#kernel
#uncertainty
#non-parametric

Bagian dari seri "Dasar ML Klasik".

Ada dua hal yang membuat proses Gaussian layak untuk dijadikan artikel terpisah di blog ini, dan tidak satu pun dari keduanya yang "memberi Anda ketidakpastian".

Yang pertama adalah desain kernel. Seluruh bias induktif seorang dokter hidup dalam satu fungsi k(x,x)k(x, x'), dan fungsi itu adalah sesuatu yang Anda tulis dengan sengaja: seberapa kasar jalurnya, apakah berulang, apakah pengulangannya berkurang. Tidak ada hal lain dalam perangkat standar yang memungkinkan Anda menyatakan hipotesis struktural tentang dinamika pasar secara eksplisit dan kemudian menyesuaikannya. Yang kedua adalah kemungkinan marjinal — tujuan pelatihan dengan penalti kompleksitas yang diperoleh dari model itu sendiri, bukan dari rangkaian yang sudah ada. Setiap artikel lain dalam rangkaian overfitting di blog ini (analisis dataran tinggi, PBO, kempis Sharpe) ada karena regularisasi set validasi rapuh dalam penelusuran. Seorang dokter umum mengaku tidak membutuhkannya. Klaim tersebut dapat diuji, dan mengujinya lebih menarik dibandingkan tutorial ukuran ketidakpastian lainnya.

Mengenai ketidakpastian itu sendiri: varians posterior GP bersifat struktural — varians tersebut berada di luar inferensi yang sama yang menghasilkan mean, dan bukannya dililitkan pada model yang sesuai setelahnya. Ini adalah perbedaan nyata dengan prediksi konformal, yang sudah membahas di blog ini mengapa ketidakpastian adalah masukan yang tepat untuk menentukan ukuran posisi dan apa yang harus dilakukan dengan interval setelah Anda memilikinya. Artikel ini tidak memperdebatkan kembali kasus tersebut; itu mengikuti modelnya.

Berikut ini adalah kernel dan mesin inferensi, implementasi GPyTorch, dan — dinyatakan dengan jelas di bagian akhir — pengukuran yang belum dimiliki artikel ini.

Apa itu Proses Gaussian?

Dokter sudah muncul di blog ini sebagai pengganti optimasi Bayesian di Optuna vs. penurunan koordinat, dengan notasi yang sama dan peringatan dimensi rendah yang sama. Di sini GP adalah model itu sendiri, disesuaikan dengan data pasar, bukan pada permukaan pencarian hyperparameter, sehingga penanganannya lebih mendalam.

Proses Gaussian adalah kumpulan variabel acak, yang bilangan berhingganya mempunyai distribusi Gaussian gabungan. Ini adalah distribusi fungsi, bukan distribusi parameter.

Secara formal, suatu fungsi f:XRf: \mathcal{X} \to \mathbb{R} diambil dari GP jika untuk himpunan input yang terbatas {x1,x2,,xn}X\{x_1, x_2, \ldots, x_n\} \subset \mathcal{X}:

(f(x1)f(x2)f(xn))N((m(x1)m(x2)m(xn)),(k(x1,x1)k(x1,xn)k(xn,x1)k(xn,xn)))\begin{pmatrix} f(x_1) \\ f(x_2) \\ \vdots \\ f(x_n) \end{pmatrix} \sim \mathcal{N}\left(\begin{pmatrix} m(x_1) \\ m(x_2) \\ \vdots \\ m(x_n) \end{pmatrix}, \begin{pmatrix} k(x_1, x_1) & \cdots & k(x_1, x_n) \\ \vdots & \ddots & \vdots \\ k(x_n, x_1) & \cdots & k(x_n, x_n) \end{pmatrix}\right)

Di mana m(x)=E[f(x)]m(x) = \mathbb{E}[f(x)] adalah fungsi rata-rata dan k(x,x)=Cov(f(x),f(x))k(x, x') = \text{Cov}(f(x), f(x')) adalah fungsi kovarians (kernel). Kami menulis ini secara kompak sebagai:

fGP(m(),k(,))f \sim \mathcal{GP}(m(\cdot), k(\cdot, \cdot))

Fungsi mean mengkodekan keyakinan sebelumnya tentang perilaku rata-rata ff. Dalam perdagangan, kami biasanya menetapkan m(x)=0m(x) = 0, mengkodekan asumsi bahwa kita tidak memiliki bias arah sebelumnya terhadap imbal hasil. Semua struktur masuk ke kernel.

Mengapa Non-Parametrik?

Model regresi linier dengan 5 fitur memiliki 6 parameter. Jaringan saraf dengan dua lapisan tersembunyi sebanyak 64 unit memiliki ribuan. GP tidak memiliki jumlah parameter yang tetap — kompleksitas model bertambah seiring dengan bertambahnya data. Dengan 10 observasi, GP mendefinisikan Gaussian 10 dimensi. Dengan 10.000 observasi, ini mendefinisikan Gaussian 10.000 dimensi.

Ini tidak berarti dokter tidak memiliki hyperparameter. Fungsi kernel memiliki hyperparameter (skala panjang, amplitudo, periodisitas) yang mengontrol properti fungsi yang diambil dari sebelumnya. Namun bentuk fungsionalnya sendiri tidak pernah tetap. GP dapat mewakili fungsi berkelanjutan apa pun, dengan data yang cukup dan kernel yang tepat. Inilah yang dimaksud dengan "non-parametrik" — model tidak dibatasi pada kelompok parametrik seperti fungsi linier atau polinomial.

Untuk pemodelan keuangan, ini sangat berharga. Pasar berubah. Hubungan antara fitur dan keuntungan bersifat nonlinier, tidak stasioner, dan bergantung pada rezim. Model parametrik menerapkan struktur yang mungkin tidak sesuai dengan kenyataan. Dokter membiarkan data berbicara.

Fungsi Kernel: Pengkodean Struktur Pasar

Fungsi kernel k(x,x)k(x, x') adalah jiwa dari proses Gaussian. Ini mendefinisikan fungsi mana yang mungkin terjadi secara apriori dengan menentukan kovarians antara nilai fungsi pada dua titik masukan mana pun. Kernel yang berbeda mengkodekan asumsi berbeda tentang kelancaran, periodisitas, dan perilaku jangka panjang.

Fungsi Basis Radial (RBF) / Eksponensial Kuadrat

Kernel RBF adalah titik awal yang paling umum:

kRBF(x,x)=σ2exp(xx222)k_{\text{RBF}}(x, x') = \sigma^2 \exp\left(-\frac{\|x - x'\|^2}{2\ell^2}\right)

Di mana σ2\sigma^2 adalah varians sinyal (skala keluaran) dan \ell adalah skala panjangnya. Fungsi yang diambil dari GP dengan kernel RBF dapat dibedakan secara tak terhingga — sangat lancar.

Interpretasi perdagangan: Skala panjangnya \ell mengontrol seberapa jauh jarak dua titik data dapat dan masih berkorelasi. Skala yang pendek berarti model bereaksi terhadap pola lokal; skala yang panjang berarti menangkap tren yang luas. Varians sinyal σ2\sigma^2 mengontrol amplitudo fungsi — seberapa besar hasil yang diprediksi.

Masalah keuangan: Kelancaran tanpa batas adalah hal yang tidak realistis. Keuntungan finansial mengalami lonjakan, perubahan rezim, dan diskontinuitas. Kernel RBF dapat memperhalus fitur-fitur ini, menghasilkan prediksi yang terlalu konservatif di dekat kerusakan struktural.

Kernel Ibu

Kelas Matern menggeneralisasi RBF dengan memperkenalkan parameter kelancaran ν\nu:

kMatern(x,x)=σ221νΓ(ν)(2νxx)νKν(2νxx)k_{\text{Matern}}(x, x') = \sigma^2 \frac{2^{1-\nu}}{\Gamma(\nu)} \left(\frac{\sqrt{2\nu}\|x - x'\|}{\ell}\right)^{\nu} K_{\nu}\left(\frac{\sqrt{2\nu}\|x - x'\|}{\ell}\right)

Di mana KνK_{\nu} adalah fungsi Bessel jenis kedua yang dimodifikasi. Sebagai ν\nu \to \infty, kernel Matern menyatu ke RBF. Pilihan umum:

  • ν=1/2\nu = 1/2: Setara dengan proses Ornstein-Uhlenbeck. Fungsinya kontinu tetapi tidak terdiferensiasi — kasar, seperti gerak Brown.
  • ν=3/2\nu = 3/2: Fungsi dapat diturunkan satu kali. Keseimbangan yang baik antara kehalusan dan fleksibilitas.
  • ν=5/2\nu = 5/2: Fungsi dapat terdiferensiasi dua kali. Lebih halus dari 3/23/2 tapi kurang kaku dibandingkan RBF.

Interpretasi perdagangan: Matern-3/23/2 kernel bisa dibilang merupakan default terbaik untuk deret waktu finansial. Hal ini memungkinkan jenis kekasaran yang ditunjukkan oleh jalur harga riil tanpa bergerigi ν=1/2\nu = 1/2. Hal ini sejalan dengan literatur “volatilitas itu kasar” (Gatheral, Jaisson, & Rosenbaum, 2018), yang secara empiris menunjukkan bahwa jalur volatilitas memiliki eksponen Hurst disekitarnya. H0.1H \approx 0.1, jauh lebih kasar dari gerak Brown.

Bukti utama yang dipublikasikan bahwa kernel Matern mengalahkan model volatilitas klasik adalah Rizvi dkk. (2017), yang melaporkan sekitar 20% lebih baik UMK daripada random walk dan 50% lebih baik dari GARCH — pada data pasangan mata uang harian tahun 2017, bukan kripto, dan tidak direproduksi di sini. Perlakukan ini sebagai motivasi untuk mencoba kernel, bukan sebagai tolok ukur. GARCH(1,1) milik blog ini sesuai dengan data harian BTC nyata, dengan diagnostik Ljung-Box dan ARCH-LM, ada dalam perkiraan volatilitas GARCH untuk kripto; head-to-head melawan dokter umum bersalin pada sampel yang sama akan menjadi perbandingan yang jujur, dan itu belum dijalankan.

Kernel Berkala

Pasar keuangan memiliki pola siklus: kurva volume harian, efek harian, arus penyeimbangan bulanan, dan musim pendapatan triwulanan. Kernel periodik menangkap ini:

kPeriodic(x,x)=σ2exp(2sin2(πxx/p)2)k_{\text{Periodic}}(x, x') = \sigma^2 \exp\left(-\frac{2\sin^2\left(\pi|x - x'|/p\right)}{\ell^2}\right)

Di mana pp adalah periodenya. Fungsi yang diambil dari kernel ini berulang dengan titik pp, dimodulasi oleh skala panjang \ell yang mengontrol seberapa cepat korelasi meluruh dalam suatu periode.

Interpretasi perdagangan: Set p=24p = 24 (jam) untuk menangkap pola intraday, atau p=5p = 5 (hari perdagangan) untuk musiman mingguan. Berbeda dengan fitur Fourier, kernel periodik tidak mengasumsikan jumlah harmonik yang tetap — GP mempelajari bentuk siklus dari data.

Menggabungkan Kernel: Komposisi Aditif dan Perkalian

Kekuatan sebenarnya dari kernel GP terletak pada komposisinya. Jika k1k_1 Dan k2k_2 adalah kernel yang valid, begitu pula:

  • Jumlah: k1+k2k_1 + k_2 — fungsinya adalah jumlah komponen independen (dekomposisi aditif)
  • Produk: k1×k2k_1 \times k_2 — interaksi antar komponen (misalnya, perilaku periodik lokal)

Kernel komposit yang berguna untuk keuntungan finansial:

k(x,x)=kMatern-3/2(x,x)+kPeriodic(x,x)kRBF(x,x)k(x, x') = k_{\text{Matern-3/2}}(x, x') + k_{\text{Periodic}}(x, x') \cdot k_{\text{RBF}}(x, x')

Ini menguraikan sinyal menjadi:

  1. Komponen tren aperiodik yang tidak mulus (Matern-3/2)
  2. Komponen periodik yang amplitudonya meluruh seiring waktu (Periodik ×\times RBF)

Produk kPeriodickRBFk_{\text{Periodic}} \cdot k_{\text{RBF}} menciptakan kernel periodik lokal: polanya berulang, namun pengulangan yang jauh memiliki pengaruh yang lebih kecil dibandingkan pengulangan yang berdekatan. Hal ini sangat tepat untuk kondisi keuangan musiman, yang berubah seiring waktu seiring dengan berkembangnya struktur mikro pasar.

Kernel Campuran Spektral

Untuk fleksibilitas maksimum, kernel campuran spektral (SM) (Wilson & Adams, 2013) membuat parameter kepadatan spektral kernel sebagai campuran Gaussian:

kSM(x,x)=q=1Qwqexp(2π2xx2vq)cos(2πxxμq)k_{\text{SM}}(x, x') = \sum_{q=1}^{Q} w_q \exp\left(-2\pi^2 \|x - x'\|^2 v_q\right) \cos\left(2\pi \|x - x'\| \mu_q\right)

Di mana wqw_q adalah bobot campuran, vqv_q adalah varians spektral, dan μq\mu_q adalah sarana spektral (frekuensi). Dengan teorema Bochner, setiap inti stasioner dapat direpresentasikan dengan cara ini. Kernel SM dapat menemukan komponen periodik, tren jangka panjang, dan korelasi jangka pendek secara bersamaan — semuanya dari data.

Interpretasi perdagangan: Kernel SM berguna ketika Anda tidak mengetahui pola apa yang ada dalam data. Ini dapat mengidentifikasi periodisitas tersembunyi dalam rangkaian pengembalian (misalnya, siklus halus 4 jam di pasar kripto yang didorong oleh penyeimbangan ulang otomatis). Kelemahannya adalah lebih banyak hyperparameter dan risiko overfitting dengan kumpulan data kecil.

Inferensi Posterior: Dari Sebelum Prediksi

Mengingat data pelatihan D={(xi,yi)}i=1n\mathcal{D} = \{(x_i, y_i)\}_{i=1}^n Di mana yi=f(xi)+ϵiy_i = f(x_i) + \epsilon_i Dan ϵiN(0,σn2)\epsilon_i \sim \mathcal{N}(0, \sigma_n^2), posterior GP di titik tes XX_* mempunyai solusi bentuk tertutup. Ini adalah keunggulan komputasi utama GP dibandingkan sebagian besar model Bayesian.

Persamaan Posterior

Biarkan K=k(X,X)K = k(X, X) menjadi n×nn \times n matriks kovarians pelatihan, K=k(X,X)K_* = k(X_*, X) menjadi m×nm \times n matriks lintas kovarians, dan K=k(X,X)K_{**} = k(X_*, X_*) menjadi m×mm \times m uji matriks kovarians. Bagian belakangnya adalah:

fX,y,XN(fˉ,Cov(f))f_* | X, y, X_* \sim \mathcal{N}(\bar{f}_*, \text{Cov}(f_*))

Di mana:

fˉ=K(K+σn2I)1y\bar{f}_* = K_* (K + \sigma_n^2 I)^{-1} y

Cov(f)=KK(K+σn2I)1KT\text{Cov}(f_*) = K_{**} - K_* (K + \sigma_n^2 I)^{-1} K_*^T

Arti posteriornya fˉ\bar{f}_* adalah kombinasi linier dari target pelatihan, yang diberi bobot berdasarkan kesamaan inti antara titik pengujian dan titik pelatihan. Kovarian posterior Cov(f)\text{Cov}(f_*) dimulai dari kovarians sebelumnya KK_{**} dan mengurangi informasi yang diperoleh dari data pelatihan. Jika data pelatihan padat, varians posteriornya kecil. Jika data pelatihan sedikit, varian posterior akan kembali ke varian sebelumnya.

Kemungkinan Marginal, dan Uji Layak Klaim

Hyperparameter kernel θ\theta (skala panjang, varians, tingkat kebisingan) dipelajari dengan memaksimalkan kemungkinan marjinal log:

logp(yX,θ)=12yT(K+σn2I)1y12logK+σn2In2log2π\log p(y | X, \theta) = -\frac{1}{2} y^T (K + \sigma_n^2 I)^{-1} y - \frac{1}{2} \log |K + \sigma_n^2 I| - \frac{n}{2} \log 2\pi

Istilah pertama adalah istilah data fit (menghukum prediksi yang jauh dari observasi). Istilah kedua adalah penalti kompleksitas (menghukum model yang terlalu fleksibel - yaitu, ketika matriks kernel memiliki determinan yang besar). Suku ketiga adalah konstanta normalisasi.

Ini adalah pisau cukur Occam otomatis, dan ini adalah hal paling menarik yang dibawa oleh dokter umum ke dalam jalur perdagangan. Versi kuat dari klaim ini adalah bahwa tidak diperlukan kumpulan validasi terpisah untuk regularisasi — penalti kompleksitas ada di dalam tujuan, sehingga model tidak dapat dibeli dengan fleksibilitas secara gratis.

Klaim tersebut patut mendapat skeptisisme khususnya pada blog ini. Analisis dataran tinggi menunjukkan bahwa skor validasi satu poin adalah kriteria pemilihan yang buruk dan ketahanan itu ada dalam bentuk lingkungan; PBO menghitung seberapa sering pemenang dalam sampel kalah di luar sampel; kempes Sharpe harga dalam jumlah uji coba. Kemungkinan marjinal masih merupakan tujuan dalam sampel yang dimaksimalkan θ\theta — faktor Occam menghukum kapasitas model, bukan pemilihan pada banyak kernel yang dipasang. Jika Anda memasukkan dua belas kandidat kernel dan memilih satu yang memiliki kemungkinan marjinal terbaik, Anda kembali ke wilayah pengujian ganda dan logika deflasi berlaku tanpa perubahan. Versi yang dapat dipalsukan: apakah pemilihan kemungkinan marjinal menghasilkan kesenjangan sampel masuk/keluar sampel yang lebih kecil dibandingkan pemilihan set validasi pada data yang sama dan keluarga kernel yang sama? Itu dapat diukur dan tidak diukur di bawah.

Permukaan kemungkinan marjinal juga memiliki optima lokal. Pengulangan ulang secara acak berulang kali atau inisialisasi yang hati-hati merupakan hal yang penting - menginisialisasi skala panjang ke median jarak berpasangan dari input pelatihan dan varian kebisingan ke varian sampel target adalah titik awal yang masuk akal.

Biaya Komputasi dan Skalabilitas

Kemacetannya sedang berbalik (K+σn2I)(K + \sigma_n^2 I), yang biayanya O(n3)O(n^3) dalam waktu dan O(n2)O(n^2) dalam memori. Dinding kubik sudah diperdebatkan di blog ini dari arah lain: metode pencarian vs. biaya evaluasi langsung mendiskualifikasi optimasi Bayesian berbasis GP ketika tujuannya murah, karena biaya penggantinya lebih besar daripada evaluasi yang dihematnya. Aritmatikanya sama di sini; aplikasinya berbeda. Sebagai model yang disesuaikan dengan data pasar, istilah kubik bukanlah diskualifikasi, melainkan anggaran: istilah ini menetapkan batas maksimum pada periode pelatihan.

Strategi skalabilitas untuk aplikasi perdagangan:

  1. GP yang jarang (titik penginduksi). Ganti n×nn \times n matriks dengan m×mm \times m matriks dimana mnm \ll n. Poin-poin pemicu Z={z1,,zm}Z = \{z_1, \ldots, z_m\} adalah input semu yang merangkum data pelatihan. Formulasi SVGP (Stochastic Variational GP) oleh Hensman dkk. (2013) memungkinkan pelatihan mini-batch dengan biaya O(nm2)O(nm^2) per iterasi. GPyTorch mendukung ini secara asli.

  2. Interpolasi kernel terstruktur (SKI/KISS-GP). Mengeksploitasi struktur Kronecker dan Toeplitz dalam matriks kernel ketika input terletak pada grid. Mengurangi biaya untuk O(n+glogg)O(n + g \log g) Di mana gg adalah ukuran grid. Ideal untuk rangkaian waktu yang diambil sampelnya secara rutin (misalnya, batang 1 menit).

  3. Dokter lokal di jendela geser. Latih dokter terpisah hanya berdasarkan data terkini. Di sinilah kendala khusus GP terjadi: kernel standar tidak bergerak (k(x,x)k(x,x') hanya bergantung pada xxx - x') dan pasar tidak, jadi jawaban yang umum adalah jendela bergulir — tetapi panjang jendela dibatasi oleh O(n3)O(n^3), bukan hanya berdasarkan statistik. Pengoptimalan maju mencakup jendela berlabuh vs. jendela bergulir, panjang kereta/pengujian, dan frekuensi pengoptimalan ulang secara umum; bagi seorang dokter umum, penentuan ukuran jendela adalah keputusan komputasi dan juga keputusan statistik, dan jendela yang tertambat (yang terus berkembang) tidak tersedia melewati beberapa ribu poin tanpa perkiraan. Pembingkaian ulang tersebut merupakan konsekuensi praktisnya: dengan dokter Anda tidak bisa memilih "gunakan seluruh riwayat".

GP untuk Prediksi Pengembalian: Kerangka Praktis

Desain Fitur: Mengapa 5-20 Fitur, Bukan 500

Taksonomi fitur umum untuk ML data pasar — ketidakseimbangan buku pesanan, tekanan buku, VPIN, lambda Kyle, fitur volatilitas yang terealisasi, pengkodean waktu siklis, sinyal lintas-aset, dan tingkat pendanaan — sudah dijelaskan dalam pemodelan spread dengan pembelajaran mesin; gunakan daftar itu.

Yang spesifik untuk GP adalah ukuran daftarnya. Metode kernel menurun dalam dimensi tinggi: jarak terkonsentrasi, dan kernel yang tidak bergerak kehilangan diskriminasi. Kisaran praktis untuk dokter keuangan adalah 5-20 masukan, bukan ratusan yang dimakan dengan senang hati oleh pohon yang ditingkatkan gradiennya. Mekanisme yang membuat hal ini dapat bertahan adalah ARD (Penentuan Relevansi Otomatis): memberikan skala panjangnya sendiri pada setiap dimensi masukan d\ell_d, dan dorongan pelatihan dengan kemungkinan marginal d\ell_d \to \infty untuk dimensi yang tidak membawa sinyal, karena skala panjangnya tak terhingga berarti kernel mengabaikan koordinat tersebut. Pemilihan fitur menjadi produk sampingan dari penyesuaian dan pembelajaran d\ell_d dapat langsung dibaca sebagai peringkat relevansi — yang juga membuatnya dapat dipalsukan: sesuaikan kernel komposit pada batang sebenarnya, cetak skala panjangnya, dan lihat apakah fitur yang Anda yakini adalah fitur yang dipertahankan oleh model.

Ukuran Posisi dan Abstensi

Posterior GP memberi σ(x)\sigma_*(x) secara langsung, sehingga langsung masuk ke dalam ukuran rasio tepi dan filter tanpa perdagangan yang dikembangkan di Prediksi Konformal untuk Ukuran Posisi Sadar Risiko, dengan lebar interval wt=2κσ(x)w_t = 2\kappa\sigma_*(x). Satu-satunya perbedaan adalah asal: GP menghasilkan lebar dari model itu sendiri dan bukan dari set kalibrasi, sehingga bervariasi berdasarkan lokasi titik pengujian relatif terhadap data pelatihan, bukan dengan jumlah global residu masa lalu.

Implementasi dengan GPyTorch

GPyTorch adalah perpustakaan berbasis PyTorch untuk inferensi GP yang dapat diskalakan. Ini memanfaatkan akselerasi GPU, diferensiasi otomatis, dan teknik aljabar linier modern (gradien konjugasi, dekomposisi Lanczos) untuk menskalakan dokter melampaui skala naif O(n3)O(n^3) membatasi.

GP Dasar yang Tepat untuk Prediksi Pengembalian

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 Inilah yang memungkinkan skala panjang per dimensi yang dibahas di atas. Setelah pelatihan, model.covar_matern.base_kernel.lengthscale adalah vektor yang akan dibaca.

Lingkaran Latihan

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

Prediksi dengan Ketidakpastian

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(),
    }

Itu fast_pred_var() manajer konteks menggunakan algoritma LOVE (Lanczos Variance Estimates) untuk menghitung varians prediktif O(n)O(n) waktu, bukannya O(n2)O(n^2).

Jalur Perdagangan Ujung-ke-Ujung

Catatan tentang pembuat fitur di bawah ini: setiap statistik bergulir harus benar-benar melihat ke belakang, dan standarisasi masukan harus dipasang pada bagian pelatihan saja. Poin kedua bukanlah kebersihan umum — melainkan saluran kebocoran normalisasi yang dibedah dan diukur dalam taksonomi bias lihat ke depan, yang melaporkan inflasi Sharpe yang dihasilkan setiap jenis kebocoran. GP menstandardisasi masukannya berdasarkan konstruksi, sehingga kebocoran inilah yang paling sering dialaminya.

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

Menskalakan ke Kumpulan Data yang Lebih Besar dengan GP yang Jarang

Ketika jendela pelatihan melebihi beberapa ribu poin, inferensi GP yang tepat menjadi lambat. Beralih ke GP renggang variasional:

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

Dengan 128 titik penginduksi, biaya per batch adalah O(1282×batch_size)O(128^2 \times \text{batch\_size}) — sekitar 4 juta operasi per batch. Ini dengan mudah menangani kumpulan data 100.000+ observasi pada satu GPU.

Pembelajaran Kernel Mendalam: GP Bertemu Jaringan Neural

Ketika ruang masukan berdimensi tinggi atau hubungan antara fitur dan hasil sangat nonlinier, kernel biasa mungkin mengalami kesulitan. Pembelajaran kernel mendalam (DKL) meneruskan masukan melalui jaringan saraf sebelum menerapkan kernel GP:

kDKL(x,x)=kbase(gϕ(x),gϕ(x))k_{\text{DKL}}(x, x') = k_{\text{base}}(g_\phi(x), g_\phi(x'))

Di mana gϕg_\phi adalah jaringan saraf dengan parameter ϕ\phi Dan kbasek_{\text{base}} adalah kernel standar (mis., Matern-3/2). Jaringan mempelajari representasi fitur di mana kernel GP paling efektif. Seluruh model — parameter jaringan dan hyperparameter kernel — dilatih secara menyeluruh dengan memaksimalkan kemungkinan marjinal.

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 menggabungkan pembelajaran representasi jaringan saraf dengan kuantifikasi ketidakpastian dokter. Lapisan GP memastikan bahwa prediksi yang jauh dari data pelatihan memiliki ketidakpastian yang tinggi — sesuatu yang gagal disediakan oleh jaringan saraf standar. Perhatikan juga bahwa DKL memperkenalkan kembali fleksibilitas yang seharusnya diberikan oleh kemungkinan marjinal: faktor Occam memberikan penalti pada kernel, namun jaringan di depannya memiliki ribuan parameter bebas dan tidak ada penalti seperti itu.

Ludkovski dan Risk (2025), Gaussian Process Models for Quantitative Finance, mensurvei DKL dalam konteks keuangan kuantitatif yang lebih luas termasuk penetapan harga opsi dan optimalisasi portofolio; hasil tersebut adalah milik mereka, atas masalah mereka, dan bukan merupakan bukti tentang prediksi pengembalian kripto.

Diagnostik dan Kesalahan

Kalibrasi

Dokter umum yang terkalibrasi dengan baik memiliki interval prediksi yang sesuai dengan cakupan empiris. Pemeriksaan ini sama dengan yang digunakan dalam prediksi konformal — yang juga mencakup teori mengapa cakupan marjinal bukan cakupan bersyarat, batasan yang juga berlaku pada interval 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}"
        )

Ekspektasi pelampauan adalah 0,317 / 0,046 / 0,003 pada 1/2/3 sigma. Angka yang penting adalah apa yang dicetak pada penelusuran nyata di atas batangan kripto, dan tabel tersebut belum ada dalam artikel ini. Ekspektasi sebelumnya adalah bahwa GP terlalu percaya diri — kemungkinan Gaussian pada hasil yang tidak stasioner dan berekor gemuk seharusnya menyamar dengan buruk pada 3 sigma — namun "seharusnya" bukanlah suatu pengukuran.

Kesalahan yang Masih Ada

  1. Penskalaan masukan. Skala panjang bersifat relatif terhadap skala masukan, sehingga fiturnya bervariasi [0,10000][0, 10000] dan satu berkisar [0,1][0, 1] tidak bisa berbagi yang berarti \ell; ARD adalah yang menyelamatkan rentang heterogen, dan standardisasi adalah yang membuat inisialisasi ARD masuk akal.

  2. Kemungkinan marjinal yang berlebihan. Dengan banyaknya hyperparameter kernel (terutama kernel campuran komposit atau spektral), kemungkinan marjinal masih bisa mengalami overfit. Gunakan prior: prior log-normal pada skala panjang yang berpusat pada median jarak berpasangan, prior setengah normal pada varians.

  3. Pengkondisian matriks kovarians. (K+σn2I)(K + \sigma_n^2 I) dapat menjadi tunggal secara numerik ketika ada kebisingan σn2\sigma_n^2 terlalu kecil atau ketika poin pelatihan hampir terduplikasi. GPyTorch menambahkan 10610^{-6} jitter ke diagonal; data keuangan yang kondisinya buruk seringkali membutuhkan lebih banyak data.

  4. Bias ke depan. Dibahas di atas dan, secara mendetail, dalam taksonomi bias ke depan.

Kapan Menggunakan GP vs. Model Lainnya

Kriteria dokter umum XGBoost Jaringan Syaraf
Ketidakpastian bawaan Ya (struktural) Tidak (membutuhkan konformal/bootstrap) Tidak (membutuhkan MC dropout/ensemble)
Efisiensi data Luar biasa (<1000 sampel) * *
Skalabilitas Tepatnya jelek, bagus jarang * *
Nonlinier Bergantung pada kernel * *
Interpretasi Dekomposisi kernel + skala panjang ARD * *
Non-stasioneritas Membutuhkan jendela geser atau DKL * *

* Untuk kolom XGBoost dan jaringan neural, patuhi perbandingan yang dipublikasikan, bukan pernyataan baru di sini: pemodelan spread dengan pembelajaran mesin memiliki tabel peningkatan gradien vs pembelajaran mendalam untuk data tabular keuangan (ambang batas ukuran data, kemampuan interpretasi, adaptasi rezim, latensi), dan fusi temporal transformator memiliki TFT vs. LSTM vs. vanilla Transformer.

Gunakan dokter ketika:

  • Anda memiliki kumpulan data kecil hingga menengah (di bawah ~10.000 observasi per jendela pelatihan)
  • Anda menginginkan hipotesis struktural yang eksplisit dan dapat diperiksa tentang sinyal (tren + musiman + kebisingan)
  • Ketidakpastian harus bervariasi berdasarkan jarak dari data pelatihan, tidak hanya berdasarkan kuantil residu global

Jangan gunakan dokter ketika:

  • Anda memerlukan inferensi sub-milidetik atas jutaan observasi
  • Dimensi masukan melebihi ~50
  • Sinyal hidup dalam interaksi fitur tingkat tinggi yang kompleks yang tidak dapat diwakili oleh kernel stasioner (DKL membantu, dengan mengorbankan properti Occam)

Apa yang Belum Diukur dalam Artikel Ini

Segala sesuatu di atas adalah mesin model. Tidak ada satu pun yang merupakan bukti bahwa seorang dokter umum menghasilkan uang dari kripto, dan standar blog ini adalah bahwa artikel tersebut memuat nomornya sendiri. Item yang terbuka, dalam urutan menjalankannya:

  1. Skala panjang ARD pada batang BTCUSDT asli 1m. Sesuaikan kernel komposit, cetak d\ell_d per fitur. Hal ini secara langsung menguji klaim "ARD adalah pemilihan fitur bawaan" dan menghasilkan peringkat relevansi fitur yang dapat dipalsukan.
  2. Tabel kalibrasi dari proses berjalan maju. Ekspektasi vs. pelampauan empiris pada 1/2/3 sigma, dinyatakan dengan jelas, termasuk kasus ketika dokter umum ternyata terlalu percaya diri.
  3. Strategi yang terjaga kepercayaannya, berjalan ke depan, pada lima jurusan yang sama dengan negatif jujur, dikempiskan untuk penghitungan uji coba. Jika gagal, maka akan dimasukkan ke dalam rangkaian tersebut sebagai hasil negatif lainnya. 4.Jam dinding O(n3)O(n^3) kurva untuk n=250/500/1000/2000/5000n = 250 / 500 / 1000 / 2000 / 5000, tepat vs. SVGP, sehingga bagian skalabilitas bertumpu pada bagan, bukan pada pernyataan.

Kesimpulan

Kasus untuk proses Gaussian dalam perdagangan bukanlah "proses tersebut memberi Anda bilah kesalahan" - prediksi konformal memberi Anda bilah kesalahan dengan asumsi distribusi yang lebih sedikit dan jaminan cakupan yang tidak dimiliki oleh GP. Kasusnya adalah GP membuat Anda menuliskan hipotesis struktural Anda sebagai sebuah kernel, mencocokkannya dengan tujuan yang memperhitungkan kompleksitasnya sendiri, dan kemudian memberi tahu Anda fitur mana yang sebenarnya digunakan melalui skala panjang ARD. Itu adalah model yang sangat mudah dibaca.

Biaya yang harus ditanggung juga sama nyatanya: penskalaan kubik yang membatasi jendela pelatihan Anda, asumsi stasioneritas bahwa jendela bergulir hanya memperbaiki sebagian, kemungkinan Gaussian bahwa pengembalian berekor gemuk akan dilanggar, dan — setelah Anda mencapai pembelajaran kernel yang mendalam — hilangnya properti Occam secara diam-diam yang memotivasi kemungkinan marjinal sejak awal. Apakah aset yang tersisa dapat diperdagangkan merupakan pertanyaan empiris, dan empat pengukuran yang tercantum di atas adalah jawabannya.

Referensi

  • Rasmussen, CE, & Williams, CKI (2006). Proses Gaussian untuk Pembelajaran Mesin. Pers MIT.
  • Wilson, A., & Adams, R. (2013). Kernel Proses Gaussian untuk Penemuan Pola dan Ekstrapolasi. ICML.
  • Hensman, J., Fusi, N., & Lawrence, ND (2013). Proses Gaussian untuk Big Data. UAI.
  • Gatheral, J., Jaisson, T., & Rosenbaum, M. (2018). Volatilitasnya kasar. Keuangan Kuantitatif, 18(6).
  • Rizvi, S.A.A., Roberts, S.J., Osborne, M.A., & Nyikosa, F. (2017). Pendekatan Baru untuk Meramalkan Volatilitas Keuangan dengan Gaussian Process Envelopes. arXiv:1705.00891.
  • Ludkovski, M., & Risiko, J. (2025). Model Proses Gaussian untuk Keuangan Kuantitatif. Peloncat.
  • Gardner, JR, Pleiss, G., Bindel, D., Weinberger, KQ, & Wilson, AG (2018). GPyTorch: Inferensi Proses Blackbox Matrix-Matrix Gaussian dengan Akselerasi GPU. NeurIPS.
Penafian: Informasi yang disediakan dalam artikel ini hanya untuk tujuan edukasi dan informasi serta tidak merupakan nasihat keuangan, investasi, atau trading. Trading mata uang kripto mengandung risiko kerugian yang signifikan.

Penulis

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

Selangkah Lebih Maju dari Pasar

Berlangganan newsletter kami untuk wawasan AI trading eksklusif, analisis pasar, dan pembaruan platform.

Kami menghormati privasi Anda. Berhenti berlangganan kapan saja.