use core::qm;
use std::sync::Arc;
use instruments::RcInstrument;
use instruments::PricingContext;
use instruments::DependencyContext;
use risk::cache::PricingContextPrefetch;
use risk::Pricer;
use risk::PricerClone;
use risk::dependencies::DependencyCollector;
use risk::Bumpable;
use risk::TimeBumpable;
use risk::Saveable;
use risk::BumpablePricingContext;
use pricers::PricerFactory;
use data::fixings::RcFixingTable;
use data::bump::Bump;
use risk::bumptime::BumpTime;
use risk::marketdata::RcMarketData;
use risk::marketdata::MarketData;
use dates::datetime::DateTime;
use dates::datetime::TimeOfDay;
use core::factories::TypeId;
use core::factories::Qrc;
use serde::Deserialize;
use erased_serde as esd;
#[derive(Clone)]
pub struct SelfPricer {
instruments: Vec<(f64, RcInstrument)>,
context: PricingContextPrefetch
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct SelfPricerFactory {
}
impl SelfPricerFactory {
pub fn new() -> SelfPricerFactory {
SelfPricerFactory {}
}
pub fn from_serial<'de>(de: &mut esd::Deserializer<'de>) -> Result<Qrc<PricerFactory>, esd::Error> {
Ok(Qrc::new(Arc::new(SelfPricerFactory::deserialize(de)?)))
}
}
impl TypeId for SelfPricerFactory {
fn type_id(&self) -> &'static str { "SelfPricerFactory" }
}
impl PricerFactory for SelfPricerFactory {
fn new(&self, instrument: RcInstrument, fixing_table: RcFixingTable,
market_data: RcMarketData) -> Result<Box<Pricer>, qm::Error> {
let instruments = match instrument.fix(&*fixing_table)? {
Some(fixed) => fixed,
None => vec!((1.0, instrument))
};
let pricer = SelfPricer::new(instruments, &*market_data)?;
Ok(Box::new(pricer))
}
}
impl SelfPricer {
pub fn new(instruments: Vec<(f64, RcInstrument)>,
market_data: &MarketData) -> Result<SelfPricer, qm::Error> {
let mut dependencies = DependencyCollector::new(
market_data.spot_date());
for &(_, ref instr) in instruments.iter() {
dependencies.spot(instr);
if let None = instr.as_priceable() {
return Err(qm::Error::new(&format!("Instrument {} is not \
priceable", instr.id())))
}
}
let context = PricingContextPrefetch::new(&*market_data,
Arc::new(dependencies))?;
Ok(SelfPricer { instruments: instruments, context: context })
}
}
impl Pricer for SelfPricer {
fn as_bumpable(&self) -> &Bumpable { self }
fn as_mut_bumpable(&mut self) -> &mut Bumpable { self }
fn as_mut_time_bumpable(&mut self) -> &mut TimeBumpable { self }
fn price(&self) -> Result<f64, qm::Error> {
let val_date = DateTime::new(self.context.as_pricing_context().spot_date(), TimeOfDay::Open);
let mut total = 0.0;
for &(weight, ref instrument) in self.instruments.iter() {
if let Some(priceable) = instrument.as_priceable() {
total += weight * priceable.price(&self.context, val_date)?;
}
}
Ok(total)
}
}
impl PricerClone for SelfPricer {
fn clone_box(&self) -> Box<Pricer> { Box::new(self.clone()) }
}
impl Bumpable for SelfPricer {
fn bump(&mut self, bump: &Bump, save: Option<&mut Saveable>)
-> Result<bool, qm::Error> {
self.context.bump(bump, save)
}
fn dependencies(&self) -> Result<&DependencyCollector, qm::Error> {
self.context.dependencies()
}
fn context(&self) -> &PricingContext {
self.context.as_pricing_context()
}
fn new_saveable(&self) -> Box<Saveable> {
self.context.new_saveable()
}
fn restore(&mut self, saved: &Saveable) -> Result<(), qm::Error> {
self.context.restore(saved)
}
}
impl TimeBumpable for SelfPricer {
fn bump_time(&mut self, bump: &BumpTime) -> Result<(), qm::Error> {
if bump.apply(&mut self.instruments, &mut self.context)? {
*self = SelfPricer::new(self.instruments.clone(), self.context.raw_market_data())?
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::Arc;
use dates::Date;
use dates::datetime::DateTime;
use dates::datetime::TimeOfDay;
use math::numerics::approx_eq;
use data::bumpspot::BumpSpot;
use data::bumpdivs::BumpDivs;
use data::bumpvol::BumpVol;
use data::bumpyield::BumpYield;
use data::bumpspotdate::SpotDynamics;
use data::fixings::FixingTable;
use risk::marketdata::tests::sample_market_data;
use risk::marketdata::tests::sample_european;
use risk::marketdata::tests::sample_forward_european;
use pricers::RcPricerFactory;
use core::factories::Qrc;
use core::factories::tests::assert_debug_eq;
use serde_json;
fn sample_fixings() -> FixingTable {
let today = Date::from_ymd(2017, 01, 02);
FixingTable::from_fixings(today, &[
("BP.L", &[
(DateTime::new(today - 7, TimeOfDay::Close), 102.0)])]).unwrap()
}
#[test]
fn self_price_european_bumped_price() {
let market_data = RcMarketData::new(Arc::new(sample_market_data()));
let instrument = RcInstrument::new(Qrc::new(sample_european()));
let fixings = RcFixingTable::new(Arc::new(sample_fixings()));
let factory = SelfPricerFactory::new();
let mut pricer = factory.new(instrument, fixings, market_data).unwrap();
let mut save = pricer.as_bumpable().new_saveable();
let unbumped_price = pricer.price().unwrap();
assert_approx(unbumped_price, 16.710717400832973, 1e-12);
let bump = Bump::new_spot("BP.L", BumpSpot::new_relative(0.01));
let bumped = pricer.as_mut_bumpable().bump(&bump, Some(&mut *save)).unwrap();
assert!(bumped);
let bumped_price = pricer.price().unwrap();
assert_approx(bumped_price, 17.343905306334765, 1e-12);
pricer.as_mut_bumpable().restore(&*save).unwrap();
save.clear();
let price = pricer.price().unwrap();
assert_approx(price, unbumped_price, 1e-12);
let bump = Bump::new_vol("BP.L", BumpVol::new_flat_additive(0.01));
let bumped = pricer.as_mut_bumpable().bump(&bump, Some(&mut *save)).unwrap();
assert!(bumped);
let bumped_price = pricer.price().unwrap();
assert_approx(bumped_price, 17.13982242072566, 1e-12);
pricer.as_mut_bumpable().restore(&*save).unwrap();
save.clear();
let price = pricer.price().unwrap();
assert_approx(price, unbumped_price, 1e-12);
let bump = Bump::new_divs("BP.L", BumpDivs::new_all_relative(0.01));
let bumped = pricer.as_mut_bumpable().bump(&bump, Some(&mut *save)).unwrap();
assert!(bumped);
let bumped_price = pricer.price().unwrap();
assert_approx(bumped_price, 16.691032323609356, 1e-12);
pricer.as_mut_bumpable().restore(&*save).unwrap();
save.clear();
let price = pricer.price().unwrap();
assert_approx(price, unbumped_price, 1e-12);
let bump = Bump::new_yield("LSE", BumpYield::new_flat_annualised(0.01));
let bumped = pricer.as_mut_bumpable().bump(&bump, Some(&mut *save)).unwrap();
assert!(bumped);
let bumped_price = pricer.price().unwrap();
assert_approx(bumped_price, 17.299620299229513, 1e-12);
pricer.as_mut_bumpable().restore(&*save).unwrap();
save.clear();
let price = pricer.price().unwrap();
assert_approx(price, unbumped_price, 1e-12);
let bump = Bump::new_yield("OPT", BumpYield::new_flat_annualised(0.01));
let bumped = pricer.as_mut_bumpable().bump(&bump, Some(&mut *save)).unwrap();
assert!(bumped);
let bumped_price = pricer.price().unwrap();
assert_approx(bumped_price, 16.710717400832973, 1e-12);
pricer.as_mut_bumpable().restore(&*save).unwrap();
save.clear();
let price = pricer.price().unwrap();
assert_approx(price, unbumped_price, 1e-12);
}
#[test]
fn self_price_forward_european_time_bumped() {
let market_data = RcMarketData::new(Arc::new(sample_market_data()));
let instrument = RcInstrument::new(Qrc::new(sample_forward_european()));
let fixings = RcFixingTable::new(Arc::new(sample_fixings()));
let factory = SelfPricerFactory::new();
let mut pricer = factory.new(instrument, fixings, market_data).unwrap();
let unbumped_price = pricer.price().unwrap();
assert_approx(unbumped_price, 19.059001770739144, 1e-12);
let mut save = pricer.as_bumpable().new_saveable();
let bump = Bump::new_spot("BP.L", BumpSpot::new_relative(0.01));
let bumped = pricer.as_mut_bumpable().bump(&bump, Some(&mut *save)).unwrap();
assert!(bumped);
let bumped_price = pricer.price().unwrap();
assert_approx(bumped_price - unbumped_price, 0.20514185426620202, 1e-12);
pricer.as_mut_bumpable().restore(&*save).unwrap();
save.clear();
let spot_date = Date::from_ymd(2017, 01, 02);
let dynamics = SpotDynamics::StickyForward;
let time_bump = BumpTime::new(spot_date + 1, spot_date, dynamics);
pricer.as_mut_time_bumpable().bump_time(&time_bump).unwrap();
let bumped_price = pricer.price().unwrap();
assert_approx(bumped_price - unbumped_price, 0.0005682000045936775, 1e-12);
let bumped = pricer.as_mut_bumpable().bump(&bump, Some(&mut *save)).unwrap();
assert!(bumped);
let delta_bumped_price = pricer.price().unwrap();
assert_approx(delta_bumped_price - bumped_price, 0.6826928935788708, 1e-12);
pricer.as_mut_bumpable().restore(&*save).unwrap();
save.clear();
let expiry_date = Date::from_ymd(2018, 06, 01);
let time_bump = BumpTime::new(expiry_date - 1, spot_date, dynamics);
pricer.as_mut_time_bumpable().bump_time(&time_bump).unwrap();
let bumped_price = pricer.price().unwrap();
assert_approx(bumped_price, 12.21692599938127, 1e-12);
let time_bump = BumpTime::new(expiry_date, spot_date, dynamics);
pricer.as_mut_time_bumpable().bump_time(&time_bump).unwrap();
let bumped_price = pricer.price().unwrap();
assert_approx(bumped_price, 12.219583564604477, 1e-12);
let time_bump = BumpTime::new(expiry_date, spot_date, dynamics);
pricer.as_mut_time_bumpable().bump_time(&time_bump).unwrap();
let bumped_price = pricer.price().unwrap();
assert_approx(bumped_price, 12.219583564604477, 1e-12);
}
#[test]
fn serde_self_pricer_roundtrip() {
let factory = RcPricerFactory::new(Arc::new(SelfPricerFactory::new()));
let serialized = serde_json::to_string_pretty(&factory).unwrap();
print!("serialized: {}\n", serialized);
let deserialized: RcPricerFactory = serde_json::from_str(&serialized).unwrap();
assert_debug_eq(&factory, &deserialized);
}
fn assert_approx(value: f64, expected: f64, tolerance: f64) {
assert!(approx_eq(value, expected, tolerance),
"value={} expected={}", value, expected);
}
}