← Kembali ke artikel
May 25, 2026
5 menit baca

Di Balik Algoritma Kami: HRP + Long/Short + CVaR dengan Hull-White

Di Balik Algoritma Kami: HRP + Long/Short + CVaR dengan Hull-White
#optimisasi portofolio
#HRP
#hierarchical risk parity
#CVaR
#Hull-White
#EWMA
#long/short
#manajemen risiko
#Rust
#keuangan kuantitatif

Dalam tinjauan kami «12 Algoritma Optimisasi Portofolio, Dibandingkan» kami menguji selusin metode alokasi secara berdampingan. Sebelas di antaranya adalah klasik dari buku teks. Yang kedua belas, Pipeline, adalah milik kami — dan hanya mendapat satu poin singkat di artikel itu. Artikel ini adalah penjelasan mendalam: apa yang ada di dalamnya, dari mana setiap formula berasal, dan bagaimana spesifikasi tersebut diwujudkan dalam Rust.

Pipeline tidak menemukan cara baru untuk menghitung bobot. Pipeline mengambil resep paling andal yang dikenal — Hierarchical Risk Parity (HRP) — dan membungkusnya dalam dua lapisan yang benar-benar dibutuhkan akun trading langsung tetapi tidak dimiliki HRP biasa: arah (long/short dari sinyal strategi) dan anggaran risiko yang ketat (CVaR yang disesuaikan untuk rezim volatilitas saat ini). Ini menghasilkan empat tahap.

Empat tahap

harga  I  log return  II  bobot HRP  III  long/short  IV  anggaran CVaR\text{harga} \;\xrightarrow{\text{I}}\; \text{log return} \;\xrightarrow{\text{II}}\; \text{bobot HRP} \;\xrightarrow{\text{III}}\; \text{long/short} \;\xrightarrow{\text{IV}}\; \text{anggaran CVaR}
  • I — log return dari setiap aset.
  • II — bobot dasar dari HRP.
  • III — pembagian long/short dari sinyal agen, dengan porsi risiko ditentukan oleh tingkat kepercayaan.
  • IV — koreksi CVaR dengan volatilitas Hull-White; kelebihan risiko dialihkan ke kas.

Mari kita telusuri satu per satu.

Tahap I. Log return

Semuanya dimulai dari perpindahan harga ke log return:

ri,t=ln ⁣(Si,tSi,t1)r_{i,t} = \ln\!\left(\frac{S_{i,t}}{S_{i,t-1}}\right)

di mana ii adalah aset dan tt adalah langkah waktu. Log return bersifat aditif terhadap waktu dan lebih simetris dibandingkan perubahan persentase biasa — masukan standar untuk semua perhitungan kovarians.

Tahap II. HRP sebagai fondasi

HRP, yang diusulkan oleh Marcos López de Prado pada 2016, menghindari penyakit utama Mean-Variance Optimization — membalik matriks kovarians yang ill-conditioned. HRP sama sekali tidak membaliknya. Sebaliknya, HRP bekerja dengan struktur korelasi.

Kovarians dan korelasi

Dari return kita membangun matriks kovarians Σ\Sigma dan menormalisasinya menjadi matriks korelasi CC:

Σi,j=Cov(ri,rj),Ci,j=ρi,j=Cov(ri,rj)σiσj\Sigma_{i,j} = \mathrm{Cov}(r_i, r_j), \qquad C_{i,j} = \rho_{i,j} = \frac{\mathrm{Cov}(r_i, r_j)}{\sigma_i \sigma_j}

Matriks jarak

Kita mengubah korelasi menjadi metrik jarak, sehingga aset yang sangat berkorelasi berada "berdekatan":

di,j=1ρi,j2d_{i,j} = \sqrt{\frac{1 - \rho_{i,j}}{2}}

Semakin ρi,j\rho_{i,j} mendekati 1, semakin di,jd_{i,j} mendekati 0 — dan semakin besar kemungkinan aset tersebut berbagi kluster yang sama.

