Transfer Entropy: Which Way Does Information Flow Between Crypto Assets?
इस ब्लॉग ने पहले ही स्थापित किया है कि क्रिप्टो बाजार लगभग एक-कारक बाजार है: जोड़ियों के बीच सिग्नल सहसंबंध में PC1 (BTC कारक) विचरण का 65% रखता है और चार कारक 90% समझाते हैं, इसलिए दस "विविधीकृत" जोड़ियां तीन या चार स्वतंत्र जोड़ियों की सूचना रखती हैं। यह भी स्थापित हो चुका है कि निर्भरता संरचना स्थिर नहीं है: DCC-GARCH सहसंबंध मैट्रिक्स को अपने अलग-अलग regimes वाली time series के रूप में मॉडल करता है, और उसका Limitations खंड स्पष्ट रूप से कहता है — "सहसंबंध कार्य-कारण नहीं है, और दिशा भी नहीं है।"
यही अंतिम बात इस लेख का विषय है। DCC बताता है कि निर्भरता कब सघन होती है। वह यह नहीं बता सकता कि वह किस दिशा में है। ट्रांसफर एंट्रॉपी यह कर सकता है: यह model-free और स्वभावतः asymmetric माप है, जो बताता है कि एक series का अतीत दूसरी series के भविष्य की भविष्यवाणी में कितने bits का योगदान देता है, उस target के अपने अतीत द्वारा पहले से समझाई गई सूचना से अधिक। यदि AAVE के repricing से पहले ETH लगातार AAVE को सूचना भेजता है, तो ट्रांसफर एंट्रॉपी वह asymmetry देखता है जिसे कोई correlation matrix व्यक्त नहीं कर सकता।
आगे माप, उसका estimator और — माप से भी अधिक महत्वपूर्ण भाग — null calibration तथा sensitivity analysis दिए गए हैं, जो तय करते हैं कि मापा गया information-flow network signal है या केवल सजावट।
मापा गया नेटवर्क

स्थिति: अभी चलाया नहीं गया। नीचे का pipeline implemented है, लेकिन इस लेख के लिए वास्तविक डेटा पर चलाया नहीं गया है। जब तक ऐसा नहीं होता, यह लेख method writeup है, result नहीं। ब्लॉग का अपना standard — ईमानदार नकारात्मक परिणाम और deflated Sharpe तथा multiple testing देखें — यह है कि uncalibrated network को अन्यथा सिद्ध होने तक noise माना जाए।
यहां चार बातें इसी क्रम में report करनी होंगी, और इनमें से किसी को भी literature के आधार पर assert नहीं किया जा सकता:
- Effective-TE matrix। Universe, exchange, date range, bar size, हर ordered pair के लिए bits में effective TE, हर pair का p-value और significance filter से बचा directed graph। यह सामान्य hand-waving ("BTC dominant source है, DeFi tokens sinks हैं") की जगह out-strength / in-strength / net-flow table देगा।
- Significance test की false-positive rate, जिसे shuffled और synthetic-independent series पर पूरा pipeline चलाकर मापा जाए। नीचे Null Calibration देखें।
- Sensitivity sweep दो free knobs पर:
n_binsको {3, 5} औरkको {1, 2, 3, 5} के साथ cross करें। यदि leader/follower ranking केवल grid के एक cell पर कायम रहती है, तो वही finding है। - समय के साथ stability। क्या मापी गई ranking out of sample भी बनी रहती है, या हर window में फिर बदल जाती है? इसका उत्तर मिलने तक downstream कुछ लिखना सार्थक नहीं है।
Machinery

तीन building blocks
Shannon entropy random variable की uncertainty मापता है:
Coin flip 1 bit है; fair die bits है; deterministic variable 0 है।
Conditional entropy मापता है कि जानने के बाद के बारे में कितनी uncertainty बचती है:
जब , को निर्धारित करता है तब यह 0 होता है, और जब दोनों independent हों तब के बराबर होता है।
Mutual information दोनों के बीच साझा सूचना है:
यह symmetric है — — और यही symmetry तोड़नी है।
ट्रांसफर एंट्रॉपी
Schreiber (2000) द्वारा प्रस्तुत transfer entropy target के अपने अतीत पर conditioning करके symmetry तोड़ता है। यह मापता है कि source का अतीत target के भविष्य की uncertainty को कितनी कम करता है, उस सूचना से आगे जिसे का अतीत पहले ही समझाता है।
मान लें , -length history और , -length source history को दर्शाता है:
इसे conditional entropies के अंतर के रूप में भी लिखा जा सकता है:
यदि का अतीत, के अपने अतीत से आगे की prediction में मदद नहीं करता, तो । यदि करता है, तो magnitude प्रवाहित predictive information के bits की संख्या है।
मुख्य गुण:
- Non-negative: ।
- Asymmetric: सामान्यतः । यही पूरा point है।
- Non-parametric: कोई model assumptions नहीं — linear और nonlinear दोनों dependencies।
- Units: के साथ bits, के साथ nats।
Net transfer entropy dominant direction देता है:
Positive का अर्थ है कि , को net sender है; negative का अर्थ है कि lead करता है।
Transfer Entropy बनाम Granger Causality

Granger causality (GC) पूछता है कि क्या का अतीत की linear autoregressive prediction को बेहतर बनाता है। यह Engle-Granger cointegration test नहीं है, जिसे statistical arbitrage और pairs trading में कवर किया गया है — surname समान है, concept अलग। Engle-Granger पूछता है कि क्या दो non-stationary series का linear combination stationary है; Granger causality पूछता है कि क्या एक series दूसरी का forecast करने में मदद करती है। इस ब्लॉग के पाठक दोनों को मिला सकते हैं, इसलिए इसे स्पष्ट कहना जरूरी है।
Gaussian processes के लिए theoretical equivalence
Barnett, Barrett और Seth (2009) ने सिद्ध किया कि jointly Gaussian processes के लिए Granger causality और transfer entropy monotonic transformation तक equivalent हैं:
जहां Granger causality statistic (log-likelihood ratio) है। Linear Gaussian data में दोनों methods से बिल्कुल वही causal structure मिलता है। इसलिए transfer entropy, GC का competitor कम और उसका non-parametric generalization अधिक है: जहां GC की assumptions लागू होती हैं, वहीं यह ठीक GC में reduce हो जाता है।
जहां दोनों अलग होते हैं
| गुण | Granger causality | Transfer entropy |
|---|---|---|
| Model assumption | Linear VAR | कोई नहीं (model-free) |
| Nonlinear dependencies | इन्हें miss करता है | इन्हें capture करता है |
| Distribution assumption | Gaussian (F-test के लिए) | कोई नहीं |
| Sample requirements | मध्यम | अधिक |
| Computation | तेज (OLS) | धीमा (density estimation) |
| Interpretation | Prediction में सुधार | Information transfer (bits) |
सिद्धांततः यह अंतर crypto में महत्वपूर्ण है: returns heavy-tailed हैं, volatility clusters बनाती है और relationships regime-dependent हैं — linear VAR इन सबको flatten कर देता है। क्या यह gap real data पर measured leader ranking बदलने के लिए पर्याप्त बड़ा है, यह empirical question है जिसका उत्तर इस लेख को देना होगा, assumption नहीं बनानी होगी।
Dimpfl और Peter (2013) report करते हैं कि transfer entropy financial series में उन flows को detect करता है जिन्हें Granger causality miss करती है, विशेषकर stress के समय; Keskin और Aste (2020) crypto में nonlinear TE से अधिक rich network report करते हैं। दोनों को यहां motivation के रूप में cite किया गया है, इस dataset के evidence के रूप में नहीं।
Effective Transfer Entropy: bias correction

