AgentSkillsCN

convex-yield-conventions

为Convex定价库实现债券收益率约定。在以下场景中使用此功能: (1) 实现收益率计算方法(复利、简单、贴现、附加) (2) 添加按顺序滚动向前的资金市场收益率计算 (3) 实现182天阈值的债券等价收益率(BEY) (4) 创建债券生成与验证的市场预设 (5) 实现复利频率的转换 (6) 扩展债券定价,以支持全球市场惯例

SKILL.md
--- frontmatter
name: convex-yield-conventions
description: |
  Bond yield convention implementation for the Convex pricing library. Use this skill when:
  (1) Implementing yield calculation methods (compounded, simple, discount, add-on)
  (2) Adding money market yield calculations with sequential roll-forward
  (3) Implementing Bond Equivalent Yield (BEY) with 182-day threshold
  (4) Creating market presets for bond creation and validation
  (5) Implementing compounding frequency conversions
  (6) Extending bond pricing to support global market conventions

Convex Yield Conventions Skill

Extends the Convex bond pricing library with generic yield conventions.

Core Principle: Separation of Concerns

code
Bond           → Owns: day_count, frequency, settlement rules
YieldMethod    → Controls: how to calculate yield from price
MarketPreset   → Provides: defaults for bond creation, validation

The bond is the source of truth for its conventions. YieldConvention does NOT override the bond's day count or frequency.

Architecture

code
convex-core/src/
├── types/
│   └── yield_method.rs      # YieldMethod enum only
└── compounding/
    ├── frequency.rs         # CompoundingFrequency enum
    └── converter.rs         # Rate conversion utilities

convex-bonds/src/
├── traits.rs                # Bond trait (owns day_count, frequency)
├── instruments/
│   └── fixed.rs             # FixedRateBond with conventions
└── pricing/
    └── yield_calculator.rs  # Uses bond's conventions

convex-yas/src/
└── presets.rs               # MarketPreset for validation/defaults

Core Types

YieldMethod (calculation approach only)

rust
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum YieldMethod {
    /// Newton-Raphson: Price = Σ CF/(1+y/f)^(f×t)
    Compounded,
    /// y = (Coupon + (Redemption-Price)/Years) / Price
    Simple,
    /// y = (Face-Price)/Face × (Basis/Days) - T-Bills
    Discount,
    /// y = (Face-Price)/Price × (Basis/Days) - Money market
    AddOn,
}

YieldCalculatorConfig (minimal)

rust
pub struct YieldCalculatorConfig {
    /// Primary calculation method
    pub method: YieldMethod,
    /// Days threshold for money market switch (typically 182)
    pub money_market_threshold: Option<u32>,
    /// Solver tolerance (default: 1e-10)
    pub tolerance: f64,
}

Bond Trait (owns conventions)

rust
pub trait Bond {
    fn day_count(&self) -> &dyn DayCount;
    fn coupon_frequency(&self) -> Frequency;
    fn coupon_rate(&self) -> Decimal;
    fn maturity(&self) -> Date;
    fn face_value(&self) -> Decimal;
    fn cash_flows_from(&self, settlement: Date) -> Vec<CashFlow>;
    fn accrued_interest(&self, settlement: Date) -> Decimal;
}

MarketPreset (for creation & validation)

rust
pub struct MarketPreset {
    pub name: &'static str,
    pub day_count: DayCountConvention,
    pub frequency: Frequency,
    pub settlement_days: u32,
    pub yield_method: YieldMethod,
    pub money_market_threshold: Option<u32>,
}

impl MarketPreset {
    /// Validate bond matches this market's conventions
    pub fn validate<B: Bond>(&self, bond: &B) -> Result<(), ConventionMismatch>;
    
    /// Get yield calculator config for this market
    pub fn yield_config(&self) -> YieldCalculatorConfig;
}

Market Presets

PresetDay CountFrequencySettleMM Threshold
US_TREASURYACT/ACT ICMASemiT+1182
US_CORPORATE30/360 USSemiT+2182
US_TBILLACT/360-T+1-
UK_GILTACT/ACT ICMASemiT+1-
GERMAN_BUNDACT/ACT ICMAAnnualT+2-
JAPANESE_JGBACT/365FSemiT+2-

Yield Calculator Flow

rust
impl YieldCalculator {
    pub fn yield_from_price<B: Bond>(
        &self,
        bond: &B,
        settlement: Date,
        price: CleanPrice,
    ) -> Result<Yield, YieldError> {
        // 1. Get conventions FROM THE BOND
        let day_count = bond.day_count();
        let frequency = bond.coupon_frequency();
        
        // 2. Determine method (config only controls this)
        let days_to_mat = (bond.maturity() - settlement).num_days() as u32;
        let method = self.effective_method(days_to_mat);
        
        // 3. Calculate using bond's conventions
        match method {
            YieldMethod::Compounded => {
                self.solve_compounded(bond, settlement, price, day_count, frequency)
            }
            YieldMethod::Simple => {
                self.calc_simple(bond, settlement, price, day_count)
            }
            YieldMethod::AddOn => {
                self.calc_money_market(bond, settlement, price, day_count)
            }
            // ...
        }
    }
}

Key Thresholds

182 days - Money market method switch for US markets 365 days - Money market threshold for Canadian markets

Sequential Roll-Forward (for short-dated coupon bonds)

code
C₁ = C × (1 + y × D₁/basis)
Cᵢ = (C + Cᵢ₋₁) × (1 + y × Dᵢ/basis)

Where basis comes from the bond's day count convention.

Reference Files

  • references/formulas.md - Mathematical formulas
  • references/market-conventions.md - Market specifications
  • references/test-cases.md - Bloomberg validation tests