No description
  • Python 97.5%
  • Jupyter Notebook 2.5%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Jeremie Fraeys 4a9533701b
Fix ExperimentRunner silently dropping scenario shocks/initial-conditions/oil price
Every scenario YAML in conf/scenario/ (36 files, e.g. oil_collapse_2014,
covid_collapse_2020) defines its own shock volatilities, starting
GDP/inflation/rates, and initial oil price to represent that episode
or what-if -- but experiments/runner.py's _run_simulations() only ever
read the energy_policy section (via _load_scenario_config() ->
Scenario.get_policy_params()). The oil/shocks/initial_conditions
sections were correctly parsed into the Scenario dataclass
(scenario_registry.py has fields for all three) but never read back
anywhere in this file, so every scenario silently ran with the same
generic default shocks and starting conditions -- only the 4
energy-policy fields actually differed between scenarios, for the
whole history of this code path.

Verified concretely: oil_collapse_2014.yaml specifies initial_price:
52.0 and ca gdp: 1.95 (representing Dec 2014's actual price collapse),
but before this fix the simulated oil_price[:, 0] was 80.0 (the
generic default) and ca_gdp[:, 0] was 2.1 -- the scenario's entire
premise was silently discarded. This affected Pipeline Analysis
(Streamlit), and any CLI/ExperimentRunner-based run. The Hydra path
(scripts/run_experiment.py, "recommended for research" per README) was
NOT affected -- it already applies these fields correctly by mutating
MC_CONFIG directly.

Fixed via the same per-instance config-override mechanism used for
PolicyOptimizer's phi_pi/phi_y earlier this session: extended
POLICY_PARAM_TO_CONFIG_FIELD (monte_carlo/engine.py) with shock-
volatility and initial-condition mappings using the same key names as
each YAML's shocks:/initial_conditions: sections, and added
_load_scenario_model_params() (experiments/runner.py) to flatten a
scenario's full oil/shocks/initial_conditions into that shape and pass
it through to get_optimal_simulator() alongside calibrated_params.

Verified end-to-end: oil_collapse_2014 now starts at oil_price=52.0 /
ca_gdp=1.95 as specified, and correctly shows 100% recession
probability -- a real, economically meaningful result for that
episode instead of a generic run indistinguishable from any other
scenario except its energy-policy fields.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KkkNxZSNBpstQGcgzCSnCZ
2026-09-09 12:18:15 -04:00
calibration Add data layer: environmental data and elasticity/Taylor-rule calibration 2026-09-08 12:19:36 -04:00
conf Add Hydra configuration tree 2026-09-08 12:20:07 -04:00
config Add demand/financial shock correlation; RL-vs-Taylor comparison; scenario provenance 2026-09-08 19:58:56 -04:00
data Add data layer: environmental data and elasticity/Taylor-rule calibration 2026-09-08 12:19:36 -04:00
docs Add gas-demand/green-transition methodology; note it as the project's actual research target 2026-09-08 13:45:58 -04:00
evaluation Add evaluation module: validation, metrics, and uncertainty quantification 2026-09-08 12:19:56 -04:00
examples Add example scripts 2026-09-08 12:20:17 -04:00
experiments Fix ExperimentRunner silently dropping scenario shocks/initial-conditions/oil price 2026-09-09 12:18:15 -04:00
monte_carlo Fix ExperimentRunner silently dropping scenario shocks/initial-conditions/oil price 2026-09-09 12:18:15 -04:00
notebooks Add exploration notebook 2026-09-08 12:20:20 -04:00
optimization Fix critical bug: PolicyOptimizer's policy parameters were never applied to the simulator 2026-09-08 20:50:10 -04:00
rl Isolate RL environment shocks from agent exploration RNG; delete dead EnergyState 2026-09-08 19:41:47 -04:00
scripts Fix Stress Testing (oil price clobbered) and Sensitivity Analysis (parameter never applied) 2026-09-09 12:11:14 -04:00
tests Fix ExperimentRunner silently dropping scenario shocks/initial-conditions/oil price 2026-09-09 12:18:15 -04:00
.gitignore Fix data pipeline, RL test drift, and Streamlit crashes; add .gitignore 2026-09-08 12:18:47 -04:00
.pre-commit-config.yaml Add project tooling and configuration 2026-09-08 12:19:31 -04:00
CONFIG.md Add project documentation 2026-09-08 12:20:31 -04:00
EXPLORATION.md Add project documentation 2026-09-08 12:20:31 -04:00
FUTURE_WORK.md Fact-check and correct numeric claims in FUTURE_WORK.md 2026-09-09 11:05:42 -04:00
mypy.ini Add project tooling and configuration 2026-09-08 12:19:31 -04:00
pyproject.toml Add project tooling and configuration 2026-09-08 12:19:31 -04:00
pytest.ini Stop silencing DeprecationWarning; move loose scripts into scripts/diagnostics/ 2026-09-08 19:41:58 -04:00
README.md Update README and FUTURE_WORK.md with this session's fixes 2026-09-08 19:42:12 -04:00
requirements.txt Fix critical bug: PolicyOptimizer's policy parameters were never applied to the simulator 2026-09-08 20:50:10 -04:00

Canadian Energy Policy Macro Research Framework

A comprehensive DSGE-lite simulation framework for analyzing Canadian energy market policies and their macroeconomic implications.

Overview

This framework implements a research-grade macroeconomic simulation of the Canada-US economic relationship, with a focus on:

  1. Energy Market Policy Design: Testing national pipeline scenarios, regional decoupling, and renewable transitions
  2. Two-Country DSGE Model: Coupled Canada-US macroeconomic dynamics with trade, interest rate, and exchange rate linkages
  3. Optimal Monetary Policy: Pareto frontier analysis and RL-based policy learning under regime uncertainty
  4. Stress Testing: Oil price scenarios ($40-$150) and volatility regimes

Key Features

Recent Improvements

  • Custom RL Configs (April 2026): Both MacroEnvironment and DQNAgent now accept optional config parameters for user-defined reward weights and policy targets
  • Enhanced State Space (April 2026 → September 2026): grew from 7 macro variables to 11 (7 macro + 4 energy) to the current 13-dimensional state (7 macro + 6 energy, adding west_to_east_flow and renewable_share for pipeline-integration and green-transition policy analysis) — see RLConfig.STATE_DIM in config/simulation.py
  • Streamlit Upgrades (April 2026): 4 new advanced experiment modes added (Pareto Frontier, Stress Tests, Sensitivity, Convergence)
  • Compute backend selection (September 2026): monte_carlo.engine.get_optimal_simulator() picks MLX (Apple Silicon), CUDA (NVIDIA/cupy), or Numba/CPU automatically, or a specific backend can be forced — selectable live from the Streamlit sidebar

Model Architecture

  • Modular Agent-Based Design: Household, firm, central bank, energy sector, and housing agents
  • Vectorized Monte Carlo: Efficient parallel simulation of 1000s of paths
  • GPU Acceleration: Optional CuPy support for large-scale experiments
  • Two-Country Coupling: Endogenous trade flows, exchange rate dynamics, and interest spillovers

Energy Sector Modeling

  • Regional split (East vs West Canada)
  • Pipeline capacity and flow modeling
  • Domestic vs export market dynamics
  • Oil price pass-through to inflation and GDP

Policy Analysis

  • Pareto Optimization: Tradeoff curves for recession risk vs inflation control
  • RL-Based Policy: Deep Q-Networks learn optimal monetary policy under uncertainty
  • Regime-Specific Calibration: Different optimal policies for high/low oil volatility

Exploration & Visualization

  • Streamlit App: Interactive web interface with 11 modes:
    • Quick Simulation, Pipeline Policy Analysis, Pareto Frontier Explorer
    • Stress Test Suite, Sensitivity Analysis, Monte Carlo Convergence
    • Energy Policy RL, Statistical Tests, Hydra Integration
    • Load Results, Compare Scenarios
  • Export Tools: Automated CSV/PNG export for papers and presentations

Installation

# Clone repository
git clone <repo-url>
cd macro-research-framework

# Install dependencies
pip install -r requirements.txt

# Optional: GPU support
pip install cupy-cuda11x  # Adjust for your CUDA version

Quick Start

1. Run Data Pipeline

python scripts/cli.py pipeline --fred-key YOUR_FRED_API_KEY

2. Baseline Simulation

# Run 2000 Monte Carlo paths with default scenarios
python scripts/cli.py baseline --n-paths 2000 --pareto --rl

# High oil price scenario only
python scripts/cli.py baseline --scenarios high --n-paths 5000

3. Stress Testing

# Test multiple oil price levels
python scripts/cli.py stress-test --oil-prices 40 60 80 100 120 150

4. Pareto Frontier Optimization

# Compute optimal policy tradeoffs
python scripts/cli.py pareto --n-points 20 --n-paths 2000

5. RL Policy Training

# Train RL-based monetary policy
python scripts/cli.py rl --episodes 500

6. Energy Policy Comparison

# Compare different energy market designs
python scripts/cli.py energy-policy

7. Interactive Exploration (Streamlit)

# Launch interactive web app for exploring results
streamlit run scripts/app.py

# Or run example script to generate and export results
python examples/run_and_export.py

Streamlit Modes:

Mode Purpose Best For
Quick Simulation Fast single-scenario runs Rapid iteration, parameter tuning
Pipeline Policy Analysis East-west energy policy comparison Canadian energy market design
Pareto Frontier Explorer Multi-objective policy optimization Finding optimal BoC policy tradeoffs
Stress Test Suite Oil price & demand shock scenarios Risk assessment, tail risk analysis
Sensitivity Analysis Parameter sweep analysis Model robustness testing
Monte Carlo Convergence Path count validation Ensuring simulation stability
Energy Policy RL Train RL-based monetary policy AI-driven policy optimization
Statistical Tests Structural break & coverage tests Model validation
Hydra Experiment Preview Hydra configurations Pre-run config validation
Load Results View saved experiments Post-hoc analysis
Compare Scenarios Side-by-side scenario comparison Policy briefings

Example - Pareto Frontier Analysis:

streamlit run scripts/app.py
# Select "Pareto Frontier Explorer"
# Adjust: 2000 paths, 10 frontier points
# Explore tradeoff between recession risk and inflation control
# Export optimal policy parameters as CSV

Example - Stress Testing:

streamlit run scripts/app.py
# Select "Stress Test Suite"
# Configure oil prices: $40, $60, $80, $100, $120
# Run 5000 paths per scenario
# Compare GDP trajectories under stress
# Run with default configuration
python scripts/run_experiment.py

# Run specific scenario with specific policy
python scripts/run_experiment.py scenario=high_oil model=aggressive

# Run large-scale simulation
python scripts/run_experiment.py simulation=large_scale

# Run parameter sweep (multirun)
python scripts/run_experiment.py --multirun scenario=baseline,low_oil,high_oil

# Run full grid search: 3 scenarios × 3 models
python scripts/run_experiment.py --multirun scenario=baseline,low_oil,high_oil model=standard_taylor,aggressive,accommodative

# Override specific parameters
python scripts/run_experiment.py scenario=high_oil simulation.n_paths=5000 experiment.seed=123

# Add verbose output
python scripts/run_experiment.py scenario=high_oil experiment.verbose=true

All outputs automatically saved to timestamped directories under results/.

See conf/ directory for all configurable options.

Framework Structure

macro-research-framework/
├── scripts/              # Executable entry points
│   ├── cli.py            # Typer CLI (baseline, stress-test, pareto, rl)
│   ├── run_experiment.py # Hydra experiment runner (recommended)
│   ├── run_pipeline_analysis.py  # Pipeline policy analysis
│   ├── app.py            # Streamlit web interface
│   └── diagnostics/      # Ad-hoc dev scripts (not the pytest suite — see tests/)
├── conf/                 # Hydra hierarchical configs
│   ├── config.yaml       # Main experiment configuration
│   ├── scenario/         # Scenario configs (36 YAML files)
│   ├── model/            # Model configs (taylor_rule variants)
│   └── simulation/       # Simulation configs (default, large_scale)
├── config/
│   └── simulation.py     # Pydantic configs (MC_CONFIG, RL_CONFIG, etc.)
├── monte_carlo/
│   └── engine.py         # Vectorized/GPU Monte Carlo simulator
├── rl/
│   ├── agent.py          # DQN agent for monetary policy
│   ├── environment.py    # Macro RL environment
│   └── trainer.py        # RL training and evaluation
├── optimization/
│   └── pareto.py         # Pareto frontier optimizer
├── data/
│   ├── pipeline.py       # FRED + StatsCan ETL (uses Polars)
│   └── async_pipeline.py # Async data loading helpers
├── calibration/
│   ├── elasticities.py   # Elasticity estimation
│   └── taylor_rule.py    # Taylor rule calibration
├── experiments/
│   ├── runner.py         # Experiment orchestration
│   ├── scenario_registry.py  # Scenario metadata registry
│   └── pipeline_analysis.py  # Pipeline policy analysis
├── examples/
│   └── run_and_export.py # Example: Run & export experiments
├── notebooks/
│   └── exploration.ipynb  # Jupyter notebook for analysis
├── tests/                # pytest test suite
├── requirements.txt      # Package versions
├── pyproject.toml        # Modern Python packaging
├── README.md             # This file
└── EXPLORATION.md        # Guide to exploration tools

Research Applications

1. Energy Market Design

Test whether a national east-west pipeline would reduce Canadian exposure to global oil price volatility:

from model.country import TwoCountryModel

# Create model with pipeline
model = TwoCountryModel(canada_params, us_params)
model.canada.build_energy_pipeline()

# Run simulation
results = model.simulate(T=40)

2. Policy Tradeoff Analysis

Find Pareto-optimal BoC policy parameters:

from optimization.pareto import PolicyOptimizer

optimizer = PolicyOptimizer(simulator, params)
frontier = optimizer.compute_pareto_frontier(n_points=20)

# Get optimal tradeoff
optimal = optimizer.find_optimal_tradeoff(
    target_recession=0.15,
    target_inflation=0.015
)

3. Regime-Dependent Policy

Train RL agent that adapts to different oil volatility regimes:

from optimization.rl_policy import RLPolicyOptimizer

rl_opt = RLPolicyOptimizer()
rl_opt.train(n_episodes=500)

# Compare with Taylor rule
results = rl_opt.compare_policies()

Model Calibration

Key calibrated parameters (from historical data):

Parameter Value Source
Oil-GDP elasticity (Canada) ~0.12 StatsCan 2000-2023
Oil-inflation elasticity ~0.08 BoC CPI decomposition
US spillover to Canada ~0.35 FRED + StatsCan
BoC Taylor rule: φ_π ~1.6 Rolling estimation
BoC Taylor rule: φ_y ~0.4 Rolling estimation

Stress Test Results

Example output from $40 vs $120 oil price scenarios:

Metric $40 Oil $120 Oil
Mean GDP Growth 1.2% 2.8%
Recession Probability 28% 12%
Mean Inflation 1.5% 3.2%
CAD/USD 0.68 0.82
House Price Growth -2% +8%

Academic Citation

If using this framework for research:

@software{macro_energy_framework,
  title = {Canadian Energy Policy Macro Research Framework},
  author = {[Author]},
  year = {2024},
  url = {[Repository URL]}
}

License

MIT License - See LICENSE file

Contact

For questions or collaboration: [email]