Correlazione dei Segnali: Quante Coppie Monitorare
Lanci una strategia su 10 coppie crypto: BTC/USDT, ETH/USDT, SOL/USDT, AVAX/USDT e altre sei alt. La logica sembra inattaccabile: se la strategia è attiva il 5% del tempo su una coppia, allora su 10 coppie almeno una dovrebbe essere attiva del tempo. Un aumento quadruplo dell'utilizzo.
In pratica, l'utilizzo risulta essere il 15-16%, non il 40%. Le tue 10 coppie si comportano come 3. Il capitale rimane fermo, la fill_efficiency cala e il rendimento effettivo del portafoglio risulta tre volte inferiore a quello previsto.
Il motivo è la correlazione dei segnali. E nelle criptovalute è catastroficamente alta.
L'Illusione della Diversificazione nel Crypto

Nella finanza tradizionale la diversificazione funziona perché le azioni Apple e un ETF petrolifero reagiscono a fattori diversi. Nel mercato delle criptovalute le cose stanno diversamente.
BTC è il fattore dominante. Quando Bitcoin cala del 5%, ETH cala del 6-8%, SOL del 8-12%, le altcoin del 10-20%. Le correlazioni dei rendimenti giornalieri nel mercato crypto sono costantemente superiori a 0.6, e durante i momenti di panico si avvicinano a 1.0.
Ma per noi — trader algoritmici — ciò che conta non è la correlazione dei prezzi, bensì la correlazione dei segnali. Se la strategia è basata sul momentum e BTC genera un segnale di entrata, è molto probabile che ETH e SOL generino un segnale analogo nello stesso minuto. Tutte le coppie entrano in long simultaneamente, tutte escono simultaneamente. Dieci posizioni — ma in sostanza una sola scommessa.
Perché 10 Coppie ≠ 10x Diversificazione

Formulazione Formale
Supponiamo che una strategia su ciascuna delle coppie sia attiva una frazione del tempo. Se i segnali fossero completamente indipendenti, la probabilità che almeno una coppia sia attiva:
Per la Strategia B (, ):
Ma i segnali non sono indipendenti. Le criptovalute si muovono in sincronia — il che significa che i segnali emergono e si spengono a grappoli.
La Correlazione Riduce 10 Coppie a 3
L'intuizione è questa: se 10 coppie sono correlate, esse contengono informazioni non da 10 fonti indipendenti ma, ad esempio, da 3-4. Formalizziamo questo attraverso effective_N:
dove è il fattore di correlazione, che riflette la correlazione media a coppie dei segnali. Quando le coppie sono completamente indipendenti; quando sono identiche.
Per le coppie crypto, un tipico . Quindi:
Non 40%, ma 15.6%. Una differenza di 2.5x. L'efficienza di riempimento cala di conseguenza, e con essa il rendimento effettivo dell'intero portafoglio (vedi PnL per Tempo Attivo).
Correlazione nei Mercati Crypto

