← Мақалаларға оралу
May 25, 2026
5 мин оқу

Біздің меншікті алгоритмнің ішінде: Hull-White көмегімен HRP + Long/Short + CVaR

Біздің меншікті алгоритмнің ішінде: Hull-White көмегімен HRP + Long/Short + CVaR
#portfolio optimization
#HRP
#hierarchical risk parity
#CVaR
#Hull-White
#EWMA
#long/short
#risk management
#Rust
#quantitative finance
📊
Part 3 of 5 · Collection
Portfolio Construction & Risk

📄 Бұл мақала зерттеу мақаласына айналды. Осы пайплайынның негізінде жатқан HRP аллокациясы белгілі ковариация жағдайында Markowitz, Ledoit-Wolf шринкеджі және 1/N-мен бақыланатын сынақта тексерілді (4 800 эксперимент). Мақаланы онлайн (интерактивті нұсқа + PDF) hrp.marketmaker.cc сайтынан оқыңыз, код пен деректер github.com/suenot/hrp-validation мекенжайында.

Біздің «12 портфельді оңтайландыру алгоритмі, салыстыру» шолуымызда біз ондаған аллокация әдістерін қатар сынадық. Оның он бірі — оқулық классикасы. Он екіншісі, Pipeline, — біздің меншігіміз, әрі ол сол мақалада тек бір ғана тармаққа ие болды. Бұл мақала — терең талдау: оның ішінде не бар, әр формула қайдан шыққан және спецификация қалай Rust кодына айналады.

Pipeline салмақты есептеудің жаңа тәсілін ойлап таппайды. Ол белгілі ең берік рецепт — Hierarchical Risk Parity (HRP) — алады да, оны нақты сауда шотына шынымен қажет, бірақ таза HRP-де жоқ екі қабатпен қаптайды: бағыт (стратегия сигналдарынан long/short) және қатаң тәуекел бюджеті (ағымдағы волатильділік режиміне сай түзетілген CVaR). Осылайша төрт кезең пайда болады.

Төрт кезең

prices  I  log returns  II  HRP weights  III  long/short  IV  CVaR budget\text{prices} \;\xrightarrow{\text{I}}\; \text{log returns} \;\xrightarrow{\text{II}}\; \text{HRP weights} \;\xrightarrow{\text{III}}\; \text{long/short} \;\xrightarrow{\text{IV}}\; \text{CVaR budget}
  • I — әр активтің логарифмдік кірістілігі.
  • II — HRP-ден алынған негізгі салмақтар.
  • III — агент сигналдарынан алынған long/short бөлінісі, тәуекел үлестері сенімділікпен белгіленеді.
  • IV — Hull-White волатильділігімен CVaR түзетуі; артық тәуекел қолма-қол ақшаға ауысады.

Оларды ретімен қарастырайық.

I кезең. Логарифмдік кірістілік

Барлығы бағалардан логарифмдік кірістілікке көшуден басталады:

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

мұндағы ii — актив, tt — уақыт қадамы. Логарифмдік кірістіліктер уақыт бойынша қосылады және қарапайым пайыздық өзгерістерге қарағанда симметриялырақ — кез келген ковариациялық математика үшін стандартты кіріс.

II кезең. Іргетас ретінде HRP

Marcos López de Prado 2016 жылы ұсынған HRP Mean-Variance Optimization-нің басты кемшілігінен — нашар шартталған ковариация матрицасын инверсиялаудан — аулақ болады. Ол оны мүлдем инверсияламайды. Оның орнына корреляциялардың құрылымымен жұмыс істейді.

Ковариация және корреляция

Кірістіліктерден біз ковариация матрицасы Σ\Sigma құрамыз және оны корреляция матрицасы 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}

Қашықтық матрицасы

Біз корреляцияны қашықтық метрикасына айналдырамыз, сол арқылы қатты корреляцияланған активтер "бір-біріне жақын" орналасады:

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

ρi,j\rho_{i,j} 1-ге жақындаған сайын, di,jd_{i,j} 0-ге жақындайды — және активтердің бір кластерге кіру мүмкіндігі соғұрлым артады.

Дендрограмма мен жапырақ реті

