use crate::currency::Currency;
use crate::errors::QlResult;
use crate::handle::Handle;
use crate::indexes::ibor::custom::CustomIborIndex;
use crate::indexes::ibor::libor::{libor_convention, libor_eom};
use crate::indexes::interestrateindex::InterestRateIndex;
use crate::require;
use crate::settings::Settings;
use crate::shared::Shared;
use crate::termstructures::yieldtermstructure::YieldTermStructure;
use crate::time::calendars::jointcalendar::{JointCalendar, JointCalendarRule};
use crate::time::calendars::target::Target;
use crate::time::calendars::unitedkingdom::{Market as UkMarket, UnitedKingdom};
use crate::time::date::Date;
use crate::time::daycounters::actual360::Actual360;
use crate::time::period::Period;
use crate::time::timeunit::TimeUnit;
pub struct EurLibor;
impl EurLibor {
#[allow(clippy::new_ret_no_self)]
pub fn new(
tenor: Period,
forwarding: Handle<dyn YieldTermStructure>,
settings: Shared<Settings<Date>>,
) -> QlResult<CustomIborIndex> {
let index = CustomIborIndex::new(
"EURLibor".into(),
tenor,
2,
Currency::eur(),
JointCalendar::of_two(
UnitedKingdom::new(UkMarket::Exchange),
Target::new(),
JointCalendarRule::JoinHolidays,
),
Target::new(),
Target::new(),
libor_convention(tenor)?,
libor_eom(tenor)?,
Actual360::new(),
forwarding,
settings,
);
require!(
index.tenor().units() != TimeUnit::Days,
"for daily tenors ({}) dedicated DailyTenor constructor must be used",
index.tenor()
);
Ok(index)
}
pub fn one_month(
forwarding: Handle<dyn YieldTermStructure>,
settings: Shared<Settings<Date>>,
) -> CustomIborIndex {
Self::named(Period::new(1, TimeUnit::Months), forwarding, settings)
}
pub fn three_months(
forwarding: Handle<dyn YieldTermStructure>,
settings: Shared<Settings<Date>>,
) -> CustomIborIndex {
Self::named(Period::new(3, TimeUnit::Months), forwarding, settings)
}
pub fn six_months(
forwarding: Handle<dyn YieldTermStructure>,
settings: Shared<Settings<Date>>,
) -> CustomIborIndex {
Self::named(Period::new(6, TimeUnit::Months), forwarding, settings)
}
pub fn one_year(
forwarding: Handle<dyn YieldTermStructure>,
settings: Shared<Settings<Date>>,
) -> CustomIborIndex {
Self::named(Period::new(1, TimeUnit::Years), forwarding, settings)
}
fn named(
tenor: Period,
forwarding: Handle<dyn YieldTermStructure>,
settings: Shared<Settings<Date>>,
) -> CustomIborIndex {
Self::new(tenor, forwarding, settings)
.expect("a month or year EUR Libor tenor is always valid")
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::indexes::index::Index;
use crate::shared::shared;
use crate::time::businessdayconvention::BusinessDayConvention;
use crate::time::date::Month;
fn eur_libor_3m(settings: Shared<Settings<Date>>) -> CustomIborIndex {
EurLibor::three_months(Handle::empty(), settings)
}
#[test]
fn eur_libor_carries_the_ice_configuration() {
let index = eur_libor_3m(shared(Settings::<Date>::new()));
assert_eq!(index.name(), "EURLibor3M Actual/360");
assert_eq!(index.fixing_days(), 2);
assert_eq!(index.currency(), &Currency::eur());
assert_eq!(index.day_counter().name(), "Actual/360");
assert_eq!(
index.fixing_calendar().name(),
"JoinHolidays(London stock exchange, TARGET)"
);
assert_eq!(index.value_calendar().name(), "TARGET");
assert_eq!(index.maturity_calendar().name(), "TARGET");
assert_eq!(
index.business_day_convention(),
BusinessDayConvention::ModifiedFollowing
);
assert!(index.end_of_month());
}
#[test]
fn daily_tenor_is_rejected() {
let err = EurLibor::new(
Period::new(3, TimeUnit::Days),
Handle::empty(),
shared(Settings::<Date>::new()),
)
.err()
.expect("daily tenors must be rejected");
assert!(err.to_string().contains("dedicated DailyTenor constructor"));
}
#[test]
fn fixing_dates_reject_uk_holidays_open_on_target() {
let index = eur_libor_3m(shared(Settings::<Date>::new()));
let uk_holiday = Date::new(30, Month::August, 2021);
assert!(Target::new().is_business_day(uk_holiday));
assert!(!index.is_valid_fixing_date(uk_holiday));
}
#[test]
fn value_date_advances_on_target_not_the_joint_calendar() {
let index = eur_libor_3m(shared(Settings::<Date>::new()));
assert_eq!(
index
.value_date(Date::new(26, Month::August, 2021))
.unwrap(),
Date::new(30, Month::August, 2021)
);
}
#[test]
fn maturity_date_advances_on_target_not_the_joint_calendar() {
let index = eur_libor_3m(shared(Settings::<Date>::new()));
assert_eq!(
index
.maturity_date(Date::new(1, Month::February, 2021))
.unwrap(),
Date::new(3, Month::May, 2021)
);
}
#[test]
fn fixing_date_round_trips_the_value_date() {
let index = eur_libor_3m(shared(Settings::<Date>::new()));
let fixing = Date::new(26, Month::August, 2021);
let value = index.value_date(fixing).unwrap();
assert_eq!(index.fixing_date(value), fixing);
}
}