# MixVECM

[![PyPI version](https://badge.fury.io/py/mixvecm.svg)](https://badge.fury.io/py/mixvecm)
[![Python 3.8+](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

**Vector Error Correction Models with Mixed I(0) and I(1) Variables**

A Python implementation of the methodology presented in Chen (2022) "Vector Error Correction Models with Stationary and Nonstationary Variables" (SSRN Working Paper 4239531).

## Overview

The standard Vector Error Correction Model (VECM) framework is restricted to time series data with the same degree of integration (all I(1) variables). However, empirical studies often encounter data with mixed integration orders. This package extends the conventional VECM to accommodate systems containing both I(1) and I(0) variables.

### Key Features

- **Mixed VECM Estimation**: Handle systems with both I(0) and I(1) variables
- **Johansen Test Integration**: Determine the dimension of the I(0) space
- **Likelihood Ratio Tests**: Sequential testing for the number of I(0) components
- **Restricted Estimation**: Boswijk and Doornik (2004) iterative procedure
- **Data Generation**: Monte Carlo simulation support with exact DGP from the paper
- **Impulse Response Functions**: Orthogonalized and generalized IRF with FEVD
- **Publication-Ready Output**: Formatted results suitable for academic journals

## Installation

```bash
pip install mixvecm
```

For development installation:

```bash
git clone https://github.com/merwanroudane/mixvecm.git
cd mixvecm
pip install -e .[dev]
```

## Mathematical Framework

### Standard VECM

The conventional VECM is formulated as:

$$\Delta Y_t = \alpha\beta' Y_{t-1} + \sum_{l=1}^{p-1} \Pi_l \Delta Y_{t-l} + U_t$$

where:
- $Y_t$ is an $n$-dimensional vector
- $\alpha$ and $\beta$ are $n \times r$ matrices (adjustment coefficients and cointegrating vectors)
- $\beta' Y_{t-1} = 0$ represents $r$ equilibrium relations
- $\Pi_l$ are short-run dynamics matrices

### Mixed VECM Extension

The key theoretical contribution of Chen (2022) is:

**Lemma 2.5**: $B_{31} = 0$ is a necessary and sufficient condition for a VECM of $Y_t$ to contain $k$ I(0) components.

**Lemma 2.6**: The necessary and sufficient condition for a VECM to contain $k$ I(0) variables is that the cointegrating matrix $\beta$ can be written as:

$$\beta' = \begin{bmatrix} B_{21} & B_{22} & 0 \\ 0 & 0 & B_{33} \end{bmatrix}$$

This structure ensures that the I(0) space can be decomposed into two orthogonal subspaces:
1. A $k$-dimensional I(0) subspace containing the $k$ I(0) variables
2. An $(n-r-k)$-dimensional cointegration space containing linear combinations of the $(n-k)$ I(1) variables

### Testing Procedure

1. **Johansen Test**: Determines the dimension of the I(0) space (cointegration rank + number of I(0) variables)
2. **Sequential LR Tests**: Test hypotheses $H_0$: $k = 1, 2, 3, \ldots$ I(0) components
3. **LR Statistic** (Equation 3.18 in Chen 2022):

$$LR = T\left(\log|\tilde{\Omega}| - \log|S_{00}| + \sum_{i=1}^{r} \log(1 - \hat{\lambda}_i)\right) \xrightarrow{d} \chi^2(rk)$$

## Quick Start

### Basic Usage

```python
import numpy as np
from mixvecm import MixedVECM, generate_mixed_vecm_data

# Generate simulated data (6 variables: 4 I(1), 2 I(0), 2 cointegrating relations)
result = generate_mixed_vecm_data(T=200, n=6, n_i1=4, n_coint=2, seed=42)
Y = result.Y

# Fit the Mixed VECM
model = MixedVECM(Y, k_ar_diff=2, det_order=0)
results = model.fit()

# View results
print(results.summary())
print(f"Detected I(1) variables: {results.i1_indices}")
print(f"Detected I(0) variables: {results.i0_indices}")
print(f"Number of cointegrating relations: {results.n_coint}")
```

### Using Paper Examples

The package includes exact parameter specifications from the Chen (2022) paper:

```python
from mixvecm import example_dgp_1, example_dgp_2

# Example 3.1: Underlying VAR approach
data1 = example_dgp_1(T=200)
print(f"Example 3.1 - I(0) indices: {data1.i0_indices}")
print(f"Example 3.1 - I(1) indices: {data1.i1_indices}")

# Example 3.2: Restricted beta approach  
data2 = example_dgp_2(T=200)
print(f"Example 3.2 - I(0) indices: {data2.i0_indices}")
print(f"Example 3.2 - I(1) indices: {data2.i1_indices}")
```

### Johansen Test and I(0) Component Testing

```python
from mixvecm import johansen_test, test_i0_components

# Johansen cointegration test
joh_results = johansen_test(Y, k_ar_diff=2, det_order=0)

print("Johansen Test Results:")
print(f"Trace statistics: {joh_results.trace_stat}")
print(f"Critical values (5%): {joh_results.trace_crit_95}")
print(f"Cointegration rank: {joh_results.rank}")

# Test for I(0) components
i0_results = test_i0_components(Y, n_coint=joh_results.rank, k_i0=2, k_ar_diff=2)
print(f"\nLR statistic for k=2 I(0) components: {i0_results.lr_stat:.4f}")
print(f"P-value: {i0_results.p_value:.4f}")
```

### Impulse Response Analysis

```python
from mixvecm import compute_irf, compute_fevd

# Compute orthogonalized IRF
irf_results = compute_irf(results, horizons=20, orthogonalized=True)

# Plot IRF (requires matplotlib)
irf_results.plot(figsize=(12, 10))

# Forecast Error Variance Decomposition
fevd_results = compute_fevd(results, horizons=20)
fevd_results.plot()
```

## API Reference

### Core Classes

#### `MixedVECM`

Main class for estimating Mixed VECM.

```python
MixedVECM(data, k_ar_diff=1, det_order=0, var_names=None)
```

**Parameters:**
- `data`: ndarray of shape (T, n) - Time series data
- `k_ar_diff`: int - Number of lagged differences (default: 1)
- `det_order`: int - Deterministic term specification (-1: none, 0: constant, 1: trend)
- `var_names`: list - Variable names for output

**Methods:**
- `fit()` → `MixedVECMResults`: Estimate the model
- `summary()`: Print formatted results

#### `MixedVECMResults`

Container for estimation results.

**Attributes:**
- `alpha`: Adjustment coefficients matrix
- `beta`: Cointegrating vectors matrix
- `Pi`: Long-run impact matrix (αβ')
- `Gamma`: List of short-run coefficient matrices
- `Omega`: Residual covariance matrix
- `residuals`: Model residuals
- `fitted_values`: Fitted values
- `n_coint`: Number of cointegrating relations
- `n_i0`: Number of I(0) variables
- `i0_indices`: Indices of I(0) variables
- `i1_indices`: Indices of I(1) variables
- `log_likelihood`: Log-likelihood value
- `aic`, `bic`: Information criteria

### Testing Functions

#### `johansen_test`

```python
johansen_test(data, k_ar_diff=1, det_order=0) → JohansenTestResults
```

Performs Johansen cointegration test.

#### `test_i0_components`

```python
test_i0_components(data, n_coint, k_i0, k_ar_diff=1) → I0ComponentTestResults
```

Tests hypothesis of k I(0) components using LR test.

### Data Generation

#### `generate_mixed_vecm_data`

```python
generate_mixed_vecm_data(T, n, n_i1, n_coint, seed=None) → DataGenerationResult
```

Generate data from a mixed VECM.

#### `example_dgp_1`, `example_dgp_2`

Generate data using exact parameters from Chen (2022) Examples 3.1 and 3.2.

### Impulse Response Functions

#### `compute_irf`

```python
compute_irf(results, horizons=20, orthogonalized=True) → IRFResults
```

Compute impulse response functions.

#### `compute_fevd`

```python
compute_fevd(results, horizons=20) → FEVDResults
```

Compute forecast error variance decomposition.

## Examples

### Replicating Paper Results

```python
import numpy as np
from mixvecm import (
    example_dgp_1, 
    MixedVECM, 
    johansen_test,
    test_i0_components
)

# Generate data from Example 3.1
np.random.seed(42)
data = example_dgp_1(T=200)

# Run Johansen test
joh = johansen_test(data.Y, k_ar_diff=2)
print("Johansen Test Results (Example 3.1):")
for i, (stat, crit) in enumerate(zip(joh.trace_stat, joh.trace_crit_95)):
    print(f"  r <= {i}: stat = {stat:.2f}, crit(5%) = {crit:.2f}")

# Sequential testing for I(0) components
print("\nSequential I(0) Component Tests:")
for k in range(1, 4):
    result = test_i0_components(data.Y, n_coint=4, k_i0=k, k_ar_diff=2)
    print(f"  k = {k}: LR = {result.lr_stat:.2f}, p-value = {result.p_value:.3f}")

# Fit the model
model = MixedVECM(data.Y, k_ar_diff=2)
results = model.fit()
print(results.summary())
```

### Empirical Application (German Wage Example)

```python
import pandas as pd
from mixvecm import MixedVECM, compute_irf

# Load your data (example structure)
# data = pd.read_csv('german_wages.csv')
# Y = data[['rw', 'U_l', 'yn', 'V_c']].values

# Assuming Y is loaded...
model = MixedVECM(Y, k_ar_diff=2, det_order=0, 
                  var_names=['rw', 'U_l', 'yn', 'V_c'])
results = model.fit()

# Print summary
print(results.summary())

# Impulse response analysis
irf = compute_irf(results, horizons=16, orthogonalized=True)
irf.plot(shock_names=['yn', 'U_l', 'rw', 'V_c'],
         response_names=['yn', 'U_l', 'rw', 'V_c'])
```

## Theoretical Background

### Relationship to Standard Johansen Procedure

A key insight from Chen (2022) is that a mixed VECM is a special case of the conventional cointegrated VECM with restrictions on the cointegrating space. Therefore:

1. The Johansen procedure can determine the dimension of the I(0) space
2. The Johansen procedure can test for the presence of I(0) variables
3. Existing econometric software (R, RATS, EViews) can be adapted for mixed VECM

### The Underlying Process

For any cointegrated VECM satisfying standard assumptions, there exists an underlying stationary VAR process:

$$\begin{bmatrix} \Delta Z_t \\ X_t \end{bmatrix}$$

where $\Delta Z_t = \beta'_\perp \Delta Y_t$ and $X_t = \beta' Y_t$.

The transformation between $Y_t$ and the underlying process determines whether $Y_t$ contains I(0) components.

## Citation

If you use this package in your research, please cite:

```bibtex
@software{mixvecm2024,
  author = {Roudane, Merwan},
  title = {MixVECM: Vector Error Correction Models with Mixed I(0) and I(1) Variables},
  year = {2024},
  url = {https://github.com/merwanroudane/mixvecm}
}

@article{chen2022vecm,
  author = {Chen, Pu},
  title = {Vector Error Correction Models with Stationary and Nonstationary Variables},
  journal = {SSRN Working Paper},
  number = {4239531},
  year = {2022}
}
```

## References

1. Chen, P. (2022). Vector Error Correction Models with Stationary and Nonstationary Variables. SSRN Working Paper 4239531.

2. Johansen, S. (1995). Likelihood-Based Inference in Cointegrated Vector Autoregressive Models. Oxford University Press.

3. Boswijk, H.P. and Doornik, J.A. (2004). Identifying, estimating and testing restricted cointegrated systems: An overview. Statistica Neerlandica.

4. Hamilton, J.D. (1994). Time Series Analysis. Princeton University Press.

5. Pesaran, M.H., Shin, Y., and Smith, R.J. (2001). Bounds testing approaches to the analysis of level relationships. Journal of Applied Econometrics.

## License

MIT License - see [LICENSE](LICENSE) for details.

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## Author

**Dr Merwan Roudane**
- Email: merwanroudane920@gmail.com
- GitHub: [@merwanroudane](https://github.com/merwanroudane)