Қашықтық матрицасынан біз average linkage арқылы кластерлер иерархиясын құрамыз және жапырақ ретін π=(π1,,πN)\pi = (\pi_1, \ldots, \pi_N) анықтаймыз — бұл ұқсас активтер бір-біріне жапсарлас орналасқан активтердің ауыстырылымы.

Қосымша қадам: кластерлердің оңтайлы санын силуэт коэффициенті si=biaimax(bi,ai)s_i = \dfrac{b_i - a_i}{\max(b_i, a_i)} арқылы таңдауға болады, мұндағы aia_i — кластер ішіндегі орташа қашықтық, ал bib_i — ең жақын көрші кластерге дейінгі орташа қашықтық. Негізгі өту оны қажет етпейді — рекурсивті бисекция иерархияны бұрыннан сақтайды.

Квази-диагоналдау

Біз Σ\Sigma-ның жолдары мен бағандарын π\pi бойынша ауыстырамыз, үлкен мәндерді диагональ бойымен жинақтаймыз:

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

Рекурсивті бисекция

Содан кейін рекурсия жоғарыдан төменге қарай жүреді. Әр қадамда кластер LL мен RR екі жартыға бөлінеді, ал капитал жартылар арасында олардың дисперсиясына кері пропорционал түрде бөлінеді:

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

Кластердің дисперсиясы оның ковариация ішкі блогында σC2=1m2i,jCΣi,jq\sigma_C^2 = \tfrac{1}{m^2}\sum_{i,j \in C}\Sigma^{q}_{i,j} ретінде есептеледі. Түсу әр түйінде бір ғана актив қалғанша жалғасады. Салмақтар long-only, теріс емес, қосындысы 1,0-ге тең.

Біздің іске асыруда бұл — hrp_from_cov(cov) -> Vec<f64> функциясы: корреляция → қашықтық → average linkage → жапырақ реті → квази-диагоналдау → рекурсивті бисекция. Pipeline оны өзінің негізі ретінде шақырады — әрі бұл сигналсыз жағдай үшін көпшілікке ашық optimize() функциясы болып та табылады.

III кезең. Long/short үстеме қабаты

Таза HRP — "тек сатып алу" портфелі. Бірақ стратегия жиі қаншалықты ғана емес, қай бағытта екенін де айтады. III кезең агенттен әр активке арналған сигналдарды (Long/Short) алады және екі ішкі портфель құрады.

  1. Активтер сигнал бойынша long және short себеттеріне бөлінеді.
  2. Әр себет ішінде салмақтар сол HRP көмегімен (сол активтердің ковариация ішкі блогында) есептеледі, себет бойынша қосындысы 1-ге тең.
  3. Егер агент сенімділік pip_i мәнін де шығарса, жақтар арасындағы тәуекел үлестері жалпы сенімділікпен белгіленеді:

ξ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}

Сенімділік болмаған жағдайда үлестер әр себеттегі активтер санына оралады. Соңғы таңбалы салмақ longs үшін wi=λLwiHRPw_i = \lambda_L \cdot w_i^{\text{HRP}}, shorts үшін wi=λSwiHRPw_i = -\lambda_S \cdot w_i^{\text{HRP}}, содан кейін жалпы жалпы экспозиция 1-ге қалыпқа келтіріледі.

Код туралы шыншыл ескерту. Бастапқы спецификацияда αL=λL/σL\alpha_L = \sqrt{\lambda_L}/\sigma_L, αS=λS/σS\alpha_S = \sqrt{\lambda_S}/\sigma_S түзету коэффициенттері бар — бірақ ол оларды "бізге бұл қадам шынымен керек пе?" деп те белгілейді. Іске асыру оларды қолданбайды: екі жақ тікелей λ\lambda тәуекел үлестерімен біріктіріледі, бұл жалпы экспозицияны дәл 1-де ұстайды және жасырын левередж тудырмайды. Бұл спецификацияның әдейі жасалған жеңілдетілуі, ұмыт кету емес.

IV кезең. Hull-White түзетуімен CVaR

HRP тәуекелді құрылымдық тұрғыдан теңестіреді, бірақ ақшалай мәндегі абсолютті тәуекел деңгейі туралы ешнәрсе білмейді. Соңғы кезең соңғы (tail) тәуекелге қатаң шек қояды — және оны нарық режимінің өзгеруіне сезімтал етеді.