BTC come Fattore Dominante
Il mercato crypto ha una struttura fattoriale pronunciata. BTC spiega il 60-80% della varianza dei rendimenti giornalieri per la maggior parte delle altcoin. Questo è chiaramente visibile attraverso la PCA (Principal Component Analysis):
import numpy as np
from sklearn.decomposition import PCA
def analyze_crypto_factor_structure(returns_matrix: np.ndarray, pair_names: list) -> dict:
"""
Analisi PCA della struttura fattoriale dei rendimenti crypto.
Args:
returns_matrix: matrice dei rendimenti [n_giorni x n_coppie]
pair_names: lista dei nomi delle coppie
"""
pca = PCA()
pca.fit(returns_matrix)
explained = pca.explained_variance_ratio_
cumulative = np.cumsum(explained)
print("Struttura fattoriale:")
for i, (var, cum) in enumerate(zip(explained[:5], cumulative[:5])):
print(f" PC{i+1}: {var:.1%} varianza (cumulativa: {cum:.1%})")
loadings = pca.components_[0]
print("\nLoadings PC1 (fattore BTC):")
for name, load in sorted(zip(pair_names, loadings), key=lambda x: -abs(x[1])):
print(f" {name}: {load:.3f}")
return {
"explained_variance": explained,
"n_effective_factors": int(np.searchsorted(cumulative, 0.90)) + 1,
"pc1_loadings": dict(zip(pair_names, loadings)),
}
Risultato tipico per un portafoglio di 10 coppie crypto:
| Componente | Varianza Spiegata | Cumulativa |
|---|---|---|
| PC1 (BTC) | 65% | 65% |
| PC2 | 12% | 77% |
| PC3 | 8% | 85% |
| PC4 | 5% | 90% |
| PC5-PC10 | 10% | 100% |
Quattro fattori spiegano il 90% della varianza. Su 10 coppie, non più di 4 sono "indipendenti."
Correlazione dei Segnali vs. Correlazione dei Prezzi
Ecco una sfumatura importante. La correlazione dei prezzi e la correlazione dei segnali sono cose diverse. I prezzi di BTC e ETH sono correlati a 0.85, ma i segnali di una specifica strategia possono essere correlati a 0.95 o a 0.50 — a seconda della logica di entrata.
Esempio: una strategia RSI ipercomprato/ipervenduto. L'RSI su BTC supera 30 (ipervenduto) — si entra in long. ETH nello stesso momento potrebbe essere anch'esso ipervenduto (correlazione dei segnali ~0.90). Oppure no, se ETH stava calando più lentamente (correlazione dei segnali ~0.40).
L'approccio corretto è misurare la correlazione dei segnali specificamente, non delle serie di prezzi:
import numpy as np
from itertools import combinations
def signal_correlation_matrix(
signals: dict, # {coppia: np.array di 0/1 per minuto}
method: str = "pearson",
) -> np.ndarray:
"""
Calcola la matrice di correlazione dei segnali (binario: 0 = flat, 1 = in posizione).
Args:
signals: dizionario {nome_coppia: array_segnale_binario}
method: metodo di correlazione ("pearson", "jaccard")
"""
pairs = sorted(signals.keys())
n = len(pairs)
corr_matrix = np.ones((n, n))
for i, j in combinations(range(n), 2):
s_i = signals[pairs[i]]
s_j = signals[pairs[j]]
if method == "pearson":
corr = np.corrcoef(s_i, s_j)[0, 1]
elif method == "jaccard":
intersection = np.sum(s_i & s_j)
union = np.sum(s_i | s_j)
corr = intersection / union if union > 0 else 0
else:
raise ValueError(f"Metodo sconosciuto: {method}")
corr_matrix[i, j] = corr
corr_matrix[j, i] = corr
return corr_matrix, pairs
def estimate_correlation_factor(corr_matrix: np.ndarray) -> float:
"""
Stima il correlation_factor dalla matrice di correlazione dei segnali.
correlation_factor = 1 + (N-1) * correlazione_media_a_coppie
Quando la correlazione è 0 → C_f = 1 (tutti indipendenti).
Quando la correlazione è 1 → C_f = N (tutti identici).
"""
n = corr_matrix.shape[0]
upper_triangle = corr_matrix[np.triu_indices(n, k=1)]
mean_corr = np.mean(upper_triangle)
correlation_factor = 1 + (n - 1) * mean_corr
return correlation_factor
Correlazione Temporale: Calma vs. Panico

