Skip to content

Commit b2dd523

Browse files
Update README: full reference for all 50 UDFs, package layout, installation, plotting section
Co-authored-by: zachessesjohnson <168567202+zachessesjohnson@users.noreply.github.com>
1 parent 5d813a1 commit b2dd523

File tree

1 file changed

+312
-1
lines changed

1 file changed

+312
-1
lines changed

README.md

Lines changed: 312 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,313 @@
11
# sovereign_debt_xl
2-
PyXLL is an Excel add-in exposing Python UDFs for sovereign debt analysis: debt sustainability modeling, yield curve forecasting, rolling averages, and portfolio indexing . No VBA, no context switching.
2+
3+
A [PyXLL](https://www.pyxll.com/) Excel add-in that exposes Python UDFs for sovereign debt analysis: debt sustainability modelling, yield curve fitting, risk metrics, macro-financial linkages, and inline Matplotlib charts — directly in Excel cells with no VBA, no context switching.
4+
5+
---
6+
7+
## Table of Contents
8+
9+
- [Project layout](#project-layout)
10+
- [Requirements](#requirements)
11+
- [Installation](#installation)
12+
- [PyXLL configuration](#pyxll-configuration)
13+
- [Function reference](#function-reference)
14+
- [Averaging & statistics](#averaging--statistics)
15+
- [Indexing & normalisation](#indexing--normalisation)
16+
- [Forecasting](#forecasting)
17+
- [Modelling utilities](#modelling-utilities)
18+
- [Utilities](#utilities)
19+
- [Fiscal sustainability](#fiscal-sustainability)
20+
- [Credit risk](#credit-risk)
21+
- [Yield curve](#yield-curve)
22+
- [Reserves & external sector](#reserves--external-sector)
23+
- [Stress testing](#stress-testing)
24+
- [Amortisation & financing](#amortisation--financing)
25+
- [Political risk & ESG](#political-risk--esg)
26+
- [Contagion](#contagion)
27+
- [Debt composition](#debt-composition)
28+
- [Macro-financial linkages](#macro-financial-linkages)
29+
- [Market microstructure](#market-microstructure)
30+
- [IMF framework](#imf-framework)
31+
- [Event studies](#event-studies)
32+
- [Plotting (inline charts)](#plotting-inline-charts)
33+
- [Running tests](#running-tests)
34+
35+
---
36+
37+
## Project layout
38+
39+
```
40+
sovereign_debt_xl/ ← repo root
41+
├── sovereign_debt_xl/ ← installable Python package
42+
│ ├── __init__.py ← re-exports every submodule
43+
│ ├── _coerce.py ← internal input-coercion helpers
44+
│ ├── amortization.py
45+
│ ├── averaging.py
46+
│ ├── contagion.py
47+
│ ├── credit_risk.py
48+
│ ├── debt_composition.py
49+
│ ├── event_studies.py
50+
│ ├── fiscal.py
51+
│ ├── forecasting.py
52+
│ ├── imf_framework.py
53+
│ ├── indexing.py
54+
│ ├── macro_financial.py
55+
│ ├── market_microstructure.py
56+
│ ├── modeling.py
57+
│ ├── plots.py ← inline Matplotlib chart UDFs
58+
│ ├── political_esg.py
59+
│ ├── reserves.py
60+
│ ├── stress.py
61+
│ ├── utils.py
62+
│ └── yield_curve.py
63+
├── test_*.py ← pytest test suite (repo root)
64+
├── conftest.py ← pyxll mock for tests
65+
├── pyproject.toml
66+
├── pyxll.cfg
67+
└── requirements.txt
68+
```
69+
70+
All source code lives inside `sovereign_debt_xl/` so that `pip install -e .` correctly packages the module. Tests remain at the repo root so pytest discovers them automatically.
71+
72+
---
73+
74+
## Requirements
75+
76+
- Python ≥ 3.11
77+
- [PyXLL](https://www.pyxll.com/) (Excel add-in runtime; not required for running tests)
78+
- Python dependencies (installed automatically via `pip install`):
79+
- `numpy`, `pandas`, `scipy`, `statsmodels`, `scikit-learn`, `matplotlib`
80+
81+
---
82+
83+
## Installation
84+
85+
```bash
86+
# 1. Install Python dependencies
87+
pip install -r requirements.txt
88+
89+
# 2. Install the package in editable mode
90+
pip install -e .
91+
```
92+
93+
`pyproject.toml` declares `sovereign_debt_xl` as the package root so setuptools will find and install everything under `sovereign_debt_xl/`.
94+
95+
---
96+
97+
## PyXLL configuration
98+
99+
`pyxll.cfg` loads the entire package through a single entry:
100+
101+
```ini
102+
[PYXLL]
103+
modules=
104+
sovereign_debt_xl
105+
```
106+
107+
`sovereign_debt_xl/__init__.py` re-exports every submodule, so PyXLL discovers all UDFs automatically when the add-in loads.
108+
109+
---
110+
111+
## Function reference
112+
113+
All UDFs follow two naming conventions:
114+
115+
| Prefix | Scope |
116+
|--------|-------|
117+
| `SOV_` | Analytic / numerical functions that return values or arrays |
118+
| `SDXL_PLOT_` | Plotting functions that return an inline PNG image |
119+
120+
### Averaging & statistics
121+
122+
| Function | Description |
123+
|----------|-------------|
124+
| `SOV_WEIGHTED_AVERAGE(values, weights)` | Weighted arithmetic mean |
125+
| `SOV_ROLLING_AVERAGE(values, window)` | Rolling / moving average |
126+
| `SOV_TRIMMED_MEAN(values, trim_pct)` | Mean after trimming extreme percentiles |
127+
| `SOV_DESCRIBE(values)` | Descriptive statistics table (count, mean, std, min, max, …) |
128+
129+
### Indexing & normalisation
130+
131+
| Function | Description |
132+
|----------|-------------|
133+
| `SOV_RANK_PCT(values)` | Rank each value as a percentile |
134+
| `SOV_ZSCORE(values)` | Z-score standardisation |
135+
| `SOV_NORMALIZE_MINMAX(values)` | Min-max normalisation to [0, 1] |
136+
| `SOV_INDEX_TO_BASE(values, base_period)` | Rebase a series to a chosen base period = 100 |
137+
138+
### Forecasting
139+
140+
| Function | Description |
141+
|----------|-------------|
142+
| `SOV_LINEAR_FORECAST(x, y, x_new)` | OLS linear regression forecast |
143+
| `SOV_EXP_SMOOTHING(values, alpha)` | Simple exponential smoothing |
144+
| `SOV_HOLT_FORECAST(values, periods_ahead)` | Holt double-exponential smoothing forecast (α and β fitted automatically) |
145+
| `SOV_MOVING_AVG_FORECAST(values, window, periods)` | Moving-average extrapolation |
146+
| `SOV_SEASONAL_DECOMPOSE(values, period)` | Seasonal decomposition (trend + seasonal + residual) |
147+
148+
### Modelling utilities
149+
150+
| Function | Description |
151+
|----------|-------------|
152+
| `SOV_REGRESSION(y, x_matrix)` | OLS regression; returns coefficients and R² |
153+
| `SOV_CORRELATION_MATRIX(data_matrix)` | Pairwise correlation matrix |
154+
| `SOV_MONTE_CARLO(mean, std, n_sims, n_steps)` | Monte Carlo path simulation |
155+
| `SOV_SCENARIO_TABLE(base, shocks)` | Scenario analysis table |
156+
157+
### Utilities
158+
159+
| Function | Description |
160+
|----------|-------------|
161+
| `SOV_ARRAY_SHAPE(range)` | Return `{rows, cols}` of an Excel range |
162+
| `SOV_FLATTEN(range)` | Flatten a 2-D range to a single column |
163+
| `SOV_DATE_DIFF_BUS(start_date, end_date)` | Business-day count between two dates |
164+
165+
### Fiscal sustainability
166+
167+
| Function | Description |
168+
|----------|-------------|
169+
| `SOV_DEBT_TRAJECTORY(debt_gdp, r, g, primary_balance, years)` | Simulate debt-to-GDP path under r–g and primary balance assumptions |
170+
| `SOV_FISCAL_REACTION(debt_gdp, output_gap)` | Estimate fiscal reaction function coefficient |
171+
| `SOV_IMPLICIT_INTEREST_RATE(interest_payments, debt_stock)` | Implicit (effective) interest rate on public debt |
172+
| `SOV_DEBT_STABILIZING_PB(debt_gdp, r, g)` | Primary balance required to stabilise debt ratio |
173+
174+
### Credit risk
175+
176+
| Function | Description |
177+
|----------|-------------|
178+
| `SOV_MERTON_DEFAULT_PROB(asset_value, debt, volatility, r, T)` | Merton structural probability of default |
179+
| `SOV_CDS_DEFAULT_PROB(cds_spread, recovery_rate)` | Risk-neutral default probability from CDS spread |
180+
| `SOV_ZSCORE_SOVEREIGN(financials)` | Altman-style Z-score adapted for sovereign issuers |
181+
| `SOV_SPREAD_DECOMPOSITION(spread, risk_free, liquidity_premium)` | Decompose spread into credit, liquidity, and other components |
182+
183+
### Yield curve
184+
185+
| Function | Description |
186+
|----------|-------------|
187+
| `SOV_NELSON_SIEGEL(tenors, beta0, beta1, beta2, tau)` | Nelson-Siegel yield curve fit |
188+
| `SOV_ZSPREAD(cashflows, schedule, price, risk_free_curve)` | Z-spread to the risk-free curve |
189+
| `SOV_CARRY_ROLLDOWN(tenors, yields, holding_period)` | Carry-and-roll-down return estimate |
190+
| `SOV_ASW_SPREAD(coupon, maturity, price, swap_curve)` | Asset-swap spread calculation |
191+
192+
### Reserves & external sector
193+
194+
| Function | Description |
195+
|----------|-------------|
196+
| `SOV_RESERVES_ADEQUACY(reserves, imports, st_debt, m2)` | IMF ARA metric — composite reserve adequacy ratio |
197+
| `SOV_BOP_FINANCING_GAP(current_account, fdi, portfolio, amortisation)` | Balance-of-payments financing gap |
198+
| `SOV_FX_MISALIGNMENT(real_exchange_rate, fundamentals)` | REER misalignment from estimated equilibrium |
199+
200+
### Stress testing
201+
202+
| Function | Description |
203+
|----------|-------------|
204+
| `SOV_FAN_CHART_DEBT(baseline, shocks, periods, n_sims)` | Monte Carlo fan chart for debt trajectory |
205+
| `SOV_CONTINGENT_LIABILITY_SHOCK(debt_gdp, shock_size, gdp_impact)` | One-off shock to debt ratio from contingent liabilities |
206+
| `SOV_FX_PASSTHROUGH_DEBT(fx_debt_share, depreciation, debt_gdp)` | Debt ratio impact of exchange-rate depreciation |
207+
208+
### Amortisation & financing
209+
210+
| Function | Description |
211+
|----------|-------------|
212+
| `SOV_AMORTIZATION_PROFILE(bonds_list)` | Amortisation schedule from a list of bond maturities and amounts |
213+
| `SOV_WEIGHTED_AVG_MATURITY(bonds_outstanding)` | Weighted average maturity of debt portfolio |
214+
| `SOV_GROSS_FINANCING_NEED(deficit, amortisation)` | Annual gross financing need |
215+
216+
### Political risk & ESG
217+
218+
| Function | Description |
219+
|----------|-------------|
220+
| `SOV_POLITICAL_RISK_SCORE(indicators)` | Composite political-risk score |
221+
| `SOV_ESG_SOVEREIGN_SCORE(e, s, g, weights)` | Weighted ESG score for a sovereign |
222+
| `SOV_SANCTIONS_EXPOSURE(trade_matrix, sanctioned_countries)` | Bilateral trade-weighted sanctions-exposure index |
223+
224+
### Contagion
225+
226+
| Function | Description |
227+
|----------|-------------|
228+
| `SOV_CONTAGION_BETA(target_spreads, peer_spreads)` | OLS contagion beta of target vs peer spreads |
229+
| `SOV_DCC_GARCH_CORR(series_a, series_b)` | DCC-GARCH dynamic conditional correlation |
230+
| `SOV_GRANGER_CAUSALITY(y, x, max_lags)` | Granger-causality p-value between spread series |
231+
| `SOV_TRADE_LINKAGE_MATRIX(trade_flows)` | Normalised bilateral trade-linkage matrix |
232+
233+
### Debt composition
234+
235+
| Function | Description |
236+
|----------|-------------|
237+
| `SOV_ORIGINAL_SIN_INDEX(fx_debt, local_debt)` | Original-sin index (share of FX-denominated debt) |
238+
| `SOV_HIDDEN_DEBT_ESTIMATOR(reported, off_balance)` | Estimate of unreported / hidden debt obligations |
239+
| `SOV_DEBT_TRANSPARENCY_SCORE(disclosure_flags)` | Debt-transparency score from creditor-disclosure indicators |
240+
| `SOV_COLLATERALIZED_DEBT_FLAG(collateral_value, debt_amount)` | Flag bonds with collateralised structures |
241+
242+
### Macro-financial linkages
243+
244+
| Function | Description |
245+
|----------|-------------|
246+
| `SOV_BANK_NEXUS_SCORE(bank_holdings, total_assets)` | Sovereign-bank nexus concentration score |
247+
| `SOV_MONETARY_FINANCING_RISK(central_bank_claims, gdp)` | Monetary-financing-risk ratio |
248+
| `SOV_RG_DIFFERENTIAL(real_rate, real_growth)` | r–g differential driving debt dynamics |
249+
| `SOV_DOLLARIZATION_VULNERABILITY(fx_liabilities, total_liabilities)` | Dollarisation vulnerability index |
250+
251+
### Market microstructure
252+
253+
| Function | Description |
254+
|----------|-------------|
255+
| `SOV_BID_ASK_LIQUIDITY_SCORE(bid, ask, mid)` | Normalised bid-ask liquidity score |
256+
| `SOV_LOCAL_VS_EXTERNAL_BASIS(local_yield, external_yield, fx_forward)` | Local-vs-external basis after FX hedging |
257+
| `SOV_AUCTION_TAIL_ANALYSIS(bids, allotment)` | Auction tail (yield spread between average and cut-off) |
258+
| `SOV_INVESTOR_BASE_CONCENTRATION(holdings_by_type)` | Herfindahl–Hirschman investor-base concentration index |
259+
260+
### IMF framework
261+
262+
| Function | Description |
263+
|----------|-------------|
264+
| `SOV_DSA_REPLICATION(debt_gdp, r, g, pb_path)` | Replicate IMF debt sustainability analysis (DSA) projection |
265+
| `SOV_IMF_PROGRAM_PROBABILITY(macro_indicators)` | Probability of an IMF programme request |
266+
| `SOV_EXCEPTIONAL_ACCESS_CHECK(debt_gdp, financing_gap, market_access)` | IMF exceptional-access criteria checklist |
267+
| `SOV_SDRS_ALLOCATION_IMPACT(quota_share, sdr_allocation)` | Impact of SDR allocation on reserve adequacy |
268+
269+
### Event studies
270+
271+
| Function | Description |
272+
|----------|-------------|
273+
| `SOV_RESTRUCTURING_COMPARABLES(debt_gdp, gdp_growth, comparables)` | Comparable restructuring case analysis |
274+
| `SOV_EVENT_STUDY_SPREAD(spreads, event_date, window)` | Abnormal spread reaction around an event date |
275+
| `SOV_CRISIS_EARLY_WARNING(macro_panel)` | Early-warning signal from macro vulnerability indicators |
276+
277+
### Plotting (inline charts)
278+
279+
These functions render a Matplotlib chart to PNG and return it as a **PyXLL inline image** — the chart appears directly inside the Excel cell that holds the formula. Outputs are LRU-cached (up to 128 entries) so recalculation is fast.
280+
281+
| Function | Description |
282+
|----------|-------------|
283+
| `SDXL_PLOT_YIELD_CURVE(tenors, yields, [title], [x_label], [y_label], [width_px], [height_px], [style])` | Plot a yield curve; `style` is `"line"` (default) or `"markers"` |
284+
| `SDXL_PLOT_TIMESERIES(dates, values, [title], [width_px], [height_px])` | Plot a time series; dates accept Excel serials, ISO strings, or date objects |
285+
| `SDXL_PLOT_ROLLING_AVG(dates, values, window, [title], [width_px], [height_px])` | Plot raw data with a rolling-average overlay; `window` is the number of periods (default 20) |
286+
287+
**Example formulas:**
288+
289+
```excel
290+
=SDXL_PLOT_YIELD_CURVE(A2:A10, B2:B10, "UST Curve")
291+
=SDXL_PLOT_TIMESERIES(A2:A300, B2:B300, "10yr UST Yield")
292+
=SDXL_PLOT_ROLLING_AVG(A2:A300, B2:B300, 20, "Rolling Avg (20d)")
293+
```
294+
295+
Error conditions (mismatched lengths, empty input) return an `#SDXL:` prefixed string so Excel can display a readable error in the cell.
296+
297+
---
298+
299+
## Running tests
300+
301+
The test suite uses [pytest](https://pytest.org/) and mocks the `pyxll` runtime via `conftest.py`, so no Excel or PyXLL installation is required.
302+
303+
```bash
304+
# Install dependencies and the package
305+
pip install -r requirements.txt
306+
pip install -e ".[dev]"
307+
308+
# Run all tests from the repo root
309+
python -m pytest
310+
```
311+
312+
Test files mirror the module they cover (`test_averaging.py``averaging.py`, `test_plots.py``plots.py`, etc.) and live at the repo root alongside `conftest.py`.
313+

0 commit comments

Comments
 (0)