यही वह हिस्सा है जिसमें गलती करना आसान है। Finite samples में raw TE estimates ऊपर की ओर biased होते हैं: दो independent series देने पर भी empirical joint distribution के sampling noise के कारण estimate होगा। Bias joint states की संख्या के साथ बढ़ता है, और यह संख्या में exponentially बढ़ती है।
Effective transfer entropy उस bias को subtract करता है:
जहां surrogate, की marginal distribution को बनाए रखते हुए उसकी temporal structure नष्ट करता है। ध्यान दें कि यह क्या है और क्या नहीं: surrogate mean estimator के अपने bias का estimate है और हम उसे subtract करते हैं। यह confidence interval नहीं है, और effective TE "error bars वाला TE" नहीं है। यही surrogate ensemble p-value के लिए null distribution का काम भी करता है, लेकिन subtraction और test इसके अलग-अलग उपयोग हैं।
Surrogate block bootstrap से बनाया जाता है, ताकि block के भीतर की autocorrelation बनी रहे — block resampling का सामान्य mechanics और rationale backtests के लिए Monte Carlo और bootstrap में कवर किया गया है।
कार्यान्वयन

Data: एक single exchange से major USDT perpetuals के fixed universe के hourly log returns, एक स्पष्ट contiguous date range में। Standard OHLCV fetch और log-return construction का boilerplate statistical arbitrage और pairs trading में covered है और दोहराया नहीं गया है।
Discretization — और leakage warning
Transfer entropy को discrete states चाहिए। Quantile binning सामान्य choice है, और future leak होने की सामान्य जगह भी यही है।
import numpy as np
import pandas as pd
def discretize_trailing(series, n_bins=3, warmup=500):
"""Discretize using bin edges estimated on a TRAILING window only.
Computing quantile edges over the full sample is whole-series
normalization leakage: every bar's label depends on the entire
future distribution. See the look-ahead bias taxonomy.
"""
x = np.asarray(series, dtype=float)
out = np.full(len(x), -1, dtype=int)
qs = np.linspace(0, 1, n_bins + 1)[1:-1]
for t in range(warmup, len(x)):
edges = np.quantile(x[:t], qs) # strictly past data
out[t] = np.digitize(x[t], edges)
return out
Naive full-sample version descriptive claim — "इस अवधि में information इस दिशा में flow हुई" — के लिए ठीक है, लेकिन किसी भी tradable claim के लिए contaminated है। यही distinction look-ahead bias taxonomy का पूरा विषय है। यदि full-sample edges का उपयोग करें, तो यह स्पष्ट कहें और "signal" शब्द से पहले रुक जाएं।
शुरुआत से Transfer entropy
from collections import Counter
def transfer_entropy(source, target, k=1, l=1):
"""Transfer entropy T_{source -> target} in bits.
source, target : 1-D integer arrays of discrete states
k : history length for the target
l : history length for the source
"""
source = np.asarray(source)
target = np.asarray(target)
n = len(target)
max_lag = max(k, l)
y_future = target[max_lag:]
y_past = np.column_stack([target[max_lag - i - 1:n - i - 1] for i in range(k)])
x_past = np.column_stack([source[max_lag - i - 1:n - i - 1] for i in range(l)])
N = len(y_future)
yf = y_future.tolist()
yp = [tuple(row) for row in y_past]
xp = [tuple(row) for row in x_past]
c_yf_yp_xp = Counter(zip(yf, yp, xp))
c_yp_xp = Counter(zip(yp, xp))
c_yf_yp = Counter(zip(yf, yp))
c_yp = Counter(yp)
te = 0.0
for (yf_val, yp_val, xp_val), count in c_yf_yp_xp.items():
p_joint = count / N
p_yf_given_yp_xp = count / c_yp_xp[(yp_val, xp_val)]
p_yf_given_yp = c_yf_yp[(yf_val, yp_val)] / c_yp[yp_val]
if p_yf_given_yp > 0 and p_yf_given_yp_xp > 0:
te += p_joint * np.log2(p_yf_given_yp_xp / p_yf_given_yp)
return te
Block-bootstrap null के साथ effective TE
def effective_transfer_entropy(source, target, k=1, l=1,
n_shuffles=200, block_size=5, rng=None):
"""Effective TE plus a surrogate p-value.
Returns dict: te, ete, p_value, null_mean, null_std
"""
rng = rng or np.random.default_rng(0)
te_observed = transfer_entropy(source, target, k, l)
n = len(source)
n_blocks = int(np.ceil(n / block_size))
null_tes = np.empty(n_shuffles)
for b in range(n_shuffles):
starts = rng.integers(0, n, size=n_blocks)
shuffled = np.concatenate(
[np.take(source, range(s, s + block_size), mode='wrap')
for s in starts]
)[:n]
null_tes[b] = transfer_entropy(shuffled, target, k, l)
null_mean = null_tes.mean()
return {
'te': te_observed,
'ete': max(te_observed - null_mean, 0.0),
'p_value': (np.sum(null_tes >= te_observed) + 1) / (n_shuffles + 1),
'null_mean': null_mean,
'null_std': null_tes.std(),
}
जोड़ीवार matrix
def compute_te_matrix(disc_returns, k=1, n_shuffles=200):
cols = list(disc_returns.columns)
m = len(cols)
te_matrix = np.zeros((m, m))
pval_matrix = np.ones((m, m))
for i in range(m):
for j in range(m):
if i == j:
continue
r = effective_transfer_entropy(
disc_returns[cols[i]].values,
disc_returns[cols[j]].values,
k=k, n_shuffles=n_shuffles,
)
te_matrix[i, j] = r['ete']
pval_matrix[i, j] = r['p_value']
return (pd.DataFrame(te_matrix, index=cols, columns=cols),
pd.DataFrame(pval_matrix, index=cols, columns=cols))
तेज मार्ग
pyinform एक optimized C implementation को wrap करता है:
from pyinform.transferentropy import transfer_entropy as te_pyinform
te_btc_to_eth = te_pyinform(btc_disc, eth_disc, k=2)
te_eth_to_btc = te_pyinform(eth_disc, btc_disc, k=2)
Null calibration