Dendrogram dan urutan daun

Dari matriks jarak kita membangun hierarki kluster via average linkage dan membaca leaf order π=(π1,,πN)\pi = (\pi_1, \ldots, \pi_N) — permutasi aset di mana aset yang mirip berada bersebelahan.

Langkah opsional: jumlah kluster optimal dapat dipilih menggunakan koefisien silhouette si=biaimax(bi,ai)s_i = \dfrac{b_i - a_i}{\max(b_i, a_i)}, di mana aia_i adalah rata-rata jarak dalam kluster dan bib_i adalah rata-rata jarak ke kluster tetangga terdekat. Proses dasar tidak memerlukannya — biseksi rekursif sudah menghormati hierarki.

Kuasi-diagonalisasi

Kita mempermutasikan baris dan kolom Σ\Sigma berdasarkan π\pi, mengumpulkan nilai-nilai besar di sepanjang diagonal:

Σi,jq=Σπi,πj\Sigma^{q}_{i,j} = \Sigma_{\pi_i, \pi_j}

Biseksi rekursif

Kemudian rekursi berjalan dari atas ke bawah. Pada setiap langkah sebuah kluster dibagi dua menjadi LL dan RR, dan modal dialokasikan antara dua bagian tersebut berbanding terbalik dengan variansinya:

wL=1/σL21σL2+1σR2,wR=1wLw_L = \frac{1/\sigma_L^2}{\dfrac{1}{\sigma_L^2} + \dfrac{1}{\sigma_R^2}}, \qquad w_R = 1 - w_L

Variansi sebuah kluster dihitung pada sub-blok kovariansnya sebagai σC2=1m2i,jCΣi,jq\sigma_C^2 = \tfrac{1}{m^2}\sum_{i,j \in C}\Sigma^{q}_{i,j}. Proses turun berlanjut hingga setiap node memuat satu aset. Bobot bersifat long-only, tidak negatif, dan berjumlah 1.0.

Dalam implementasi kami ini adalah fungsi hrp_from_cov(cov) -> Vec<f64>: korelasi → jarak → average linkage → leaf order → kuasi-diagonalisasi → biseksi rekursif. Pipeline memanggilnya sebagai dasarnya — dan juga merupakan optimize() publik untuk kasus tanpa sinyal.

Tahap III. Overlay long/short

HRP biasa adalah portofolio "beli saja". Namun sebuah strategi sering kali menunjukkan bukan hanya seberapa banyak tetapi juga ke arah mana. Tahap III mengambil sinyal per aset (Long/Short) dari agen dan membangun dua sub-portofolio.

  1. Aset dibagi menjadi keranjang long dan short berdasarkan sinyal.
  2. Di dalam masing-masing keranjang, bobot dihitung dengan HRP yang sama (pada sub-blok kovarians dari aset tersebut), berjumlah 1 per keranjang.
  3. Jika agen juga mengeluarkan tingkat kepercayaan pip_i, porsi risiko antara kedua sisi ditentukan oleh total kepercayaan:

ξL=iLpi,ξS=iSpi,λL=ξLξL+ξS,λS=ξSξL+ξS\xi_L = \sum_{i \in L} p_i, \quad \xi_S = \sum_{i \in S} p_i, \qquad \lambda_L = \frac{\xi_L}{\xi_L + \xi_S}, \quad \lambda_S = \frac{\xi_S}{\xi_L + \xi_S}

Tanpa tingkat kepercayaan, porsi dikembalikan ke jumlah aset di setiap keranjang. Bobot bertanda akhir adalah wi=λLwiHRPw_i = \lambda_L \cdot w_i^{\text{HRP}} untuk long dan wi=λSwiHRPw_i = -\lambda_S \cdot w_i^{\text{HRP}} untuk short, setelah itu seluruh gross exposure dinormalisasi menjadi 1.

