TCA — Transmission Channel Analysis in Python
TCA is a Python library for Transmission Channel Analysis of structural macro-econometric models. It is a careful Python port of the MATLAB reference toolbox accompanying
Wegner, Lieb, Smeekes & Wilms (2024). Transmission Channel Analysis in Dynamic Models. arXiv:2405.18987.
with first-class plotting and reporting helpers.
- Author: Dr Merwan Roudane — merwanroudane920@gmail.com
- GitHub: https://github.com/merwanroudane/tca
What is TCA?
For a structural shock $\varepsilon_{i,t}$ and a target variable $y_{j,t+h}$, the impulse response function (IRF) measures the total dynamic causal effect of the shock. TCA decomposes that total effect into effects flowing through user-defined transmission channels, where a channel is defined either:
- graphically, as a subset of paths in the DAG induced by the systems-form representation $x = Bx + \Omega \varepsilon$, or
- via potential outcomes, as an assignment vector that turns some intermediate dependencies on or off.
TCA is fully compatible with traditional impulse-response analysis: it needs only the structural identification of the shock of interest plus a transmission ordering (a permutation of the variables encoded in the transmission matrix $T$).
Installation
pip install tca-channels
# Optional pretty terminals + DAG layouts:
pip install "tca-channels[all]"
Editable install for development:
git clone https://github.com/merwanroudane/tca
cd tca
pip install -e .[dev]
The distribution name on PyPI is tca-channels, but the Python package is imported as tca:
import tca
from tca.models import SVAR
Pure-Python dependencies: numpy, scipy, pandas, matplotlib.
Optional: rich (coloured tables), networkx (alternative DAG layout),
statsmodels (alternative VAR estimators).
Library map
| Module | What lives there |
|---|---|
tca.q |
Q Boolean condition algebra; make_condition, make_condition_y |
tca.transmission |
transmission, transmission_BOmega, transmission_irfs, through, not_through |
tca.systems |
make_B, make_Omega, make_systems_form, to_transmission_irfs |
tca.models |
VAR, SVAR, LP, DSGE, Recursive, ExternalInstrument, InternalInstrument |
tca.viz |
plot_decomposition, plot_compare_decompositions, plot_irf_grid, plot_dag, plot_heatmap |
tca.tables |
decomposition_table, channel_share_table, render_rich, style_dataframe |
Quick start
import numpy as np, pandas as pd
from tca.models import SVAR, Recursive
from tca import transmission, through, not_through
from tca.systems import make_systems_form, to_transmission_irfs
from tca.viz import plot_decomposition, plot_dag
from tca.tables import decomposition_table, render_rich
# 1) Estimate a structural VAR (recursive / Cholesky identification).
data = pd.DataFrame(np.random.RandomState(0).randn(200, 3),
columns=["x", "pi", "i"])
m = SVAR(data, p=2, identification=Recursive()).fit()
# 2) Choose a transmission ordering (here: x -> pi -> i).
order = m.define_order(["x", "pi", "i"])
# 3) Build channels:
direct = m.not_through("pi", horizons=[0], order=["x", "pi", "i"])
indirect = m.through ("pi", horizons=[0], order=["x", "pi", "i"])
# 4) Compute total IRFs and channel decompositions.
H = 12
irfs = m.irfs(H) # structural IRFs
B, Om = make_systems_form(m.Phi0, m.var.coeff_lags(), [], order, H)
eff_dir = transmission(from_=1, arr1=B, arr2=Om, q=direct, method="BOmega", order=order)
eff_ind = transmission(from_=1, arr1=B, arr2=Om, q=indirect, method="BOmega", order=order)
# 5) Pretty table + decomposition plot.
df = decomposition_table(idx_outcome=3, irfs_total=irfs,
channel_effects=[eff_dir, eff_ind],
channel_names=["Direct", "Indirect (via π)"])
render_rich(df, title="Demand shock → interest rate")
plot_decomposition(idx_outcome=3, irfs_total=irfs,
channel_effects=[eff_dir, eff_ind],
channel_names=["Direct", "Indirect (via π)"],
ylabel="Response of i").show()
API at a glance
Boolean conditions
from tca import Q, make_condition
# Atomic variables follow systems-form ordering: x1 = first variable at horizon 0.
q = (Q(1) | Q(2)) & ~Q(3)
q = make_condition("(x1 | x2) & !x3")
Channel builders
from tca import through, not_through
order = [1, 2, 3]
contemporaneous = through(1, [0], order) # paths through x_{1,0}
no_inflation = not_through(2, range(0, 13), order)
combined = through([1, 2], [0, 1], order) # joint condition
Engine
from tca import transmission
# Systems-form method.
eff = transmission(from_=1, arr1=B, arr2=Omega, q=q, method="BOmega", order=order)
# IRF method (works with local projections).
eff = transmission(from_=1, arr1=irfs_T, arr2=ortho_T, q=q, method="irf", order=order)
eff is a 3-D array of shape (K, 1, H+1) when order is supplied.
Models
from tca.models import VAR, SVAR, LP, DSGE, Recursive, ExternalInstrument
VAR(data, p=4).fit_and_select(max_p=8, ic="aic")
SVAR(data, p=4, identification=Recursive()).fit()
SVAR(data, p=4, identification=ExternalInstrument(z, normalize_to=2)).fit()
LP(data, shock=z, max_horizon=20, n_lags=4).fit()
# DSGE: provide a *linearised* model in VARMA form, an ABCD state-space
# (Morris 2016 conversion is built in), or pre-extracted Dynare structs.
DSGE.from_varma(Phi0, As=[A1], Psis=[])
DSGE.from_state_space(A, B, C, D, Sigma_e=Sigma_e)
DSGE.from_dynare(M_, options_, oo_)
Visualisations
tca.viz provides four chart families:
plot_decomposition— stacked-bar decomposition of an IRF.plot_compare_decompositions— side-by-side comparison of two decompositions.plot_irf_grid— IRF panel with optional confidence bands.plot_heatmap— heatmap ofB/Omega/Phi.plot_dag— DAG of the systems form across horizons.
A consistent TCA_PALETTE and set_style() helper keep plots
publication-ready.
Tables
from tca.tables import decomposition_table, channel_share_table, render_rich, style_dataframe
df = decomposition_table(2, irfs_total, [eff_dir, eff_ind], ["Direct", "Indirect"])
render_rich(df, title="Demand shock → inflation") # coloured terminal table
style_dataframe(df, cmap="RdBu_r") # notebook / HTML / LaTeX
render_rich requires the optional rich dependency and falls back to
plain text otherwise.
Citing
If you use this library, please cite both the original framework and this implementation:
@article{wegner2024tca,
title = {Transmission Channel Analysis in Dynamic Models},
author = {Wegner, Enrico and Lieb, Lenard and Smeekes, Stephan and Wilms, Ines},
journal= {arXiv preprint arXiv:2405.18987},
year = {2024}
}
@misc{roudane2026tcapy,
title = {tca: Transmission Channel Analysis in Python},
author = {Roudane, Merwan},
year = {2026},
url = {https://github.com/merwanroudane/tca}
}
License
MIT — see LICENSE.
Metadata
Release files for tca-channels 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| tca_channels-0.1.0.tar.gz | 36.6 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tca_channels-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 72.4 kB
Release files / tca_channels-0.1.0.tar.gz
| Download URL | tca_channels-0.1.0.tar.gz |
|---|---|
| Size | 36.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
419df2636e04daee9f6fe737ded115e513315057f8a2d7a61792e54e4c6728d6
|
|
BLAKE2b-256 checksum How to use checksums |
5664f645fe9e5ca9581c4b49e78a6139d072c3f1efa279550efc5d5e38762243
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.0
|
Release files / tca_channels-0.1.0-py3-none-any.whl
| Download URL | tca_channels-0.1.0-py3-none-any.whl |
|---|---|
| Size | 35.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0d307d578a64602a63221873da2d6228a3f80de1b529f2a8e511bf438339251b
|
|
BLAKE2b-256 checksum How to use checksums |
cc48abd063f2c5a96f8e09240805eb3ee1a14c4ccf4c8b5affebd8a42861d279
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.0
|
Security for tca-channels 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.