La correlazione non è statica. Nei periodi di calma, BTC e le alt possono divergere — ETH sale sulle notizie di Ethereum, SOL sulle notizie di Solana. In una crisi, tutto collassa in un unico fattore: risk-on/risk-off.
def rolling_correlation_factor(
signals: dict,
window_days: int = 30,
step_days: int = 7,
) -> list:
"""
Rolling correlation_factor per rilevare i cambiamenti di regime.
"""
pairs = sorted(signals.keys())
minutes_per_day = 1440
window = window_days * minutes_per_day
step = step_days * minutes_per_day
total_minutes = len(signals[pairs[0]])
results = []
for start in range(0, total_minutes - window, step):
end = start + window
window_signals = {p: signals[p][start:end] for p in pairs}
corr_matrix, _ = signal_correlation_matrix(window_signals)
cf = estimate_correlation_factor(corr_matrix)
results.append({
"start_minute": start,
"end_minute": end,
"correlation_factor": cf,
"effective_n": len(pairs) / cf,
})
return results
Quadro tipico per 10 coppie crypto:
| Regime di Mercato | Correlazione Media dei Segnali | ||
|---|---|---|---|
| Laterale (bassa vol) | 0.15-0.25 | 2.4-3.3 | 3.0-4.2 |
| Uptrend | 0.25-0.40 | 3.3-4.6 | 2.2-3.0 |
| Downtrend | 0.30-0.50 | 3.7-5.5 | 1.8-2.7 |
| Panico (crash) | 0.60-0.90 | 6.4-9.1 | 1.1-1.6 |
Durante il panico, 10 coppie si comprimono a 1-2 effettive. Proprio quando la diversificazione è più necessaria, svanisce. Questo è l'analogo crypto del classico "le correlazioni vanno a 1 durante una crisi."
effective_N: Il Concetto Chiave

Formula e Derivazione
L'idea di effective_N è presa in prestito dalla statistica, dove la dimensione campionaria effettiva tiene conto dell'autocorrelazione delle osservazioni. Per i nostri scopi:
dove è la correlazione media a coppie dei segnali. Notazione semplificata:
Proprietà:
- Quando : , — piena indipendenza
- Quando : , — tutte le coppie sono identiche
- Quando e : ,
Come Stimare il correlation_factor dai Dati
In pratica, ci sono tre approcci:
1. Dalla matrice di correlazione dei segnali (esatto).
Esegui la strategia su tutte le coppie, ottieni i segnali binari (0/1 per ogni minuto), costruisci la matrice di correlazione, calcola usando la formula sopra.
2. Dalla PCA dei rendimenti dei prezzi (approssimato).
Se i segnali dipendono fortemente dalla dinamica dei prezzi (momentum, mean-reversion), puoi stimare come il numero di componenti PCA che spiegano il 90% della varianza.
3. Dalle euristiche della classe di attivi (approssimativo).
| Classe di Attivo | Tipico |
|---|---|
| Crypto (top-10) | 2.5-4.0 |
| Crypto (con DeFi/memecoins) | 2.0-3.0 |
| Forex (major) | 1.5-2.5 |
| Azioni (singolo settore) | 2.0-3.5 |
| Azioni (cross-settoriale) | 1.2-1.8 |
Per un portafoglio crypto composto da BTC, ETH, SOL, AVAX, MATIC, DOGE, DOT, LINK, UNI, ATOM, una stima prudente è .
Modellazione dell'Utilizzo degli Slot