Catatan jujur tentang kode. Spesifikasi asli memuat faktor koreksi αL=λL/σL\alpha_L = \sqrt{\lambda_L}/\sigma_L, αS=λS/σS\alpha_S = \sqrt{\lambda_S}/\sigma_S — tetapi juga menandainya dengan "apakah kita bahkan membutuhkan langkah ini?". Implementasi tidak menerapkannya: dua sisi digabungkan langsung berdasarkan porsi risiko λ\lambda, yang membuat gross exposure tepat di 1 dan tidak menciptakan leverage tersembunyi. Ini adalah penyederhanaan spesifikasi yang disengaja, bukan kelalaian.

Tahap IV. CVaR dengan penyesuaian Hull-White

HRP menyeimbangkan risiko secara struktural, tetapi tidak mengetahui apa-apa tentang tingkat risiko absolut dalam satuan uang. Tahap akhir menempatkan batas keras pada risiko ekor — dan membuatnya peka terhadap perubahan rezim pasar.

Return portofolio dan volatilitas EWMA

Pertama kita mereduksi bobot menjadi return portofolio dan memperkirakan volatilitas kondisional dengan EWMA:

rp,t=i=1nwiri,t,σp,t2=λσp,t12+(1λ)rp,t12r_{p,t} = \sum_{i=1}^{n} w_i\, r_{i,t}, \qquad \sigma_{p,t}^2 = \lambda\, \sigma_{p,t-1}^2 + (1 - \lambda)\, r_{p,t-1}^2

dengan λ=0.94\lambda = 0.94 (nilai RiskMetrics klasik). EWMA memberikan volatilitas "hari ini" daripada yang dirata-ratakan sepanjang sejarah.

Penyekalaan ulang Hull-White

Ide utama: return masa lalu tidak bisa diambil apa adanya — return tersebut terjadi di bawah volatilitas yang berbeda. Metode Hull-White menyekalakan ulang setiap return masa lalu ke tingkat saat ini:

r~p,s=σp,t+1σp,srp,s,s=tN+1,,t\widetilde{r}_{p,s} = \frac{\sigma_{p,t+1}}{\sigma_{p,s}}\, r_{p,s}, \qquad s = t - N + 1, \ldots, t

Bulan yang tenang "diregangkan", bulan yang bergolak "dikompres", dan distribusi dibawa ke rezim saat ini.

VaR dan CVaR

Pada distribusi yang telah disekalakan ulang kita mengambil kuantil kerugian dan rata-rata kerugian di ekor:

VaRαHW=q1α(r~p)VaR_\alpha^{HW} = -q_{1-\alpha}(\widetilde{r}_p)

CVaRαHW=E ⁣[r~pr~pq1α(r~p)]CVaR_\alpha^{HW} = -\mathbb{E}\!\left[\widetilde{r}_p \mid \widetilde{r}_p \le q_{1-\alpha}(\widetilde{r}_p)\right]

CVaR (a.k.a. Expected Shortfall) menjawab bukan "seberapa buruk hari buruk yang tipikal" tetapi "seberapa buruk rata-rata di seluruh α\alpha persen terburuk" — sehingga ia melihat ketebalan ekor, bukan hanya tepinya.

Anggaran risiko dan kas

Jika CVaR melebihi ambang batas yang dapat diterima, setiap posisi berisiko dikecilkan dengan satu faktor tunggal, dan modal yang dibebaskan dipindahkan ke kas:

winew=γwi,γ=CVaRmaxCVaRαHW,wcash=1i=1nwineww_i^{new} = \gamma\, w_i, \quad \gamma = \frac{CVaR_{\max}}{CVaR_\alpha^{HW}}, \qquad w_{cash} = 1 - \sum_{i=1}^{n} |w_i^{new}|

Dengan demikian portofolio mengurangi risiko sendiri ketika risiko ekor meningkat dan memasuki kembali pasar ketika keadaan mereda.

Dari spesifikasi ke kode

