Skip to content

Calibration generates negative values #14

@eliebnn

Description

@eliebnn

Hi,

I have tried to run the calibration code. Some runs return negative values for v0, theta, kappa, signa, which should all be strictly positive.

Attached is a code sample. It runs the calibration over several v0, and keep the minimul mape loss.

Also, if you uncomment the set_initial_params line, you will see that sigma and rho will have NaN assigned values.

Am I doing something wrong? I run the calibration over call options with 1 months maturity with same spot, and different strikes.

use stochastic_rs::quant::calibration::heston::{HestonCalibrator, HestonParams};
use stochastic_rs::quant::OptionType;

use std::cmp::Ordering;
use ndarray::Array1;

#[tokio::main]
async fn main() {

    let r = 0.04;
    let q = 0.06;
    let t = 0.083;

    let strikes_ls: Vec<f64> = vec![5220.318, 6090.371, 6960.424, 7830.477, 8265.5035, 8483.01675, 8700.53, 8918.04325, 9135.5565, 9570.583, 10440.636, 11310.689];
    let spots_ls: Vec<f64> = vec![8700.53, 8700.53, 8700.53, 8700.53, 8700.53, 8700.53, 8700.53, 8700.53, 8700.53, 8700.53, 8700.53, 8700.53];
    let vol_ls: Vec<f64> = vec![0.3669, 0.3082, 0.2218, 0.1799, 0.1393, 0.1156, 0.1019, 0.0923, 0.0915, 0.1086, 0.1237, 0.136];
    let markets_ls: Vec<f64> = vec![3499.564, 2632.74, 1765.933, 901.846, 479.055, 279.313, 118.848, 28.79, 4.23, 0.143, 1.799e-5, 1.259e-9];

    let v0 = Array1::linspace(1e-5, 2.0, 5);

    for v in v0.iter() {
      let mut calibrator = HestonCalibrator::new(
        HestonParams {
            v0: *v,
            theta: 6.47e-5,
            rho: -1.98e-3,
            kappa: 6.57e-3,
            sigma: 5.09e-4,
        },
        markets_ls.clone().into(), spots_ls.clone().into(), strikes_ls.clone().into(),
        t, r, Some(q), OptionType::Call,
      );

      // Uncomment to witness NaN Sigma/Rho
      // calibrator.set_initial_params(spots_ls.clone().into(), vol_ls.clone().into(), r);

      let result = calibrator.calibrate();
      let result_unwrap = result.unwrap();

      let minimum_loss = result_unwrap.iter().min_by(|a, b| {
        a.loss_scores.mape.partial_cmp(&b.loss_scores.mape).unwrap_or(Ordering::Equal)
      });

      println!("{:?}", minimum_loss.clone().unwrap().loss_scores.mape);
      println!("{:?}", minimum_loss.clone().unwrap().params);

    }
    }

The markets_ls array was computed with:

    let markets_ls: Vec<f64> = data.iter().map(|x| {

        let bs = BSMPricer::new(x.spot, x.vol, x.strike, r, None, None, Some(q), Some(t), None, None, OptionType::Call, BSMCoc::BSM1973);
        let (c, _) = bs.calculate_call_put();

        return c;

    }).collect()

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions