pub struct EquityOptionBase {Show 21 fields
pub symbol: String,
pub currency: Option<String>,
pub exchange: Option<String>,
pub name: Option<String>,
pub cusip: Option<String>,
pub isin: Option<String>,
pub settlement_type: Option<String>,
pub underlying_price: Quote,
pub current_price: Quote,
pub strike_price: f64,
pub dividend_yield: f64,
pub borrow_cost: f64,
pub futures_settlement: Option<FuturesSettlement>,
pub cash_dividends: Vec<(NaiveDate, f64)>,
pub vol_surface: VolSurface,
pub maturity_date: NaiveDate,
pub valuation_date: NaiveDate,
pub discount_curve: YieldCurve,
pub entry_price: f64,
pub long_short: LongShort,
pub multiplier: f64,
}Fields§
§symbol: String§currency: Option<String>§exchange: Option<String>§name: Option<String>§cusip: Option<String>§isin: Option<String>§settlement_type: Option<String>§underlying_price: Quote§current_price: Quote§strike_price: f64§dividend_yield: f64§borrow_cost: f64Continuous stock borrow (repo) cost; part of the carry alongside the dividend yield.
futures_settlement: Option<FuturesSettlement>When set, the underlying is a future priced with Black-76
(underlying_price is the futures price F), settled either with an
up-front discounted premium or futures-style margined. European
vanilla only, on the Analytical engine.
cash_dividends: Vec<(NaiveDate, f64)>Discrete cash dividends (ex-date, amount per share). Analytic, tree and terminal Monte Carlo engines use the escrowed model (spot minus PV of dividends); path-wise Monte Carlo and finite difference apply the jumps at the ex-dates.
vol_surface: VolSurfaceVolatility surface; a flat surface represents a single constant vol.
maturity_date: NaiveDate§valuation_date: NaiveDate§discount_curve: YieldCurveDiscounting curve anchored at valuation_date; discount factors are
the source of truth, rates are derived views.
entry_price: f64§long_short: LongShort§multiplier: f64Implementations§
Source§impl EquityOptionBase
impl EquityOptionBase
pub fn time_to_maturity(&self) -> f64
Sourcepub fn maturity_discount_factor(&self) -> f64
pub fn maturity_discount_factor(&self) -> f64
Discount factor from the valuation date to maturity, off the curve.
Sourcepub fn risk_free_rate(&self) -> f64
pub fn risk_free_rate(&self) -> f64
Continuously compounded zero rate to maturity implied by the curve.
This is the r that enters d1/d2; it is consistent with
maturity_discount_factor by construction.
Sourcepub fn carry_yield(&self) -> f64
pub fn carry_yield(&self) -> f64
Total continuous carry on the underlying: dividend yield plus borrow cost. This is the “q” every pricing formula uses.
Examples found in repository?
39fn main() {
40 common::title("DIVIDENDS AND BORROW COST — S=100 K=100 sigma=30% r=5% T=1y");
41
42 common::section("Continuous carry: dividend yield and borrow cost are interchangeable");
43 common::table_header();
44 common::row("no carry", &base().vanilla(PutOrCall::Call).build());
45 common::row("q = 4%", &base().dividend_yield(0.04).vanilla(PutOrCall::Call).build());
46 common::row("borrow = 4%", &base().borrow_cost(0.04).vanilla(PutOrCall::Call).build());
47 common::row(
48 "q = 1% + borrow = 3%",
49 &base().dividend_yield(0.01).borrow_cost(0.03).vanilla(PutOrCall::Call).build(),
50 );
51 common::note("carry_yield() = dividend_yield + borrow_cost enters every formula as 'q'");
52
53 let q_only = base().dividend_yield(0.04).vanilla(PutOrCall::Call).build();
54 let split = base().dividend_yield(0.01).borrow_cost(0.03).vanilla(PutOrCall::Call).build();
55 common::check("q=4% vs q=1%+b=3%", split.npv(), q_only.npv(), 1e-12);
56
57 common::section("Hard-to-borrow names: high borrow cost lowers the forward");
58 common::table_header();
59 for b in [0.0, 0.02, 0.05, 0.15] {
60 let option = base().borrow_cost(b).vanilla(PutOrCall::Call).build();
61 common::row(&format!("borrow = {:.0}%", b * 100.0), &option);
62 }
63 let hard = base().borrow_cost(0.15).vanilla(PutOrCall::Call).build();
64 println!(
65 " forward with 15% borrow: {:.4} (vs spot {SPOT})",
66 hard.base.forward_price()
67 );
68
69 common::section("Discrete cash dividends: 2 x 1.50 over the year");
70 let with_divs = |b: EquityOptionBuilder| {
71 b.cash_dividend(NaiveDate::from_ymd_opt(2026, 4, 1).unwrap(), 1.5)
72 .cash_dividend(NaiveDate::from_ymd_opt(2026, 10, 1).unwrap(), 1.5)
73 };
74 let analytic = with_divs(base()).vanilla(PutOrCall::Call).build();
75 println!(
76 " spot {SPOT} - PV(dividends) {:.6} = escrowed spot {:.6}",
77 analytic.base.pv_cash_dividends(),
78 analytic.base.effective_spot()
79 );
80 common::table_header();
81 common::row("Analytical (escrowed model)", &analytic);
82 common::row(
83 "Binomial (escrowed)",
84 &with_divs(base()).vanilla(PutOrCall::Call).engine(Engine::Binomial).build(),
85 );
86 common::row(
87 "Finite difference (jump model)",
88 &with_divs(base()).vanilla(PutOrCall::Call).engine(Engine::FiniteDifference).build(),
89 );
90 common::row(
91 "Monte Carlo terminal (escrowed)",
92 &with_divs(base()).vanilla(PutOrCall::Call).engine(Engine::MonteCarlo).build(),
93 );
94 common::row(
95 "Monte Carlo path-wise (jump model)",
96 &with_divs(base())
97 .vanilla(PutOrCall::Call)
98 .engine(Engine::MonteCarlo)
99 .mc_time_steps(200)
100 .paths(50_000)
101 .build(),
102 );
103 common::note("escrowed: lognormal on S - PV(divs); jump: dividends subtracted at each ex-date");
104 common::note("the two models differ slightly by construction — that gap is expected, not a bug");
105
106 common::check(
107 "escrowed analytic == BS on the escrowed spot",
108 analytic.npv(),
109 bs_price(analytic.base.effective_spot(), STRIKE, RATE, 0.0, VOL, 1.0, PutOrCall::Call),
110 1e-10,
111 );
112
113 common::section("Where the jump model matters: American exercise and barriers");
114 common::table_header();
115 common::row(
116 "American put, FD (jumps)",
117 &with_divs(base())
118 .american()
119 .vanilla(PutOrCall::Put)
120 .engine(Engine::FiniteDifference)
121 .build(),
122 );
123 common::row(
124 "American put, no dividends",
125 &base().american().vanilla(PutOrCall::Put).engine(Engine::FiniteDifference).build(),
126 );
127 common::row(
128 "Down-and-out call H=85, MC (jumps)",
129 &with_divs(base())
130 .barrier(PutOrCall::Call, BarrierDirection::Down, KnockType::Out, 85.0)
131 .engine(Engine::MonteCarlo)
132 .paths(50_000)
133 .build(),
134 );
135 common::row(
136 "Down-and-out call H=85, no dividends",
137 &base()
138 .barrier(PutOrCall::Call, BarrierDirection::Down, KnockType::Out, 85.0)
139 .engine(Engine::MonteCarlo)
140 .paths(50_000)
141 .build(),
142 );
143 common::note("dividend drops push the path toward a down barrier and change exercise timing");
144
145 common::section("Put-call parity with full carry");
146 let call = with_divs(base()).borrow_cost(0.02).vanilla(PutOrCall::Call).build();
147 let put = with_divs(base()).borrow_cost(0.02).vanilla(PutOrCall::Put).build();
148 let parity = call.base.effective_spot() * (-call.base.carry_yield() * 1.0_f64).exp()
149 - STRIKE * (-RATE * 1.0_f64).exp();
150 common::check("C - P = S_eff e^{-(q+b)T} - K e^{-rT}", call.npv() - put.npv(), parity, 1e-10);
151 println!();
152}Sourcepub fn is_futures_option(&self) -> bool
pub fn is_futures_option(&self) -> bool
True when the underlying is a future priced with Black-76.
Sourcepub fn pv_cash_dividends(&self) -> f64
pub fn pv_cash_dividends(&self) -> f64
Escrow value of the cash dividends with ex-dates inside the option’s life: the amount to carve out of spot so the risky stub reproduces the jump-model forward.
Each dividend is discounted at the net carry rate r - carry,
not the risk-free rate, so that the escrow accretes at the same rate
the risky stub grows (effective_spot is grown at r - carry in
[forward_price]). This makes the analytic forward match the
well-defined jump model F = (S - D e^{-(r-carry)t}) e^{(r-carry)T}
used by the FD and path-wise Monte Carlo engines. With no continuous
carry this reduces to plain risk-free discounting.
Examples found in repository?
39fn main() {
40 common::title("DIVIDENDS AND BORROW COST — S=100 K=100 sigma=30% r=5% T=1y");
41
42 common::section("Continuous carry: dividend yield and borrow cost are interchangeable");
43 common::table_header();
44 common::row("no carry", &base().vanilla(PutOrCall::Call).build());
45 common::row("q = 4%", &base().dividend_yield(0.04).vanilla(PutOrCall::Call).build());
46 common::row("borrow = 4%", &base().borrow_cost(0.04).vanilla(PutOrCall::Call).build());
47 common::row(
48 "q = 1% + borrow = 3%",
49 &base().dividend_yield(0.01).borrow_cost(0.03).vanilla(PutOrCall::Call).build(),
50 );
51 common::note("carry_yield() = dividend_yield + borrow_cost enters every formula as 'q'");
52
53 let q_only = base().dividend_yield(0.04).vanilla(PutOrCall::Call).build();
54 let split = base().dividend_yield(0.01).borrow_cost(0.03).vanilla(PutOrCall::Call).build();
55 common::check("q=4% vs q=1%+b=3%", split.npv(), q_only.npv(), 1e-12);
56
57 common::section("Hard-to-borrow names: high borrow cost lowers the forward");
58 common::table_header();
59 for b in [0.0, 0.02, 0.05, 0.15] {
60 let option = base().borrow_cost(b).vanilla(PutOrCall::Call).build();
61 common::row(&format!("borrow = {:.0}%", b * 100.0), &option);
62 }
63 let hard = base().borrow_cost(0.15).vanilla(PutOrCall::Call).build();
64 println!(
65 " forward with 15% borrow: {:.4} (vs spot {SPOT})",
66 hard.base.forward_price()
67 );
68
69 common::section("Discrete cash dividends: 2 x 1.50 over the year");
70 let with_divs = |b: EquityOptionBuilder| {
71 b.cash_dividend(NaiveDate::from_ymd_opt(2026, 4, 1).unwrap(), 1.5)
72 .cash_dividend(NaiveDate::from_ymd_opt(2026, 10, 1).unwrap(), 1.5)
73 };
74 let analytic = with_divs(base()).vanilla(PutOrCall::Call).build();
75 println!(
76 " spot {SPOT} - PV(dividends) {:.6} = escrowed spot {:.6}",
77 analytic.base.pv_cash_dividends(),
78 analytic.base.effective_spot()
79 );
80 common::table_header();
81 common::row("Analytical (escrowed model)", &analytic);
82 common::row(
83 "Binomial (escrowed)",
84 &with_divs(base()).vanilla(PutOrCall::Call).engine(Engine::Binomial).build(),
85 );
86 common::row(
87 "Finite difference (jump model)",
88 &with_divs(base()).vanilla(PutOrCall::Call).engine(Engine::FiniteDifference).build(),
89 );
90 common::row(
91 "Monte Carlo terminal (escrowed)",
92 &with_divs(base()).vanilla(PutOrCall::Call).engine(Engine::MonteCarlo).build(),
93 );
94 common::row(
95 "Monte Carlo path-wise (jump model)",
96 &with_divs(base())
97 .vanilla(PutOrCall::Call)
98 .engine(Engine::MonteCarlo)
99 .mc_time_steps(200)
100 .paths(50_000)
101 .build(),
102 );
103 common::note("escrowed: lognormal on S - PV(divs); jump: dividends subtracted at each ex-date");
104 common::note("the two models differ slightly by construction — that gap is expected, not a bug");
105
106 common::check(
107 "escrowed analytic == BS on the escrowed spot",
108 analytic.npv(),
109 bs_price(analytic.base.effective_spot(), STRIKE, RATE, 0.0, VOL, 1.0, PutOrCall::Call),
110 1e-10,
111 );
112
113 common::section("Where the jump model matters: American exercise and barriers");
114 common::table_header();
115 common::row(
116 "American put, FD (jumps)",
117 &with_divs(base())
118 .american()
119 .vanilla(PutOrCall::Put)
120 .engine(Engine::FiniteDifference)
121 .build(),
122 );
123 common::row(
124 "American put, no dividends",
125 &base().american().vanilla(PutOrCall::Put).engine(Engine::FiniteDifference).build(),
126 );
127 common::row(
128 "Down-and-out call H=85, MC (jumps)",
129 &with_divs(base())
130 .barrier(PutOrCall::Call, BarrierDirection::Down, KnockType::Out, 85.0)
131 .engine(Engine::MonteCarlo)
132 .paths(50_000)
133 .build(),
134 );
135 common::row(
136 "Down-and-out call H=85, no dividends",
137 &base()
138 .barrier(PutOrCall::Call, BarrierDirection::Down, KnockType::Out, 85.0)
139 .engine(Engine::MonteCarlo)
140 .paths(50_000)
141 .build(),
142 );
143 common::note("dividend drops push the path toward a down barrier and change exercise timing");
144
145 common::section("Put-call parity with full carry");
146 let call = with_divs(base()).borrow_cost(0.02).vanilla(PutOrCall::Call).build();
147 let put = with_divs(base()).borrow_cost(0.02).vanilla(PutOrCall::Put).build();
148 let parity = call.base.effective_spot() * (-call.base.carry_yield() * 1.0_f64).exp()
149 - STRIKE * (-RATE * 1.0_f64).exp();
150 common::check("C - P = S_eff e^{-(q+b)T} - K e^{-rT}", call.npv() - put.npv(), parity, 1e-10);
151 println!();
152}Sourcepub fn effective_spot(&self) -> f64
pub fn effective_spot(&self) -> f64
Escrowed-model spot: the quoted spot minus the PV of cash dividends paid over the option’s life. This is the lognormal driver for the analytic and terminal-simulation engines.
Examples found in repository?
39fn main() {
40 common::title("DIVIDENDS AND BORROW COST — S=100 K=100 sigma=30% r=5% T=1y");
41
42 common::section("Continuous carry: dividend yield and borrow cost are interchangeable");
43 common::table_header();
44 common::row("no carry", &base().vanilla(PutOrCall::Call).build());
45 common::row("q = 4%", &base().dividend_yield(0.04).vanilla(PutOrCall::Call).build());
46 common::row("borrow = 4%", &base().borrow_cost(0.04).vanilla(PutOrCall::Call).build());
47 common::row(
48 "q = 1% + borrow = 3%",
49 &base().dividend_yield(0.01).borrow_cost(0.03).vanilla(PutOrCall::Call).build(),
50 );
51 common::note("carry_yield() = dividend_yield + borrow_cost enters every formula as 'q'");
52
53 let q_only = base().dividend_yield(0.04).vanilla(PutOrCall::Call).build();
54 let split = base().dividend_yield(0.01).borrow_cost(0.03).vanilla(PutOrCall::Call).build();
55 common::check("q=4% vs q=1%+b=3%", split.npv(), q_only.npv(), 1e-12);
56
57 common::section("Hard-to-borrow names: high borrow cost lowers the forward");
58 common::table_header();
59 for b in [0.0, 0.02, 0.05, 0.15] {
60 let option = base().borrow_cost(b).vanilla(PutOrCall::Call).build();
61 common::row(&format!("borrow = {:.0}%", b * 100.0), &option);
62 }
63 let hard = base().borrow_cost(0.15).vanilla(PutOrCall::Call).build();
64 println!(
65 " forward with 15% borrow: {:.4} (vs spot {SPOT})",
66 hard.base.forward_price()
67 );
68
69 common::section("Discrete cash dividends: 2 x 1.50 over the year");
70 let with_divs = |b: EquityOptionBuilder| {
71 b.cash_dividend(NaiveDate::from_ymd_opt(2026, 4, 1).unwrap(), 1.5)
72 .cash_dividend(NaiveDate::from_ymd_opt(2026, 10, 1).unwrap(), 1.5)
73 };
74 let analytic = with_divs(base()).vanilla(PutOrCall::Call).build();
75 println!(
76 " spot {SPOT} - PV(dividends) {:.6} = escrowed spot {:.6}",
77 analytic.base.pv_cash_dividends(),
78 analytic.base.effective_spot()
79 );
80 common::table_header();
81 common::row("Analytical (escrowed model)", &analytic);
82 common::row(
83 "Binomial (escrowed)",
84 &with_divs(base()).vanilla(PutOrCall::Call).engine(Engine::Binomial).build(),
85 );
86 common::row(
87 "Finite difference (jump model)",
88 &with_divs(base()).vanilla(PutOrCall::Call).engine(Engine::FiniteDifference).build(),
89 );
90 common::row(
91 "Monte Carlo terminal (escrowed)",
92 &with_divs(base()).vanilla(PutOrCall::Call).engine(Engine::MonteCarlo).build(),
93 );
94 common::row(
95 "Monte Carlo path-wise (jump model)",
96 &with_divs(base())
97 .vanilla(PutOrCall::Call)
98 .engine(Engine::MonteCarlo)
99 .mc_time_steps(200)
100 .paths(50_000)
101 .build(),
102 );
103 common::note("escrowed: lognormal on S - PV(divs); jump: dividends subtracted at each ex-date");
104 common::note("the two models differ slightly by construction — that gap is expected, not a bug");
105
106 common::check(
107 "escrowed analytic == BS on the escrowed spot",
108 analytic.npv(),
109 bs_price(analytic.base.effective_spot(), STRIKE, RATE, 0.0, VOL, 1.0, PutOrCall::Call),
110 1e-10,
111 );
112
113 common::section("Where the jump model matters: American exercise and barriers");
114 common::table_header();
115 common::row(
116 "American put, FD (jumps)",
117 &with_divs(base())
118 .american()
119 .vanilla(PutOrCall::Put)
120 .engine(Engine::FiniteDifference)
121 .build(),
122 );
123 common::row(
124 "American put, no dividends",
125 &base().american().vanilla(PutOrCall::Put).engine(Engine::FiniteDifference).build(),
126 );
127 common::row(
128 "Down-and-out call H=85, MC (jumps)",
129 &with_divs(base())
130 .barrier(PutOrCall::Call, BarrierDirection::Down, KnockType::Out, 85.0)
131 .engine(Engine::MonteCarlo)
132 .paths(50_000)
133 .build(),
134 );
135 common::row(
136 "Down-and-out call H=85, no dividends",
137 &base()
138 .barrier(PutOrCall::Call, BarrierDirection::Down, KnockType::Out, 85.0)
139 .engine(Engine::MonteCarlo)
140 .paths(50_000)
141 .build(),
142 );
143 common::note("dividend drops push the path toward a down barrier and change exercise timing");
144
145 common::section("Put-call parity with full carry");
146 let call = with_divs(base()).borrow_cost(0.02).vanilla(PutOrCall::Call).build();
147 let put = with_divs(base()).borrow_cost(0.02).vanilla(PutOrCall::Put).build();
148 let parity = call.base.effective_spot() * (-call.base.carry_yield() * 1.0_f64).exp()
149 - STRIKE * (-RATE * 1.0_f64).exp();
150 common::check("C - P = S_eff e^{-(q+b)T} - K e^{-rT}", call.npv() - put.npv(), parity, 1e-10);
151 println!();
152}Sourcepub fn forward_price(&self) -> f64
pub fn forward_price(&self) -> f64
Forward price of the underlying at maturity: escrowed spot grown at
the carry-adjusted rate, (S - PV(divs)) * exp((r - q - b) * T).
Examples found in repository?
39fn main() {
40 common::title("DIVIDENDS AND BORROW COST — S=100 K=100 sigma=30% r=5% T=1y");
41
42 common::section("Continuous carry: dividend yield and borrow cost are interchangeable");
43 common::table_header();
44 common::row("no carry", &base().vanilla(PutOrCall::Call).build());
45 common::row("q = 4%", &base().dividend_yield(0.04).vanilla(PutOrCall::Call).build());
46 common::row("borrow = 4%", &base().borrow_cost(0.04).vanilla(PutOrCall::Call).build());
47 common::row(
48 "q = 1% + borrow = 3%",
49 &base().dividend_yield(0.01).borrow_cost(0.03).vanilla(PutOrCall::Call).build(),
50 );
51 common::note("carry_yield() = dividend_yield + borrow_cost enters every formula as 'q'");
52
53 let q_only = base().dividend_yield(0.04).vanilla(PutOrCall::Call).build();
54 let split = base().dividend_yield(0.01).borrow_cost(0.03).vanilla(PutOrCall::Call).build();
55 common::check("q=4% vs q=1%+b=3%", split.npv(), q_only.npv(), 1e-12);
56
57 common::section("Hard-to-borrow names: high borrow cost lowers the forward");
58 common::table_header();
59 for b in [0.0, 0.02, 0.05, 0.15] {
60 let option = base().borrow_cost(b).vanilla(PutOrCall::Call).build();
61 common::row(&format!("borrow = {:.0}%", b * 100.0), &option);
62 }
63 let hard = base().borrow_cost(0.15).vanilla(PutOrCall::Call).build();
64 println!(
65 " forward with 15% borrow: {:.4} (vs spot {SPOT})",
66 hard.base.forward_price()
67 );
68
69 common::section("Discrete cash dividends: 2 x 1.50 over the year");
70 let with_divs = |b: EquityOptionBuilder| {
71 b.cash_dividend(NaiveDate::from_ymd_opt(2026, 4, 1).unwrap(), 1.5)
72 .cash_dividend(NaiveDate::from_ymd_opt(2026, 10, 1).unwrap(), 1.5)
73 };
74 let analytic = with_divs(base()).vanilla(PutOrCall::Call).build();
75 println!(
76 " spot {SPOT} - PV(dividends) {:.6} = escrowed spot {:.6}",
77 analytic.base.pv_cash_dividends(),
78 analytic.base.effective_spot()
79 );
80 common::table_header();
81 common::row("Analytical (escrowed model)", &analytic);
82 common::row(
83 "Binomial (escrowed)",
84 &with_divs(base()).vanilla(PutOrCall::Call).engine(Engine::Binomial).build(),
85 );
86 common::row(
87 "Finite difference (jump model)",
88 &with_divs(base()).vanilla(PutOrCall::Call).engine(Engine::FiniteDifference).build(),
89 );
90 common::row(
91 "Monte Carlo terminal (escrowed)",
92 &with_divs(base()).vanilla(PutOrCall::Call).engine(Engine::MonteCarlo).build(),
93 );
94 common::row(
95 "Monte Carlo path-wise (jump model)",
96 &with_divs(base())
97 .vanilla(PutOrCall::Call)
98 .engine(Engine::MonteCarlo)
99 .mc_time_steps(200)
100 .paths(50_000)
101 .build(),
102 );
103 common::note("escrowed: lognormal on S - PV(divs); jump: dividends subtracted at each ex-date");
104 common::note("the two models differ slightly by construction — that gap is expected, not a bug");
105
106 common::check(
107 "escrowed analytic == BS on the escrowed spot",
108 analytic.npv(),
109 bs_price(analytic.base.effective_spot(), STRIKE, RATE, 0.0, VOL, 1.0, PutOrCall::Call),
110 1e-10,
111 );
112
113 common::section("Where the jump model matters: American exercise and barriers");
114 common::table_header();
115 common::row(
116 "American put, FD (jumps)",
117 &with_divs(base())
118 .american()
119 .vanilla(PutOrCall::Put)
120 .engine(Engine::FiniteDifference)
121 .build(),
122 );
123 common::row(
124 "American put, no dividends",
125 &base().american().vanilla(PutOrCall::Put).engine(Engine::FiniteDifference).build(),
126 );
127 common::row(
128 "Down-and-out call H=85, MC (jumps)",
129 &with_divs(base())
130 .barrier(PutOrCall::Call, BarrierDirection::Down, KnockType::Out, 85.0)
131 .engine(Engine::MonteCarlo)
132 .paths(50_000)
133 .build(),
134 );
135 common::row(
136 "Down-and-out call H=85, no dividends",
137 &base()
138 .barrier(PutOrCall::Call, BarrierDirection::Down, KnockType::Out, 85.0)
139 .engine(Engine::MonteCarlo)
140 .paths(50_000)
141 .build(),
142 );
143 common::note("dividend drops push the path toward a down barrier and change exercise timing");
144
145 common::section("Put-call parity with full carry");
146 let call = with_divs(base()).borrow_cost(0.02).vanilla(PutOrCall::Call).build();
147 let put = with_divs(base()).borrow_cost(0.02).vanilla(PutOrCall::Put).build();
148 let parity = call.base.effective_spot() * (-call.base.carry_yield() * 1.0_f64).exp()
149 - STRIKE * (-RATE * 1.0_f64).exp();
150 common::check("C - P = S_eff e^{-(q+b)T} - K e^{-rT}", call.npv() - put.npv(), parity, 1e-10);
151 println!();
152}Sourcepub fn volatility(&self) -> f64
pub fn volatility(&self) -> f64
Black volatility for this option’s strike and expiry, read off the surface (a flat surface returns its single vol).