Seluruh algoritma berada dalam satu crate Rust, portfolio-pipeline, dan mengikuti kontrak seragam workspace:

pub fn optimize(prices: &[Vec<f64>]) -> Vec<f64>

Ini adalah proyeksi long-only (tahap I, II, IV tanpa sinyal) — antarmuka prices -> weights yang persis sama dengan sebelas algoritma lainnya, sehingga Pipeline dapat menggantikan semua di antaranya secara langsung. Versi lengkap dengan setiap tahap adalah fungsi terpisah:

pub fn run(
    prices: &[Vec<f64>],
    signals: Option<&[Side]>,      // Long / Short per asset
    confidence: Option<&[f64]>,    // agent confidence → risk shares λ
    cfg: &PipelineConfig,          // CVaR / Hull-White parameters
) -> PipelineResult                // signed weights + cash + cvar + σ

Default overlay: ekor cvar_alpha = 0.05, anggaran cvar_max = 0.05, EWMA ewma_lambda = 0.94, jendela Hull-White hw_window = 0 (seluruh sejarah). Implementasi tidak memiliki dependensi eksternal dan secara sengaja bersifat defensif: pada sejarah singkat (kurang dari 4 titik harga) ia mengembalikan bobot yang sama, dan overlay CVaR hanya aktif pada ≥8 observasi return — jika tidak, tidak ada yang bisa diperkirakan dari ekor.

Mengapa Rust: satu basis kode deterministik untuk backtest dan produksi, tanpa "Python di riset, sesuatu yang lain di prod" yang menyimpang, dan cukup cepat untuk menjalankan semua dua belas algoritma dalam satu permintaan melalui backend perbandingan.

Berapa biaya waktu yang diperlukan

Seberapa cepat "cukup cepat"? Kami mengekstrak inti HRP (log return → kovarians → average linkage → kuasi-diagonalisasi → bobot rekursif) ke dalam benchmark mandiri dan menjalankan matematika yang persis sama di tujuh bahasa — C, C++, Rust, Zig, Python, Node.js dan Bun — dalam kondisi identik: Apple Silicon, satu utas, 365 observasi harian per aset, harga sintetis, jumlah aset NN dari 10 hingga 10.000.

Sepatah kata tentang kompleksitas, karena itu menentukan keseluruhan bentuk. Versi buku teks dari average linkage memindai ulang seluruh matriks jarak untuk menemukan pasangan terdekat pada setiap penggabungan — itu adalah O(N3)O(N^3) dan menjadi bottleneck pada beberapa ribu aset. Benchmark ini menggunakan algoritma O(N2)O(N^2) nearest-neighbour-chain (Müllner 2011) — yang sama dengan yang digunakan SciPy's linkage(method='average'). Dengan itu, klusterisasi bukan lagi tahap dominan: pada N=2000N = 2000 sekitar ~15 ms dari ~0,5 s total. Biaya sekarang didominasi oleh matriks kovarians, O(N2T)O(N^2 \cdot T) — satu-satunya tahap yang tidak dapat dihindari oleh metode gaya HRP mana pun.

Yang ditunjukkan oleh percobaan (tabel per bahasa lengkap dan skrip reproduksi satu perintah ada di repositori proyek):

  • Pada portofolio realistis, ini gratis. Keranjang kripto terdiri dari puluhan aset, jarang lebih dari seratus. Pada N100N \le 100 satu pass HRP penuh adalah milidetik satu digit bahkan di Node dan mikrodetik di Rust/C. Menghitung ulang bobot pada setiap tick bukan masalah.
  • Rust berada dalam ~1,0–1,3× dari C — urutan besaran yang sama, keduanya terkompilasi, dan efektif setara begitu NN mencapai ribuan. C sedikit lebih cepat pada aritmatika mentah, tetapi Rust memberikan prediktabilitas yang sama tanpa garbage collector dan tanpa UB.
  • Skala hingga ribuan aset. Dengan linkage O(N2)O(N^2) satu pass penuh adalah ~0,5 detik pada N=2000N = 2000 dan beberapa detik pada N=5000N = 5000 dalam bahasa terkompilasi; bahkan Node yang diinterpretasikan berhasil melewati N=2000N = 2000 dalam kurang dari dua detik. Yang menjadi batas sekarang adalah tahap kovarians, bukan klusterisasi.

