固收 Z Spread 与 Oas
Fi Z Spread Vs Oas
题目详情
分析某 5 年期可赎回债券。当前收益率曲线向上倾斜。此可赎回债券的 Option-Adjusted Spread(OAS)与 Z-spread 通常有何差异?原因是什么?
任务:Z-spread 是包含嵌入期权价值的总利差;OAS 是剔除嵌入期权价值后的利差。对可赎回债券:Z-spread > OAS,因为 Z-spread 包含了赎回期权对投资者的不利价值(投资者卖出期权)。OAS = Z-spread - 期权价值利差。
英文原题
You are analyzing a 5-year callable bond. The current yield curve is upward sloping. How does the Option-Adjusted Spread (OAS) typically differ from the Z-spread for this callable bond, and why?
解析
问题分析
Z-spread(零波动率利差)是在基准收益率曲线上平行移动的固定利差,使债券现金流折现值等于市场价格。OAS(期权调整利差)进一步考虑了嵌入式期权的价值。两者之差反映了期权成本。
实现
class BondPricer {
std::vector<double> spot_rates_; // 各期限即期利率
public:
double zSpread(const std::vector<double>& cashflows,
const std::vector<double>& times, double price) {
auto pv = [&] (\1) {
double sum = 0;
for (size_t i = 0; i < cashflows.size(); ++i)
sum += cashflows[i] / std::pow(1 + spot_rates_[i] + spread, times[i]);
return sum;
};
double lo = -0.10, hi = 0.50; // [-10%, 50%]
for (int iter = 0; iter < 50; ++iter) {
double mid = (lo + hi) / 2;
if (pv(mid) > price) lo = mid; else hi = mid;
}
return (lo + hi) / 2;
}
};复杂度与边界
- 时间复杂度:O(N * 迭代次数),N 为现金流数
- 空间复杂度:O(N)
- 边界条件:(1) 价格<=0 无解 (2) 利差范围可能需扩展 (3) 负利差是合法的(债券优于基准)
英文解析
Analysis
The Z-spread (zero-volatility spread) is a constant spread added to each point on the benchmark spot curve such that the bond's discounted cash flows equal its market price. The OAS (Option-Adjusted Spread) additionally accounts for the value of embedded options by simulating interest rate paths and averaging the spread across all scenarios.
For a callable bond: Z-spread = OAS + option cost. The option cost represents the value of the call option held by the issuer. Since the call option reduces the bond's value, Z-spread > OAS for callable bonds.
Solution
class BondPricer {
std::vector<double> spot_rates_; // spot rates by maturity
public:
double zSpread(const std::vector<double>& cashflows,
const std::vector<double>& times, double price) {
auto pv = [&] (double spread) {
double sum = 0;
for (size_t i = 0; i < cashflows.size(); ++i)
sum += cashflows[i] / std::pow(1 + spot_rates_[i] + spread, times[i]);
return sum;
};
double lo = -0.10, hi = 0.50;
for (int iter = 0; iter < 50; ++iter) {
double mid = (lo + hi) / 2;
if (pv(mid) > price) lo = mid; else hi = mid;
}
return (lo + hi) / 2;
}
double oas(const std::vector<double>& cashflows,
const std::vector<double>& times, double price,
int num_paths, double vol, double callPrice) {
// Monte Carlo: simulate rate paths, compute average PV at each trial spread
double best_oas = 0;
for (double spread = -0.05; spread < 0.20; spread += 0.001) {
double avg_pv = 0;
for (int p = 0; p < num_paths; ++p) {
double path_pv = 0;
// simulate rate path with vol, apply call decision each period
avg_pv += path_pv;
}
avg_pv /= num_paths;
if (std::abs(avg_pv - price) < 0.01) { best_oas = spread; break; }
}
return best_oas;
}
};Relationship: Z-spread = OAS + Option Cost (for callable bonds)
Complexity & Edge Cases
- Time complexity: O(N * iterations) for Z-spread binary search; O(N * paths * iterations) for OAS
- Space complexity: O(N) for Z-spread; O(N * paths) for OAS
- Edge cases: (1) Price <= 0 yields no valid spread. (2) Spread range may need expansion for distressed bonds. (3) Negative spreads are valid (bond outperforms benchmark). (4) Non-callable bonds: Z-spread = OAS (option cost = 0).
Verification
5-year callable bond, upward-sloping curve, Z-spread = 150bps:
- If option cost = 50bps then OAS = 100bps
- If rates drop then call probability rises then option cost increases then Z-spread widens relative to OAS
- For a non-callable bond: Z-spread = OAS = 150bps
Key Considerations
- OAS is the fair comparison metric for bonds with different embedded option structures
- Z-spread overstates the "true" spread for callable/putable bonds because it ignores option risk
- Option cost varies with rate levels: when rates are near call threshold, option cost is highest
- OAS calculation requires an interest rate model (Hull-White, Black-Karasinski) and Monte Carlo simulation