pub struct HestonParams {
pub v0: f64,
pub kappa: f64,
pub theta: f64,
pub vol_of_vol: f64,
pub rho: f64,
}Expand description
Heston parameters. theta is the long-run variance, v0 the initial
variance, vol_of_vol the volatility of variance (often written xi or
sigma), rho the spot-variance correlation.
Fields§
§v0: f64§kappa: f64§theta: f64§vol_of_vol: f64§rho: f64Implementations§
Source§impl HestonParams
impl HestonParams
pub fn validate(&self) -> Result<(), String>
Sourcepub fn feller_condition_holds(&self) -> bool
pub fn feller_condition_holds(&self) -> bool
Whether the Feller condition 2 kappa theta >= vol_of_vol^2 holds
(if not, the variance process can touch zero; pricing still works).
Examples found in repository?
examples/heston_option.rs (line 48)
40fn main() {
41 let p = params();
42 common::title(&format!(
43 "HESTON — v0={} kappa={} theta={} vol-of-vol={} rho={}",
44 p.v0, p.kappa, p.theta, p.vol_of_vol, p.rho
45 ));
46 common::note(&format!(
47 "Feller condition 2*kappa*theta >= vol_of_vol^2: {}",
48 if p.feller_condition_holds() { "holds" } else { "VIOLATED (variance can touch zero)" }
49 ));
50
51 common::section("Vanilla: semi-analytic vs Monte Carlo");
52 common::table_header();
53 for pc in [PutOrCall::Call, PutOrCall::Put] {
54 common::row(
55 &format!("Analytical (char. function), {pc:?}"),
56 &base().vanilla(pc).engine(Engine::BlackScholes).build(),
57 );
58 common::row(
59 &format!("Monte Carlo (full-trunc Euler), {pc:?}"),
60 &base().vanilla(pc).engine(Engine::MonteCarlo).paths(100_000).build(),
61 );
62 }
63 common::row(
64 "Finite difference (unsupported)",
65 &base().vanilla(PutOrCall::Call).engine(Engine::FiniteDifference).build(),
66 );
67 common::note("MC vega/theta bump sqrt(v0) and sqrt(theta) in parallel");
68
69 common::section("Binaries under Heston");
70 common::table_header();
71 common::row(
72 "Cash-or-nothing call (analytic)",
73 &base()
74 .binary(PutOrCall::Call, BinaryType::CashOrNothing, 1.0)
75 .engine(Engine::BlackScholes)
76 .build(),
77 );
78 common::row(
79 "Cash-or-nothing call (MC)",
80 &base()
81 .binary(PutOrCall::Call, BinaryType::CashOrNothing, 1.0)
82 .engine(Engine::MonteCarlo)
83 .paths(100_000)
84 .build(),
85 );
86 common::row(
87 "Asset-or-nothing call (analytic)",
88 &base()
89 .binary(PutOrCall::Call, BinaryType::AssetOrNothing, 0.0)
90 .engine(Engine::BlackScholes)
91 .build(),
92 );
93
94 common::section("Path-dependent payoffs (Monte Carlo only)");
95 common::table_header();
96 common::row(
97 "Down-and-out call H=85",
98 &base()
99 .barrier(PutOrCall::Call, BarrierDirection::Down, KnockType::Out, 85.0)
100 .engine(Engine::MonteCarlo)
101 .paths(50_000)
102 .build(),
103 );
104 common::row(
105 "Down-and-in put H=85",
106 &base()
107 .barrier(PutOrCall::Put, BarrierDirection::Down, KnockType::In, 85.0)
108 .engine(Engine::MonteCarlo)
109 .paths(50_000)
110 .build(),
111 );
112
113 common::section("Identities");
114 let call = base().vanilla(PutOrCall::Call).engine(Engine::BlackScholes).build();
115 let put = base().vanilla(PutOrCall::Put).engine(Engine::BlackScholes).build();
116 let parity = SPOT * (-DIV * 1.0_f64).exp() - STRIKE * (-RATE * 1.0_f64).exp();
117 common::check("put-call parity", call.npv() - put.npv(), parity, 1e-10);
118 let asset = base()
119 .binary(PutOrCall::Call, BinaryType::AssetOrNothing, 0.0)
120 .engine(Engine::BlackScholes)
121 .build();
122 let k_cash = base()
123 .binary(PutOrCall::Call, BinaryType::CashOrNothing, STRIKE)
124 .engine(Engine::BlackScholes)
125 .build();
126 common::check("vanilla = asset digital - K cash digitals", call.npv(), asset.npv() - k_cash.npv(), 1e-10);
127 common::check(
128 "vol-of-vol -> 0 degenerates to Black-Scholes",
129 heston_price(
130 SPOT,
131 STRIKE,
132 RATE,
133 DIV,
134 1.0,
135 &HestonParams { vol_of_vol: 1e-4, ..params() },
136 PutOrCall::Call,
137 ),
138 bs_price(SPOT, STRIKE, RATE, DIV, p.v0.sqrt(), 1.0, PutOrCall::Call),
139 1e-4,
140 );
141
142 common::section("The Heston smile (implied vol backed out of Heston prices)");
143 println!(" {:>8} {:>14} {:>14}", "strike", "heston price", "implied vol");
144 for k in [70.0, 80.0, 90.0, 100.0, 110.0, 120.0, 130.0] {
145 let price = heston_price(SPOT, k, RATE, DIV, 1.0, &p, PutOrCall::Call);
146 let iv = implied_vol_from_price(SPOT, k, RATE, DIV, 1.0, price, PutOrCall::Call)
147 .unwrap_or(f64::NAN);
148 println!(" {k:>8.1} {price:>14.6} {:>13.4}%", iv * 100.0);
149 }
150 common::note("rho < 0 tilts the smile: low strikes carry higher implied vol");
151
152 common::section("Correlation and vol-of-vol control the smile shape");
153 println!(" {:>6} {:>8} {:>12} {:>12} {:>12}", "rho", "vol-of-vol", "iv(80)", "iv(100)", "iv(120)");
154 for (rho, vov) in [(-0.7, 0.4), (0.0, 0.4), (0.7, 0.4), (-0.7, 0.1), (-0.7, 0.8)] {
155 let hp = HestonParams { rho, vol_of_vol: vov, ..params() };
156 let iv = |k: f64| {
157 let price = heston_price(SPOT, k, RATE, DIV, 1.0, &hp, PutOrCall::Call);
158 implied_vol_from_price(SPOT, k, RATE, DIV, 1.0, price, PutOrCall::Call)
159 .unwrap_or(f64::NAN)
160 * 100.0
161 };
162 println!(" {rho:>6.1} {vov:>10.1} {:>11.3}% {:>11.3}% {:>11.3}%", iv(80.0), iv(100.0), iv(120.0));
163 }
164 common::note("rho controls the skew (tilt); vol-of-vol controls the smile (curvature)");
165 println!();
166}Sourcepub fn with_vol_shift(&self, shift: f64) -> HestonParams
pub fn with_vol_shift(&self, shift: f64) -> HestonParams
Parameters with a parallel shift applied to the instantaneous and long-run vol (used for vega bump-and-reprice).
Trait Implementations§
Source§impl Clone for HestonParams
impl Clone for HestonParams
Source§fn clone(&self) -> HestonParams
fn clone(&self) -> HestonParams
Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
Performs copy-assignment from
source. Read moreimpl Copy for HestonParams
Source§impl Debug for HestonParams
impl Debug for HestonParams
Source§impl<'de> Deserialize<'de> for HestonParams
impl<'de> Deserialize<'de> for HestonParams
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Deserialize this value from the given Serde deserializer. Read more
Auto Trait Implementations§
impl Freeze for HestonParams
impl RefUnwindSafe for HestonParams
impl Send for HestonParams
impl Sync for HestonParams
impl Unpin for HestonParams
impl UnsafeUnpin for HestonParams
impl UnwindSafe for HestonParams
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more