Портфель кірістілігі және EWMA волатильділігі

Алдымен біз салмақтарды портфель кірістілігіне жинақтаймыз және шартты волатильділікті 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

λ=0.94\lambda = 0.94 мәнімен (классикалық RiskMetrics мәні). EWMA бүкіл тарихтан орташаланған емес, "бүгінгі" волатильділікті береді.

Hull-White қайта масштабтауы

Негізгі идея: өткен кірістіліктерді бар күйінде алуға болмайды — олар басқа волатильділік жағдайында болған. Hull-White әдісі әр өткен кірістілікті ағымдағы деңгейге қайта масштабтайды:

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

Тыныш ай "созылады", толқынды ай "сығылады", ал үлестірім ағымдағы режимге келтіріледі.

VaR және CVaR

Қайта масштабталған үлестірімде біз шығын квантилі мен соңдағы орташа шығынды аламыз:

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 (Expected Shortfall деп те аталады) "әдеттегі жаман күн қаншалықты жаман" деген сұраққа емес, "ең жаман α\alpha пайызда орта есеппен қаншалықты жаман" деген сұраққа жауап береді — сондықтан ол соңы шетін ғана емес, оның қалыңдығын да көреді.

Тәуекел бюджеті және қолма-қол ақша

Егер CVaR қолайлы шектен асып кетсе, әрбір тәуекелді позиция бір коэффициентпен қысқарады, ал босаған капитал қолма-қол ақшаға өтеді:

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

Осылайша соңдағы тәуекел өскенде портфель өз тәуекелін азайтады, ал ол тынышталғанда нарыққа қайта оралады.

Спецификациядан кодқа дейін

Бүкіл алгоритм бір ғана Rust crate-інде, portfolio-pipeline, орналасады және жұмыс кеңістігінің біртұтас келісіміне бағынады:

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

Бұл — long-only проекция (сигналсыз I, II, IV кезеңдер) — қалған он бір алгоритммен бірдей prices -> weights интерфейсі, сондықтан Pipeline олардың кез келгенін тікелей алмастыра алады. Әр кезеңі бар толық нұсқа жеке функция болып табылады:

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 + σ

Үстеме қабаттың әдепкі мәндері: соңы cvar_alpha = 0.05, бюджет cvar_max = 0.05, EWMA ewma_lambda = 0.94, Hull-White терезесі hw_window = 0 (бүкіл тарих). Іске асыруда сыртқы тәуелділіктер жоқ және ол әдейі сақтық танытады: қысқа тарихта (4-тен аз баға нүктесі) ол тең салмақтарды қайтарады, ал CVaR үстеме қабаты тек ≥8 кірістілік бақылауынан бастап қосылады — әйтпесе соңды бағалайтын ештеңе жоқ.

Неге Rust: бэктест пен өндіріс үшін бір ғана детерминистік кодтық база, "зерттеуде Python, өндірісте бірдеңе басқа" деген ауытқусыз, әрі он екі алгоритмнің барлығын салыстыру бэкенді арқылы бір сұраныста жүргізе алатындай жылдам.

Уақыт бойынша қанша тұрады

"Жеткілікті жылдам" деген қаншалықты жылдам? Біз HRP ядросын (логарифмдік кірістілік → ковариация → average linkage → квази-диагоналдау → рекурсивті салмақтар) дербес бенчмаркқа бөліп алдық және дәл сол математиканы бірдей жағдайларда жеті тілде — C, C++, Rust, Zig, Python, Node.js және Bun — жүргіздік: Apple Silicon, бір ағын, актив басына 365 күндік бақылау, синтетикалық бағалар, актив саны NN 10-нан 10 000-ға дейін.

