При спробі вручну згрупувати сотні криптовалют за поведінкою легко заплутатися — активи зі схожою волатильністю можуть мати різну кореляцію з BTC, а обсяги торгів змінюються випадково. Наші інженери з 5-річним досвідом у ML та 50+ проектами з аналізу крипторинку автоматизують цей процес за допомогою ML-моделі кластеризації, яка виділяє приховані групи на основі 15+ метрик: річна дохідність, волатильність, коефіцієнт Шарпа, асиметрія, ексцес, VaR 95%, CVaR 95%, максимальна просідання, кореляція з BTC, моментум за 30 днів, середній денний обсяг. Це не класифікація — ми не навішуємо ярлики, а знаходимо природні групи, об'єднуючи активи за схожими поведінковими патернами. Такий підхід дозволяє виявляти приховані поведінкові патерни та групувати активи для подальшого аналізу.
Така кластеризація дозволяє забезпечити портфельну диверсифікацію, вибираючи по 1-2 активи з кожного кластера, знижуючи кореляцію між криптовалютами. Вона також застосовна для ротаційних стратегій: коли один актив у кластері різко зростає, ми шукаємо відстаючі активи того ж кластера. Нарешті, вона допомагає зрозуміти ринкову структуру: виділяються групи «блакитних фішок», високобета-альткоїнів, декоррельованих активів.
Як ми збираємо ознаки для кластеризації
Feature engineering — ключовий етап. На вхід беремо годинні ціни закриття за останні 90 днів. Для кожного активу розраховуємо:
- дохідність та волатильність (річні),
- коефіцієнт Шарпа (відношення дохідності до ризику),
- моментум за 30 днів,
- максимальну просідання,
- кореляцію з BTC (якщо доступна),
- середній денний обсяг у USD.
Код функції створення ознак:
import pandas as pd import numpy as np from sklearn.preprocessing import StandardScaler def create_behavioral_features(prices_dict, lookback_days=90): features = {} for symbol, price_series in prices_dict.items(): returns = price_series.pct_change().dropna() if len(returns) < lookback_days * 24: # hourly data continue recent_returns = returns.iloc[-lookback_days*24:] features[symbol] = { # Return characteristics 'annualized_return': recent_returns.mean() * 365 * 24, 'annualized_vol': recent_returns.std() * np.sqrt(365 * 24), 'sharpe': recent_returns.mean() / (recent_returns.std() + 1e-8) * np.sqrt(365*24), # Distribution shape 'skewness': recent_returns.skew(), 'kurtosis': recent_returns.kurt(), # Tail risk 'var_95': np.percentile(recent_returns, 5), 'cvar_95': recent_returns[recent_returns <= np.percentile(recent_returns, 5)].mean(), # Trend characteristics 'momentum_30d': price_series.iloc[-720:].pct_change(720).iloc[-1], # 30d return 'trend_strength': abs(recent_returns.mean()) / (recent_returns.std() + 1e-8), # Drawdown 'max_drawdown': calculate_max_drawdown(price_series.iloc[-lookback_days*24:]), # Correlation with BTC (if available) 'btc_corr': recent_returns.corr(prices_dict.get('BTC', pd.Series()).pct_change().dropna()), # Volume-based (якщо доступні volume дані) 'avg_daily_volume_usd': get_avg_daily_volume(symbol), } return pd.DataFrame(features).T На одному з проектів для хедж-фонду ми кластеризували 150 криптовалют за 2 тижні. В результаті клієнт сформував портфель з кореляцією 0.35 між активами з різних кластерів, знизивши ризик просідання на 40%. Це дозволило заощадити на ручному аналізі понад 200 годин на рік.
Як інтерпретувати кластери?
Після кластеризації аналізуємо середні значення метрик по кожному кластеру. Для аналізу волатильності ми використовуємо річну волатильність, а для порівняння ризику — коефіцієнт Шарпа. Наприклад:
| Кластер | Кореляція з BTC | Волатильність (річна) | Коефіцієнт Шарпа | Інтерпретація |
|---|---|---|---|---|
| 0 | >0.85 | >1.5 | <1.0 | High-beta altcoins |
| 1 | >0.8 | <1.0 | >1.5 | Blue-chip crypto |
| 2 | <0.5 | <0.8 | >2.0 | Decorrelated assets |
| 3 | <0.5 | >2.0 | <0.5 | Speculative / memes |
Код автоматичної інтерпретації:
def describe_clusters(features_df, labels): features_df['cluster'] = labels cluster_stats = features_df.groupby('cluster').agg({ 'annualized_return': 'mean', 'annualized_vol': 'mean', 'sharpe': 'mean', 'btc_corr': 'mean', 'max_drawdown': 'mean', 'skewness': 'mean' }).round(3) cluster_names = {} for cluster_id, row in cluster_stats.iterrows(): if row['btc_corr'] > 0.85 and row['annualized_vol'] > 1.5: name = 'High-beta altcoins' elif row['btc_corr'] > 0.8 and row['annualized_vol'] < 1.0: name = 'Blue-chip crypto' elif row['btc_corr'] < 0.5: name = 'Decorrelated assets' elif row['sharpe'] > 2.0: name = 'Strong performers' else: name = f'Cluster {cluster_id}' cluster_names[cluster_id] = name return cluster_stats, cluster_names Порівняння алгоритмів кластеризації:
| Алгоритм | Швидкість | Необхідність завдання k | Виявлення викидів | Форма кластерів |
|---|---|---|---|---|
| K-Means | Швидкий | Так (k) | Ні | Сферична |
| DBSCAN | Середній | Ні (eps, min_samples) | Так | Довільна |
| Hierarchical | Повільний | Ні (k) | Ні | Будь-яка (дендрограма) |
Найважливіші метрики для кластеризації
Не всі метрики однаково корисні. Кореляція з BTC та волатильність часто домінують, але додавання моментуму та просідань покращує розділення спекулятивних активів. Ми застосовуємо PCA для аналізу важливості ознак та видаляємо мультиколінеарні.
Порівняння алгоритмів кластеризації
Ми використовуємо три підходи — кожен зі своїми сильними сторонами.
K-Means — класика: швидкий, наприклад, виконується в 3 рази швидше, ніж DBSCAN, на датасеті з 500+ об'єктами. Але передбачає сферичні кластери однакового розміру. Підходить для первинного розбиття.
from sklearn.cluster import KMeans from sklearn.preprocessing import StandardScaler def kmeans_clustering(features_df, n_clusters=6, seed=42): scaler = StandardScaler() features_scaled = scaler.fit_transform(features_df.fillna(0)) inertias = [] k_range = range(2, 15) for k in k_range: km = KMeans(n_clusters=k, random_state=seed, n_init=10) km.fit(features_scaled) inertias.append(km.inertia_) best_k = find_elbow(inertias, k_range) km = KMeans(n_clusters=best_k, random_state=seed, n_init=10) labels = km.fit_predict(features_scaled) return labels, km, scaler DBSCAN — не вимагає вказівки числа кластерів, знаходить викиди (шумові точки). Хороший, коли кластери мають складну форму.
from sklearn.cluster import DBSCAN def dbscan_clustering(features_scaled, eps=0.5, min_samples=3): db = DBSCAN(eps=eps, min_samples=min_samples, metric='euclidean') labels = db.fit_predict(features_scaled) n_clusters = len(set(labels)) - (1 if -1 in labels else 0) n_noise = (labels == -1).sum() return labels, n_clusters, n_noise Hierarchical clustering — будує дендрограму, наочно показуючи ієрархію. Його ми використовуємо для візуального аналізу, коли потрібно побачити вкладеність кластерів.
Чому UMAP кращий за PCA для візуалізації кластерів?
Для візуалізації багатовимірних даних ми зменшуємо розмірність до 2D. UMAP (Uniform Manifold Approximation and Projection), на відміну від лінійного PCA, краще зберігає глобальну та локальну структуру. На практиці UMAP дає більш компактні та розділені кластери, особливо для даних з нелінійними залежностями. UMAP описаний в роботі McInnes et al..
from sklearn.decomposition import PCA from sklearn.manifold import TSNE import umap def reduce_dimensions(features_scaled, method='umap', n_components=2): if method == 'pca': reducer = PCA(n_components=n_components, random_state=42) elif method == 'tsne': reducer = TSNE(n_components=n_components, random_state=42, perplexity=min(30, len(features_scaled)//4)) elif method == 'umap': reducer = umap.UMAP(n_components=n_components, random_state=42, n_neighbors=min(15, len(features_scaled)//3)) embedding = reducer.fit_transform(features_scaled) return embedding Після редукції будуємо scatter plot з кольоровою маркуванням по кластерах — це головна візуалізація результатів.
Як відбувається процес роботи?
- Збір та очищення даних — історичні ціни, обсяги, on-chain метрики за 90-180 днів.
- Feature engineering — розрахунок 15+ метрик, нормалізація, відбір ознак.
- Вибір алгоритму — тестуємо K-Means, DBSCAN, Hierarchical; оптимізуємо число кластерів.
- Валідація — silhouette score, візуалізація UMAP, стабільність кластерів.
- Візуалізація — дашборд з інтерактивною картою кластерів.
- Документація — інтерпретація кожного кластера, інструкція з оновлення.
Що входить у роботу?
- Код моделі на Python з коментарями.
- Дашборд (Plotly/Dash) з візуалізацією кластерів.
- Документація з інтерпретацією кожного кластера.
- Інструкція з оновлення моделі (рекомендована періодичність — раз на місяць).
- Підтримка протягом 1 місяця після здачі.
Завдяки багаторічному досвіду та сертифікованим спеціалістам ми гарантуємо високу якість роботи. Вартість розробки моделі залежить від кількості активів та глибини даних, зазвичай від 2 000 до 5 000 доларів США. Наприклад, вартість моделі для 100 активів становить 3 000 доларів. Зв'яжіться з нами для попередньої оцінки вашого датасету — ми підберемо архітектуру під вашу задачу. Замовте розробку моделі та отримайте готовий інструмент для диверсифікації портфеля.