Formula per
La formula base che tiene conto della correlazione:
Tabella per diverse strategie e numero di coppie ():
| Strategia | (tempo di trading) | 5 coppie () | 10 coppie () | 20 coppie () | 50 coppie () |
|---|---|---|---|---|---|
| Strategia B | 5% | 8.2% | 15.6% | 29.1% | 58.0% |
| Strategia A | 15% | 23.6% | 41.8% | 65.9% | 92.8% |
| Strategia C | 45% | 67.1% | 89.0% | 98.8% | ~100% |
Per la Strategia B con attività al 5%, servono 50 coppie solo per avere almeno una posizione attiva la metà del tempo. E questo senza nemmeno considerare che 50 coppie crypto sono più fortemente correlate di 10.
Orchestratore Multi-Slot
Un orchestratore reale gestisce più slot simultaneamente. Se hai 5 slot e 10 coppie, l'utilizzo si calcola diversamente:
def estimate_fill_efficiency(
trading_time_pct: float,
n_pairs: int,
correlation_factor: float = 3.0,
max_slots: int = 1,
) -> dict:
"""
Stima analitica della fill efficiency per un orchestratore multi-slot.
Args:
trading_time_pct: frazione del tempo attivo per una strategia su una coppia
n_pairs: numero di coppie di trading
correlation_factor: coefficiente di correlazione dei segnali
max_slots: numero massimo di posizioni simultanee
Returns:
dict con le metriche di utilizzo
"""
effective_n = n_pairs / correlation_factor
p_at_least_one = 1 - (1 - trading_time_pct) ** effective_n
expected_active = effective_n * trading_time_pct
utilization = min(expected_active, max_slots) / max_slots
fill_efficiency = min(p_at_least_one, utilization)
return {
"effective_n": effective_n,
"p_at_least_one": p_at_least_one,
"expected_active": expected_active,
"utilization": utilization,
"fill_efficiency": fill_efficiency,
}
configs = [
("Strategia B, 10 coppie, 1 slot", 0.05, 10, 3.0, 1),
("Strategia B, 10 coppie, 3 slot", 0.05, 10, 3.0, 3),
("Strategia B, 30 coppie, 1 slot", 0.05, 30, 3.0, 1),
("Strategia A, 10 coppie, 1 slot", 0.15, 10, 3.0, 1),
("Strategia C, 10 coppie, 1 slot", 0.45, 10, 3.0, 1),
("Strategia C, 10 coppie, 5 slot", 0.45, 10, 3.0, 5),
]
for name, p, n, cf, slots in configs:
result = estimate_fill_efficiency(p, n, cf, slots)
print(f"{name}:")
print(f" N_eff = {result['effective_n']:.1f}")
print(f" P(≥1 attivo) = {result['p_at_least_one']:.1%}")
print(f" E[attivi] = {result['expected_active']:.2f}")
print(f" fill_efficiency = {result['fill_efficiency']:.1%}")
print()
Output atteso:
Strategia B, 10 coppie, 1 slot:
N_eff = 3.3
P(≥1 attivo) = 15.6%
E[attivi] = 0.17
fill_efficiency = 15.6%
Strategia B, 10 coppie, 3 slot:
N_eff = 3.3
P(≥1 attivo) = 15.6%
E[attivi] = 0.17
fill_efficiency = 5.6%
Strategia B, 30 coppie, 1 slot:
N_eff = 10.0
P(≥1 attivo) = 40.1%
E[attivi] = 0.50
fill_efficiency = 40.1%
Strategia A, 10 coppie, 1 slot:
N_eff = 3.3
P(≥1 attivo) = 41.8%
E[attivi] = 0.50
fill_efficiency = 41.8%
Strategia C, 10 coppie, 1 slot:
N_eff = 3.3
P(≥1 attivo) = 89.0%
E[attivi] = 1.50
fill_efficiency = 89.0%
Strategia C, 10 coppie, 5 slot:
N_eff = 3.3
P(≥1 attivo) = 89.0%
E[attivi] = 1.50
fill_efficiency = 30.0%
Nota: la Strategia B con 3 slot e 10 coppie mostra una fill_efficiency del 5.6%. Tre slot sono inutili quando il numero atteso di coppie attive è solo 0.17. Gli slot devono essere allocati proporzionalmente al carico atteso.
Simulazione su Dati Reali
Il modello analitico è un'approssimazione. Per una stima accurata, è necessaria una simulazione su segnali reali:
import numpy as np
def simulate_fill_efficiency(
all_signals: dict, # {(strategia, coppia): [(minuto_entrata, minuto_uscita), ...]}
max_slots: int = 10,
test_period_minutes: int = 750 * 24 * 60, # 750 giorni
priority_fn=None, # funzione di priorità per la selezione delle posizioni
) -> dict:
"""
Simula il carico reale degli slot dell'orchestratore.
Per ogni minuto: conta quante coppie vogliono entrare in posizione,
e quanti slot sono effettivamente occupati (tenendo conto del limite).
Args:
all_signals: segnali per coppie e strategie
max_slots: numero massimo di posizioni simultanee
test_period_minutes: durata del periodo di test in minuti
priority_fn: se None — FIFO; altrimenti — funzione di ranking
"""
demand_timeline = np.zeros(test_period_minutes, dtype=np.int32)
capped_timeline = np.zeros(test_period_minutes, dtype=np.int32)
for signals in all_signals.values():
for entry_min, exit_min in signals:
if entry_min < test_period_minutes:
end = min(exit_min, test_period_minutes)
demand_timeline[entry_min:end] += 1
capped_timeline = np.minimum(demand_timeline, max_slots)
total_demand = np.sum(demand_timeline)
total_filled = np.sum(capped_timeline)
time_with_any_active = np.sum(demand_timeline > 0)
fill_efficiency = np.mean(capped_timeline) / max_slots
demand_fill_ratio = total_filled / total_demand if total_demand > 0 else 0
time_utilization = time_with_any_active / test_period_minutes
slot_distribution = {}
for s in range(max_slots + 1):
slot_distribution[s] = np.mean(capped_timeline == s)
return {
"fill_efficiency": fill_efficiency,
"demand_fill_ratio": demand_fill_ratio,
"time_utilization": time_utilization,
"avg_demand": np.mean(demand_timeline),
"avg_filled": np.mean(capped_timeline),
"slot_distribution": slot_distribution,
"overflow_pct": np.mean(demand_timeline > max_slots),
}
La simulazione su dati reali spesso mostra un utilizzo ancora più basso rispetto alla stima analitica, perché tiene conto del raggruppamento temporale dei segnali: tutte le coppie entrano simultaneamente in un cluster, creando overflow, e poi tutte tacciono, creando un vuoto.
Quante Coppie Monitorare? Analisi dei Rendimenti Decrescenti

