Transmission Channel Analysis (TCA) for SVAR / SVARMA / LP / DSGE models, with beautiful plots and tables. Import as `import tca`.
Project description
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.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tca_channels-0.1.0.tar.gz.
File metadata
- Download URL: tca_channels-0.1.0.tar.gz
- Upload date:
- Size: 36.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
419df2636e04daee9f6fe737ded115e513315057f8a2d7a61792e54e4c6728d6
|
|
| MD5 |
e10f86b49a0fed59c8bb70ac66055ab4
|
|
| BLAKE2b-256 |
5664f645fe9e5ca9581c4b49e78a6139d072c3f1efa279550efc5d5e38762243
|
File details
Details for the file tca_channels-0.1.0-py3-none-any.whl.
File metadata
- Download URL: tca_channels-0.1.0-py3-none-any.whl
- Upload date:
- Size: 35.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0d307d578a64602a63221873da2d6228a3f80de1b529f2a8e511bf438339251b
|
|
| MD5 |
8ff8b49e141222d5453290de25873205
|
|
| BLAKE2b-256 |
cc48abd063f2c5a96f8e09240805eb3ee1a14c4ccf4c8b5affebd8a42861d279
|