यह analysis का सबसे अधिक मूल्य वाला और सबसे अधिक छोड़ा जाने वाला भाग है। मापे गए network में किसी भी edge पर भरोसा करने से पहले पूरा pipeline — discretization, effective TE, surrogate test, significance filter — ऐसे data पर चलाएं जहां वास्तविक उत्तर शून्य है:
- Shuffled real returns। हर series की marginal distribution बनाए रखते हुए cross-series timing नष्ट करें।
- Synthetic independent series। संरचना के अनुसार बिना cross-dependence वाली independent heavy-tailed, volatility-clustered processes simulate करें।
फिर report करें कि test पर ordered pairs के किस fraction को flag करता है। यदि यह fraction 0.05 के करीब नहीं है, तो test miscalibrated है और real network की हर edge संदिग्ध है।
Multiple testing इसे और बढ़ाता है। 8 assets का universe ordered pairwise tests है; 20 assets का 380। Corrections — Bonferroni, Holm, Benjamini-Yekutieli FDR — deflated Sharpe और multiple testing में पूरी तरह derive किए गए हैं, साथ में वह calibration study भी है जहां naive test का FDR 1.000 और BHY का 0.007 है।
लेकिन raw Bonferroni पर रुकें नहीं, क्योंकि ये 56 tests 56 independent looks नहीं हैं। Crypto assets आपस में heavily correlated हैं — इस ब्लॉग ने PC1 को variance का 65% मापा — और यही उस article के Act 5 में documented correlated-grid failure mode है, जहां correlated grid के raw cell count को trial count मानने से over-deflation होती है और genuine edge गलत तरीके से reject हो जाती है। वहां deliverable point नहीं, effective-trial estimates की band थी: soft end पर average-correlation one-liner , और defensible middle में eigenvalue estimators (participation ratio, PCA-95%, Kaiser)। TE grid के लिए effective- band report करें और जांचें कि surviving edges पूरी band में stable हैं या नहीं।
Sensitivity: दो free knobs