La domanda chiave: a quale l'aggiunta di un'ulteriore coppia smette di aumentare sensibilmente la fill_efficiency?
import numpy as np
def diminishing_returns_analysis(
trading_time_pct: float,
correlation_factor: float = 3.0,
max_pairs: int = 100,
target_utilization: float = 0.80,
) -> dict:
"""
Analisi dei rendimenti decrescenti dall'aggiunta di nuove coppie.
"""
results = []
target_n = None
for n in range(1, max_pairs + 1):
n_eff = n / correlation_factor
p_active = 1 - (1 - trading_time_pct) ** n_eff
marginal = 0
if n > 1:
prev_eff = (n - 1) / correlation_factor
prev_p = 1 - (1 - trading_time_pct) ** prev_eff
marginal = p_active - prev_p
results.append({
"n_pairs": n,
"n_effective": n_eff,
"p_at_least_one": p_active,
"marginal_gain": marginal,
})
if target_n is None and p_active >= target_utilization:
target_n = n
return {
"results": results,
"target_n_for_utilization": target_n,
}
analysis_b = diminishing_returns_analysis(0.05, correlation_factor=3.0, target_utilization=0.80)
print(f"Strategia B: servono {analysis_b['target_n_for_utilization']} coppie per P(≥1) all'80%")
for r in analysis_b["results"]:
if r["n_pairs"] in [1, 3, 5, 10, 20, 30, 50, 80]:
print(f" N={r['n_pairs']:3d}: N_eff={r['n_effective']:.1f}, "
f"P(≥1)={r['p_at_least_one']:.1%}, "
f"marginale={r['marginal_gain']:.2%}")
Risultati per la Strategia B (, ):
| Coppie | Guadagno marginale | ||
|---|---|---|---|
| 1 | 0.3 | 1.7% | — |
| 3 | 1.0 | 5.0% | +1.7% |
| 5 | 1.7 | 8.2% | +1.6% |
| 10 | 3.3 | 15.6% | +1.4% |
| 20 | 6.7 | 29.1% | +1.1% |
| 30 | 10.0 | 40.1% | +0.9% |
| 50 | 16.7 | 58.0% | +0.6% |
| 80 | 26.7 | 74.5% | +0.4% |
Per la Strategia B, raggiungere l'80% di utilizzo su un singolo slot è impossibile anche con 100 coppie (ne servirebbero ~96). Questa è una limitazione fondamentale: una strategia con il 5% di tempo di trading non è adatta per l'operatività su singolo slot — ha bisogno di un approccio portfolio con più strategie.
Per la Strategia A (, ):
| Coppie | Guadagno marginale | ||
|---|---|---|---|
| 5 | 1.7 | 23.6% | — |
| 10 | 3.3 | 41.8% | +3.3% |
| 20 | 6.7 | 65.9% | +2.1% |
| 30 | 10.0 | 80.3% | +1.2% |
La Strategia A raggiunge l'80% di utilizzo con ~30 coppie. Il guadagno marginale alla 30a coppia è solo +1.2%.
Per la Strategia C (, ):
| Coppie | ||
|---|---|---|
| 3 | 1.0 | 45.0% |
| 5 | 1.7 | 67.1% |
| 10 | 3.3 | 89.0% |
| 15 | 5.0 | 95.0% |
La Strategia C con il 45% di tempo di trading raggiunge il 90% di utilizzo con sole 10 coppie. Aggiungerne altre è inutile.
Degradazione dell'Edge Tra le Coppie

