
Fixed Income Corporate
- 395 installs
- 161 repo stars
- Updated July 18, 2026
- joellewis/finance_skills
fixed-income-corporate is a finance_skills agent skill that models corporate bond credit spreads, default probabilities, callable bond yields, and covenant analysis for developers integrating fixed-income analytics into
About
fixed-income-corporate is a wealth-management skill from joellewis/finance_skills with fixed_income_corporate.py (numpy, scipy, --verify) for corporate bond credit analysis. It covers G-spread, Z-spread, and OAS spread measures, investment-grade versus high-yield rating boundaries at BBB/BB, migration matrices, expected loss EL = PD × LGD × EAD, recovery rates by seniority, callable bond yield-to-worst, maintenance versus incurrence covenants, private credit illiquidity premiums of 150-400bp, and CDS-implied default probabilities. Worked examples compare 130bp G-spread to 118bp Z-spread and compute $12,000 expected annual loss. Developers reach for fixed-income-corporate when building bond pricing engines, credit risk dashboards, or portfolio analytics with corporate debt exposure.
- Bond identifier mapping
- Coupon and amortization schedules
- Callable andputable features
- Spread and yield conventions
- Vendor pricing fallbacks
Fixed Income Corporate by the numbers
- 395 all-time installs (skills.sh)
- +17 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #265 of 1,106 Finance & Trading skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/joellewis/finance_skills --skill fixed-income-corporateAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 395 |
|---|---|
| repo stars | ★ 161 |
| Last updated | July 18, 2026 |
| Repository | joellewis/finance_skills ↗ |
How do you calculate corporate bond credit spreads?
Model, price, and integrate corporate bond positions—including coupons, call schedules, ratings, and liquidity—into portfolios, risk systems, and client analytics.
Who is it for?
Fixed-income and fintech developers building corporate bond pricing, credit spread analytics, or expected loss models in portfolio and risk management systems.
Skip if: Developers modeling sovereign Treasury curves or municipal bond tax equivalency, which have separate fixed-income-sovereign and fixed-income-municipal skills.
When should I use this skill?
User asks about corporate bonds, credit spreads OAS/Z-spread, yield-to-worst, default probability, or covenant analysis for corporate debt.
What you get
G-spread, Z-spread, OAS, yield-to-worst, expected loss estimates, and covenant analysis for corporate bond positions.
- Credit spread calculations
- Expected loss estimates
- Callable bond yield analysis
By the numbers
- Includes fixed_income_corporate.py with numpy/scipy and --verify mode
- Documents recovery rates: senior secured 60-65%, senior unsecured 40-50%, subordinated 20-30%
- Part of finance_skills repository with 81 skills across 7 domain plugins
Files
Fixed Income — Corporate
Core Concepts
Credit Spreads
Compensation for default risk, liquidity risk, and downgrade risk above the risk-free rate. Multiple spread measures exist with increasing precision:
G-spread (Government Spread): Bond yield minus interpolated Treasury yield of the same maturity. Simple but assumes a flat term structure between benchmark maturities.
Z-spread (Zero-Volatility Spread): The constant spread added to each point on the risk-free spot rate curve such that the sum of discounted cash flows equals the bond's market price. Superior to G-spread because it accounts for the full shape of the term structure.
OAS (Option-Adjusted Spread): For bonds with embedded options, OAS = Z-spread minus the value of the embedded option. OAS represents the "true" credit compensation after removing the option component. Requires an interest rate model to compute.
Credit Ratings
AAA/AA/A/BBB are investment grade. BB/B/CCC/CC/C/D are high yield (speculative grade). The BBB/BB boundary is the most consequential threshold — many institutional mandates prohibit sub-investment-grade holdings. A downgrade across this boundary ("fallen angel") forces selling by constrained investors.
Migration Matrix
A transition matrix shows the probability of moving from one rating to another over a 1-year horizon. A BBB-rated issuer has roughly 85-90% probability of remaining BBB, 4-5% chance of upgrade, 4-5% chance of downgrade, and a small probability (~0.2%) of default. Migration matrices are published annually by rating agencies.
Default Probability, Loss Given Default, and Recovery Rate
- PD = Probability of Default over a given horizon
- LGD = Loss Given Default (percentage of exposure lost)
- Recovery Rate (RR) = 1 - LGD
- Expected Loss: EL = PD × LGD × EAD (Exposure at Default)
Recovery rates vary by seniority: senior secured (60-65%), senior unsecured (40-50%), subordinated (20-30%).
Callable Bonds
The issuer can redeem the bond early. Call schedules specify prices and dates. Yield-to-call (YTC) is calculated using the call date and call price. Yield-to-worst (YTW) is the minimum of YTM and all possible YTCs. For callable bonds, OAS is the appropriate spread measure (not G-spread or Z-spread).
Covenants
Maintenance covenants: Tested periodically (e.g., quarterly). Issuer must maintain financial ratios at all times. Common in bank loans.
Incurrence covenants: Tested only when the issuer takes a specific action (e.g., issues new debt). Common in bond indentures. Key covenants include leverage ratio (Debt/EBITDA), interest coverage (EBITDA/Interest), and restricted payments.
Private Credit
Direct lending by non-bank lenders to middle-market companies. Offers an illiquidity premium of 150-400bp over comparable syndicated loans. Typically features stronger covenant protection than public market deals. Valuations are mark-based (quarterly), which smooths reported volatility.
CDS (Credit Default Swaps)
A derivative where the protection buyer pays a periodic spread and receives payment upon a credit event. CDS spreads can be used to derive market-implied default probabilities. CDS spreads are often more responsive to credit deterioration than bond spreads.
Key Formulas
| Formula | Expression | Use Case |
|---|---|---|
| G-spread | Bond Yield - Interpolated Treasury Yield | Simple spread measure |
| Z-spread | Constant spread s: P = sum CF_t / (1+s_t+s)^t | Full curve spread |
| OAS | Z-spread - Option Cost | Spread for callable bonds |
| Expected Loss | EL = PD × LGD × EAD | Credit loss estimation |
| Recovery Rate | RR = 1 - LGD | Recovery from default |
| Yield-to-Worst | min(YTM, YTC_1, YTC_2, ...) | Conservative yield measure |
Worked Examples
Example 1: Compare Z-spread vs G-spread
Given: A 7-year corporate bond yields 5.8%. The 7-year interpolated Treasury yield is 4.5%. The Z-spread (computed using the full spot curve) is 118bp. Calculate: G-spread and compare to Z-spread Solution: G-spread = 5.8% - 4.5% = 1.30% = 130bp Z-spread = 118bp The G-spread (130bp) exceeds the Z-spread (118bp) by 12bp. This difference arises because the G-spread uses a single interpolated benchmark point while the Z-spread properly accounts for the shape of the entire yield curve. In a steep curve environment, G-spread tends to overstate the true spread.
Example 2: Expected Loss Calculation
Given: PD = 2% (annual), LGD = 60%, EAD = $1,000,000 Calculate: Expected annual loss Solution: EL = PD × LGD × EAD EL = 0.02 × 0.60 × $1,000,000 EL = $12,000
The expected annual credit loss is $12,000, or 1.2% of the exposure. This represents the actuarial cost of credit risk — the spread must at least cover this expected loss, with additional compensation for unexpected losses and risk aversion.
Common Pitfalls
- Using G-spread for callable bonds — use OAS instead, which removes the option component
- Ignoring liquidity premium in spread analysis — part of the spread compensates for illiquidity, not just default risk
- Rating agency lag vs market-implied credit quality — CDS spreads often move before rating actions
- Assuming recovery rates are constant — they vary significantly by seniority and economic cycle (lower in recessions)
Cross-References
- fixed-income-sovereign: the Treasury curve used as the risk-free benchmark
- fixed-income-structured: CLOs and structured credit products
- alternatives: private credit as an alternative investment
- asset-allocation: credit allocation in multi-asset portfolios
Running the Script
uv run scripts/fixed_income_corporate.py # run the demo (uses PEP 723 inline deps)
uv run scripts/fixed_income_corporate.py --verify # check demo outputs against the worked examples (exit 1 on mismatch)
python3 scripts/fixed_income_corporate.py # alternative (requires: pip install numpy scipy)The demo prints the calculations covered above; its values match the worked examples in this skill. Run --help for a list of the classes and functions. For programmatic use, import the module rather than running it — the demo only executes under python fixed_income_corporate.py.
# /// script
# dependencies = ["numpy", "scipy"]
# requires-python = ">=3.11"
# ///
"""
Fixed Income — Corporate
=========================
Credit spread calculation (G-spread, Z-spread, OAS approximation), expected
loss from default probability and recovery rate, and credit migration
probability analysis.
Part of Layer 2 (Asset Classes) in the finance skills framework.
"""
import argparse
import sys
import numpy as np
from scipy.optimize import brentq
class CreditSpread:
"""Compute credit spread measures for a corporate bond.
All spread calculations require the bond's cash flows, market price,
and a risk-free yield curve (spot rates).
Parameters
----------
cash_flows : np.ndarray
Array of cash flows (coupon + principal at maturity).
cash_flow_times : np.ndarray
Array of times (in years) corresponding to each cash flow.
market_price : float
Observed market price of the corporate bond.
spot_rates : np.ndarray
Risk-free spot (zero-coupon) rates for each cash flow time,
as annual decimals.
"""
def __init__(
self,
cash_flows: np.ndarray,
cash_flow_times: np.ndarray,
market_price: float,
spot_rates: np.ndarray,
):
self.cash_flows = np.asarray(cash_flows, dtype=np.float64)
self.cash_flow_times = np.asarray(cash_flow_times, dtype=np.float64)
self.market_price = market_price
self.spot_rates = np.asarray(spot_rates, dtype=np.float64)
def risk_free_price(self) -> float:
"""Compute the price using the risk-free spot curve (no spread).
Returns
-------
float
Sum of cash flows discounted at the corresponding spot rates.
"""
discount = (1.0 + self.spot_rates) ** self.cash_flow_times
return float(np.sum(self.cash_flows / discount))
def g_spread(self, bond_ytm: float, treasury_ytm: float) -> float:
"""Compute the G-spread (Government spread).
Parameters
----------
bond_ytm : float
Yield to maturity of the corporate bond (annual, decimal).
treasury_ytm : float
Interpolated Treasury yield at the same maturity (annual, decimal).
Returns
-------
float
G-spread = bond_ytm - treasury_ytm, in decimal.
"""
return float(bond_ytm - treasury_ytm)
def z_spread(self, tol: float = 1e-10) -> float:
"""Compute the Z-spread (zero-volatility spread).
The constant spread added to each risk-free spot rate such that
the discounted cash flows equal the market price.
Parameters
----------
tol : float, optional
Convergence tolerance. Default is 1e-10.
Returns
-------
float
Z-spread as an annual decimal.
"""
def objective(spread: float) -> float:
discount = (1.0 + self.spot_rates + spread) ** self.cash_flow_times
pv = np.sum(self.cash_flows / discount)
return pv - self.market_price
lo, hi = -0.05, 1.0
try:
return float(brentq(objective, lo, hi, xtol=tol))
except ValueError as exc:
raise ValueError(
f"Z-spread root not bracketed in [{lo:.0%}, {hi:.0%}]: the "
f"market price ({self.market_price}) is inconsistent with the "
"cash flows and spot curve (PV at the bracket endpoints does "
"not straddle the price). Check that cash flows, times, spot "
"rates, and price are on consistent scales."
) from exc
def oas(self, z_spread: float, option_cost: float) -> float:
"""Compute the Option-Adjusted Spread.
Parameters
----------
z_spread : float
Z-spread of the bond (annual, decimal).
option_cost : float
Value of the embedded option in spread terms (annual, decimal).
Positive for callable bonds (issuer benefits from the option).
Returns
-------
float
OAS = Z-spread - option_cost
"""
return float(z_spread - option_cost)
def summary(self, bond_ytm: float, treasury_ytm: float,
option_cost: float = 0.0) -> dict:
"""Compute all spread measures.
Parameters
----------
bond_ytm : float
YTM of the corporate bond.
treasury_ytm : float
Interpolated Treasury YTM for the same maturity.
option_cost : float, optional
Embedded option cost in spread terms. Default 0.0 (bullet bond).
Returns
-------
dict
Dictionary of spread measures.
"""
z_spd = self.z_spread()
return {
"g_spread": self.g_spread(bond_ytm, treasury_ytm),
"z_spread": z_spd,
"oas": self.oas(z_spd, option_cost),
"risk_free_price": self.risk_free_price(),
"market_price": self.market_price,
}
class CreditRisk:
"""Expected loss and default probability analysis.
Provides static methods for credit loss calculations.
"""
@staticmethod
def expected_loss(
probability_of_default: float,
loss_given_default: float,
exposure_at_default: float,
) -> float:
"""Compute expected credit loss.
Parameters
----------
probability_of_default : float
PD as a decimal (e.g., 0.02 = 2%).
loss_given_default : float
LGD as a decimal (e.g., 0.60 = 60%).
exposure_at_default : float
EAD in dollar terms.
Returns
-------
float
EL = PD * LGD * EAD
"""
return float(probability_of_default * loss_given_default * exposure_at_default)
@staticmethod
def recovery_rate(loss_given_default: float) -> float:
"""Compute recovery rate from LGD.
Parameters
----------
loss_given_default : float
LGD as a decimal.
Returns
-------
float
RR = 1 - LGD
"""
return float(1.0 - loss_given_default)
@staticmethod
def implied_default_probability(
credit_spread: float,
loss_given_default: float,
) -> float:
"""Estimate market-implied default probability from spread and LGD.
Uses the simple approximation: spread ~ PD * LGD.
Parameters
----------
credit_spread : float
Credit spread as a decimal (e.g., 0.015 = 150bp).
loss_given_default : float
LGD as a decimal.
Returns
-------
float
Implied PD = spread / LGD.
"""
if loss_given_default == 0:
raise ValueError("LGD cannot be zero for implied PD calculation.")
return float(credit_spread / loss_given_default)
@staticmethod
def cumulative_default_probability(
annual_pd: float,
years: int,
) -> float:
"""Compute cumulative default probability over multiple years.
Assumes constant annual PD and independence across years.
Parameters
----------
annual_pd : float
Annual probability of default as a decimal.
years : int
Number of years.
Returns
-------
float
Cumulative PD = 1 - (1 - annual_pd)^years
"""
return float(1.0 - (1.0 - annual_pd) ** years)
@staticmethod
def yield_to_worst(
ytm: float,
ytc_values: list[float],
) -> float:
"""Compute yield-to-worst.
Parameters
----------
ytm : float
Yield to maturity.
ytc_values : list[float]
List of yield-to-call values for each call date.
Returns
-------
float
min(YTM, YTC_1, YTC_2, ...)
"""
all_yields = [ytm] + list(ytc_values)
return float(min(all_yields))
class MigrationMatrix:
"""Credit rating transition (migration) matrix analysis.
Parameters
----------
matrix : np.ndarray
Square transition matrix where element (i,j) is the probability
of migrating from rating i to rating j over one period.
Rows must sum to 1.0. The last column represents default.
rating_labels : list[str]
Labels for each rating state (e.g., ['AAA', 'AA', ..., 'D']).
"""
def __init__(
self,
matrix: np.ndarray,
rating_labels: list[str],
):
self.matrix = np.asarray(matrix, dtype=np.float64)
self.rating_labels = rating_labels
if self.matrix.shape[0] != self.matrix.shape[1]:
raise ValueError("Transition matrix must be square.")
if len(rating_labels) != self.matrix.shape[0]:
raise ValueError("Number of labels must match matrix dimension.")
def transition_probability(self, from_rating: str, to_rating: str) -> float:
"""Look up the 1-period transition probability.
Parameters
----------
from_rating : str
Starting rating label.
to_rating : str
Ending rating label.
Returns
-------
float
Probability of transitioning from from_rating to to_rating.
"""
i = self.rating_labels.index(from_rating)
j = self.rating_labels.index(to_rating)
return float(self.matrix[i, j])
def multi_period_matrix(self, periods: int) -> np.ndarray:
"""Compute the multi-period transition matrix via matrix exponentiation.
Parameters
----------
periods : int
Number of periods.
Returns
-------
np.ndarray
M^periods, the cumulative transition matrix.
"""
result = np.linalg.matrix_power(self.matrix, periods)
return result
def upgrade_probability(self, rating: str) -> float:
"""Probability of any upgrade from the given rating.
Parameters
----------
rating : str
Current rating label.
Returns
-------
float
Sum of probabilities of moving to any higher-rated state.
"""
idx = self.rating_labels.index(rating)
# Ratings are ordered from highest to lowest; upgrade = move left
return float(np.sum(self.matrix[idx, :idx]))
def downgrade_probability(self, rating: str) -> float:
"""Probability of any downgrade from the given rating.
Parameters
----------
rating : str
Current rating label.
Returns
-------
float
Sum of probabilities of moving to any lower-rated state.
"""
idx = self.rating_labels.index(rating)
# Downgrade = move right (excluding the stay-in-place diagonal)
return float(np.sum(self.matrix[idx, idx + 1:]))
def default_probability(self, rating: str) -> float:
"""Probability of defaulting from the given rating (1-period).
Parameters
----------
rating : str
Current rating label.
Returns
-------
float
Probability of transitioning to the default state (last column).
"""
idx = self.rating_labels.index(rating)
return float(self.matrix[idx, -1])
def _demo() -> None:
# ----------------------------------------------------------------
# Demo: Corporate bond credit analysis
# ----------------------------------------------------------------
print("=" * 60)
print("Fixed Income Corporate — Demo")
print("=" * 60)
# ----- Z-spread and G-spread -----
print("\n--- Credit Spread Analysis ---")
# 7-year corporate bond, semi-annual coupons
face = 1000.0
coupon_rate = 0.058 # 5.8% coupon
n_periods = 14 # 7 years, semi-annual
coupon = face * coupon_rate / 2.0
cash_flows = np.full(n_periods, coupon)
cash_flows[-1] += face
times = np.arange(1, n_periods + 1) * 0.5 # 0.5, 1.0, ..., 7.0
# Upward-sloping spot curve
spot_rates = np.array([
0.040, 0.041, 0.042, 0.043, 0.044, 0.045, 0.046,
0.047, 0.048, 0.049, 0.050, 0.051, 0.052, 0.053,
])
market_price = 985.0 # trading below par
spreads = CreditSpread(
cash_flows=cash_flows,
cash_flow_times=times,
market_price=market_price,
spot_rates=spot_rates,
)
bond_ytm = 0.058
treasury_ytm = 0.045
g_spd = spreads.g_spread(bond_ytm, treasury_ytm)
z_spd = spreads.z_spread()
print(f"\n 7-Year Corporate Bond (5.8% coupon, price = ${market_price:.2f}):")
print(f" G-spread: {g_spd*10000:.1f} bp")
print(f" Z-spread: {z_spd*10000:.1f} bp")
print(f" Risk-free price: ${spreads.risk_free_price():.2f}")
# OAS for a callable bond
option_cost = 0.0015 # 15bp option cost
oas_value = spreads.oas(z_spd, option_cost)
print(f" OAS (15bp option): {oas_value*10000:.1f} bp")
# ----- Expected Loss -----
print("\n--- Expected Loss Calculation ---")
pd = 0.02 # 2% annual PD
lgd = 0.60 # 60% LGD
ead = 1_000_000.0
el = CreditRisk.expected_loss(pd, lgd, ead)
rr = CreditRisk.recovery_rate(lgd)
print(f"\n PD = {pd*100:.1f}%, LGD = {lgd*100:.0f}%, EAD = ${ead:,.0f}")
print(f" Expected Loss: ${el:,.0f}")
print(f" Recovery Rate: {rr*100:.0f}%")
print(f" EL as % of EAD: {el/ead*100:.2f}%")
# Implied PD from spread
spread_for_impl = 0.015 # 150bp
implied_pd = CreditRisk.implied_default_probability(spread_for_impl, lgd)
print(f"\n Implied PD from 150bp spread (LGD=60%): {implied_pd*100:.2f}%")
# Cumulative PD
for years in [1, 3, 5, 10]:
cum_pd = CreditRisk.cumulative_default_probability(pd, years)
print(f" Cumulative PD ({years:2d}yr): {cum_pd*100:.2f}%")
# Yield-to-worst
ytw = CreditRisk.yield_to_worst(
ytm=0.058,
ytc_values=[0.055, 0.052, 0.057],
)
print(f"\n YTM = 5.80%, YTCs = [5.50%, 5.20%, 5.70%]")
print(f" Yield-to-Worst: {ytw*100:.2f}%")
# ----- Migration Matrix -----
print("\n--- Credit Migration Matrix ---")
labels = ["AAA", "AA", "A", "BBB", "BB", "B", "CCC", "D"]
# Simplified 1-year transition matrix (illustrative, not empirical)
migration = np.array([
[0.9080, 0.0830, 0.0060, 0.0012, 0.0006, 0.0002, 0.0000, 0.0010],
[0.0070, 0.9070, 0.0740, 0.0060, 0.0014, 0.0011, 0.0002, 0.0033],
[0.0009, 0.0227, 0.9105, 0.0552, 0.0074, 0.0026, 0.0001, 0.0006],
[0.0002, 0.0033, 0.0595, 0.8693, 0.0530, 0.0117, 0.0012, 0.0018],
[0.0003, 0.0014, 0.0067, 0.0773, 0.8053, 0.0884, 0.0100, 0.0106],
[0.0000, 0.0011, 0.0024, 0.0043, 0.0648, 0.8346, 0.0407, 0.0521],
[0.0022, 0.0000, 0.0022, 0.0130, 0.0238, 0.1124, 0.6486, 0.1978],
[0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 1.0000],
])
mm = MigrationMatrix(matrix=migration, rating_labels=labels)
for rating in ["AAA", "A", "BBB", "BB", "B"]:
stay = mm.transition_probability(rating, rating)
upgrade = mm.upgrade_probability(rating)
downgrade = mm.downgrade_probability(rating)
default = mm.default_probability(rating)
print(f"\n {rating}:")
print(f" Stay: {stay*100:.2f}%")
print(f" Upgrade: {upgrade*100:.2f}%")
print(f" Downgrade: {downgrade*100:.2f}%")
print(f" Default: {default*100:.2f}%")
# Multi-period (5-year cumulative)
m5 = mm.multi_period_matrix(5)
bbb_idx = labels.index("BBB")
print(f"\n BBB 5-year cumulative default probability: {m5[bbb_idx, -1]*100:.2f}%")
print("\n" + "=" * 60)
print("Demo complete.")
print("=" * 60)
def _check(failures: list, name: str, actual: float, expected: float, tol: float) -> None:
"""Record a verification check result."""
ok = abs(actual - expected) <= tol
status = "PASS" if ok else "FAIL"
print(f" [{status}] {name}: actual={actual:.6g}, expected={expected:.6g}, tol={tol:.2g}")
if not ok:
failures.append(name)
def _verify() -> None:
"""Verify key outputs against the SKILL.md worked examples."""
failures: list = []
# SKILL.md Example 1: G-spread = 5.8% - 4.5% = 130bp
cash_flows = np.full(14, 29.0)
cash_flows[-1] += 1000.0
times = np.arange(1, 15) * 0.5
spot_rates = np.array([0.040, 0.041, 0.042, 0.043, 0.044, 0.045, 0.046,
0.047, 0.048, 0.049, 0.050, 0.051, 0.052, 0.053])
spreads = CreditSpread(cash_flows, times, market_price=985.0, spot_rates=spot_rates)
_check(failures, "Ex1 G-spread", spreads.g_spread(0.058, 0.045), 0.013, 1e-12)
# Z-spread round trip: price the bond with a known 118bp spread, then recover it
known_spread = 0.0118
price = float(np.sum(cash_flows / (1.0 + spot_rates + known_spread) ** times))
roundtrip = CreditSpread(cash_flows, times, market_price=price, spot_rates=spot_rates)
_check(failures, "Z-spread round trip (118bp)", roundtrip.z_spread(), known_spread, 1e-8)
# SKILL.md Example 2: expected loss
_check(failures, "Ex2 expected loss", CreditRisk.expected_loss(0.02, 0.60, 1_000_000), 12000.0, 1e-9)
_check(failures, "recovery rate (LGD 60%)", CreditRisk.recovery_rate(0.60), 0.40, 1e-12)
_check(failures, "yield-to-worst", CreditRisk.yield_to_worst(0.058, [0.055, 0.052, 0.057]), 0.052, 1e-12)
if failures:
print(f"\n{len(failures)} check(s) FAILED: {', '.join(failures)}")
sys.exit(1)
print("\nAll checks passed.")
def main() -> None:
parser = argparse.ArgumentParser(
description=__doc__.strip().splitlines()[2] if __doc__ else "",
epilog=(
"Provides: CreditSpread, CreditRisk, MigrationMatrix. "
"For programmatic use, import this module (fixed_income_corporate) instead of running it. "
"Bare run executes a demo whose printed values match the SKILL.md worked examples; "
"--verify asserts those values and exits nonzero on mismatch."
),
)
parser.add_argument(
"--verify",
action="store_true",
help="run the verification checks against the SKILL.md worked-example values",
)
args = parser.parse_args()
if args.verify:
_verify()
else:
_demo()
if __name__ == "__main__":
main()
Related skills
How it compares
Pick fixed-income-corporate over fixed-income-sovereign when modeling credit spreads, default risk, and covenant structures rather than Treasury benchmark curves.
FAQ
What spread measures does fixed-income-corporate cover?
fixed-income-corporate covers G-spread (yield minus Treasury), Z-spread (constant spread over spot curve), and OAS (option-adjusted spread for callable bonds). OAS is required for bonds with embedded call options.
Does fixed-income-corporate include a Python calculation script?
fixed-income-corporate bundles fixed_income_corporate.py requiring numpy and scipy, with a --verify flag checking demo outputs against worked G-spread and expected loss examples.