नीचे के दोनों knobs आमतौर पर rule of thumb से तय किए जाते हैं और फिर दोबारा नहीं देखे जाते। इसके बजाय sweep करें और हर cell पर leader/follower ranking report करें।
History length
तय करता है कि target के अपने अतीत की कितनी मात्रा पर condition किया जाए। बहुत छोटा हो तो target की अपनी autocorrelation source को assign हो जाती है; बहुत बड़ा हो तो joint distribution estimate करने के लिए बहुत sparse हो जाती है — joint states की संख्या है, इसलिए 3 bins, , पर states होते हैं, और पर कुछ हजार observations के सामने यह हो जाता है।
सामान्य starting points hourly data के लिए और daily data के लिए हैं; इन्हें equivalent VAR lag पर AIC/BIC से cross-check भी किया जा सकता है। इन्हें sweep करने वाली grid मानें, answer नहीं।
Discretization
- 3 bins (down / flat / up): robust, limited data में काम करता है, केवल directional structure capture करता है।
- 5 bins: magnitude capture करता है, materially अधिक data चाहिए।
- Quantile edges: लगभग equal occupancy, कोई empty bins नहीं — लेकिन ऊपर की leakage warning देखें।
- Ordinal/symbolic encoding: permutation-entropy style, monotone transforms के प्रति robust।
Continuous kernel-based TE bandwidth selection और काफी भारी computation की कीमत पर discretization loss से पूरी तरह बचता है।
Sweep
for n_bins in (3, 5):
for k in (1, 2, 3, 5):
disc = discretize_all(returns, n_bins=n_bins)
te_df, p_df = compute_te_matrix(disc, k=k)
rank = net_flow_ranking(te_df, p_df)
report(n_bins, k, rank)
सवाल "ranking क्या है" नहीं, बल्कि "क्या हर cell पर ranking समान है" है। यदि कोई asset केवल , पर net sender है, तो यह instability ही result है और इसे उसी रूप में report करना चाहिए।
Confounding: Conditional Transfer Entropy

यदि और दोनों latent factor से driven हैं, तो pairwise TE उनके बीच ऐसा flow report करेगा जो पूरी तरह common driver का artifact है। One-factor market में यह corner case नहीं, default expectation है। Conditional transfer entropy conditioning के जरिए इसे हटाता है:
SOL द्वारा AVAX को information भेजने के किसी भी claim को BTC पर conditioning करके फिर test करना चाहिए। यदि flow गायब हो जाता है, तो pairwise result असल में costume पहना हुआ market factor था।
te_sol_avax_given_btc = te_pyinform(sol_disc, avax_disc, k=2,
condition=btc_disc)
Conditioning free नहीं है: हर conditioning variable joint state space को से multiply करता है, इसलिए उसी पर conditional TE को pairwise version से काफी अधिक data चाहिए।
Stability और क्या इसमें से कुछ tradable है

Information flow static नहीं है — और इस market में कुछ भी static नहीं है। यही HMMs के साथ regime detection का opening premise है और इसी कारण यहां हर estimate को एक बार fit करने के बजाय windowed होना चाहिए। हालांकि इस analysis का rolling-window version कोई नई खोज नहीं करता, बल्कि known result को inherit करता है। Crisis में crypto dependence tight होती है, यह numbers के साथ पहले ही publish हो चुका है: जोड़ियों के बीच signal correlation sideways markets में average signal correlation 0.15 से panic में 0.90 तक की table देता है, जहां 4.2 से गिरकर 1.1 होता है; और DCC-GARCH का Application 3 average pairwise correlation को trailing-quantile flag के साथ risk-off regime signal में बदलता है और स्पष्ट caveat देता है कि "यह risk signal है, alpha signal नहीं।"
TE out-strength का Freeman centralization अलग matrix पर अलग scalar है, लेकिन move वही है: dependence object को एक number में collapse करना और उसके बढ़ने को देखना। इसलिए कसौटी यह नहीं है कि "क्या centralization drawdowns से पहले बढ़ती है" — बल्कि क्या यह risk-off signal के रूप में average pairwise correlation से बेहतर है, समान windows और समान drawdowns पर head-to-head मापा जाए।
def network_centralization(G):
"""Freeman centralization of out-strength. High = one dominant source."""
if G.number_of_nodes() < 2:
return 0.0
s = [sum(d['weight'] for _, _, d in G.out_edges(v, data=True)) for v in G.nodes()]
total = sum(s)
if total == 0:
return 0.0
n = len(s)
return sum(max(s) - x for x in s) / ((n - 1) * total)
किसी downstream application को लिखने से पहले दो सवालों के उत्तर चाहिए:
- क्या leader ranking out of sample बनी रहती है? Window पर network fit करें और window पर ranking जांचें। Windows के बीच rank correlation report करें। हर सप्ताह बदलने वाली ranking noise का वर्णन करती है।
- क्या TE filter lead-lag trade में कुछ जोड़ता है? सही experiment एक controlled comparison है: statistical arbitrage और pairs trading तथा distance approach में covered वही rolling z-score entry/exit machinery दो बार चलाएं, जहां केवल TE significance filter की मौजूदगी अलग हो और fees शामिल हों।
इस लेख के लिए दोनों में से कोई भी नहीं चलाया गया है। न lead-lag backtest, न information-momentum portfolio, न regime-detection comparison। Hypothetical information-momentum sleeve के weight-construction machinery को portfolio optimization algorithms compared में कवर किया गया है — लेकिन ध्यान दें कि bits में raw net-strength पर softmax scale-arbitrary है और meaningful होने से पहले normalization argument चाहिए। Untested strategy code यहां ship नहीं किया गया है।
लागत

