diff --git a/Cargo.toml b/Cargo.toml index d7cf1984..8669811f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,8 +62,8 @@ argmin-math = "0.4.0" # https://docs.rs/argmin-math/latest/argmin_math/ derive_builder = "0.20.0" # https://docs.rs/derive_builder/latest/derive_builder/ errorfunctions = "0.2.0" # https://docs.rs/errorfunctions/latest/errorfunctions/ nalgebra = "0.33.0" # https://docs.rs/nalgebra/latest/nalgebra/ -ndrustfft = "0.4.0" # https://docs.rs/ndrustfft/latest/ndrustfft/ -ndarray-rand = "0.14.0" # https://docs.rs/ndarray-rand/latest/ndarray_rand/ +ndrustfft = "0.5.0" # https://docs.rs/ndrustfft/latest/ndrustfft/ +ndarray-rand = "0.15.0" # https://docs.rs/ndarray-rand/latest/ndarray_rand/ plotly = "0.10.0" # https://docs.rs/plotly/latest/plotly/ plotters = "0.3.5" # https://docs.rs/plotters/latest/plotters/ rand = "0.8.5" # https://docs.rs/rand/latest/rand/ @@ -72,7 +72,7 @@ rayon = "1.9.0" # https://docs.rs/rayon/latest/rayon/ rust_decimal = "1.34.3" # https://docs.rs/rust_decimal/latest/rust_decimal/ statrs = "0.17.1" # https://docs.rs/statrs/latest/statrs/ thiserror = "1.0.57" # https://docs.rs/thiserror/latest/thiserror/ -yahoo_finance_api = "2.1.0" # https://docs.rs/yahoo-finance-api/latest/yahoo_finance_api/ +yahoo_finance_api = "2.3.0" # https://docs.rs/yahoo-finance-api/latest/yahoo_finance_api/ tokio-test = "0.4.3" # https://docs.rs/tokio-test/latest/tokio_test/ # https://docs.rs/ndarray/latest/ndarray/ @@ -90,6 +90,9 @@ polars = { version = "0.43.1", features = ["docs-selection"] } # https://docs.rs/uuid/latest/uuid/ uuid = { version = "1.10.0", features = ["v4", "fast-rng"] } +# https://docs.rs/serde/latest/hashbrown/ +# Remove when Polars is updated, since we don't use it directly. +hashbrown = { version = "=0.14.5", features = ["raw"] } [dev-dependencies] finitediff = "0.1.4" # https://docs.rs/finitediff/latest/finitediff/ diff --git a/examples/market_data.rs b/examples/market_data.rs index 3c6d4243..1ca8eb85 100644 --- a/examples/market_data.rs +++ b/examples/market_data.rs @@ -1,5 +1,4 @@ -use RustQuant::pricer::MarketData; -use RustQuant::pricer::MarketDataBuilder; +use RustQuant::data::{MarketData, MarketDataBuilder}; use RustQuant::time::oceania::australia::AustraliaCalendar; fn main() { diff --git a/examples/monte_carlo_pricing.rs b/examples/monte_carlo_pricing.rs index ea051609..616d4301 100644 --- a/examples/monte_carlo_pricing.rs +++ b/examples/monte_carlo_pricing.rs @@ -15,7 +15,7 @@ use RustQuant::instruments::options::AsianOption; use RustQuant::instruments::options::OptionContractBuilder; use RustQuant::instruments::BarrierOption; use RustQuant::models::geometric_brownian_motion::GeometricBrownianMotion; -use RustQuant::pricer::MonteCarloPricer; +use RustQuant::pricing::MonteCarloPricer; use RustQuant::stochastics::StochasticProcessConfig; fn main() { diff --git a/src/pricer/context_data.rs b/src/data/context_data.rs similarity index 100% rename from src/pricer/context_data.rs rename to src/data/context_data.rs diff --git a/src/pricer/market_data.rs b/src/data/market_data.rs similarity index 100% rename from src/pricer/market_data.rs rename to src/data/market_data.rs diff --git a/src/data/mod.rs b/src/data/mod.rs index 6f1c7bf1..9ddcebc6 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -120,6 +120,14 @@ pub use yahoo::*; pub mod curves; pub use curves::*; +/// Market data structures and implementations. +pub mod market_data; +pub use market_data::*; + +/// Context data structures and implementations. +pub mod context_data; +pub use context_data::*; + // /// Base surface data structure and implementations. // /// Surfaces are simply [Curve]s with an additional dimension. // /// For example, a volatility surface is a function of time and strike/moneyness. diff --git a/src/data/yahoo.rs b/src/data/yahoo.rs index 3df9c0d2..aa492a5f 100644 --- a/src/data/yahoo.rs +++ b/src/data/yahoo.rs @@ -52,8 +52,10 @@ pub enum ReturnsType { pub trait YahooFinanceReader { /// Retrieves the price history from Yahoo! Finance. fn get_price_history(&mut self) -> Result<(), RustQuantError>; - /// Retrieves the options chain from Yahoo! Finance. - fn get_options_chain(&mut self) -> Result<(), RustQuantError>; + + // /// Retrieves the options chain from Yahoo! Finance. + // fn get_options_chain(&mut self) -> Result<(), RustQuantError>; + /// Retrieves the latest quote from Yahoo! Finance. fn get_latest_quote(&mut self) -> Result<(), RustQuantError>; } @@ -222,69 +224,75 @@ impl YahooFinanceReader for YahooFinanceData { Ok(()) } - fn get_options_chain(&mut self) -> Result<(), RustQuantError> { - let provider = yahoo::YahooConnector::new()?; - let response = tokio_test::block_on(provider.search_options(self.ticker.as_ref().ok_or( - RustQuantError::MissingInput("No ticker provided.".to_string()), - )?))?; - - let options = response.options; - - // YOptionResult { name: "AAPL230526C00250000", strike: 250.0, last_trade_date: "2023-05-25 3:12PM EDT", - // last_price: 250.0, bid: 250.0, ask: 250.0, change: 250.0, change_pct: 250.0, - // volume: 0, open_interest: 0, impl_volatility: 250.0 } - - // CANNOT IMPLEMENT THIS YET, BECAUSE THE YAHOO FINANCE API - // DOES NOT RETURN THE CORRECT OPTIONS CHAIN. - // Issue opened: https://github.com/xemwebe/yahoo_finance_api/issues/28 - // Pull request opened: https://github.com/xemwebe/yahoo_finance_api/pull/29 - // Pull request was merged. - // Now we need to wait for the next release of the yahoo_finance_api crate. - - let contract = options.iter().map(|o| o.name.clone()).collect::>(); - let strike = options.iter().map(|o| o.strike).collect::>(); - let last_trade_date = options - .iter() - .map(|o| o.last_trade_date.clone()) //(o.last_trade_date / (24 * 60 * 60)) as i32) - .collect::>(); - let last_price = options.iter().map(|o| o.last_price).collect::>(); - let bid = options.iter().map(|o| o.bid).collect::>(); - let ask = options.iter().map(|o| o.ask).collect::>(); - let change = options.iter().map(|o| o.change).collect::>(); - let change_pct = options.iter().map(|o| o.change_pct).collect::>(); - let volume = options.iter().map(|o| o.volume as u64).collect::>(); - let open_interest = options - .iter() - .map(|o| o.open_interest as u64) - .collect::>(); - let impl_volatility = options - .iter() - .map(|o| o.impl_volatility) - .collect::>(); - - let df = df!( - "contract" => contract, - "strike" => strike, - "last_trade_date" => Series::new("last_trade_date".into(), last_trade_date) - .cast(&DataType::Date) - ?, - "last_price" => last_price, - "bid" => bid, - "ask" => ask, - "change" => change, - "change_pct" => change_pct, - "volume" => volume, - "open_interest" => open_interest, - "impl_volatility" => impl_volatility - // "contract" => Series::new("date", date).cast(&DataType::Date)?, - ); - - self.options_chain = Some(df?); - - println!("{:?}", self.options_chain); - - Ok(()) - } + // fn get_options_chain(&mut self) -> Result<(), RustQuantError> { + // let provider = yahoo::YahooConnector::new()?; + // let response = tokio_test::block_on(provider.search_options(self.ticker.as_ref().ok_or( + // RustQuantError::MissingInput("No ticker provided.".to_string()), + // )?))?; + + // let options = response.option_chain.result; + + // // YOptionResult { name: "AAPL230526C00250000", strike: 250.0, last_trade_date: "2023-05-25 3:12PM EDT", + // // last_price: 250.0, bid: 250.0, ask: 250.0, change: 250.0, change_pct: 250.0, + // // volume: 0, open_interest: 0, impl_volatility: 250.0 } + + // // CANNOT IMPLEMENT THIS YET, BECAUSE THE YAHOO FINANCE API + // // DOES NOT RETURN THE CORRECT OPTIONS CHAIN. + // // Issue opened: https://github.com/xemwebe/yahoo_finance_api/issues/28 + // // Pull request opened: https://github.com/xemwebe/yahoo_finance_api/pull/29 + // // Pull request was merged. + // // Now we need to wait for the next release of the yahoo_finance_api crate. + + // let contract = options + // .iter() + // .map(|o| o.underlying_symbol) + // .collect::>(); + // let strike = options.iter().map(|o| o.strikes).collect::>(); + // let last_trade_date = options + // .iter() + // .map(|o| o.options.last_trade_date.clone()) //(o.last_trade_date / (24 * 60 * 60)) as i32) + // .collect::>(); + // let last_price = options + // .iter() + // .map(|o| o.options..last_price) + // .collect::>(); + // let bid = options.iter().map(|o| o.bid).collect::>(); + // let ask = options.iter().map(|o| o.ask).collect::>(); + // let change = options.iter().map(|o| o.change).collect::>(); + // let change_pct = options.iter().map(|o| o.change_pct).collect::>(); + // let volume = options.iter().map(|o| o.volume as u64).collect::>(); + // let open_interest = options + // .iter() + // .map(|o| o.open_interest as u64) + // .collect::>(); + // let impl_volatility = options + // .iter() + // .map(|o| o.impl_volatility) + // .collect::>(); + + // let df = df!( + // "contract" => contract, + // "strike" => strike, + // "last_trade_date" => Series::new("last_trade_date".into(), last_trade_date) + // .cast(&DataType::Date) + // ?, + // "last_price" => last_price, + // "bid" => bid, + // "ask" => ask, + // "change" => change, + // "change_pct" => change_pct, + // "volume" => volume, + // "open_interest" => open_interest, + // "impl_volatility" => impl_volatility + // // "contract" => Series::new("date", date).cast(&DataType::Date)?, + // ); + + // self.options_chain = Some(df?); + + // println!("{:?}", self.options_chain); + + // Ok(()) + // } fn get_latest_quote(&mut self) -> Result<(), RustQuantError> { let provider = yahoo::YahooConnector::new()?; @@ -369,12 +377,12 @@ mod test_yahoo { println!("Apple's latest quote: {:?}", yfd.latest_quote) } - #[test] - fn test_get_options_chain() { - let mut yfd = YahooFinanceData::new("AAPL".to_string()); + // #[test] + // fn test_get_options_chain() { + // let mut yfd = YahooFinanceData::new("AAPL".to_string()); - let _ = yfd.get_options_chain(); + // let _ = yfd.get_options_chain(); - // println!("Apple's options chain: {:?}", yfd.options_chain) - } + // // println!("Apple's options chain: {:?}", yfd.options_chain) + // } } diff --git a/src/instruments/options/vanilla.rs b/src/instruments/options/vanilla.rs index 2230e013..9336b5d3 100644 --- a/src/instruments/options/vanilla.rs +++ b/src/instruments/options/vanilla.rs @@ -44,7 +44,7 @@ mod test_vanilla_option_monte_carlo { use crate::instruments::AsianOption; use crate::instruments::AveragingMethod; use crate::instruments::StrikeFlag; - use crate::pricer::monte_carlo_pricer::MonteCarloPricer; + use crate::pricing::monte_carlo_pricer::MonteCarloPricer; use crate::stochastics::StochasticProcessConfig; use crate::{ instruments::{ExerciseFlag, OptionContractBuilder}, diff --git a/src/lib.rs b/src/lib.rs index e25c600e..0202c368 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -71,7 +71,7 @@ pub mod math; pub mod ml; pub mod models; pub mod portfolio; -pub mod pricer; +pub mod pricing; pub mod stochastics; pub mod time; pub mod trading; diff --git a/src/pricer/analytic_pricer.rs b/src/pricer/analytic_pricer.rs deleted file mode 100644 index 03cddcd8..00000000 --- a/src/pricer/analytic_pricer.rs +++ /dev/null @@ -1,94 +0,0 @@ -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// RustQuant: A Rust library for quantitative finance tools. -// Copyright (C) 2023 https://github.com/avhz -// Dual licensed under Apache 2.0 and MIT. -// See: -// - LICENSE-APACHE.md -// - LICENSE-MIT.md -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -//! Analytic pricer trait. - -use std::any::TypeId; - -use crate::{ - instruments::VanillaOption, - models::{ArithmeticBrownianMotion, GeometricBrownianMotion}, - stochastics::{process, StochasticProcess}, -}; - -/// Analytic pricer trait. -pub trait AnalyticPricer -where - S: StochasticProcess, -{ - /// Price the instrument using an analytic solution. - /// - /// # Arguments - /// - /// * `process` - The [StochasticProcess] model to use for the price. - fn price_analytic(&self, process: S) -> f64; -} - -impl AnalyticPricer for VanillaOption -where - S: StochasticProcess + 'static, -{ - fn price_analytic(&self, process: S) -> f64 { - let process_id = TypeId::of::(); - - if process_id == TypeId::of::() { - let params = process.parameters(); - let mu = params[0]; - let sigma = params[1]; - - println!( - "Geometric Brownian Motion detected. mu: {}, sigma: {}", - mu, sigma - ); - - // Implement the specific analytic pricing for Geometric Brownian Motion - // Example: return some calculation - return 2.0; // Placeholder value for demonstration - } else if process_id == TypeId::of::() { - // Add another specific process handling here - println!("Another process detected."); - - // Implement another pricing logic for `AnotherProcess` - return 3.0; // Placeholder value - } else { - println!("Unknown process."); - // Handle the case where the process type is unknown or not handled - return 0.0; - } - } -} - -#[cfg(test)] -mod tests_analytic_pricer { - use time::macros::date; - - use super::*; - use crate::{ - instruments::{ExerciseFlag, OptionContract, TypeFlag}, - models::model_parameter::ModelParameter, - }; - - #[test] - fn test_price_analytic() { - let contract = OptionContract { - type_flag: TypeFlag::Call, - exercise_flag: ExerciseFlag::European { - expiry: date!(2025 - 01 - 01), - }, - strike_flag: None, - settlement_flag: None, - }; - let option = VanillaOption::new(contract, 1.0); - let process = ArithmeticBrownianMotion::new(0.05, 0.2); - - let price = option.price_analytic(process); - - assert_eq!(price, 0.0); - } -} diff --git a/src/pricer/finite_difference_pricer.rs b/src/pricer/finite_difference_pricer.rs deleted file mode 100644 index e69de29b..00000000 diff --git a/src/pricer/lattice_pricer.rs b/src/pricer/lattice_pricer.rs deleted file mode 100644 index e69de29b..00000000 diff --git a/src/pricer/priceable.rs b/src/pricer/priceable.rs deleted file mode 100644 index 4b829b76..00000000 --- a/src/pricer/priceable.rs +++ /dev/null @@ -1,55 +0,0 @@ -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// RustQuant: A Rust library for quantitative finance tools. -// Copyright (C) 2023 https://github.com/avhz -// Dual licensed under Apache 2.0 and MIT. -// See: -// - LICENSE-APACHE.md -// - LICENSE-MIT.md -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -//! Priceable trait. - -use super::{ContextData, MarketData}; -use crate::{ - instruments::{Instrument, Payoff}, - stochastics::process::StochasticProcess, - time::Calendar, -}; - -/// Priceable trait. -pub trait Priceable: Payoff + Instrument -where - C: Calendar, - S: StochasticProcess, - P: Payoff, -{ - /// Function to prepare the data for the specific instrument. - fn prepare_data(&self) -> (); - - /// Analytic pricer implementation. - fn price_analytic_impl( - &self, - context_data: &Option>, - market_data: &mut Option>, - model: &Option, - // engine: &Option, - ) -> f64; - - /// Simulation pricer implementation. - fn price_simulation_impl( - &self, - context_data: &Option>, - market_data: &mut Option>, - model: &Option, - // engine: &Option, - ) -> f64; - - /// Numerical pricer implementation. - fn price_numerical_impl( - &self, - context_data: &Option>, - market_data: &mut Option>, - model: &Option, - // engine: &Option, - ) -> f64; -} diff --git a/src/pricer/backends/asian.rs b/src/pricing/backends/asian.rs similarity index 100% rename from src/pricer/backends/asian.rs rename to src/pricing/backends/asian.rs diff --git a/src/pricer/backends/bachelier.rs b/src/pricing/backends/bachelier.rs similarity index 100% rename from src/pricer/backends/bachelier.rs rename to src/pricing/backends/bachelier.rs diff --git a/src/pricer/backends/barrier.rs b/src/pricing/backends/barrier.rs similarity index 100% rename from src/pricer/backends/barrier.rs rename to src/pricing/backends/barrier.rs diff --git a/src/pricer/backends/binary.rs b/src/pricing/backends/binary.rs similarity index 100% rename from src/pricer/backends/binary.rs rename to src/pricing/backends/binary.rs diff --git a/src/pricer/backends/binomial.rs b/src/pricing/backends/binomial.rs similarity index 100% rename from src/pricer/backends/binomial.rs rename to src/pricing/backends/binomial.rs diff --git a/src/pricer/backends/forward_start.rs b/src/pricing/backends/forward_start.rs similarity index 100% rename from src/pricer/backends/forward_start.rs rename to src/pricing/backends/forward_start.rs diff --git a/src/pricer/backends/heston.rs b/src/pricing/backends/heston.rs similarity index 100% rename from src/pricer/backends/heston.rs rename to src/pricing/backends/heston.rs diff --git a/src/pricer/backends/lookback.rs b/src/pricing/backends/lookback.rs similarity index 100% rename from src/pricer/backends/lookback.rs rename to src/pricing/backends/lookback.rs diff --git a/src/pricer/backends/merton_jump_diffusion.rs b/src/pricing/backends/merton_jump_diffusion.rs similarity index 100% rename from src/pricer/backends/merton_jump_diffusion.rs rename to src/pricing/backends/merton_jump_diffusion.rs diff --git a/src/pricer/backends/power.rs b/src/pricing/backends/power.rs similarity index 100% rename from src/pricer/backends/power.rs rename to src/pricing/backends/power.rs diff --git a/src/pricer/mod.rs b/src/pricing/mod.rs similarity index 93% rename from src/pricer/mod.rs rename to src/pricing/mod.rs index 1c5fa36f..3fcf4274 100644 --- a/src/pricer/mod.rs +++ b/src/pricing/mod.rs @@ -13,21 +13,9 @@ // MODULES // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -pub mod context_data; -pub use context_data::*; - -pub mod market_data; -pub use market_data::*; - -pub mod priceable; -pub use priceable::*; - pub mod monte_carlo_pricer; pub use monte_carlo_pricer::*; -pub mod analytic_pricer; -pub use analytic_pricer::*; - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // PRICER STRUCT // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/pricer/monte_carlo_pricer.rs b/src/pricing/monte_carlo_pricer.rs similarity index 100% rename from src/pricer/monte_carlo_pricer.rs rename to src/pricing/monte_carlo_pricer.rs diff --git a/src/stochastics/fractional_brownian_motion.rs b/src/stochastics/fractional_brownian_motion.rs index bd224f75..799d7420 100644 --- a/src/stochastics/fractional_brownian_motion.rs +++ b/src/stochastics/fractional_brownian_motion.rs @@ -7,13 +7,14 @@ // - LICENSE-MIT.md // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +use super::StochasticProcessConfig; use crate::{ models::fractional_brownian_motion::FractionalBrownianMotion, stochastics::process::{StochasticProcess, Trajectories}, }; use nalgebra::{DMatrix, DVector, Dim, Dyn, RowDVector}; use ndarray::{concatenate, prelude::*}; -use ndarray_rand::RandomExt; +use ndarray_rand::{rand::random, RandomExt}; use ndrustfft::{ndfft_par, FftHandler}; use num::{complex::ComplexDistribution, Complex}; use rand::Rng; @@ -21,8 +22,6 @@ use rand::{rngs::StdRng, SeedableRng}; use rand_distr::StandardNormal; use rayon::prelude::*; -use super::StochasticProcessConfig; - /// Method used to generate the Fractional Brownian Motion. #[derive(Debug)] pub enum FractionalProcessGeneratorMethod {