C'è un altro fattore che limita il numero di coppie: la degradazione dell'edge. Una strategia sviluppata e ottimizzata su BTC/USDT potrebbe funzionare peggio su alt meno liquide.
Cause della degradazione:
- Liquidità: lo slippage su DOGE/USDT è diverse volte superiore a quello su BTC/USDT
- Spread: le coppie meno liquide hanno spread bid-ask più ampi
- Microstruttura: i pattern del book degli ordini differiscono tra le coppie
- Manipolazione: le alt a bassa liquidità sono soggette a pump-and-dump
def edge_decay_analysis(
strategy_results: dict, # {coppia: {"pnl_per_day": float, "n_trades": int}}
min_trades: int = 30,
) -> list:
"""
Classifica le coppie per edge tenendo conto della degradazione.
"""
ranked = []
for pair, metrics in strategy_results.items():
if metrics["n_trades"] < min_trades:
continue
ranked.append({
"pair": pair,
"pnl_per_day": metrics["pnl_per_day"],
"n_trades": metrics["n_trades"],
"sharpe": metrics.get("sharpe", 0),
})
ranked.sort(key=lambda x: x["pnl_per_day"], reverse=True)
cumulative_pnl = []
running_sum = 0
for i, r in enumerate(ranked):
running_sum += r["pnl_per_day"]
avg = running_sum / (i + 1)
cumulative_pnl.append({
"n_pairs": i + 1,
"last_added": r["pair"],
"last_pnl_per_day": r["pnl_per_day"],
"avg_pnl_per_day": avg,
})
return cumulative_pnl
Quadro tipico:
| # coppie | Ultima Aggiunta | PnL/giorno ultima | PnL/giorno medio |
|---|---|---|---|
| 1 | BTC/USDT | 0.89% | 0.89% |
| 2 | ETH/USDT | 0.82% | 0.86% |
| 3 | SOL/USDT | 0.71% | 0.81% |
| 5 | AVAX/USDT | 0.55% | 0.73% |
| 8 | DOT/USDT | 0.31% | 0.61% |
| 10 | DOGE/USDT | 0.12% | 0.53% |
Aggiungere la 10a coppia abbassa il PnL/giorno medio del portafoglio. All'8a coppia, l'edge è già la metà rispetto alla migliore. È necessario un equilibrio tra fill_efficiency (cresce con il numero di coppie) e edge medio (diminuisce).
Numero Ottimale di Coppie: Modello Unificato