Kesimpulan pragmatis: pada ukuran portofolio kami, memilih Rust bukan tentang "mengalahkan C" (C sedikit lebih cepat di sini) — ini tentang satu basis kode deterministik untuk riset dan produksi, tanpa jeda GC dan headroom performa selama bertahun-tahun. Benchmark tujuh bahasa lengkap, dengan hasil dan skrip reproduksi, terbuka di repositori proyek.

Di mana Pipeline berada di antara dua belas algoritma

Dalam perbandingan kami pada satu keranjang (yang sengaja dirancang), Pipeline berperilaku seperti HRP — karena melalui titik masuk optimize() long-only ia adalah HRP dengan overlay CVaR. Mesin arahnya hanya aktif ketika Anda memberinya sinyal strategi. Itulah inti permasalahannya: Pipeline bukan "optimizer lain untuk bobot backtesting" tetapi lapisan eksekusi antara sinyal strategi dan order nyata — Pipeline mengambil panggilan beli/jual Anda, menyusun modal berdasarkan HRP di setiap sisi, menyeimbangkan sisi-sisi berdasarkan tingkat kepercayaan, dan memotong risiko ekor hingga anggaran yang ditentukan.

Untuk konteks lengkap — sebelas metode lain apa yang ada dan bagaimana perbedaannya — lihat tinjauan, «12 Algoritma Optimisasi Portofolio, Dibandingkan». Dan Anda dapat mencoba semuanya secara langsung di portfolio-optimizer.marketmaker.cc.

Referensi

  1. López de Prado, M. (2016). Building Diversified Portfolios that Outperform Out of Sample. The Journal of Portfolio Management.
  2. López de Prado, M. (2018). Advances in Financial Machine Learning. Wiley.
  3. Hull, J., & White, A. (1998). Incorporating Volatility Updating into the Historical Simulation Method for Value at Risk. Journal of Risk.
  4. Rockafellar, R. T., & Uryasev, S. (2000). Optimization of Conditional Value-at-Risk. Journal of Risk.
  5. RiskMetrics Group (1996). RiskMetrics — Technical Document. J.P. Morgan.
  6. Marketmaker.cc: marketmaker.cc

Kutipan

@article{soloviov2026pipeline,
  author = {Soloviov, Eugen and Zhuravleva, Marina and Kiselev, Kirill},
  title = {Inside Our House Algorithm: HRP + Long/Short + CVaR with Hull-White Adjustment},
  year = {2026},
  url = {https://marketmaker.cc/id/blog/post/portfolio-pipeline-hrp-cvar},
  description = {Penjelasan mendalam tentang Pipeline, algoritma alokasi portofolio komposit yang dibangun di atas Hierarchical Risk Parity dengan overlay long/short berbasis sinyal dan koreksi anggaran risiko CVaR Hull-White, beserta spesifikasi lengkap dan implementasi Rust-nya.}
}
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.

Marina Zhuravleva
Marina Zhuravleva

Financial mathematics

Fifth-year student at Bauman Moscow State Technical University (Automatic Control Systems), specializing in financial mathematics. Background in calibrating stochastic-volatility (Heston) and local-volatility (Dupire) models, fair pricing of options including exotics via both Monte-Carlo and analytic formulas, hedging-error reduction, and exposure to LSV models.

Kirill Kiselev
Kirill Kiselev

Portfolio optimization

Fourth-year student at the Faculty of Mechanics and Mathematics, Novosibirsk State University (NSU); thesis on Heston-model calibration and delta-hedging within the same model. Works on portfolio optimization.

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.