use kestrel_chartkit::{
BondSpec, BusinessCalendar, BusinessDayConvention, Date, DayCountConvention, ScheduleStub,
};
fn iso(date: &Date) -> String {
format!("{:04}-{:02}-{:02}", date.year, date.month, date.day)
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let spec = BondSpec::new(
1_000.0,
0.05,
2,
Date::new(2026, 6, 15).unwrap(),
Date::new(2031, 6, 15).unwrap(),
DayCountConvention::Actual365Fixed,
);
let calendar = BusinessCalendar::weekends_only();
let bond = spec.build(&calendar)?;
let settlement = Date::new(2026, 9, 20).unwrap();
let priced = bond.price(settlement, 0.04)?;
println!("Kupontermine:");
for (accrual, payment) in bond
.schedule()
.accrual_dates()
.iter()
.skip(1)
.zip(bond.schedule().payment_dates())
{
println!(
" Abgrenzung bis {}, Zahlung am {}",
iso(accrual),
iso(payment)
);
}
println!();
println!("Settlement {} bei 4% Rendite:", iso(&settlement));
println!(" Dirty {:.4}", priced.dirty_price);
println!(" Clean {:.4}", priced.clean_price);
println!(" Stückzinsen {:.4}", priced.accrued_interest);
println!(" Modified Duration {:.4}", priced.modified_duration);
println!(" DV01 {:.4}", priced.dv01);
let adjusted = BondSpec::new(
1_000.0,
0.04,
2,
Date::new(2026, 4, 30).unwrap(),
Date::new(2026, 10, 31).unwrap(),
DayCountConvention::Actual365Fixed,
)
.with_stub(ScheduleStub::ShortFirst)
.with_business_day_convention(BusinessDayConvention::ModifiedFollowing)
.schedule(&calendar)?;
println!();
println!(
"Fälligkeit {} fällt auf einen Samstag, gezahlt wird am {}",
iso(adjusted.accrual_dates().last().unwrap()),
iso(adjusted.payment_dates().last().unwrap())
);
Ok(())
}