Күрделілік туралы бір сөз, өйткені ол бүкіл пішінді анықтайды. average linkage-тің оқулықтағы нұсқасы әр біріктіру кезінде ең жақын жұпты іздеу үшін қашықтық матрицасын толығымен қайта қарайды — бұл O(N3)O(N^3), әрі бірнеше мың активте кедергіге айналады. Бенчмарк оның орнына O(N2)O(N^2) nearest-neighbour-chain алгоритмін (Müllner 2011) қолданады — бұл SciPy-дың linkage(method='average') артындағы дәл сол алгоритм. Осымен кластерлеу енді басым кезең емес: N=2000N = 2000 кезінде ~0,5 с өтуден ~15 мс ғана. Шығын енді ковариация матрицасымен, O(N2T)O(N^2 \cdot T), басым — бұл HRP тәрізді ешбір әдіс аулақ бола алмайтын жалғыз кезең.

Жүргізулер не көрсетеді (әр тіл бойынша толық кестелер мен бір командалық репродукция скрипті жоба репозиторийінде жатыр):

  • Шынайы портфельдерде бұл тегін. Крипто себеті ондаған активтен тұрады, жүзден асатыны сирек. N100N \le 100 кезінде толық HRP өтуі тіпті Node-де бір таңбалы миллисекунд, ал Rust/C-де микросекунд құрайды. Әр тикте салмақтарды қайта есептеу проблема емес.
  • Rust C-ден ~1,0–1,3× шамасында ғана артта қалады — бірдей ретті шама, екеуі де компиляцияланған, әрі NN мыңдарға жеткенде іс жүзінде теңеседі. Таза арифметикада C сәл жылдамырақ, бірақ Rust қоқыс жинаушысыз және UB-сыз дәл сондай болжамдылықты береді.
  • Ол мыңдаған активке дейін масштабталады. O(N2)O(N^2) linkage-мен толық өту компиляцияланған тілдерде N=2000N = 2000 кезінде ~0,5 с, ал N=5000N = 5000 кезінде бірнеше секунд құрайды; интерпретацияланған Node тіпті N=2000N = 2000-ды екі секундтан аз уақытта өтеді. Енді шекті ковариация кезеңі белгілейді, кластерлеу емес.

Прагматикалық қорытынды: біздің портфель өлшемдерінде Rust таңдау "C-ден озу" туралы емес (мұнда C сәл жылдамырақ) — бұл зерттеу мен өндіріс үшін бір детерминистік кодтық база, GC үзілістерінсіз және көп жылдық өнімділік қоры туралы. Нәтижелер мен репродукция скрипті бар жеті тілдің толық бенчмаркі жоба репозиторийінде ашық жатыр.

Pipeline он екеудің арасында қайда орналасады

Бір ғана (әдейі дайындалған) себетке жасалған салыстыруымызда Pipeline HRP сияқты әрекет етті — өйткені long-only optimize() кіру нүктесі арқылы ол CVaR үстеме қабаты бар HRP болып табылады. Оның бағыттық механизмі тек стратегия сигналдары берілгенде ғана жанданады. Бүкіл мән осында: Pipeline "салмақтарды бэктестеуге арналған тағы бір оптимизатор" емес, ол стратегия сигналдары мен нақты бұйрықтар арасындағы орындау қабаты — ол сіздің сатып алу/сату шешімдеріңізді алады, әр жақ ішінде капиталды HRP бойынша орналастырады, жақтарды сенімділікпен теңестіреді, әрі соңдағы тәуекелді белгіленген бюджетке дейін қияды.

Толық контекст үшін — қалған он бір әдіс қандай және олар қалай ерекшеленеді — шолуды қараңыз, «12 портфельді оңтайландыру алгоритмі, салыстыру». Әрі мұның бәрін portfolio-optimizer.marketmaker.cc сайтында тікелей сынап көре аласыз.

Дереккөздер

  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

Дәйексөз

@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/kk/blog/post/portfolio-pipeline-hrp-cvar},
  description = {A deep dive into Pipeline, a composite portfolio allocation algorithm built on Hierarchical Risk Parity with a signal-driven long/short overlay and a Hull-White CVaR risk-budget correction, with the full specification and its Rust implementation.}
}
blog.disclaimer

Authors

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

Нарықтан бір қадам алда болыңыз

AI сауда талдаулары, нарық аналитикасы және платформа жаңалықтары үшін біздің ақпараттық бюллетеньге жазылыңыз.

Біз сіздің жекелігіңізді құрметтейміз. Кез келген уақытта жазылымнан шығуға болады.