Combiniamo fill_efficiency e decadimento dell'edge in un'unica metrica — PnL atteso del portafoglio per giorno:
def optimal_pairs_count(
pair_edges: list, # PnL/giorno in ordine decrescente: [0.89, 0.82, 0.71, ...]
trading_time_pct: float,
correlation_factor: float = 3.0,
max_slots: int = 1,
) -> dict:
"""
Trova il numero ottimale di coppie che massimizza il PnL del portafoglio.
"""
best_n = 0
best_score = 0
results = []
for n in range(1, len(pair_edges) + 1):
avg_edge = np.mean(pair_edges[:n])
n_eff = n / correlation_factor
p_active = 1 - (1 - trading_time_pct) ** n_eff
expected_active = n_eff * trading_time_pct
utilization = min(expected_active, max_slots) / max_slots
fill_eff = min(p_active, utilization)
portfolio_score = avg_edge * fill_eff * 365
results.append({
"n_pairs": n,
"avg_edge": avg_edge,
"fill_efficiency": fill_eff,
"portfolio_annualized": portfolio_score,
})
if portfolio_score > best_score:
best_score = portfolio_score
best_n = n
return {
"optimal_n": best_n,
"optimal_score": best_score,
"results": results,
}
edges = [0.89, 0.82, 0.71, 0.65, 0.55, 0.48, 0.40, 0.31, 0.22, 0.12,
0.08, 0.05, 0.02, -0.01, -0.05]
opt = optimal_pairs_count(edges, trading_time_pct=0.15, correlation_factor=3.0)
print(f"Numero ottimale di coppie: {opt['optimal_n']}")
print(f"Portafoglio annualizzato: {opt['optimal_score']:.1f}%")
for r in opt["results"]:
print(f" N={r['n_pairs']:2d}: avg_edge={r['avg_edge']:.2f}%, "
f"fill_eff={r['fill_efficiency']:.1%}, "
f"portfolio={r['portfolio_annualized']:.1f}%")
L'ottimo si trova tipicamente nel punto in cui il guadagno marginale di fill_efficiency dall'aggiunta di una coppia non compensa più il calo dell'edge medio. Per un tipico portafoglio crypto:
- Strategia B (5% del tempo): ottimo a 8-12 coppie
- Strategia A (15% del tempo): ottimo a 6-10 coppie
- Strategia C (45% del tempo): ottimo a 4-6 coppie
Un paradosso: la strategia con il minor tempo di trading beneficia del maggior numero di coppie, eppure la fill_efficiency rimane comunque bassa. La soluzione non è più coppie, ma la combinazione con altre strategie (vedi Strategie Combo).
Diversificazione Cross-Coppia: Strategie per Ridurre la Correlazione

