Skip to content

Commit

Permalink
feat: rework calibrator
Browse files Browse the repository at this point in the history
  • Loading branch information
dancixx committed Sep 29, 2024
1 parent f010023 commit c062eda
Show file tree
Hide file tree
Showing 5 changed files with 246 additions and 238 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
- uses: actions/checkout@v3

- name: Install dependencies
run: sudo apt-get update && sudo apt-get install -y gcc gobjc
run: sudo apt-get update && sudo apt-get install -y gcc gobjc libobjc-12-dev

- name: Set up Rust
uses: actions-rs/toolchain@v1
Expand All @@ -28,7 +28,7 @@ jobs:
override: true

- name: Build
run: cargo build --verbose
run: cargo build --release

- name: Run tests
run: cargo test --verbose
run: cargo test
4 changes: 2 additions & 2 deletions stochastic-rs-quant/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ quadrature = "0.1.2"
rand = "0.8.5"
rand_distr = "0.4.3"
stochastic-rs = { version = "0.8.2", path = "../stochastic-rs-core" }
stochastic-rs-stats = { version = "0.1.2", path = "../stochastic-rs-stats" }
stochastic-rs-stats = { version = "0.1.4", path = "../stochastic-rs-stats" }
tikv-jemallocator = { version = "0.6.0", optional = true }
time = { version = "0.3.36", features = ["formatting", "parsing"] }
tokio-test = "0.4.4"
yahoo_finance_api = { git = "https://github.com/dancixx/yahoo_finance_api.git", branch = "master" }
yahoo_finance_api = { git = "https://github.com/dancixx/yahoo_finance_api.git", rev = "476ebdc" }

[features]
mimalloc = ["dep:mimalloc"]
Expand Down
89 changes: 56 additions & 33 deletions stochastic-rs-quant/src/volatility.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,23 @@ pub mod heston;

use std::cell::RefCell;

use either::Either;
use levenberg_marquardt::LeastSquaresProblem;
use nalgebra::{DMatrix, DVector, Dyn, Owned};

use crate::yahoo::OptionType;

/// Pricer trait.
pub(crate) trait Pricer {
/// Calculate the price of an option.
fn calculate_price(&mut self) -> Either<(f64, f64), Vec<(f64, f64)>>;
fn calculate_price(&mut self);
/// Update the parameters.
fn update_params(&mut self, params: DVector<f64>);
/// Update strike price.
fn update_strike(&mut self, k: f64);
/// Prices.
fn prices(&self) -> Option<Either<(f64, f64), Vec<(f64, f64)>>>;
fn prices(&self) -> (f64, f64);
/// Derivatives.
fn derivates(&self) -> Option<Either<Vec<f64>, Vec<Vec<f64>>>>;
fn derivates(&self) -> Vec<f64>;
}

/// A calibrator.
Expand All @@ -26,18 +29,37 @@ where
/// Params to calibrate.
pub params: DVector<f64>,
/// Option prices from the market.
pub c: Option<DVector<f64>>,
pub c_market: DVector<f64>,
/// Strike price vector.
pub k: DVector<f64>,
/// Option type
pub option_type: &'a OptionType,
/// Pricer backend.
pricer: &'a RefCell<P>,
/// Derivate matrix.
derivates: RefCell<Vec<Vec<f64>>>,
}

impl<'a, P> Calibrator<'a, P>
where
P: Pricer,
{
#[must_use]
pub(crate) fn new(params: DVector<f64>, c: Option<DVector<f64>>, pricer: &'a RefCell<P>) -> Self {
Self { params, c, pricer }
pub(crate) fn new(
params: DVector<f64>,
c_market: Vec<f64>,
k: Vec<f64>,
option_type: &'a OptionType,
pricer: &'a RefCell<P>,
) -> Self {
Self {
params,
c_market: DVector::from_vec(c_market),
k: DVector::from_vec(k),
option_type,
pricer,
derivates: RefCell::new(Vec::new()),
}
}
}

Expand All @@ -60,38 +82,39 @@ where

fn residuals(&self) -> Option<DVector<f64>> {
self.pricer.borrow_mut().calculate_price();
let options = self.pricer.borrow().prices().unwrap();
let calls = options
.as_ref()
.right()
.unwrap()
.iter()
.map(|x| x.0)
.collect::<Vec<f64>>();

let residuals = calls
.iter()
.zip(self.c.as_ref().unwrap().iter())
.map(|(x, y)| x - y)
.collect::<Vec<f64>>();

Some(DVector::from_vec(residuals))
let mut c_model = DVector::zeros(self.c_market.len());
let mut derivates = Vec::new();

for i in 0..c_model.len() {
self.pricer.borrow_mut().update_strike(self.k[i]);
self.pricer.borrow_mut().calculate_price();
let (c, p) = self.pricer.borrow().prices();

if self.option_type == &OptionType::Call {
c_model[i] = c;
} else {
c_model[i] = p;
}

derivates.push(self.pricer.borrow().derivates());
}

self.derivates.replace(derivates);
Some(c_model - self.c_market.clone())
}

fn jacobian(&self) -> Option<DMatrix<f64>> {
let derivates = self.pricer.borrow().derivates().unwrap();
let derivates = derivates
.as_ref()
.right()
.unwrap()
.iter()
.flatten()
.cloned()
.collect::<Vec<f64>>();
let derivates = self.derivates.borrow();
let derivates = derivates.iter().flatten().cloned().collect::<Vec<f64>>();
println!("{:?}", derivates.len());

// The Jacobian matrix is a matrix of partial derivatives
// of the residuals with respect to the parameters.
let jacobian = DMatrix::from_vec(derivates.len() / self.params.len(), 5, derivates);
let jacobian = DMatrix::from_vec(
derivates.len() / self.params.len(),
self.params.len(),
derivates,
);
Some(jacobian)
}
}
Loading

0 comments on commit c062eda

Please sign in to comment.