TE प्रति pair है, लेकिन constant joint state count और surrogate count से driven है। assets और bootstrap replicates के लिए TE evaluations चाहिए — 50 assets और 200 surrogates पर यह 490,000 है। Per-evaluation cost पूरी तरह hardware, pyinform version और पर निर्भर है; quoted figure पर भरोसा करने के बजाय अपनी machine पर measure करें। यदि धीमा हो तो तीन levers हैं:
- Parallelize। हर pair independent है —
joblibयाmultiprocessing। - Pre-screen। पहले raw TE compute करें; केवल threshold से ऊपर वाले pairs पर surrogates चलाएं। (ध्यान दें कि इससे significance test screen पास करने पर conditional हो जाता है और इसका हिसाब रखना होगा।)
- Universe छोटा करें। पहले cluster करें, फिर cluster representatives के बीच TE compute करें।
सारांश

Transfer entropy directed information flow का principled, model-free measure है और इस ब्लॉग के toolkit में वास्तविक gap भरता है: DCC-GARCH बताता है कि dependence कब tight होती है, TE बताता है कि किस दिशा में। Gaussian processes के लिए यह के जरिए ठीक Granger causality में collapse हो जाता है, इसलिए यह rival नहीं बल्कि generalization है।
अभी यह result नहीं है। यहां pipeline implemented है और failure modes गिनाए गए हैं — surrogates से corrected finite-sample bias, whole-series binning के रूप में look-ahead leakage, 56 tests की correlated grid जो naive multiple-testing corrections को तोड़ती है, one-factor market में common-driver confounding और free parameters जो संभवतः answer तय कर सकते हैं। इनमें से हर बात uncalibrated TE network पर अविश्वास करने का कारण है। Null calibration, sensitivity sweep और out-of-sample stability check के बिना network publish करना failure modes को findings की तरह publish करना होगा।
संदर्भ
- Schreiber, T. (2000). "Measuring Information Transfer." Physical Review Letters, 85(2), 461-464.
- Barnett, L., Barrett, A.B., Seth, A.K. (2009). "Granger Causality and Transfer Entropy Are Equivalent for Gaussian Variables." Physical Review Letters, 103(23), 238701.
- Marschinski, R., Kantz, H. (2002). "Analysing the information flow between financial time series." European Physical Journal B, 30(2), 275-281.
- Dimpfl, T., Peter, F.J. (2013). "Using Transfer Entropy to Measure Information Flows Between Financial Markets." Studies in Nonlinear Dynamics & Econometrics, 17(1), 85-102.
- Keskin, Z., Aste, T. (2020). "Information-theoretic measures for nonlinear causality detection: application to social media sentiment and cryptocurrency prices." Royal Society Open Science, 7(9), 200863.
- Jang, S.M. et al. (2022). "Using transfer entropy to measure information flows between cryptocurrencies." Physica A, 586, 126476.
- Nicola, G. et al. (2020). "Network Analysis of Multivariate Transfer Entropy of Cryptocurrencies in Times of Turbulence." Entropy, 22(7), 760.
Authors
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.