Se non è possibile aumentare il numero di coppie indefinitamente, si può ridurre — ossia aumentare la diversità dei segnali.
Strategia 1: Mix di Token Liquidi e DeFi
BTC, ETH, BNB sono molto fortemente correlati. Ma UNI (DEX), AAVE (lending), CRV (stablecoin) possono avere i propri driver. L'aggiunta di token DeFi riduce la media da 0.35 a 0.20-0.25:
Strategia 2: Strategie Diverse sulle Stesse Coppie
Invece di 10 coppie con una strategia — 5 coppie con due strategie diverse. Se le strategie si basano su principi diversi (momentum vs. mean-reversion), i loro segnali possono essere anti-correlati:
- Il momentum entra in long quando il prezzo sale
- Il mean-reversion entra in long quando il prezzo scende
Questo è l'unico modo per ottenere — usare strategie con correlazione negativa dei segnali.
Strategia 3: Spot vs. Futures
L'arbitraggio sul tasso di funding e il trading spot hanno una struttura di correlazione diversa. L'aggiunta di strategie di arbitraggio al portafoglio riduce significativamente il complessivo, perché l'arbitraggio per definizione sfrutta le divergenze, non le convergenze.
Raccomandazioni Pratiche per Tipo di Strategia
Strategie ad Alta Frequenza con Basso Tempo di Trading (tempo di trading < 10%)
Rappresentante tipico: Strategia B (5% del tempo, 38 trade in 750 giorni).
- Numero di coppie: 10-15 (ottimo per l'equilibrio edge/fill)
- Problema: la fill_efficiency è bassa anche con 15 coppie (~20-25%)
- Soluzione: combinazione obbligatoria con altre strategie nell'orchestratore
- per crypto: 2.5-3.5
- Monitoraggio: rolling per adattare il numero di coppie al regime di mercato
Strategie a Tempo Medio (tempo di trading 10-30%)
Rappresentante tipico: Strategia A (15% del tempo, 418 trade in 750 giorni).
- Numero di coppie: 6-10
- Fill_efficiency con 10 coppie: ~40%
- Soluzione: la combinazione di 2-3 tali strategie riempie l'80%+ del tempo
- per crypto: 2.5-3.5
- Focus: selezionare le coppie con il massimo edge, non inseguire la quantità
Strategie ad Alto Tempo di Trading (tempo di trading > 30%)
Rappresentante tipico: Strategia C (45% del tempo).
- Numero di coppie: 4-6
- Fill_efficiency con 6 coppie: ~80%
- Problema: overflow — più coppie attive simultaneamente, ma meno slot
- Soluzione: aumentare max_slots o aggiungere la prioritizzazione delle coppie
- per crypto: 2.5-4.0 (più alto a causa della sovrapposizione delle posizioni lunghe durante le crisi)
Tabella Riassuntiva
| Parametro | Strategia B (5%) | Strategia A (15%) | Strategia C (45%) |
|---|---|---|---|
| raccomandato | 10-15 | 6-10 | 4-6 |
| con | 3.3-5.0 | 2.0-3.3 | 1.3-2.0 |
| Fill eff. (1 slot) | 15-23% | 32-42% | 77-89% |
| Combinazione necessaria? | Obbligatoria | Consigliabile | No |
| Collo di bottiglia | Pochi segnali | Equilibrio | Overflow |
Connessione con Altre Metriche della Serie
Questo articolo è l'undicesimo della serie "Backtest Senza Illusioni". La correlazione dei segnali impatta direttamente le metriche degli articoli precedenti:
-
PnL per Tempo Attivo: la fill_efficiency è il moltiplicatore chiave nella formula del rendimento effettivo. Se sovrastimi la fill_efficiency ignorando la correlazione, le previsioni di PnL del portafoglio saranno eccessivamente ottimistiche.
-
Tassi di funding: con alta correlazione, le posizioni si aprono simultaneamente — e i costi di funding crescono linearmente con il numero di slot. Overflow + funding = bruciatura accelerata del capitale.
-
Arbitraggio sui tassi di funding: le strategie di arbitraggio sono un diversificatore naturale che riduce il del portafoglio. I loro segnali sono debolmente correlati con le strategie momentum e mean-reversion.
-
Strategie combo (prossimo articolo): come assemblare un portafoglio di strategie con diversi e per raggiungere un utilizzo del 90%+. L'orchestrazione a cascata tiene conto della correlazione dei segnali nell'assegnazione delle priorità.
Conclusione
La diversificazione nel crypto non riguarda il numero di coppie. 10 coppie correlate producono l'effetto di 3-4 indipendenti. Durante il panico, ancora meno.
Quattro punti chiave:
-
Calcola effective_N, non N. Per le coppie crypto . Dieci coppie sono ~3.3 effettive. Pianifica la fill_efficiency basandoti su , non su .
-
Misura la correlazione dei segnali, non dei prezzi. La correlazione dei prezzi è un proxy, non un sostituto. Esegui la strategia su tutte le coppie e calcola la matrice di correlazione dei segnali binari.
-
Tieni conto della degradazione dell'edge. Più coppie significa un PnL/giorno medio inferiore. L'ottimo è nel punto in cui la fill_efficiency marginale derivante da una nuova coppia compensa ancora il calo dell'edge.
-
Riduci , non aumentare . Combinare strategie diverse sulle stesse coppie è più efficace che una strategia su più coppie. La diversificazione cross-strategia può produrre .
Il fattore di correlazione è la variabile nascosta che determina quanto siano realistiche le previsioni di utilizzo e rendimento. Ignorarlo significa costruire un portafoglio su illusioni.
Link Utili
- Markowitz, H. — Portfolio Selection (1952)
- López de Prado — Advances in Financial Machine Learning: Denoising and Detoning
- Ledoit, O. & Wolf, M. — Honey, I Shrunk the Sample Covariance Matrix (2004)
- Laloux, L. et al. — Noise Dressing of Financial Correlation Matrices (1999)
- Cont, R. — Empirical Properties of Asset Returns: Stylized Facts and Statistical Issues
- Ernest Chan — Algorithmic Trading: Portfolio Construction and Risk Management
- Rebonato, R. & Jäckel, P. — The Most General Methodology for Creating a Valid Correlation Matrix
Citazione
@article{soloviov2026signalcorrelation,
author = {Soloviov, Eugen},
title = {Correlazione dei Segnali: Quante Coppie Monitorare},
year = {2026},
url = {https://marketmaker.cc/it/blog/post/signal-correlation-pairs},
version = {0.1.0},
description = {Perché 10 coppie crypto non offrono una diversificazione 10x, come calcolare effective\_N tramite correlation\_factor, e quante coppie è davvero necessario monitorare per un utilizzo degli slot dell'orchestratore dell'80-90\%.}
}
Autori
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.