An explainable, confidence-aware macro investment framework for comparing 13 investable asset groups across 18 countries.
The model combines official-source observations, explicit provenance, country-aware regime detection, asset scoring, optional valuation inputs, and uncertainty-aware cross-country comparison. It produces terminal, JSON, and self-contained responsive HTML reports.
Research and decision support only. Outputs are model signals, not personalized financial advice or standalone buy/sell instructions.
The project is now a layered Python package instead of duplicated, thousand-line scripts.
investment_dashboard.py is the single root launcher; country selection is handled by the
provider registry.
Key improvements:
- one shared domain model for observations, confidence, regimes, and asset scores;
- one application pipeline for merge precedence and report generation;
- isolated country adapters for official-source extraction;
- strategy objects for generic and Iran-specific economic behavior;
- shared HTTP retry, parsing, and strict JSON infrastructure;
- separate terminal and HTML presentation layers;
- editable HTML template and stylesheet with portable single-file output;
- regression and architecture tests that protect numerical behavior and dependency direction.
- 12 additional country providers using explicit central-bank policy settings and comparable World Bank macro observations;
- instrument-level labels for named FX baskets, sovereign bonds, inflation-linked bonds, and local cash instruments;
- silver, corporate credit, broad and energy commodities, Bitcoin, and Ether scoring;
- implementation guidance, risk labels, valuation-input requirements, and evidence-aware assessment statuses for every asset.
See ARCHITECTURE.md for boundaries, design decisions, roles, and the extension contract.
| Code | Country | Currency | Primary monetary source |
|---|---|---|---|
ir |
Iran | IRR | Central Bank of Iran |
us |
United States | USD | Federal Reserve / FRED |
cn |
China | CNY | People's Bank of China |
de |
Germany | EUR | Deutsche Bundesbank / Eurosystem |
jp |
Japan | JPY | Bank of Japan |
gb |
United Kingdom | GBP | Bank of England |
tr |
Turkey | TRY | Central Bank of the Republic of Türkiye / World Bank WDI |
fr |
France | EUR | Banque de France / ECB / World Bank WDI |
be |
Belgium | EUR | National Bank of Belgium / ECB / World Bank WDI |
nl |
Netherlands | EUR | De Nederlandsche Bank / ECB / World Bank WDI |
es |
Spain | EUR | Banco de España / ECB / World Bank WDI |
it |
Italy | EUR | Banca d'Italia / ECB / World Bank WDI |
az |
Azerbaijan | AZN | Central Bank of Azerbaijan / World Bank WDI |
am |
Armenia | AMD | Central Bank of Armenia / World Bank WDI |
fi |
Finland | EUR | Bank of Finland / ECB / World Bank WDI |
se |
Sweden | SEK | Sveriges Riksbank / World Bank WDI |
ca |
Canada | CAD | Bank of Canada / World Bank WDI |
br |
Brazil | BRL | Banco Central do Brasil / World Bank WDI |
The World Bank adapter is intentionally labeled live_official_auxiliary and receives a source
quality penalty relative to a current national release. Its annual observations improve
international comparability but do not pretend to be higher-frequency national data.
Official source + manual input + seed fallback
|
v
manual > live > seed merge
|
v
provenance and staleness confidence
|
v
normalized macro features
|
v
regime detection and asset scoring
|
v
optional market valuation
|
v
terminal / JSON / responsive HTML report
The model asks which asset classes the current macro environment supports. A high macro score
does not mean the asset is attractively priced. Without market inputs, its scope is explicitly
reported as MACRO_ONLY.
Python 3.10 or newer is required.
py -m venv .venv
.venv\Scripts\activate
py -m pip install -e ".[test]"Optional PDF support for some official publications:
py -m pip install -e ".[pdf]"Optional Iran spreadsheet and browser extraction support:
py -m pip install -e ".[iran]"
py -m playwright install chromiumOn Linux or macOS, use python3 and the platform's virtual-environment activation command.
py investment_dashboard.pyEquivalent package command:
py -m countries_investment_modelRun deterministically with seed and manual data only:
py investment_dashboard.py --no-webExport both machine-readable and visual reports:
py investment_dashboard.py --no-web --output report.json --html dashboard.htmlAnalyze a subset:
py investment_dashboard.py --countries tr,fr,ca,br --no-webList supported country keys:
py investment_dashboard.py --list-countriesUse the same canonical command with one country code:
py investment_dashboard.py --countries ir
py investment_dashboard.py --countries us
py investment_dashboard.py --countries trThe command accepts:
--no-web Skip live retrieval
--no-seed Disable seed fallbacks
--input-json Supply manual macro observations
--market-json Supply optional valuation inputs
--output Write a complete JSON report
--json Print JSON rather than terminal output
--debug Print retrieval diagnostics
--http-timeout Set the per-request timeout
Simple values are accepted:
{
"inflation_yoy": 2.7,
"core_inflation": 2.9,
"gdp_growth": 1.8,
"policy_rate": 3.5,
"money_growth": 4.7
}Auditable metadata can be provided with a value:
{
"inflation_yoy": {
"value": 2.7,
"unit": "percent",
"period": "2026-07",
"release_date": "2026-08-15",
"frequency": "monthly",
"source": "Manually verified official release",
"source_url": "https://example.org/official-release",
"base_confidence": 0.98
}
}For a comparison run, group overrides by country:
{
"us": {"inflation_yoy": 2.7, "gdp_growth": 1.8},
"jp": {"inflation_yoy": 2.1, "gdp_growth": 0.9}
}Inputs must be valid JSON objects. Non-finite values such as NaN and Infinity are rejected.
Depending on the country strategy, supported inputs can include:
{
"gold_premium_pct": 2.0,
"equity_forward_pe": 17.0,
"housing_price_to_annual_rent": 22.0,
"government_bond_yield": 4.0,
"inflation_linked_real_yield": 1.5,
"corporate_bond_spread_bps": 145,
"cash_rate": 3.5,
"local_currency_reer_overvaluation_pct": 5.0,
"silver_premium_pct": 4.0,
"broad_commodity_roll_yield_pct": 1.5,
"energy_commodity_roll_yield_pct": -2.0,
"bitcoin_mvrv_zscore": 1.2,
"ether_mvrv_zscore": 1.0
}When at least one applicable valuation input exists, the affected output is labeled
MACRO_PLUS_VALUATION and retains both the raw macro score and valuation adjustment.
The valuation_evidence.supported_inputs list is country-specific: for example, generic gold
uses gold_premium_pct, while Iran gold uses gold_coin_bubble_pct. Inputs must be finite JSON
numbers; unknown fields are retained for auditability and reported as unused.
Every generic-country report evaluates:
- gold and silver;
- a named reserve-currency basket versus the country's local currency;
- listed real estate and broad domestic equities;
- nominal sovereign, inflation-linked sovereign, and investment-grade corporate bonds;
- local Treasury bills or insured cash instruments;
- diversified broad and energy commodities;
- unleveraged spot Bitcoin and Ether exposure.
Iran uses the same expanded real, commodity, and digital-asset coverage but labels local fixed
income explicitly as IRR sovereign sukuk or high-grade fixed-rate debt—never as a “fixed salary.”
Each output includes an implementation route, major risks, and the market inputs needed to move
beyond macro-only analysis. Digital assets are marked EXTREME risk and include custody, legal,
sanctions, protocol, and drawdown warnings.
Every observation retains:
- value, unit, and frequency;
- observation period;
- release date, when the source supplies one;
- retrieval date for live access;
- source label and URL;
- provenance type (
live_*,official_auxiliary,manual, orseed); - base, staleness, source-quality, estimate, and effective confidence factors.
Release and retrieval dates are deliberately separate. Fetching an old observation today does not make that observation fresh.
Missing weighted indicators contribute zero to overall data confidence and are treated as neutral in scoring. They are never silently converted into observed zero-percent values.
Current source factors are transparent heuristics:
| Provenance | Factor |
|---|---|
| Live or manual | 1.00 |
| Official auxiliary | 0.94 |
| Seed fallback | 0.65 |
| Unknown | 0.75 |
| Forecast or projection multiplier | 0.82 |
These factors are not calibrated probabilities. Historical backtesting is still required.
Each country report contains:
model
regime
data_confidence
analysis_confidence
features
observations
market_inputs
assets_ranked
warnings
Each asset record also includes its precise country-specific label, instrument profile,
valuation_evidence, and an assessment:
DUE_DILIGENCE_CANDIDATE: supportive adjusted score, adequate evidence confidence, and a supplied valuation input;MACRO_WATCHLIST: macro backdrop is supportive, but valuation or other due diligence remains;NEUTRAL/UNFAVORABLE_MACRO: no supportive model signal;INSUFFICIENT_EVIDENCE: analysis confidence is too low for a directional status.
These statuses are research gates, not buy or sell instructions.
The comparison report adds quality coverage, source mix, global opportunities, and confidence- adjusted scores. The adjustment is:
50 + (raw score - 50) * analysis confidence
Low-confidence scores therefore move toward neutral. The shown range is a transparent heuristic sensitivity band, not a statistical confidence interval.
countries-investment-model/
├── countries_investment_model/
│ ├── domain/
│ │ ├── entities.py
│ │ ├── assets.py
│ │ ├── confidence.py
│ │ └── strategies.py
│ ├── application/
│ │ ├── provider.py
│ │ ├── assessment.py
│ │ ├── report_service.py
│ │ └── suite_service.py
│ ├── infrastructure/
│ │ ├── http.py
│ │ ├── parsing.py
│ │ └── json_io.py
│ ├── countries/
│ │ ├── registry.py
│ │ ├── expanded.py
│ │ ├── world_bank.py
│ │ └── <national source adapters>.py
│ └── presentation/
│ ├── country_cli.py
│ ├── dashboard_cli.py
│ ├── console.py
│ ├── html_report.py
│ ├── assets/report.css
│ └── templates/report.html
├── tests/
├── ARCHITECTURE.md
├── pyproject.toml
└── investment_dashboard.py
The architecture was reviewed through these responsibilities:
- macro methodology lead;
- quantitative model engineer;
- data integration engineer;
- application architect;
- product and visualization designer;
- QA and reliability engineer;
- documentation and release owner.
Detailed ownership and review evidence are defined in ARCHITECTURE.md.
Run the test suite:
py -B -m unittest discover -s tests -vThe tests cover:
- confidence penalties and staleness semantics;
- neutral handling of missing evidence;
- all 18 offline country pipelines;
- preserved numerical regression baselines;
- the expanded asset universe, precise FX labels, risk profiles, and assessment gates;
- annual-period staleness and official-auxiliary source penalties;
- valuation scope changes;
- cross-country score adjustment and output validation;
- safe, complete, responsive HTML generation;
- supported aliases;
- package dependency direction;
- one thin canonical root entry point and no duplicate country launchers.
Add a focused adapter under countries_investment_model/countries/, configure its official
sources and seed observations, create a CountryProvider, and register it in registry.py.
Reuse GenericMacroStrategy when its assumptions fit. Add a dedicated domain strategy when the
country's monetary system requires genuinely different economic logic.
Every new adapter should include regression expectations for its regime, confidence, and leading asset score. Full instructions are in ARCHITECTURE.md.
The current rules are economically interpretable but not yet historically calibrated. Priority next steps are:
- point-in-time historical datasets that preserve publication lags and revisions;
- country and asset return backtests without look-ahead bias;
- calibrated uncertainty and regime probabilities;
- fiscal, sovereign-risk, external-balance, labor, and credit features;
- standardized cross-country accessibility, liquidity, tax, and FX-risk adjustments;
- automated source-contract fixtures for scraper change detection;
- a hosted API and interactive dashboard after model validation.
MIT. See LICENSE.