5 * Elliot Lee <sopwith@redhat.com> All initial work.
6 * Morten Welinder <terra@gnome.org> Port to new plugin framework.
8 * Hal Ashburner <hal_ashburner@yahoo.co.uk>
9 * Black Scholes Code re-structure, optional asset leakage paramaters,
10 * American approximations, alternative models to Black-Scholes
11 * and All exotic Options Functions.
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, see <https://www.gnu.org/licenses/>.
26 #include <gnumeric-config.h>
29 #include <goffice/goffice.h>
30 #include <gnm-plugin.h>
41 GNM_PLUGIN_MODULE_HEADER
;
43 /* Some common decriptors */
44 #define DEF_ARG_CALL_PUT_FLAG { GNM_FUNC_HELP_ARG, F_("call_put_flag:'c' for a call and 'p' for a put") }
45 #define DEF_ARG_SPOT { GNM_FUNC_HELP_ARG, F_("spot:spot price") }
46 #define DEF_ARG_STRIKE { GNM_FUNC_HELP_ARG, F_("strike:strike price") }
47 #define DEF_ARG_TIME_MATURITY_Y { GNM_FUNC_HELP_ARG, F_("time:time to maturity in years") }
48 #define DEF_ARG_TIME_MATURITY_D { GNM_FUNC_HELP_ARG, F_("time:time to maturity in days") }
49 #define DEF_ARG_TIME_DIVIDEND { GNM_FUNC_HELP_ARG, F_("time_payout:time to dividend payout") }
50 #define DEF_ARG_TIME_EXPIRATION { GNM_FUNC_HELP_ARG, F_("time_exp:time to expiration") }
51 #define DEF_ARG_RATE_RISKFREE { GNM_FUNC_HELP_ARG, F_("rate:risk-free interest rate to the exercise date in percent") }
52 #define DEF_ARG_RATE_ANNUALIZED { GNM_FUNC_HELP_ARG, F_("rate:annualized interest rate") }
53 #define DEF_ARG_RATE_RISKFREE_ANN { GNM_FUNC_HELP_ARG, F_("rate:annualized risk-free interest rate") }
54 #define DEF_ARG_VOLATILITY { GNM_FUNC_HELP_ARG, F_("volatility:annualized volatility of the asset in percent for the period through to the exercise date") }
55 #define DEF_ARG_VOLATILITY_SHORT { GNM_FUNC_HELP_ARG, F_("volatility:annualized volatility of the asset") }
56 #define DEF_ARG_AMOUNT { GNM_FUNC_HELP_ARG, F_("d:amount of the dividend to be paid expressed in currency") }
57 #define DEF_ARG_CC_OPT { GNM_FUNC_HELP_ARG, F_("cost_of_carry:net cost of holding the underlying asset (for common stocks, the risk free rate less the dividend yield), defaults to 0") }
58 #define DEF_ARG_CC { GNM_FUNC_HELP_ARG, F_("cost_of_carry:net cost of holding the underlying asset") }
60 #define DEF_NOTE_UNITS { GNM_FUNC_HELP_NOTE, F_("The returned value will be expressed in the same units as @{strike} and @{spot}.")}
75 static gnm_float
opt_baw_call (gnm_float s
, gnm_float x
, gnm_float t
, gnm_float r
, gnm_float b
, gnm_float v
);
76 static gnm_float
opt_baw_put (gnm_float s
, gnm_float x
, gnm_float t
, gnm_float r
, gnm_float b
, gnm_float v
);
77 static gnm_float
NRA_c (gnm_float x
, gnm_float t
, gnm_float r
, gnm_float b
, gnm_float v
);
78 static gnm_float
NRA_p (gnm_float x
, gnm_float t
, gnm_float r
, gnm_float b
, gnm_float v
);
79 static gnm_float
opt_bjer_stens1_c (gnm_float s
, gnm_float x
, gnm_float t
, gnm_float r
, gnm_float b
, gnm_float v
);
80 /* static gnm_float opt_bjer_stens1_p (gnm_float s, gnm_float x, gnm_float t, gnm_float r, gnm_float b, gnm_float v); */
81 static gnm_float
phi (gnm_float s
, gnm_float t
, gnm_float gamma
, gnm_float H
, gnm_float I
, gnm_float r
, gnm_float b
, gnm_float v
);
82 static gnm_float
CriticalValueOptionsOnOptions (OptionSide side
, gnm_float x1
, gnm_float x2
, gnm_float t
,
83 gnm_float r
, gnm_float b
, gnm_float v
);
84 static gnm_float
opt_crit_val_chooser (gnm_float s
,gnm_float xc
,gnm_float xp
,gnm_float t
,
85 gnm_float tc
, gnm_float tp
, gnm_float r
, gnm_float b
, gnm_float v
);
89 option_side (char const *s
)
91 if (s
[0] == 'p' || s
[0] == 'P')
93 else if (s
[0] == 'c' || s
[0] == 'C')
100 option_type (char const *s
)
102 if (s
[0] == 'a' || s
[0] == 'A')
104 else if (s
[0] == 'e' || s
[0] == 'E')
110 /* The normal distribution function */
114 return pnorm (x
, 0.0, 1.0, TRUE
, FALSE
);
120 return dnorm (x
, 0.0, 1.0, FALSE
);
134 /* The cumulative bivariate normal distribution function */
136 cum_biv_norm_dist1 (gnm_float a
, gnm_float b
, gnm_float rho
)
138 gnm_float rho1
, rho2
, delta
;
139 gnm_float a1
, b1
, sum
= 0.0;
142 static const gnm_float x
[] = {0.24840615, 0.39233107, 0.21141819, 0.03324666, 0.00082485334};
143 static const gnm_float y
[] = {0.10024215, 0.48281397, 1.0609498, 1.7797294, 2.6697604};
144 a1
= a
/ gnm_sqrt (2.0 * (1 - (rho
* rho
)));
145 b1
= b
/ gnm_sqrt (2.0 * (1 - (rho
* rho
)));
147 if (a
<= 0 && b
<= 0 && rho
<= 0) {
148 for (i
= 0; i
!= 5; ++i
) {
149 for (j
= 0; j
!= 5; ++j
) {
150 sum
= sum
+ x
[i
] * x
[j
] * gnm_exp (a1
* (2.0 * y
[i
] - a1
) + b1
* (2.0 *
151 y
[j
] - b1
) + 2 * rho
* (y
[i
] - a1
) * (y
[j
] - b1
));
154 return gnm_sqrt (1.0 - (rho
* rho
)) / M_PIgnum
* sum
;
155 } else if (a
<= 0 && b
>= 0 && rho
>= 0)
156 return ncdf (a
) - cum_biv_norm_dist1 (a
,-b
,-rho
);
157 else if (a
>= 0 && b
<= 0 && rho
>= 0)
158 return ncdf (b
) - cum_biv_norm_dist1 (-a
,b
,-rho
);
159 else if (a
>= 0 && b
>= 0 && rho
<= 0)
160 return ncdf (a
) + ncdf (b
) - 1.0 + cum_biv_norm_dist1 (-a
,-b
,rho
);
161 else if ((a
* b
* rho
) > 0) {
162 rho1
= (rho
* a
- b
) * Sgn (a
) / gnm_sqrt ((a
* a
) - 2 * rho
* a
164 rho2
= (rho
* b
- a
) * Sgn (b
) / gnm_sqrt ((a
* a
) - 2 * rho
* a
166 delta
= (1.0 - Sgn (a
) * Sgn (b
)) / 4.0;
167 return (cum_biv_norm_dist1 (a
,0.0,rho1
) +
168 cum_biv_norm_dist1 (b
,0.0,rho2
) -
176 cum_biv_norm_dist(GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
178 gnm_float a
= value_get_as_float (argv
[0]);
179 gnm_float b
= value_get_as_float (argv
[1]);
180 gnm_float rho
= value_get_as_float (argv
[2]);
181 gnm_float result
= cum_biv_norm_dist1 (a
,b
,rho
);
183 if (gnm_isnan (result
))
184 return value_new_error_NUM (ei
->pos
);
186 return value_new_float (result
);
189 static GnmFuncHelp
const help_cum_biv_norm_dist
[] = {
190 { GNM_FUNC_HELP_NAME
, F_("CUM_BIV_NORM_DIST:cumulative bivariate normal distribution")},
191 { GNM_FUNC_HELP_ARG
, F_("a:limit for first random variable")},
192 { GNM_FUNC_HELP_ARG
, F_("b:limit for second random variable")},
193 { GNM_FUNC_HELP_ARG
, F_("rho:correlation of the two random variables")},
194 { GNM_FUNC_HELP_DESCRIPTION
, F_("CUM_BIV_NORM_DIST calculates the probability that two standard "
195 "normal distributed random variables with correlation @{rho} are "
196 "respectively each less than @{a} and @{b}.")},
197 { GNM_FUNC_HELP_EXAMPLES
, "=CUM_BIV_NORM_DIST(0,0,0.5)" },
203 /* the generalized Black and Scholes formula*/
205 opt_bs1 (OptionSide side
,
206 gnm_float s
, gnm_float x
, gnm_float t
, gnm_float r
, gnm_float v
,
209 gnm_float d1
= (gnm_log (s
/ x
) + (b
+ (v
* v
) / 2.0) * t
) / (v
* gnm_sqrt (t
));
210 gnm_float d2
= d1
- v
* gnm_sqrt (t
);
214 return (s
* gnm_exp ((b
- r
) * t
) * ncdf (d1
) -
215 x
* gnm_exp (-r
* t
) * ncdf (d2
));
217 return (x
* gnm_exp (-r
* t
) * ncdf (-d2
) -
218 s
* gnm_exp ((b
- r
) * t
) * ncdf (-d1
));
226 opt_bs (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
228 OptionSide call_put
= option_side (value_peek_string (argv
[0]));
229 gnm_float s
= value_get_as_float (argv
[1]);
230 gnm_float x
= value_get_as_float (argv
[2]);
231 gnm_float t
= value_get_as_float (argv
[3]);
232 gnm_float r
= value_get_as_float (argv
[4]);
233 gnm_float v
= value_get_as_float (argv
[5]);
234 gnm_float b
= argv
[6] ? value_get_as_float (argv
[6]) : 0;
235 gnm_float gfresult
= opt_bs1 (call_put
, s
, x
, t
, r
, v
, b
);
237 if (gnm_isnan (gfresult
))
238 return value_new_error_NUM (ei
->pos
);
239 return value_new_float (gfresult
);
242 static GnmFuncHelp
const help_opt_bs
[] = {
243 { GNM_FUNC_HELP_NAME
, F_("OPT_BS:price of a European option")},
244 DEF_ARG_CALL_PUT_FLAG
,
247 DEF_ARG_TIME_MATURITY_Y
,
248 DEF_ARG_RATE_RISKFREE
,
251 { GNM_FUNC_HELP_DESCRIPTION
, F_("OPT_BS uses the Black-Scholes model to calculate "
252 "the price of a European option struck at @{strike} "
253 "on an asset with spot price @{spot}.")},
255 { GNM_FUNC_HELP_SEEALSO
, "OPT_BS_DELTA,OPT_BS_RHO,OPT_BS_THETA,OPT_BS_VEGA,OPT_BS_GAMMA"},
259 /* Delta for the generalized Black and Scholes formula */
261 opt_bs_delta1 (OptionSide side
,
262 gnm_float s
, gnm_float x
, gnm_float t
, gnm_float r
, gnm_float v
, gnm_float b
)
265 (gnm_log (s
/ x
) + (b
+ (v
* v
) / 2.0) * t
) /
270 return gnm_exp ((b
- r
) * t
) * ncdf (d1
);
273 return gnm_exp ((b
- r
) * t
) * (ncdf (d1
) - 1.0);
282 opt_bs_delta (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
284 OptionSide call_put
= option_side (value_peek_string (argv
[0]));
285 gnm_float s
= value_get_as_float (argv
[1]);
286 gnm_float x
= value_get_as_float (argv
[2]);
287 gnm_float t
= value_get_as_float (argv
[3]);
288 gnm_float r
= value_get_as_float (argv
[4]);
289 gnm_float v
= value_get_as_float (argv
[5]);
290 gnm_float b
= argv
[6] ? value_get_as_float (argv
[6]) : 0.0;
291 gnm_float gfresult
= opt_bs_delta1 (call_put
, s
, x
, t
, r
, v
, b
);
293 if (gnm_isnan (gfresult
))
294 return value_new_error_NUM (ei
->pos
);
296 return value_new_float (gfresult
);
299 static GnmFuncHelp
const help_opt_bs_delta
[] = {
300 { GNM_FUNC_HELP_NAME
, F_("OPT_BS_DELTA:delta of a European option")},
301 DEF_ARG_CALL_PUT_FLAG
,
304 DEF_ARG_TIME_MATURITY_Y
,
305 DEF_ARG_RATE_RISKFREE
,
308 { GNM_FUNC_HELP_DESCRIPTION
, F_("OPT_BS_DELTA uses the Black-Scholes model to calculate "
309 "the 'delta' of a European option struck at @{strike} "
310 "on an asset with spot price @{spot}.")},
312 { GNM_FUNC_HELP_SEEALSO
, "OPT_BS,OPT_BS_RHO,OPT_BS_THETA,OPT_BS_VEGA,OPT_BS_GAMMA"},
317 /* Gamma for the generalized Black and Scholes formula */
319 opt_bs_gamma1 (gnm_float s
,gnm_float x
,gnm_float t
,gnm_float r
,gnm_float v
,gnm_float b
)
323 d1
= (gnm_log (s
/ x
) + (b
+ (v
* v
) / 2.0) * t
) / (v
* gnm_sqrt (t
));
324 return gnm_exp ((b
- r
) * t
) * npdf (d1
) / (s
* v
* gnm_sqrt (t
));
329 opt_bs_gamma (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
331 gnm_float s
= value_get_as_float (argv
[0]);
332 gnm_float x
= value_get_as_float (argv
[1]);
333 gnm_float t
= value_get_as_float (argv
[2]);
334 gnm_float r
= value_get_as_float (argv
[3]);
335 gnm_float v
= value_get_as_float (argv
[4]);
336 gnm_float b
= argv
[5] ? value_get_as_float (argv
[5]) : 0.0;
337 gnm_float gfresult
= opt_bs_gamma1 (s
,x
,t
,r
,v
,b
);
338 return value_new_float (gfresult
);
341 static GnmFuncHelp
const help_opt_bs_gamma
[] = {
342 { GNM_FUNC_HELP_NAME
, F_("OPT_BS_GAMMA:gamma of a European option")},
345 DEF_ARG_TIME_MATURITY_Y
,
346 DEF_ARG_RATE_RISKFREE
,
349 { GNM_FUNC_HELP_DESCRIPTION
, F_("OPT_BS_GAMMA uses the Black-Scholes model to calculate "
350 "the 'gamma' of a European option struck at @{strike} "
351 "on an asset with spot price @{spot}. The gamma of an "
352 "option is the second derivative of its price "
353 "with respect to the price of the underlying asset.")},
354 { GNM_FUNC_HELP_NOTE
, F_("Gamma is expressed as the rate of change "
355 "of delta per unit change in @{spot}.")},
356 { GNM_FUNC_HELP_NOTE
, F_("Gamma is the same for calls and puts.")},
357 { GNM_FUNC_HELP_SEEALSO
, "OPT_BS,OPT_BS_DELTA,OPT_BS_RHO,OPT_BS_THETA,OPT_BS_VEGA"},
361 /* theta for the generalized Black and Scholes formula */
363 opt_bs_theta1 (OptionSide side
,
364 gnm_float s
,gnm_float x
,gnm_float t
,gnm_float r
,gnm_float v
,gnm_float b
)
366 gnm_float d1
= (gnm_log (s
/ x
) + (b
+ (v
* v
) / 2.0) * t
) / (v
* gnm_sqrt (t
));
367 gnm_float d2
= d1
- v
* gnm_sqrt (t
);
371 return -s
* gnm_exp ((b
- r
) * t
) * npdf (d1
) * v
/ (2.0 * gnm_sqrt (t
)) -
372 (b
- r
) * s
* gnm_exp ((b
- r
) * t
) * ncdf (d1
) - r
* x
* gnm_exp (-r
* t
) * ncdf (d2
);
374 return -s
* gnm_exp ((b
- r
) * t
) * npdf (d1
) * v
/ (2.0 * gnm_sqrt (t
)) +
375 (b
- r
) * s
* gnm_exp ((b
- r
) * t
) * ncdf (-d1
) + r
* x
* gnm_exp (-r
* t
) * ncdf (-d2
);
382 opt_bs_theta (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
384 OptionSide call_put
= option_side (value_peek_string (argv
[0]));
385 gnm_float s
= value_get_as_float (argv
[1]);
386 gnm_float x
= value_get_as_float (argv
[2]);
387 gnm_float t
= value_get_as_float (argv
[3]);
388 gnm_float r
= value_get_as_float (argv
[4]);
389 gnm_float v
= value_get_as_float (argv
[5]);
390 gnm_float b
= argv
[6] ? value_get_as_float (argv
[6]) : 0.0;
391 gnm_float gfresult
= opt_bs_theta1 (call_put
, s
, x
, t
, r
, v
, b
);
393 if (gnm_isnan (gfresult
))
394 return value_new_error_NUM (ei
->pos
);
395 return value_new_float (gfresult
);
398 static GnmFuncHelp
const help_opt_bs_theta
[] = {
399 { GNM_FUNC_HELP_NAME
, F_("OPT_BS_THETA:theta of a European option")},
400 DEF_ARG_CALL_PUT_FLAG
,
403 DEF_ARG_TIME_MATURITY_Y
,
404 DEF_ARG_RATE_RISKFREE
,
407 { GNM_FUNC_HELP_DESCRIPTION
, F_("OPT_BS_THETA uses the Black-Scholes model to calculate "
408 "the 'theta' of a European option struck at @{strike} "
409 "on an asset with spot price @{spot}. The theta of an "
410 "option is the rate of change of its price with "
411 "respect to time to expiry.")},
412 { GNM_FUNC_HELP_NOTE
, F_("Theta is expressed as the negative of the rate of change "
413 "of the option value, per 365.25 days.")},
414 { GNM_FUNC_HELP_SEEALSO
, "OPT_BS,OPT_BS_DELTA,OPT_BS_RHO,OPT_BS_VEGA,OPT_BS_GAMMA"},
419 /* Vega for the generalized Black and Scholes formula */
421 opt_bs_vega1 (gnm_float s
, gnm_float x
, gnm_float t
,
422 gnm_float r
, gnm_float v
, gnm_float b
)
424 gnm_float d1
= (gnm_log (s
/ x
) + (b
+ (v
* v
) / 2.0) * t
) /
426 return s
* gnm_exp ((b
- r
) * t
) * npdf (d1
) * gnm_sqrt (t
);
430 opt_bs_vega (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
432 gnm_float s
= value_get_as_float (argv
[0]);
433 gnm_float x
= value_get_as_float (argv
[1]);
434 gnm_float t
= value_get_as_float (argv
[2]);
435 gnm_float r
= value_get_as_float (argv
[3]);
436 gnm_float v
= value_get_as_float (argv
[4]);
437 gnm_float b
= argv
[5] ? value_get_as_float (argv
[5]) : 0.0;
439 return value_new_float (opt_bs_vega1 (s
, x
, t
, r
, v
, b
));
442 static GnmFuncHelp
const help_opt_bs_vega
[] = {
443 { GNM_FUNC_HELP_NAME
, F_("OPT_BS_VEGA:vega of a European option")},
446 DEF_ARG_TIME_MATURITY_Y
,
447 DEF_ARG_RATE_RISKFREE
,
450 { GNM_FUNC_HELP_DESCRIPTION
, F_("OPT_BS_VEGA uses the Black-Scholes model to calculate "
451 "the 'vega' of a European option struck at @{strike} "
452 "on an asset with spot price @{spot}. The vega of an "
453 "option is the rate of change of its price with "
454 "respect to volatility.")},
455 { GNM_FUNC_HELP_NOTE
, F_("Vega is the same for calls and puts.")},
456 /* xgettext:no-c-format */
457 { GNM_FUNC_HELP_NOTE
, F_("Vega is expressed as the rate of change "
458 "of option value, per 100% volatility.")},
459 { GNM_FUNC_HELP_SEEALSO
, "OPT_BS,OPT_BS_DELTA,OPT_BS_RHO,OPT_BS_THETA,OPT_BS_GAMMA"},
464 /* Rho for the generalized Black and Scholes formula */
466 opt_bs_rho1 (OptionSide side
, gnm_float s
, gnm_float x
,
467 gnm_float t
, gnm_float r
, gnm_float v
, gnm_float b
)
469 gnm_float d1
= (gnm_log (s
/ x
) + (b
+ (v
* v
) / 2.0) * t
) / (v
* gnm_sqrt (t
));
470 gnm_float d2
= d1
- v
* gnm_sqrt (t
);
474 return t
* x
* gnm_exp (-r
* t
) * ncdf (d2
);
476 return -t
* opt_bs1 (side
, s
, x
, t
, r
, v
, b
);
480 return -t
* x
* gnm_exp (-r
* t
) * ncdf (-d2
);
482 return -t
* opt_bs1 (side
, s
, x
, t
, r
, v
, b
);
491 opt_bs_rho (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
493 OptionSide call_put
= option_side (value_peek_string (argv
[0]));
494 gnm_float s
= value_get_as_float (argv
[1]);
495 gnm_float x
= value_get_as_float (argv
[2]);
496 gnm_float t
= value_get_as_float (argv
[3]);
497 gnm_float r
= value_get_as_float (argv
[4]);
498 gnm_float v
= value_get_as_float (argv
[5]);
499 gnm_float b
= argv
[6] ? value_get_as_float (argv
[6]) : 0.0;
500 gnm_float gfresult
= opt_bs_rho1 (call_put
, s
, x
, t
, r
, v
, b
);
502 if (gnm_isnan (gfresult
))
503 return value_new_error_NUM (ei
->pos
);
504 return value_new_float (gfresult
);
507 static GnmFuncHelp
const help_opt_bs_rho
[] = {
508 { GNM_FUNC_HELP_NAME
, F_("OPT_BS_RHO:rho of a European option")},
509 DEF_ARG_CALL_PUT_FLAG
,
512 DEF_ARG_TIME_MATURITY_Y
,
513 DEF_ARG_RATE_RISKFREE
,
516 { GNM_FUNC_HELP_DESCRIPTION
, F_("OPT_BS_RHO uses the Black-Scholes model to calculate "
517 "the 'rho' of a European option struck at @{strike} "
518 "on an asset with spot price @{spot}. The rho of an "
519 "option is the rate of change of its price with "
520 "respect to the risk free interest rate.")},
521 /* xgettext:no-c-format */
522 { GNM_FUNC_HELP_NOTE
, F_("Rho is expressed as the rate of change "
523 "of the option value, per 100% change in @{rate}.")},
524 { GNM_FUNC_HELP_SEEALSO
, "OPT_BS,OPT_BS_DELTA,OPT_BS_THETA,OPT_BS_VEGA,OPT_BS_GAMMA"},
528 /* Carry for the generalized Black and Scholes formula */
530 opt_bs_carrycost1 (OptionSide side
, gnm_float s
, gnm_float x
, gnm_float t
, gnm_float r
, gnm_float v
, gnm_float b
)
532 gnm_float d1
= (gnm_log (s
/ x
) + (b
+ (v
* v
) / 2.0) * t
) /
537 return t
* s
* gnm_exp ((b
- r
) * t
) * ncdf (d1
);
539 return -t
* s
* gnm_exp ((b
- r
) * t
) * ncdf (-d1
);
541 return gnm_nan
; /*should never get to here*/
546 opt_bs_carrycost (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
548 OptionSide call_put
= option_side (value_peek_string (argv
[0]));
549 gnm_float s
= value_get_as_float (argv
[1]);
550 gnm_float x
= value_get_as_float (argv
[2]);
551 gnm_float t
= value_get_as_float (argv
[3]);
552 gnm_float r
= value_get_as_float (argv
[4]);
553 gnm_float v
= value_get_as_float (argv
[5]);
554 gnm_float b
= argv
[6] ? value_get_as_float (argv
[6]) : 0.0;
555 gnm_float gfresult
= opt_bs_carrycost1 (call_put
, s
, x
, t
, r
, v
, b
);
557 if (gnm_isnan (gfresult
))
558 return value_new_error_NUM (ei
->pos
);
559 return value_new_float (gfresult
);
563 static GnmFuncHelp
const help_opt_bs_carrycost
[] = {
564 { GNM_FUNC_HELP_NAME
, F_("OPT_BS_CARRYCOST:elasticity of a European option")},
565 DEF_ARG_CALL_PUT_FLAG
,
568 DEF_ARG_TIME_MATURITY_Y
,
569 DEF_ARG_RATE_RISKFREE
,
572 { GNM_FUNC_HELP_DESCRIPTION
, F_("OPT_BS_CARRYCOST uses the Black-Scholes model to calculate "
573 "the 'elasticity' of a European option struck at @{strike} "
574 "on an asset with spot price @{spot}. The elasticity of an option "
575 "is the rate of change of its price "
576 "with respect to its @{cost_of_carry}.")},
577 /* xgettext:no-c-format */
578 { GNM_FUNC_HELP_NOTE
, F_("Elasticity is expressed as the rate of change "
579 "of the option value, per 100% volatility.")},
580 { GNM_FUNC_HELP_SEEALSO
, "OPT_BS,OPT_BS_DELTA,OPT_BS_RHO,OPT_BS_THETA,OPT_BS_GAMMA"},
585 /* Currency Options - Garman and Kohlhagen */
587 opt_garman_kohlhagen1 (OptionSide side
,
588 gnm_float s
, gnm_float x
, gnm_float t
,
589 gnm_float r
, gnm_float rf
, gnm_float v
)
591 gnm_float d1
= (gnm_log (s
/ x
) + (r
- rf
+ (v
* v
) / 2.0) * t
) / (v
* gnm_sqrt (t
));
592 gnm_float d2
= d1
- v
* gnm_sqrt (t
);
595 return s
* gnm_exp (-rf
* t
) * ncdf (d1
) - x
* gnm_exp (-r
* t
) * ncdf (d2
);
597 return x
* gnm_exp (-r
* t
) * ncdf (-d2
) - s
* gnm_exp (-rf
* t
) * ncdf (-d1
);
599 return gnm_nan
; /*should never get to here*/
604 opt_garman_kohlhagen (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
606 OptionSide call_put
= option_side (value_peek_string (argv
[0]));
607 gnm_float s
= value_get_as_float (argv
[1]);
608 gnm_float x
= value_get_as_float (argv
[2]);
609 gnm_float t
= value_get_as_float (argv
[3]);
610 gnm_float r
= value_get_as_float (argv
[4]);
611 gnm_float rf
= value_get_as_float (argv
[5]);
612 gnm_float v
= value_get_as_float (argv
[6]);
613 gnm_float gfresult
= opt_garman_kohlhagen1 (call_put
, s
, x
, t
, r
, rf
, v
);
615 if (gnm_isnan (gfresult
))
616 return value_new_error_NUM (ei
->pos
);
618 return value_new_float (gfresult
);
621 static GnmFuncHelp
const help_opt_garman_kohlhagen
[] = {
622 { GNM_FUNC_HELP_NAME
, F_("OPT_GARMAN_KOHLHAGEN:theoretical price of a European currency option")},
623 DEF_ARG_CALL_PUT_FLAG
,
626 { GNM_FUNC_HELP_ARG
, F_("time:number of days to exercise")},
627 { GNM_FUNC_HELP_ARG
, F_("domestic_rate:domestic risk-free interest rate to the exercise date in percent")},
628 { GNM_FUNC_HELP_ARG
, F_("foreign_rate:foreign risk-free interest rate to the exercise date in percent")},
630 { GNM_FUNC_HELP_DESCRIPTION
, F_("OPT_GARMAN_KOHLHAGEN values the theoretical price of a European "
631 "currency option struck at @{strike} on an asset with spot price @{spot}.")},
632 { GNM_FUNC_HELP_SEEALSO
, "OPT_BS,OPT_BS_DELTA,OPT_BS_RHO,OPT_BS_THETA,OPT_BS_GAMMA"},
637 /* French (1984) adjusted Black and scholes model for trading day volatility */
639 opt_french1 (OptionSide side
, gnm_float s
, gnm_float x
, gnm_float tradingt
, gnm_float calendart
,
640 gnm_float r
, gnm_float v
, gnm_float b
)
642 gnm_float d1
= (gnm_log (s
/ x
) + b
* calendart
+ ((v
* v
) / 2.0) * tradingt
) / (v
* gnm_sqrt (tradingt
));
643 gnm_float d2
= d1
- v
* gnm_sqrt (tradingt
);
647 return s
* gnm_exp ((b
- r
) * calendart
) * ncdf (d1
) - x
* gnm_exp (-r
* calendart
) * ncdf (d2
);
649 return x
* gnm_exp (-r
* calendart
) * ncdf (-d2
) - s
* gnm_exp ((b
- r
) * calendart
) * ncdf (-d1
);
657 opt_french (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
659 OptionSide call_put
= option_side (value_peek_string (argv
[0]));
660 gnm_float s
= value_get_as_float (argv
[1]);
661 gnm_float x
= value_get_as_float (argv
[2]);
662 gnm_float t
= value_get_as_float (argv
[3]);
663 gnm_float t1
= value_get_as_float (argv
[4]);
664 gnm_float r
= value_get_as_float (argv
[5]);
665 gnm_float v
= value_get_as_float (argv
[6]);
666 gnm_float b
= value_get_as_float (argv
[7]);
667 gnm_float gfresult
= opt_french1 (call_put
, s
, x
, t
, t1
, r
, v
, b
);
669 if (gnm_isnan (gfresult
))
670 return value_new_error_NUM (ei
->pos
);
672 return value_new_float (gfresult
);
675 static GnmFuncHelp
const help_opt_french
[] = {
676 { GNM_FUNC_HELP_NAME
, F_("OPT_FRENCH:theoretical price of a European option adjusted for trading day volatility")},
677 DEF_ARG_CALL_PUT_FLAG
,
680 { GNM_FUNC_HELP_ARG
, F_("time:ratio of the number of calendar days to exercise and the number of calendar days in the year")},
681 { GNM_FUNC_HELP_ARG
, F_("ttime:ratio of the number of trading days to exercise and the number of trading days in the year")},
682 DEF_ARG_RATE_RISKFREE
,
685 { GNM_FUNC_HELP_DESCRIPTION
, F_("OPT_FRENCH values the theoretical price of a "
686 "European option adjusted for trading day volatility, struck at "
687 "@{strike} on an asset with spot price @{spot}.")},
688 { GNM_FUNC_HELP_SEEALSO
, "OPT_BS,OPT_BS_DELTA,OPT_BS_RHO,OPT_BS_THETA,OPT_BS_GAMMA"},
692 /* Merton jump diffusion model*/
694 opt_jump_diff1 (OptionSide side
, gnm_float s
, gnm_float x
, gnm_float t
, gnm_float r
, gnm_float v
,
695 gnm_float lambda
, gnm_float gamma
)
697 gnm_float delta
, sum
;
701 delta
= gnm_sqrt (gamma
* (v
* v
) / lambda
);
702 Z
= gnm_sqrt ((v
* v
) - lambda
* (delta
* delta
));
704 for (i
= 0; i
!= 11; ++i
) {
705 vi
= gnm_sqrt ((Z
* Z
) + (delta
* delta
) * (i
/ t
));
706 sum
= sum
+ gnm_exp (-lambda
* t
) * gnm_pow (lambda
* t
, i
) / gnm_fact(i
) *
707 opt_bs1 (side
, s
, x
, t
, r
, vi
, r
);
713 opt_jump_diff (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
715 OptionSide call_put
= option_side (value_peek_string (argv
[0]));
716 gnm_float s
= value_get_as_float (argv
[1]);
717 gnm_float x
= value_get_as_float (argv
[2]);
718 gnm_float t
= value_get_as_float (argv
[3]);
719 gnm_float r
= value_get_as_float (argv
[4]);
720 gnm_float v
= value_get_as_float (argv
[5]);
721 gnm_float lambda
= value_get_as_float (argv
[6]);
722 gnm_float gamma
= value_get_as_float (argv
[7]);
724 opt_jump_diff1 (call_put
, s
, x
, t
, r
, v
, lambda
, gamma
);
725 return value_new_float (gfresult
);
728 static GnmFuncHelp
const help_opt_jump_diff
[] = {
729 { GNM_FUNC_HELP_NAME
, F_("OPT_JUMP_DIFF:theoretical price of an option according to the Jump Diffusion process")},
730 DEF_ARG_CALL_PUT_FLAG
,
733 DEF_ARG_TIME_MATURITY_Y
,
734 { GNM_FUNC_HELP_ARG
, F_("rate:the annualized rate of interest")},
736 { GNM_FUNC_HELP_ARG
, F_("lambda:expected number of 'jumps' per year")},
737 { GNM_FUNC_HELP_ARG
, F_("gamma:proportion of volatility explained by the 'jumps'")},
738 { GNM_FUNC_HELP_DESCRIPTION
, F_("OPT_JUMP_DIFF models the theoretical price of an option according "
739 "to the Jump Diffusion process (Merton).")},
740 { GNM_FUNC_HELP_SEEALSO
, "OPT_BS,OPT_BS_DELTA,OPT_BS_RHO,OPT_BS_THETA,OPT_BS_GAMMA"},
746 /* Miltersen schwartz (1997) commodity option model */
748 opt_miltersen_schwartz1 (OptionSide side
, gnm_float p_t
, gnm_float f_t
, gnm_float x
, gnm_float t1
,
749 gnm_float t2
, gnm_float v_s
, gnm_float v_e
, gnm_float v_f
, gnm_float rho_se
,
750 gnm_float rho_sf
, gnm_float rho_ef
, gnm_float kappa_e
, gnm_float kappa_f
)
755 vz
= (v_s
* v_s
) * t1
+ 2.0 * v_s
* (v_f
* rho_sf
* 1.0/ kappa_f
* (t1
- 1.0/ kappa_f
* gnm_exp (-kappa_f
* t2
) * (gnm_exp (kappa_f
* t1
) - 1.0))
756 - v_e
* rho_se
* 1.0/ kappa_e
* (t1
- 1.0/ kappa_e
* gnm_exp (-kappa_e
* t2
) * (gnm_exp (kappa_e
* t1
) - 1.0)))
757 + (v_e
* v_e
) * 1.0/ (kappa_e
* kappa_e
) * (t1
+ 1.0/ (2.0 * kappa_e
) * gnm_exp (-2 * kappa_e
* t2
) * (gnm_exp (2.0 * kappa_e
* t1
) - 1.0)
758 - 2.0 * 1.0/ kappa_e
* gnm_exp (-kappa_e
* t2
) * (gnm_exp (kappa_e
* t1
) - 1.0))
759 + (v_f
* v_f
) * 1.0/ (kappa_f
* kappa_f
) * (t1
+ 1.0/ (2.0 * kappa_f
) * gnm_exp (-2.0 * kappa_f
* t2
) * (gnm_exp (2.0 * kappa_f
* t1
) - 1.0)
760 - 2.0 * 1.0/ kappa_f
* gnm_exp (-kappa_f
* t2
) * (gnm_exp (kappa_f
* t1
) - 1.0))
761 - 2.0 * v_e
* v_f
* rho_ef
* 1.0/ kappa_e
* 1.0/ kappa_f
* (t1
- 1.0/ kappa_e
* gnm_exp (-kappa_e
* t2
) * (gnm_exp (kappa_e
* t1
) - 1.0)
762 - 1.0/ kappa_f
* gnm_exp (-kappa_f
* t2
) * (gnm_exp (kappa_f
* t1
) - 1.0)
763 + 1.0/ (kappa_e
+ kappa_f
) * gnm_exp (-(kappa_e
+ kappa_f
) * t2
) * (gnm_exp ((kappa_e
+ kappa_f
) * t1
) - 1.0));
765 vxz
= v_f
* 1.0/ kappa_f
* (v_s
* rho_sf
* (t1
- 1.0/ kappa_f
* (1.0 - gnm_exp (-kappa_f
* t1
)))
766 + v_f
* 1.0/ kappa_f
* (t1
- 1.0/ kappa_f
* gnm_exp (-kappa_f
* t2
) * (gnm_exp (kappa_f
* t1
) - 1.0) - 1.0/ kappa_f
* (1 - gnm_exp (-kappa_f
* t1
))
767 + 1.0/ (2.0 * kappa_f
) * gnm_exp (-kappa_f
* t2
) * (gnm_exp (kappa_f
* t1
) - gnm_exp (-kappa_f
* t1
)))
768 - v_e
* rho_ef
* 1.0/ kappa_e
* (t1
- 1.0/ kappa_e
* gnm_exp (-kappa_e
* t2
) * (gnm_exp (kappa_e
* t1
) - 1.0) - 1.0/ kappa_f
* (1.0 - gnm_exp (-kappa_f
* t1
))
769 + 1.0/ (kappa_e
+ kappa_f
) * gnm_exp (-kappa_e
* t2
) * (gnm_exp (kappa_e
* t1
) - gnm_exp (-kappa_f
* t1
))));
773 d1
= (gnm_log (f_t
/ x
) - vxz
+ (vz
* vz
) / 2.0) / vz
;
774 d2
= (gnm_log (f_t
/ x
) - vxz
- (vz
* vz
) / 2.0) / vz
;
778 return p_t
* (f_t
* gnm_exp (-vxz
) * ncdf (d1
) - x
* ncdf (d2
));
780 return p_t
* (x
* ncdf (-d2
) - f_t
* gnm_exp (-vxz
) * ncdf (-d1
));
787 opt_miltersen_schwartz (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
789 OptionSide call_put
= option_side (value_peek_string (argv
[0]));
790 gnm_float p_t
= value_get_as_float (argv
[1]);
791 gnm_float f_t
= value_get_as_float (argv
[2]);
792 gnm_float x
= value_get_as_float (argv
[3]);
793 gnm_float t1
= value_get_as_float (argv
[4]);
794 gnm_float t2
= value_get_as_float (argv
[5]);
795 gnm_float v_s
= value_get_as_float (argv
[6]);
796 gnm_float v_e
= value_get_as_float (argv
[7]);
797 gnm_float v_f
= value_get_as_float (argv
[8]);
798 gnm_float rho_se
= value_get_as_float (argv
[9]);
799 gnm_float rho_sf
= value_get_as_float (argv
[10]);
800 gnm_float rho_ef
= value_get_as_float (argv
[11]);
801 gnm_float kappa_e
= value_get_as_float (argv
[12]);
802 gnm_float kappa_f
= value_get_as_float (argv
[13]);
805 opt_miltersen_schwartz1 (call_put
, p_t
, f_t
, x
, t1
, t2
,
807 rho_se
, rho_sf
, rho_ef
, kappa_e
, kappa_f
);
809 if (gnm_isnan (gfresult
))
810 return value_new_error_NUM (ei
->pos
);
811 return value_new_float (gfresult
);
815 static GnmFuncHelp
const help_opt_miltersen_schwartz
[] = {
816 { GNM_FUNC_HELP_NAME
, F_("OPT_MILTERSEN_SCHWARTZ:theoretical price of options on commodities futures according to Miltersen & Schwartz")},
817 DEF_ARG_CALL_PUT_FLAG
,
818 { GNM_FUNC_HELP_ARG
, F_("p_t:zero coupon bond with expiry at option maturity")},
819 { GNM_FUNC_HELP_ARG
, F_("f_t:futures price")},
821 { GNM_FUNC_HELP_ARG
, F_("t1:time to maturity of the option")},
822 { GNM_FUNC_HELP_ARG
, F_("t2:time to maturity of the underlying commodity futures contract")},
823 { GNM_FUNC_HELP_ARG
, F_("v_s:volatility of the spot commodity price")},
824 { GNM_FUNC_HELP_ARG
, F_("v_e:volatility of the future convenience yield")},
825 { GNM_FUNC_HELP_ARG
, F_("v_f:volatility of the forward rate of interest")},
826 { GNM_FUNC_HELP_ARG
, F_("rho_se:correlation between the spot commodity price and the convenience yield")},
827 { GNM_FUNC_HELP_ARG
, F_("rho_sf:correlation between the spot commodity price and the forward interest rate")},
828 { GNM_FUNC_HELP_ARG
, F_("rho_ef:correlation between the forward interest rate and the convenience yield")},
829 { GNM_FUNC_HELP_ARG
, F_("kappa_e:speed of mean reversion of the convenience yield")},
830 { GNM_FUNC_HELP_ARG
, F_("kappa_f:speed of mean reversion of the forward interest rate")},
831 { GNM_FUNC_HELP_SEEALSO
, "OPT_BS,OPT_BS_DELTA,OPT_BS_RHO,OPT_BS_THETA,OPT_BS_GAMMA"},
835 /* American options */
838 /* American Calls on stocks with known dividends, Roll-Geske-Whaley */
839 static gnm_float
opt_rgw1 (gnm_float s
, gnm_float x
, gnm_float t1
, gnm_float t2
, gnm_float r
, gnm_float d
, gnm_float v
)
840 /*t1 time to dividend payout
841 t2 time to option expiration */
844 gnm_float a1
, a2
, b1
, b2
;
845 gnm_float HighS
, LowS
, epsilon
;
846 gnm_float ci
, infinity
;
852 infinity
= 100000000;
854 sx
= s
- d
* gnm_exp (-r
* t1
);
855 if (d
<= (x
* (1.0 - gnm_exp (-r
* (t2
- t1
)))))
856 /* Not optimal to exercise */
857 return opt_bs1 (OS_Call
, sx
, x
, t2
, r
, v
,0.0);
859 ci
= opt_bs1 (OS_Call
, s
, x
, t2
- t1
, r
, v
,0.0);
861 while ((ci
- HighS
- d
+ x
) > 0.0 && HighS
< infinity
) {
864 ci
= opt_bs1 (OS_Call
, HighS
, x
, t2
- t1
, r
, v
,0.0);
866 if (HighS
> infinity
)
867 return opt_bs1 (OS_Call
, sx
, x
, t2
, r
, v
,0.0);
871 ci
= opt_bs1 (OS_Call
, i
, x
, t2
- t1
, r
, v
, 0.0);
873 /* search algorithm to find the critical stock price i */
874 while (gnm_abs (ci
- i
- d
+ x
) > epsilon
&& HighS
- LowS
> epsilon
) {
875 if ((ci
- i
- d
+ x
) < 0)
879 i
= (HighS
+ LowS
) / 2.0;
880 ci
= opt_bs1 (OS_Call
, i
, x
, (t2
- t1
), r
, v
, 0.0);
883 a1
= (gnm_log (sx
/ x
) + (r
+ (v
* v
) / 2.0) * t2
) / (v
* gnm_sqrt (t2
));
884 a2
= a1
- v
* gnm_sqrt (t2
);
885 b1
= (gnm_log (sx
/ i
) + (r
+ (v
* v
) / 2.0) * t1
) / (v
* gnm_sqrt (t1
));
886 b2
= b1
- v
* gnm_sqrt (t1
);
888 gfresult
= sx
* ncdf (b1
) + sx
* cum_biv_norm_dist1 (a1
, -b1
, -gnm_sqrt (t1
/ t2
))
889 - x
* gnm_exp (-r
* t2
) * cum_biv_norm_dist1 (a2
, -b2
, -gnm_sqrt (t1
/ t2
)) - (x
- d
)
890 * gnm_exp (-r
* t1
) * ncdf (b2
);
896 opt_rgw(GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
898 gnm_float s
= value_get_as_float (argv
[0]);
899 gnm_float x
= value_get_as_float (argv
[1]);
900 gnm_float t1
= value_get_as_float (argv
[2]);
901 gnm_float t2
= value_get_as_float (argv
[3]);
902 gnm_float r
= value_get_as_float (argv
[4]);
903 gnm_float d
= value_get_as_float (argv
[5]);
904 gnm_float v
= value_get_as_float (argv
[6]);
905 gnm_float gfresult
= 0.0;
907 gfresult
= opt_rgw1 (s
, x
, t1
, t2
, r
, d
, v
);
909 return value_new_float (gfresult
);
912 static GnmFuncHelp
const help_opt_rgw
[] = {
913 { GNM_FUNC_HELP_NAME
, F_("OPT_RGW:theoretical price of an American option according to the Roll-Geske-Whaley approximation")},
916 DEF_ARG_TIME_DIVIDEND
,
917 DEF_ARG_TIME_EXPIRATION
,
918 DEF_ARG_RATE_ANNUALIZED
,
921 { GNM_FUNC_HELP_SEEALSO
, "OPT_BS,OPT_BS_DELTA,OPT_BS_RHO,OPT_BS_THETA,OPT_BS_GAMMA"},
925 /* the Barone-Adesi and Whaley (1987) American approximation */
927 opt_baw_amer (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
929 OptionSide call_put
= option_side (value_peek_string (argv
[0]));
930 gnm_float s
= value_get_as_float (argv
[1]);
931 gnm_float x
= value_get_as_float (argv
[2]);
932 gnm_float t
= value_get_as_float (argv
[3]);
933 gnm_float r
= value_get_as_float (argv
[4]);
934 gnm_float v
= value_get_as_float (argv
[5]);
935 gnm_float b
= value_get_as_float (argv
[6]);
940 gfresult
= opt_baw_call (s
, x
, t
, r
, v
, b
);
943 gfresult
= opt_baw_put (s
, x
, t
, r
, v
, b
);
946 return value_new_error_NUM (ei
->pos
);
949 if (gnm_isnan (gfresult
))
950 return value_new_error_NUM (ei
->pos
);
952 return value_new_float (gfresult
);
955 static GnmFuncHelp
const help_opt_baw_amer
[] = {
956 { GNM_FUNC_HELP_NAME
, F_("OPT_BAW_AMER:theoretical price of an option according to the Barone Adesie & Whaley approximation")},
957 DEF_ARG_CALL_PUT_FLAG
,
960 DEF_ARG_TIME_MATURITY_D
,
961 DEF_ARG_RATE_RISKFREE_ANN
,
963 DEF_ARG_VOLATILITY_SHORT
,
964 { GNM_FUNC_HELP_SEEALSO
, "OPT_BS,OPT_BS_DELTA,OPT_BS_RHO,OPT_BS_THETA,OPT_BS_GAMMA"},
970 opt_baw_call (gnm_float s
, gnm_float x
, gnm_float t
, gnm_float r
, gnm_float v
, gnm_float b
)
973 gnm_float d1
, q2
, a2
;
976 gfresult
= opt_bs1 (OS_Call
, s
, x
, t
, r
, v
, b
);
979 sk
= NRA_c (x
, t
, r
, v
, b
);
981 k
= 2 * r
/ ((v
* v
) * (1.0 - gnm_exp (-r
* t
)));
982 d1
= (gnm_log (sk
/ x
) + (b
+ (v
* v
) / 2.0) * t
) / (v
* gnm_sqrt (t
));
983 q2
= (-(n
- 1.0) + gnm_sqrt ((n
- 1.0) * (n
- 1.0) + 4.0 * k
)) / 2.0;
984 a2
= (sk
/ q2
) * (1.0 - gnm_exp ((b
- r
) * t
) * ncdf (d1
));
986 gfresult
= opt_bs1 (OS_Call
, s
, x
, t
, r
, v
, b
) + a2
* gnm_pow (s
/ sk
, q2
);
990 } /*end if statement*/
998 /* Newton Raphson algorithm to solve for the critical commodity price for a Call */
1000 NRA_c (gnm_float x
, gnm_float t
, gnm_float r
, gnm_float v
, gnm_float b
)
1005 gnm_float d1
, q2
, q2u
;
1009 /* Calculation of seed value, si */
1010 n
= 2 * b
/ (v
* v
);
1011 m
= 2 * r
/ (v
* v
);
1012 q2u
= (-(n
- 1.0) + gnm_sqrt (((n
- 1.0) * (n
- 1.0)) + 4.0 * m
)) / 2.0;
1013 su
= x
/ (1.0 - 1.0/ q2u
);
1014 h2
= -(b
* t
+ 2.0 * v
* gnm_sqrt (t
)) * x
/ (su
- x
);
1015 si
= x
+ (su
- x
) * (1.0 - gnm_exp (h2
));
1017 k
= 2 * r
/ ((v
* v
) * (1.0 - gnm_exp (-r
* t
)));
1018 d1
= (gnm_log (si
/ x
) + (b
+ (v
* v
) / 2.0) * t
) / (v
* gnm_sqrt (t
));
1019 q2
= (-(n
- 1.0) + gnm_sqrt (((n
- 1.0) * (n
- 1.0)) + 4.0 * k
)) / 2.0;
1021 RHS
= opt_bs1 (OS_Call
, si
, x
, t
, r
, v
, b
) + (1.0 - gnm_exp ((b
- r
) * t
) * ncdf (d1
)) * si
/ q2
;
1022 bi
= gnm_exp ((b
- r
) * t
) * ncdf (d1
) * (1.0 - 1.0/ q2
)
1023 + (1.0 - gnm_exp ((b
- r
) * t
) * ncdf (d1
) / (v
* gnm_sqrt (t
))) / q2
;
1026 /* Newton Raphson algorithm for finding critical price si */
1027 while ((gnm_abs (LHS
- RHS
) / x
) > e
)
1029 si
= (x
+ RHS
- bi
* si
) / (1.0 - bi
);
1030 d1
= (gnm_log (si
/ x
) + (b
+ (v
* v
) / 2.0) * t
) / (v
* gnm_sqrt (t
));
1032 RHS
= opt_bs1 (OS_Call
, si
, x
, t
, r
, v
, b
) + (1.0 - gnm_exp ((b
- r
) * t
) * ncdf (d1
)) * si
/ q2
;
1033 bi
= gnm_exp ((b
- r
) * t
) * ncdf (d1
) * (1.0 - 1.0/ q2
)
1034 + (1.0 - gnm_exp ((b
- r
) * t
) * npdf (d1
) / (v
* gnm_sqrt (t
))) / q2
;
1040 opt_baw_put (gnm_float s
, gnm_float x
, gnm_float t
, gnm_float r
, gnm_float v
, gnm_float b
)
1042 gnm_float sk
= NRA_p (x
, t
, r
, v
, b
);
1043 gnm_float n
= 2 * b
/ (v
* v
);
1044 gnm_float k
= 2 * r
/ ((v
* v
) * (1.0 - gnm_exp (-r
* t
)));
1045 gnm_float d1
= (gnm_log (sk
/ x
) + (b
+ (v
* v
) / 2.0) * t
) / (v
* gnm_sqrt (t
));
1046 gnm_float q1
= (-(n
- 1.0) - gnm_sqrt (((n
- 1.0) * (n
- 1.0)) + 4.0 * k
)) / 2.0;
1047 gnm_float a1
= -(sk
/ q1
) * (1.0 - gnm_exp ((b
- r
) * t
) * ncdf (-d1
));
1050 return opt_bs1 (OS_Put
, s
, x
, t
, r
, v
, b
) + a1
* gnm_pow (s
/ sk
, q1
);
1055 /* Newton Raphson algorithm to solve for the critical commodity price for a Put*/
1057 NRA_p (gnm_float x
, gnm_float t
, gnm_float r
, gnm_float v
, gnm_float b
)
1063 gnm_float d1
, q1u
, q1
;
1067 /* Calculation of seed value, si */
1068 n
= 2 * b
/ (v
* v
);
1069 m
= 2 * r
/ (v
* v
);
1070 q1u
= (-(n
- 1.0) - gnm_sqrt (((n
- 1.0) * (n
- 1.0)) + 4.0 * m
)) / 2.0;
1071 su
= x
/ (1.0 - 1.0/ q1u
);
1072 h1
= (b
* t
- 2.0 * v
* gnm_sqrt (t
)) * x
/ (x
- su
);
1073 si
= su
+ (x
- su
) * gnm_exp (h1
);
1075 k
= 2 * r
/ ((v
* v
) * (1.0 - gnm_exp (-r
* t
)));
1076 d1
= (gnm_log (si
/ x
) + (b
+ (v
* v
) / 2.0) * t
) / (v
* gnm_sqrt (t
));
1077 q1
= (-(n
- 1.0) - gnm_sqrt (((n
- 1.0) * (n
- 1.0)) + 4.0 * k
)) / 2.0;
1079 RHS
= opt_bs1 (OS_Put
, si
, x
, t
, r
, v
, b
) - (1.0 - gnm_exp ((b
- r
) * t
) * ncdf (-d1
)) * si
/ q1
;
1080 bi
= -gnm_exp ((b
- r
) * t
) * ncdf (-d1
) * (1.0 - 1.0/ q1
)
1081 - (1.0 + gnm_exp ((b
- r
) * t
) * npdf (-d1
) / (v
* gnm_sqrt (t
))) / q1
;
1084 /* Newton Raphson algorithm for finding critical price si */
1085 while(gnm_abs (LHS
- RHS
) / x
> e
) {
1086 si
= (x
- RHS
+ bi
* si
) / (1.0 + bi
);
1087 d1
= (gnm_log (si
/ x
) + (b
+ (v
* v
) / 2.0) * t
) / (v
* gnm_sqrt (t
));
1089 RHS
= opt_bs1 (OS_Put
, si
, x
, t
, r
, v
, b
) - (1.0 - gnm_exp ((b
- r
) * t
) * ncdf (-d1
)) * si
/ q1
;
1090 bi
= -gnm_exp ((b
- r
) * t
) * ncdf (-d1
) * (1.0 - 1.0/ q1
)
1091 - (1.0 + gnm_exp ((b
- r
) * t
) * ncdf (-d1
) / (v
* gnm_sqrt (t
))) / q1
;
1096 /* the Bjerksund and stensland (1993) American approximation */
1098 opt_bjer_stens1 (OptionSide side
, gnm_float s
, gnm_float x
, gnm_float t
, gnm_float r
, gnm_float v
, gnm_float b
)
1102 return opt_bjer_stens1_c (s
, x
, t
, r
, v
, b
);
1104 /* Use the Bjerksund and stensland put-call transformation */
1105 return opt_bjer_stens1_c (x
, s
, t
, r
- b
, v
, -b
);
1112 opt_bjer_stens (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1114 OptionSide call_put
= option_side (value_peek_string (argv
[0]));
1115 gnm_float s
= value_get_as_float (argv
[1]);
1116 gnm_float x
= value_get_as_float (argv
[2]);
1117 gnm_float t
= value_get_as_float (argv
[3]);
1118 gnm_float r
= value_get_as_float (argv
[4]);
1119 gnm_float v
= value_get_as_float (argv
[5]);
1120 gnm_float b
= argv
[6] ? value_get_as_float (argv
[6]):0;
1121 gnm_float gfresult
=
1122 opt_bjer_stens1 (call_put
, s
, x
, t
, r
, v
, b
);
1123 return value_new_float (gfresult
);
1127 static GnmFuncHelp
const help_opt_bjer_stens
[] = {
1128 { GNM_FUNC_HELP_NAME
, F_("OPT_BJER_STENS:theoretical price of American options according to the Bjerksund & Stensland approximation technique")},
1129 DEF_ARG_CALL_PUT_FLAG
,
1132 DEF_ARG_TIME_MATURITY_D
,
1133 DEF_ARG_RATE_RISKFREE_ANN
,
1134 DEF_ARG_VOLATILITY_SHORT
,
1136 { GNM_FUNC_HELP_SEEALSO
, "OPT_BS,OPT_BS_DELTA,OPT_BS_RHO,OPT_BS_THETA,OPT_BS_GAMMA"},
1137 { GNM_FUNC_HELP_END
}
1141 opt_bjer_stens1_c (gnm_float s
, gnm_float x
, gnm_float t
, gnm_float r
, gnm_float v
, gnm_float b
)
1143 if (b
>= r
) /* Never optimal to exersice before maturity */
1144 return opt_bs1 (OS_Call
, s
, x
, t
, r
, v
, b
);
1147 (1.0/ 2.0 - b
/ (v
* v
)) +
1148 gnm_sqrt (gnm_pow (b
/ (v
* v
) - 1.0/ 2.0, 2) + 2 * r
/ (v
* v
));
1149 gnm_float BInfinity
= Beta
/ (Beta
- 1.0) * x
;
1150 gnm_float B0
= MAX (x
, r
/ (r
- b
) * x
);
1151 gnm_float ht
= -(b
* t
+ 2.0 * v
* gnm_sqrt (t
)) * B0
/ (BInfinity
- B0
);
1152 gnm_float I
= B0
+ (BInfinity
- B0
) * (1.0 - gnm_exp (ht
));
1156 gnm_float alpha
= (I
- x
) * gnm_pow (I
,-Beta
);
1157 return alpha
* gnm_pow (s
,Beta
) -
1158 alpha
* phi (s
, t
, Beta
, I
, I
, r
, v
, b
) +
1159 phi (s
, t
, 1.0, I
, I
, r
, v
, b
) -
1160 phi (s
, t
, 1.0, x
, I
, r
, v
, b
) -
1161 x
* phi (s
, t
, 0.0, I
, I
, r
, v
, b
) +
1162 x
* phi (s
, t
, 0.0, x
, I
, r
, v
, b
);
1168 phi (gnm_float s
, gnm_float t
, gnm_float gamma
, gnm_float H
, gnm_float I
, gnm_float r
, gnm_float v
, gnm_float b
)
1170 gnm_float lambda
, kappa
;
1174 lambda
= (-r
+ gamma
* b
+ 0.5 * gamma
* (gamma
- 1.0) * (v
* v
)) * t
;
1175 d
= -(gnm_log (s
/ H
) + (b
+ (gamma
- 0.5) * (v
* v
)) * t
) / (v
* gnm_sqrt (t
));
1176 kappa
= 2 * b
/ (v
* v
) + (2.0 * gamma
- 1.0);
1177 gfresult
= gnm_exp (lambda
) * gnm_pow (s
, gamma
) * (ncdf (d
) - gnm_pow (I
/ s
, kappa
) * ncdf (d
- 2.0 * gnm_log (I
/ s
) / (v
* gnm_sqrt (t
))));
1183 /* Executive stock options */
1185 opt_exec (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1187 OptionSide call_put
= option_side (value_peek_string (argv
[0]));
1188 gnm_float s
= value_get_as_float (argv
[1]);
1189 gnm_float x
= value_get_as_float (argv
[2]);
1190 gnm_float t
= value_get_as_float (argv
[3]);
1191 gnm_float r
= value_get_as_float (argv
[4]);
1192 gnm_float v
= value_get_as_float (argv
[5]);
1193 gnm_float b
= value_get_as_float (argv
[6]);
1194 gnm_float lambda
= value_get_as_float (argv
[7]);
1195 gnm_float gfresult
=
1196 gnm_exp (-lambda
* t
) * opt_bs1 (call_put
, s
, x
, t
, r
, v
, b
);
1197 return value_new_float (gfresult
);
1201 static GnmFuncHelp
const help_opt_exec
[] = {
1202 { GNM_FUNC_HELP_NAME
, F_("OPT_EXEC:theoretical price of executive stock options")},
1203 DEF_ARG_CALL_PUT_FLAG
,
1206 DEF_ARG_TIME_MATURITY_D
,
1207 DEF_ARG_RATE_RISKFREE_ANN
,
1208 DEF_ARG_VOLATILITY_SHORT
,
1210 { GNM_FUNC_HELP_ARG
, F_("lambda:jump rate for executives")},
1211 { GNM_FUNC_HELP_NOTE
, F_("The model assumes executives forfeit their options if they leave the company.")},
1212 { GNM_FUNC_HELP_SEEALSO
, "OPT_BS,OPT_BS_DELTA,OPT_BS_RHO,OPT_BS_THETA,OPT_BS_GAMMA"},
1213 { GNM_FUNC_HELP_END
}
1220 /* Forward start options */
1222 opt_forward_start(GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1224 OptionSide call_put
= option_side (value_peek_string (argv
[0]));
1225 gnm_float s
= value_get_as_float (argv
[1]);
1226 gnm_float alpha
= value_get_as_float (argv
[2]);
1227 gnm_float t1
= value_get_as_float (argv
[3]);
1228 gnm_float t
= value_get_as_float (argv
[4]);
1229 gnm_float r
= value_get_as_float (argv
[5]);
1230 gnm_float v
= value_get_as_float (argv
[6]);
1231 gnm_float b
= value_get_as_float (argv
[7]);
1232 gnm_float gfresult
=
1233 s
* gnm_exp ((b
- r
) * t1
) * opt_bs1 (call_put
, 1, alpha
, t
- t1
, r
, v
, b
);
1234 return value_new_float (gfresult
);
1239 static GnmFuncHelp
const help_opt_forward_start
[] = {
1240 { GNM_FUNC_HELP_NAME
, F_("OPT_FORWARD_START:theoretical price of forward start options")},
1241 DEF_ARG_CALL_PUT_FLAG
,
1243 { GNM_FUNC_HELP_ARG
, F_("alpha:fraction setting the strike price at the future date @{time_start}")},
1244 { GNM_FUNC_HELP_ARG
, F_("time_start:time until the option starts in days")},
1245 DEF_ARG_TIME_MATURITY_D
,
1246 DEF_ARG_RATE_RISKFREE_ANN
,
1247 DEF_ARG_VOLATILITY_SHORT
,
1249 { GNM_FUNC_HELP_SEEALSO
, "OPT_BS,OPT_BS_DELTA,OPT_BS_RHO,OPT_BS_THETA,OPT_BS_GAMMA"},
1250 { GNM_FUNC_HELP_END
}
1254 /* time switch options (discrete) */
1256 opt_time_switch (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1258 OptionSide call_put
= option_side (value_peek_string (argv
[0]));
1259 gnm_float s
= value_get_as_float (argv
[1]);
1260 gnm_float x
= value_get_as_float (argv
[2]);
1261 gnm_float a
= value_get_as_float (argv
[3]);
1262 gnm_float t
= value_get_as_float (argv
[4]);
1263 gnm_float m
= value_get_as_float (argv
[5]);
1264 gnm_float dt
= value_get_as_float (argv
[6]);
1265 gnm_float r
= value_get_as_float (argv
[7]);
1266 gnm_float b
= value_get_as_float (argv
[8]);
1267 gnm_float v
= value_get_as_float (argv
[9]);
1274 case OS_Call
: Z
= +1; break;
1275 case OS_Put
: Z
= -1; break;
1276 default: return value_new_error_NUM (ei
->pos
);
1281 for (i
= 1; i
< n
; ++i
) {
1282 d
= (gnm_log (s
/ x
) + (b
- (v
* v
) / 2.0) * i
* dt
) / (v
* gnm_sqrt (i
* dt
));
1283 sum
= sum
+ ncdf (Z
* d
) * dt
;
1286 gfresult
= a
* gnm_exp (-r
* t
) * sum
+ dt
* a
* gnm_exp (-r
* t
) * m
;
1287 return value_new_float (gfresult
);
1291 static GnmFuncHelp
const help_opt_time_switch
[] = {
1292 { GNM_FUNC_HELP_NAME
, F_("OPT_TIME_SWITCH:theoretical price of time switch options")},
1293 DEF_ARG_CALL_PUT_FLAG
,
1296 { GNM_FUNC_HELP_ARG
, F_("a:amount received for each time period")},
1297 DEF_ARG_TIME_MATURITY_Y
,
1298 { GNM_FUNC_HELP_ARG
, F_("m:number of time units the option has already met the condition")},
1299 { GNM_FUNC_HELP_ARG
, F_("dt:agreed upon discrete time period expressed as "
1300 "a fraction of a year")},
1301 DEF_ARG_RATE_RISKFREE_ANN
,
1303 DEF_ARG_VOLATILITY_SHORT
,
1304 { GNM_FUNC_HELP_DESCRIPTION
, F_("OPT_TIME_SWITCH models the theoretical price of time switch options. (Pechtl 1995). "
1305 "The holder receives @{a} * @{dt} for each period that the asset price was "
1306 "greater than @{strike} (for a call) or below it (for a put).")},
1307 { GNM_FUNC_HELP_SEEALSO
, "OPT_BS,OPT_BS_DELTA,OPT_BS_RHO,OPT_BS_THETA,OPT_BS_GAMMA"},
1308 { GNM_FUNC_HELP_END
}
1312 /* simple chooser options */
1314 opt_simple_chooser (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1316 gnm_float s
= value_get_as_float (argv
[0]);
1317 gnm_float x
= value_get_as_float (argv
[1]);
1318 gnm_float t1
= value_get_as_float (argv
[2]);
1319 gnm_float t2
= value_get_as_float (argv
[3]);
1320 gnm_float r
= value_get_as_float (argv
[4]);
1321 gnm_float b
= value_get_as_float (argv
[5]);
1322 gnm_float v
= value_get_as_float (argv
[6]);
1324 gnm_float d
= (gnm_log (s
/ x
) + (b
+ (v
* v
) / 2.0) * t2
) / (v
* gnm_sqrt (t2
));
1325 gnm_float y
= (gnm_log (s
/ x
) + b
* t2
+ (v
* v
) * t1
/ 2.0) / (v
* gnm_sqrt (t1
));
1326 gnm_float gfresult
=
1327 s
* gnm_exp ((b
- r
) * t2
) * ncdf ( d
) - x
* gnm_exp (-r
* t2
) * ncdf ( d
- v
* gnm_sqrt (t2
)) -
1328 s
* gnm_exp ((b
- r
) * t2
) * ncdf (-y
) + x
* gnm_exp (-r
* t2
) * ncdf (-y
+ v
* gnm_sqrt (t1
));
1330 return value_new_float (gfresult
);
1333 static GnmFuncHelp
const help_opt_simple_chooser
[] = {
1334 { GNM_FUNC_HELP_NAME
, F_("OPT_SIMPLE_CHOOSER:theoretical price of a simple chooser option")},
1335 DEF_ARG_CALL_PUT_FLAG
,
1338 { GNM_FUNC_HELP_ARG
, F_("time1:time in years until the holder chooses a put or a call option")},
1339 { GNM_FUNC_HELP_ARG
, F_("time2:time in years until the chosen option expires")},
1341 DEF_ARG_VOLATILITY_SHORT
,
1342 { GNM_FUNC_HELP_SEEALSO
, "OPT_BS,OPT_BS_DELTA,OPT_BS_RHO,OPT_BS_THETA,OPT_BS_GAMMA"},
1343 { GNM_FUNC_HELP_END
}
1347 /* Complex chooser options */
1349 opt_complex_chooser(GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1351 gnm_float s
= value_get_as_float (argv
[0]);
1352 gnm_float xc
= value_get_as_float (argv
[1]);
1353 gnm_float xp
= value_get_as_float (argv
[2]);
1354 gnm_float t
= value_get_as_float (argv
[3]);
1355 gnm_float tc
= value_get_as_float (argv
[4]);
1356 gnm_float tp
= value_get_as_float (argv
[5]);
1357 gnm_float r
= value_get_as_float (argv
[6]);
1358 gnm_float b
= value_get_as_float (argv
[7]);
1359 gnm_float v
= value_get_as_float (argv
[8]);
1363 gnm_float d1
, d2
, y1
, y2
;
1364 gnm_float rho1
, rho2
, I
;
1366 I
= opt_crit_val_chooser (s
, xc
, xp
, t
, tc
, tp
, r
, b
, v
);
1367 d1
= (gnm_log (s
/ I
) + (b
+ (v
* v
) / 2.0) * t
) / (v
* gnm_sqrt (t
));
1368 d2
= d1
- v
* gnm_sqrt (t
);
1369 y1
= (gnm_log (s
/ xc
) + (b
+ (v
* v
) / 2.0) * tc
) / (v
* gnm_sqrt (tc
));
1370 y2
= (gnm_log (s
/ xp
) + (b
+ (v
* v
) / 2.0) * tp
) / (v
* gnm_sqrt (tp
));
1371 rho1
= gnm_sqrt (t
/ tc
);
1372 rho2
= gnm_sqrt (t
/ tp
);
1374 gfresult
= s
* gnm_exp ((b
- r
) * tc
) * cum_biv_norm_dist1 (d1
, y1
, rho1
) - xc
* gnm_exp (-r
* tc
)
1375 * cum_biv_norm_dist1 (d2
, y1
- v
* gnm_sqrt (tc
), rho1
) - s
* gnm_exp ((b
- r
) * tp
)
1376 * cum_biv_norm_dist1 (-d1
, -y2
, rho2
) + xp
* gnm_exp (-r
* tp
) * cum_biv_norm_dist1 (-d2
, -y2
+ v
* gnm_sqrt (tp
), rho2
);
1378 return value_new_float (gfresult
);
1382 static GnmFuncHelp
const help_opt_complex_chooser
[] = {
1383 { GNM_FUNC_HELP_NAME
, F_("OPT_COMPLEX_CHOOSER:theoretical price of a complex chooser option")},
1385 { GNM_FUNC_HELP_ARG
, F_("strike_call:strike price, if exercised as a call option")},
1386 { GNM_FUNC_HELP_ARG
, F_("strike_put:strike price, if exercised as a put option")},
1387 { GNM_FUNC_HELP_ARG
, F_("time:time in years until the holder chooses a put or a call option")},
1388 { GNM_FUNC_HELP_ARG
, F_("time_call:time in years to maturity of the call option if chosen")},
1389 { GNM_FUNC_HELP_ARG
, F_("time_put:time in years to maturity of the put option if chosen")},
1390 DEF_ARG_RATE_RISKFREE_ANN
,
1393 { GNM_FUNC_HELP_SEEALSO
, "OPT_BS,OPT_BS_DELTA,OPT_BS_RHO,OPT_BS_THETA,OPT_BS_GAMMA"},
1394 { GNM_FUNC_HELP_END
}
1400 /* Critical value complex chooser option */
1402 opt_crit_val_chooser (gnm_float s
,gnm_float xc
,gnm_float xp
,gnm_float t
,
1403 gnm_float tc
, gnm_float tp
, gnm_float r
, gnm_float b
, gnm_float v
)
1405 gnm_float sv
, ci
, Pi
, epsilon
;
1406 gnm_float dc
, dp
, yi
, di
;
1409 ci
= opt_bs1 (OS_Call
, sv
, xc
, tc
- t
, r
, v
, b
);
1410 Pi
= opt_bs1 (OS_Put
, sv
, xp
, tp
- t
, r
, v
, b
);
1411 dc
= opt_bs_delta1 (OS_Call
, sv
, xc
, tc
- t
, r
, v
, b
);
1412 dp
= opt_bs_delta1 (OS_Put
, sv
, xp
, tp
- t
, r
, v
, b
);
1416 /* Newton-Raphson */
1417 while (gnm_abs (yi
) > epsilon
)
1419 sv
= sv
- (yi
) / di
;
1420 ci
= opt_bs1 (OS_Call
, sv
, xc
, tc
- t
, r
, v
, b
);
1421 Pi
= opt_bs1 (OS_Put
, sv
, xp
, tp
- t
, r
, v
, b
);
1422 dc
= opt_bs_delta1 (OS_Call
, sv
, xc
, tc
- t
, r
, v
, b
);
1423 dp
= opt_bs_delta1 (OS_Put
, sv
, xp
, tp
- t
, r
, v
, b
);
1432 /* Options on options */
1434 opt_on_options (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1436 char const *type_flag
= value_peek_string (argv
[0]);
1437 gnm_float s
= value_get_as_float (argv
[1]);
1438 gnm_float x1
= value_get_as_float (argv
[2]);
1439 gnm_float x2
= value_get_as_float (argv
[3]);
1440 gnm_float t1
= value_get_as_float (argv
[4]);
1441 gnm_float t2
= value_get_as_float (argv
[5]);
1442 gnm_float r
= value_get_as_float (argv
[6]);
1443 gnm_float b
= value_get_as_float (argv
[7]);
1444 gnm_float v
= value_get_as_float (argv
[8]);
1448 gnm_float y1
, y2
, z1
, z2
;
1450 OptionSide call_put
;
1452 if (!strcmp (type_flag
, "cc") || !strcmp (type_flag
, "pc"))
1457 I
= CriticalValueOptionsOnOptions (call_put
, x1
, x2
, t2
- t1
, r
, b
, v
);
1459 rho
= gnm_sqrt (t1
/ t2
);
1460 y1
= (gnm_log (s
/ I
) + (b
+ (v
* v
) / 2.0) * t1
) / (v
* gnm_sqrt (t1
));
1461 y2
= y1
- v
* gnm_sqrt (t1
);
1462 z1
= (gnm_log (s
/ x1
) + (b
+ (v
* v
) / 2.0) * t2
) / (v
* gnm_sqrt (t2
));
1463 z2
= z1
- v
* gnm_sqrt (t2
);
1465 if (!strcmp (type_flag
, "cc"))
1466 gfresult
= s
* gnm_exp ((b
- r
) * t2
) * cum_biv_norm_dist1 (z1
, y1
, rho
) -
1467 x1
* gnm_exp (-r
* t2
) * cum_biv_norm_dist1 (z2
, y2
, rho
) - x2
* gnm_exp (-r
* t1
) * ncdf (y2
);
1468 else if (!strcmp (type_flag
, "pc"))
1469 gfresult
= x1
* gnm_exp (-r
* t2
) * cum_biv_norm_dist1 (z2
, -y2
, -rho
) -
1470 s
* gnm_exp ((b
- r
) * t2
) * cum_biv_norm_dist1 (z1
, -y1
, -rho
) + x2
* gnm_exp (-r
* t1
) * ncdf (-y2
);
1471 else if (!strcmp (type_flag
, "cp"))
1472 gfresult
= x1
* gnm_exp (-r
* t2
) * cum_biv_norm_dist1 (-z2
, -y2
, rho
) -
1473 s
* gnm_exp ((b
- r
) * t2
) * cum_biv_norm_dist1 (-z1
, -y1
, rho
) - x2
* gnm_exp (-r
* t1
) * ncdf (-y2
);
1474 else if (!strcmp (type_flag
, "pp"))
1475 gfresult
= s
* gnm_exp ((b
- r
) * t2
) * cum_biv_norm_dist1 (-z1
, y1
, -rho
) -
1476 x1
* gnm_exp (-r
* t2
) * cum_biv_norm_dist1 (-z2
, y2
, -rho
) + gnm_exp (-r
* t1
) * x2
* ncdf (y2
);
1478 return value_new_error_VALUE (ei
->pos
);
1480 return value_new_float (gfresult
);
1483 static GnmFuncHelp
const help_opt_on_options
[] = {
1484 { GNM_FUNC_HELP_NAME
, F_("OPT_ON_OPTIONS:theoretical price of options on options")},
1485 { GNM_FUNC_HELP_ARG
, F_("type_flag:'cc' for calls on calls, 'cp' for calls on puts, and so on for 'pc', and 'pp'")},
1487 { GNM_FUNC_HELP_ARG
, F_("strike1:strike price at which the option being valued is struck")},
1488 { GNM_FUNC_HELP_ARG
, F_("strike2:strike price at which the underlying option is struck")},
1489 { GNM_FUNC_HELP_ARG
, F_("time1:time in years to maturity of the option")},
1490 { GNM_FUNC_HELP_ARG
, F_("time2:time in years to the maturity of the underlying option")},
1491 DEF_ARG_RATE_RISKFREE_ANN
,
1492 { GNM_FUNC_HELP_ARG
, F_("cost_of_carry:net cost of holding the underlying asset of the underlying option")},
1493 { GNM_FUNC_HELP_ARG
, F_("volatility:annualized volatility in price of the underlying asset of the underlying option")},
1494 { GNM_FUNC_HELP_NOTE
, F_("For common stocks, @{cost_of_carry} is the risk free rate less the dividend yield.")},
1495 { GNM_FUNC_HELP_NOTE
, F_("@{time2} \xe2\x89\xa5 @{time1}")},
1496 { GNM_FUNC_HELP_SEEALSO
, "OPT_BS,OPT_BS_DELTA,OPT_BS_RHO,OPT_BS_THETA,OPT_BS_GAMMA"},
1497 { GNM_FUNC_HELP_END
}
1501 /* Calculation of critical price options on options */
1503 CriticalValueOptionsOnOptions (OptionSide side
, gnm_float x1
, gnm_float x2
, gnm_float t
,
1504 gnm_float r
, gnm_float b
, gnm_float v
)
1506 gnm_float si
, ci
, di
, epsilon
;
1509 ci
= opt_bs1 (side
, si
, x1
, t
, r
, v
, b
);
1510 di
= opt_bs_delta1 (side
, si
, x1
, t
, r
, v
, b
);
1512 /* Newton-Raphson algorithm */
1514 while (gnm_abs (ci
- x2
) > epsilon
) {
1515 si
= si
- (ci
- x2
) / di
;
1516 ci
= opt_bs1 (side
, si
, x1
, t
, r
, v
, b
);
1517 di
= opt_bs_delta1 (side
, si
, x1
, t
, r
, v
, b
);
1522 /* Writer extendible options */
1524 opt_extendible_writer (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1526 OptionSide call_put
= option_side (value_peek_string (argv
[0]));
1527 gnm_float s
= value_get_as_float (argv
[1]);
1528 gnm_float x1
= value_get_as_float (argv
[2]);
1529 gnm_float x2
= value_get_as_float (argv
[3]);
1530 gnm_float t1
= value_get_as_float (argv
[4]);
1531 gnm_float t2
= value_get_as_float (argv
[5]);
1532 gnm_float r
= value_get_as_float (argv
[6]);
1533 gnm_float b
= value_get_as_float (argv
[7]);
1534 gnm_float v
= value_get_as_float (argv
[8]);
1536 gnm_float rho
= gnm_sqrt (t1
/ t2
);
1537 gnm_float z1
= (gnm_log (s
/ x2
) + (b
+ (v
* v
) / 2.0) * t2
) / (v
* gnm_sqrt (t2
));
1538 gnm_float z2
= (gnm_log (s
/ x1
) + (b
+ (v
* v
) / 2.0) * t1
) / (v
* gnm_sqrt (t1
));
1544 gfresult
= opt_bs1 (call_put
, s
, x1
, t1
, r
, v
, b
) +
1545 s
* gnm_exp ((b
- r
) * t2
) * cum_biv_norm_dist1 (z1
, -z2
, -rho
) -
1546 x2
* gnm_exp (-r
* t2
) * cum_biv_norm_dist1 (z1
- gnm_sqrt ((v
* v
) * t2
), -z2
+ gnm_sqrt ((v
* v
) * t1
), -rho
);
1549 gfresult
= opt_bs1 (call_put
, s
, x1
, t1
, r
, v
, b
) +
1550 x2
* gnm_exp (-r
* t2
) * cum_biv_norm_dist1 (-z1
+ gnm_sqrt ((v
* v
) * t2
), z2
- gnm_sqrt ((v
* v
) * t1
), -rho
) -
1551 s
* gnm_exp ((b
- r
) * t2
) * cum_biv_norm_dist1 (-z1
, z2
, -rho
);
1554 return value_new_error_NUM (ei
->pos
);
1557 return value_new_float (gfresult
);
1560 static GnmFuncHelp
const help_opt_extendible_writer
[] = {
1561 { GNM_FUNC_HELP_NAME
, F_("OPT_EXTENDIBLE_WRITER:theoretical price of extendible writer options")},
1562 DEF_ARG_CALL_PUT_FLAG
,
1564 { GNM_FUNC_HELP_ARG
, F_("strike1:strike price at which the option is struck")},
1565 { GNM_FUNC_HELP_ARG
, F_("strike2:strike price at which the option is re-struck if out of the money at @{time1}")},
1566 { GNM_FUNC_HELP_ARG
, F_("time1:initial maturity of the option in years")},
1567 { GNM_FUNC_HELP_ARG
, F_("time2:extended maturity in years if chosen")},
1568 DEF_ARG_RATE_RISKFREE_ANN
,
1570 DEF_ARG_VOLATILITY_SHORT
,
1571 { GNM_FUNC_HELP_DESCRIPTION
, F_("OPT_EXTENDIBLE_WRITER models the theoretical price of extendible "
1572 "writer options. These are options that have their maturity "
1573 "extended to @{time2} if the option is "
1574 "out of the money at @{time1}.")},
1575 { GNM_FUNC_HELP_SEEALSO
, "OPT_BS,OPT_BS_DELTA,OPT_BS_RHO,OPT_BS_THETA,OPT_BS_GAMMA"},
1576 { GNM_FUNC_HELP_END
}
1581 /* Two asset correlation options */
1583 opt_2_asset_correlation(GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1585 OptionSide call_put
= option_side (value_peek_string(argv
[0]));
1586 gnm_float s1
= value_get_as_float (argv
[1]);
1587 gnm_float s2
= value_get_as_float (argv
[2]);
1588 gnm_float x1
= value_get_as_float (argv
[3]);
1589 gnm_float x2
= value_get_as_float (argv
[4]);
1590 gnm_float t
= value_get_as_float (argv
[5]);
1591 gnm_float b1
= value_get_as_float (argv
[6]);
1592 gnm_float b2
= value_get_as_float (argv
[7]);
1593 gnm_float r
= value_get_as_float (argv
[8]);
1594 gnm_float v1
= value_get_as_float (argv
[9]);
1595 gnm_float v2
= value_get_as_float (argv
[10]);
1596 gnm_float rho
= value_get_as_float (argv
[11]);
1598 gnm_float y1
= (gnm_log (s1
/ x1
) + (b1
- (v1
* v1
) / 2.0) * t
) / (v1
* gnm_sqrt (t
));
1599 gnm_float y2
= (gnm_log (s2
/ x2
) + (b2
- (v2
* v2
) / 2.0) * t
) / (v2
* gnm_sqrt (t
));
1601 if (call_put
== OS_Call
) {
1602 return value_new_float (s2
* gnm_exp ((b2
- r
) * t
)
1603 * cum_biv_norm_dist1 (y2
+ v2
* gnm_sqrt (t
), y1
+ rho
* v2
* gnm_sqrt (t
), rho
)
1604 - x2
* gnm_exp (-r
* t
) * cum_biv_norm_dist1 (y2
, y1
, rho
));
1605 } else if (call_put
== OS_Put
) {
1606 return value_new_float (x2
* gnm_exp (-r
* t
) * cum_biv_norm_dist1 (-y2
, -y1
, rho
)
1607 - s2
* gnm_exp ((b2
- r
) * t
) * cum_biv_norm_dist1 (-y2
- v2
* gnm_sqrt (t
), -y1
- rho
* v2
* gnm_sqrt (t
), rho
));
1609 return value_new_error_NUM (ei
->pos
);
1612 static GnmFuncHelp
const help_opt_2_asset_correlation
[] = {
1613 { GNM_FUNC_HELP_NAME
, F_("OPT_2_ASSET_CORRELATION:theoretical price of options on 2 assets with correlation @{rho}")},
1614 DEF_ARG_CALL_PUT_FLAG
,
1615 { GNM_FUNC_HELP_ARG
, F_("spot1:spot price of the underlying asset of the first option")},
1616 { GNM_FUNC_HELP_ARG
, F_("spot2:spot price of the underlying asset of the second option")},
1617 { GNM_FUNC_HELP_ARG
, F_("strike1:strike prices of the first option")},
1618 { GNM_FUNC_HELP_ARG
, F_("strike2:strike prices of the second option")},
1619 DEF_ARG_TIME_MATURITY_Y
,
1620 { GNM_FUNC_HELP_ARG
, F_("cost_of_carry1:net cost of holding the underlying asset of the first option "
1621 "(for common stocks, the risk free rate less the dividend yield)")},
1622 { GNM_FUNC_HELP_ARG
, F_("cost_of_carry2:net cost of holding the underlying asset of the second option "
1623 "(for common stocks, the risk free rate less the dividend yield)")},
1624 DEF_ARG_RATE_RISKFREE_ANN
,
1625 { GNM_FUNC_HELP_ARG
, F_("volatility1:annualized volatility in price of the underlying asset of the first option")},
1626 { GNM_FUNC_HELP_ARG
, F_("volatility2:annualized volatility in price of the underlying asset of the second option")},
1627 { GNM_FUNC_HELP_ARG
, F_("rho:correlation between the two underlying assets")},
1628 { GNM_FUNC_HELP_DESCRIPTION
, F_("OPT_2_ASSET_CORRELATION models the theoretical price of options "
1629 "on 2 assets with correlation @{rho}. The payoff for a call is "
1630 "max(@{spot2} - @{strike2},0) if @{spot1} > @{strike1} or 0 otherwise. "
1631 "The payoff for a put is max (@{strike2} - @{spot2}, 0) if @{spot1} < @{strike1} or 0 otherwise.")},
1632 { GNM_FUNC_HELP_SEEALSO
, "OPT_BS,OPT_BS_DELTA,OPT_BS_RHO,OPT_BS_THETA,OPT_BS_GAMMA"},
1633 { GNM_FUNC_HELP_END
}
1637 /* European option to exchange one asset for another */
1639 opt_euro_exchange(GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1641 gnm_float s1
= value_get_as_float (argv
[0]);
1642 gnm_float s2
= value_get_as_float (argv
[1]);
1643 gnm_float q1
= value_get_as_float (argv
[2]);
1644 gnm_float q2
= value_get_as_float (argv
[3]);
1645 gnm_float t
= value_get_as_float (argv
[4]);
1646 gnm_float r
= value_get_as_float (argv
[5]);
1647 gnm_float b1
= value_get_as_float (argv
[6]);
1648 gnm_float b2
= value_get_as_float (argv
[7]);
1649 gnm_float v1
= value_get_as_float (argv
[8]);
1650 gnm_float v2
= value_get_as_float (argv
[9]);
1651 gnm_float rho
= value_get_as_float (argv
[10]);
1652 gnm_float v
, d1
, d2
;
1654 v
= gnm_sqrt (v1
* v1
+ v2
* v2
- 2 * rho
* v1
* v2
);
1655 d1
= (gnm_log (q1
* s1
/ (q2
* s2
)) + (b1
- b2
+ (v
* v
) / 2.0) * t
) / (v
* gnm_sqrt (t
));
1656 d2
= d1
- v
* gnm_sqrt (t
);
1658 return value_new_float (q1
* s1
* gnm_exp ((b1
- r
) * t
) * ncdf (d1
) -
1659 q2
* s2
* gnm_exp ((b2
- r
) * t
) * ncdf (d2
));
1662 static GnmFuncHelp
const help_opt_euro_exchange
[] = {
1663 { GNM_FUNC_HELP_NAME
, F_("OPT_EURO_EXCHANGE:theoretical price of a European option to exchange assets")},
1664 { GNM_FUNC_HELP_ARG
, F_("spot1:spot price of asset 1")},
1665 { GNM_FUNC_HELP_ARG
, F_("spot2:spot price of asset 2")},
1666 { GNM_FUNC_HELP_ARG
, F_("qty1:quantity of asset 1")},
1667 { GNM_FUNC_HELP_ARG
, F_("qty2:quantity of asset 2")},
1668 DEF_ARG_TIME_MATURITY_Y
,
1669 DEF_ARG_RATE_RISKFREE_ANN
,
1670 { GNM_FUNC_HELP_ARG
, F_("cost_of_carry1:net cost of holding asset 1 "
1671 "(for common stocks, the risk free rate less the dividend yield)")},
1672 { GNM_FUNC_HELP_ARG
, F_("cost_of_carry2:net cost of holding asset 2 "
1673 "(for common stocks, the risk free rate less the dividend yield)")},
1674 { GNM_FUNC_HELP_ARG
, F_("volatility1:annualized volatility in price of asset 1")},
1675 { GNM_FUNC_HELP_ARG
, F_("volatility2:annualized volatility in price of asset 2")},
1676 { GNM_FUNC_HELP_ARG
, F_("rho:correlation between the prices of the two assets")},
1677 { GNM_FUNC_HELP_DESCRIPTION
, F_("OPT_EURO_EXCHANGE models the theoretical price of a European "
1678 "option to exchange one asset with quantity @{qty2} and spot "
1679 "price @{spot2} for another with quantity @{qty1} and spot price "
1681 { GNM_FUNC_HELP_SEEALSO
, "OPT_AMER_EXCHANGE,OPT_BS,OPT_BS_DELTA,OPT_BS_RHO,OPT_BS_THETA,OPT_BS_GAMMA"},
1682 { GNM_FUNC_HELP_END
}
1686 /* American option to exchange one asset for another */
1688 opt_amer_exchange(GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1690 gnm_float s1
= value_get_as_float (argv
[0]);
1691 gnm_float s2
= value_get_as_float (argv
[1]);
1692 gnm_float q1
= value_get_as_float (argv
[2]);
1693 gnm_float q2
= value_get_as_float (argv
[3]);
1694 gnm_float t
= value_get_as_float (argv
[4]);
1695 gnm_float r
= value_get_as_float (argv
[5]);
1696 gnm_float b1
= value_get_as_float (argv
[6]);
1697 gnm_float b2
= value_get_as_float (argv
[7]);
1698 gnm_float v1
= value_get_as_float (argv
[8]);
1699 gnm_float v2
= value_get_as_float (argv
[9]);
1700 gnm_float rho
= value_get_as_float (argv
[10]);
1701 gnm_float v
= gnm_sqrt (v1
* v1
+ v2
* v2
- 2 * rho
* v1
* v2
);
1703 return value_new_float (opt_bjer_stens1 (OS_Call
, q1
* s1
, q2
* s2
, t
, r
- b2
, v
,b1
- b2
));
1706 static GnmFuncHelp
const help_opt_amer_exchange
[] = {
1707 { GNM_FUNC_HELP_NAME
, F_("OPT_AMER_EXCHANGE:theoretical price of an American option to exchange assets")},
1708 { GNM_FUNC_HELP_ARG
, F_("spot1:spot price of asset 1")},
1709 { GNM_FUNC_HELP_ARG
, F_("spot2:spot price of asset 2")},
1710 { GNM_FUNC_HELP_ARG
, F_("qty1:quantity of asset 1")},
1711 { GNM_FUNC_HELP_ARG
, F_("qty2:quantity of asset 2")},
1712 DEF_ARG_TIME_MATURITY_Y
,
1713 DEF_ARG_RATE_RISKFREE_ANN
,
1714 { GNM_FUNC_HELP_ARG
, F_("cost_of_carry1:net cost of holding asset 1 "
1715 "(for common stocks, the risk free rate less the dividend yield)")},
1716 { GNM_FUNC_HELP_ARG
, F_("cost_of_carry2:net cost of holding asset 2 "
1717 "(for common stocks, the risk free rate less the dividend yield)")},
1718 { GNM_FUNC_HELP_ARG
, F_("volatility1:annualized volatility in price of asset 1")},
1719 { GNM_FUNC_HELP_ARG
, F_("volatility2:annualized volatility in price of asset 2")},
1720 { GNM_FUNC_HELP_ARG
, F_("rho:correlation between the prices of the two assets")},
1721 { GNM_FUNC_HELP_DESCRIPTION
, F_("OPT_AMER_EXCHANGE models the theoretical price of an American "
1722 "option to exchange one asset with quantity @{qty2} and spot "
1723 "price @{spot2} for another with quantity @{qty1} and spot price "
1725 { GNM_FUNC_HELP_SEEALSO
, "OPT_EURO_EXCHANGE,OPT_BS,OPT_BS_DELTA,OPT_BS_RHO,OPT_BS_THETA,OPT_BS_GAMMA"},
1726 { GNM_FUNC_HELP_END
}
1730 /* Spread option approximation */
1732 opt_spread_approx(GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1734 OptionSide call_put_flag
= option_side (value_peek_string(argv
[0]));
1735 gnm_float f1
= value_get_as_float (argv
[1]);
1736 gnm_float f2
= value_get_as_float (argv
[2]);
1737 gnm_float x
= value_get_as_float (argv
[3]);
1738 gnm_float t
= value_get_as_float (argv
[4]);
1739 gnm_float r
= value_get_as_float (argv
[5]);
1740 gnm_float v1
= value_get_as_float (argv
[6]);
1741 gnm_float v2
= value_get_as_float (argv
[7]);
1742 gnm_float rho
= value_get_as_float (argv
[8]);
1744 gnm_float v
= gnm_sqrt (v1
* v1
+ gnm_pow ((v2
* f2
/ (f2
+ x
)), 2) - 2 * rho
* v1
* v2
* f2
/ (f2
+ x
));
1745 gnm_float F
= f1
/ (f2
+ x
);
1747 return value_new_float (opt_bs1 (call_put_flag
, F
, 1.0, t
, r
, v
, 0.0) * (f2
+ x
));
1750 static GnmFuncHelp
const help_opt_spread_approx
[] = {
1751 { GNM_FUNC_HELP_NAME
, F_("OPT_SPREAD_APPROX:theoretical price of a European option on the spread between two futures contracts")},
1752 DEF_ARG_CALL_PUT_FLAG
,
1753 { GNM_FUNC_HELP_ARG
, F_("fut_price1:price of the first futures contract")},
1754 { GNM_FUNC_HELP_ARG
, F_("fut_price2:price of the second futures contract")},
1756 DEF_ARG_TIME_MATURITY_Y
,
1757 DEF_ARG_RATE_RISKFREE_ANN
,
1758 { GNM_FUNC_HELP_ARG
, F_("volatility1:annualized volatility in price of the first underlying futures contract")},
1759 { GNM_FUNC_HELP_ARG
, F_("volatility2:annualized volatility in price of the second underlying futures contract")},
1760 { GNM_FUNC_HELP_ARG
, F_("rho:correlation between the two futures contracts")},
1761 { GNM_FUNC_HELP_SEEALSO
, "OPT_BS,OPT_BS_DELTA,OPT_BS_RHO,OPT_BS_THETA,OPT_BS_GAMMA"},
1762 { GNM_FUNC_HELP_END
}
1766 /* Floating strike lookback options */
1768 opt_float_strk_lkbk(GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1770 OptionSide call_put_flag
= option_side (value_peek_string(argv
[0]));
1771 gnm_float s
= value_get_as_float (argv
[1]);
1772 gnm_float s_min
= value_get_as_float (argv
[2]);
1773 gnm_float s_max
= value_get_as_float (argv
[3]);
1774 gnm_float t
= value_get_as_float (argv
[4]);
1775 gnm_float r
= value_get_as_float (argv
[5]);
1776 gnm_float b
= value_get_as_float (argv
[6]);
1777 gnm_float v
= value_get_as_float (argv
[7]);
1779 gnm_float a1
, a2
, m
;
1781 if(OS_Call
== call_put_flag
)
1783 else if(OS_Put
== call_put_flag
)
1786 return value_new_error_NUM (ei
->pos
);
1788 a1
= (gnm_log (s
/ m
) + (b
+ (v
* v
) / 2.0) * t
) / (v
* gnm_sqrt (t
));
1789 a2
= a1
- v
* gnm_sqrt (t
);
1791 if(OS_Call
== call_put_flag
)
1792 return value_new_float (s
* gnm_exp ((b
- r
) * t
) * ncdf (a1
) -
1793 m
* gnm_exp (-r
* t
) * ncdf (a2
) +
1794 gnm_exp (-r
* t
) * (v
* v
) / (2 * b
) * s
* (gnm_pow (s
/ m
, (-2 * b
/ (v
* v
))) * ncdf (-a1
+ 2 * b
/ v
* gnm_sqrt (t
)) -
1795 gnm_exp (b
* t
) * ncdf (-a1
)));
1796 else if(OS_Put
== call_put_flag
)
1797 return value_new_float (m
* gnm_exp (-r
* t
) * ncdf (-a2
) -
1798 s
* gnm_exp ((b
- r
) * t
) * ncdf (-a1
) +
1799 gnm_exp (-r
* t
) * (v
* v
) / (2 * b
) * s
* (-gnm_pow (s
/ m
, ((-2 * b
) / (v
* v
))) * ncdf (a1
- 2 * b
/ v
* gnm_sqrt (t
)) +
1800 gnm_exp (b
* t
) * ncdf (a1
)));
1802 return value_new_error_VALUE (ei
->pos
);
1805 static GnmFuncHelp
const help_opt_float_strk_lkbk
[] = {
1806 { GNM_FUNC_HELP_NAME
, F_("OPT_FLOAT_STRK_LKBK:theoretical price of floating-strike lookback option")},
1807 DEF_ARG_CALL_PUT_FLAG
,
1809 { GNM_FUNC_HELP_ARG
, F_("spot_min:minimum spot price of the underlying asset so far observed")},
1810 { GNM_FUNC_HELP_ARG
, F_("spot_max:maximum spot price of the underlying asset so far observed")},
1811 DEF_ARG_TIME_MATURITY_Y
,
1812 DEF_ARG_RATE_RISKFREE_ANN
,
1814 DEF_ARG_VOLATILITY_SHORT
,
1815 { GNM_FUNC_HELP_DESCRIPTION
, F_("OPT_FLOAT_STRK_LKBK determines the theoretical price of a "
1816 "floating-strike lookback option where the holder "
1817 "of the option may exercise on expiry at the most favourable price "
1818 "observed during the options life of the underlying asset.")},
1819 { GNM_FUNC_HELP_SEEALSO
, "OPT_BS,OPT_BS_DELTA,OPT_BS_RHO,OPT_BS_THETA,OPT_BS_GAMMA"},
1820 { GNM_FUNC_HELP_END
}
1824 /* Fixed strike lookback options */
1827 opt_fixed_strk_lkbk(GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1829 OptionSide call_put_flag
= option_side (value_peek_string(argv
[0]));
1830 gnm_float s
= value_get_as_float (argv
[1]);
1831 gnm_float s_min
= value_get_as_float (argv
[2]);
1832 gnm_float s_max
= value_get_as_float (argv
[3]);
1833 gnm_float x
= value_get_as_float (argv
[4]);
1834 gnm_float t
= value_get_as_float (argv
[5]);
1835 gnm_float r
= value_get_as_float (argv
[6]);
1836 gnm_float b
= value_get_as_float (argv
[7]);
1837 gnm_float v
= value_get_as_float (argv
[8]);
1840 gnm_float e1
, e2
, m
;
1842 if (OS_Call
== call_put_flag
)
1844 else if (OS_Put
== call_put_flag
)
1847 return value_new_error_VALUE (ei
->pos
);
1849 d1
= (gnm_log (s
/ x
) + (b
+ (v
* v
) / 2.0) * t
) / (v
* gnm_sqrt (t
));
1850 d2
= d1
- v
* gnm_sqrt (t
);
1851 e1
= (gnm_log (s
/ m
) + (b
+ (v
* v
) / 2.0) * t
) / (v
* gnm_sqrt (t
));
1852 e2
= e1
- v
* gnm_sqrt (t
);
1854 if (OS_Call
== call_put_flag
&& x
> m
)
1855 return value_new_float (s
* gnm_exp ((b
- r
) * t
) * ncdf (d1
) - x
* gnm_exp (-r
* t
) * ncdf (d2
) + s
* gnm_exp (-r
* t
) * (v
* v
) / (2 * b
) * (-gnm_pow ((s
/ x
), (-2 * b
/ (v
* v
))) * ncdf (d1
- 2 * b
/ v
* gnm_sqrt (t
)) + gnm_exp (b
* t
) * ncdf (d1
)));
1857 else if (OS_Call
== call_put_flag
&& x
<= m
)
1858 return value_new_float (gnm_exp (-r
* t
) * (m
- x
) + s
* gnm_exp ((b
- r
) * t
) * ncdf (e1
) - gnm_exp (-r
* t
) * m
* ncdf (e2
) + s
* gnm_exp (-r
* t
) * (v
* v
) / (2 * b
) * (-gnm_pow ((s
/ m
), (-2 * b
/ (v
* v
))) * ncdf (e1
- 2 * b
/ v
* gnm_sqrt (t
)) + gnm_exp (b
* t
) * ncdf (e1
)));
1860 else if (OS_Put
== call_put_flag
&& x
< m
)
1861 return value_new_float (-s
* gnm_exp ((b
- r
) * t
) * ncdf (-d1
) + x
* gnm_exp (-r
* t
) * ncdf (-d1
+ v
* gnm_sqrt (t
)) + s
* gnm_exp (-r
* t
) * (v
* v
) / (2 * b
) * (gnm_pow ((s
/ x
), (-2 * b
/ (v
* v
))) * ncdf (-d1
+ 2 * b
/ v
* gnm_sqrt (t
)) - gnm_exp (b
* t
) * ncdf (-d1
)));
1863 else if (OS_Put
== call_put_flag
&& x
>= m
)
1864 return value_new_float (gnm_exp (-r
* t
) * (x
- m
) - s
* gnm_exp ((b
- r
) * t
) * ncdf (-e1
) + gnm_exp (-r
* t
) * m
* ncdf (-e1
+ v
* gnm_sqrt (t
)) + gnm_exp (-r
* t
) * (v
* v
) / (2 * b
) * s
* (gnm_pow ((s
/ m
), (-2 * b
/ (v
* v
))) * ncdf (-e1
+ 2 * b
/ v
* gnm_sqrt (t
)) - gnm_exp (b
* t
) * ncdf (-e1
)));
1866 return value_new_error_VALUE (ei
->pos
);
1869 static GnmFuncHelp
const help_opt_fixed_strk_lkbk
[] = {
1870 { GNM_FUNC_HELP_NAME
, F_("OPT_FIXED_STRK_LKBK:theoretical price of a fixed-strike lookback option")},
1871 DEF_ARG_CALL_PUT_FLAG
,
1873 { GNM_FUNC_HELP_ARG
, F_("spot_min:minimum spot price of the underlying asset so far observed")},
1874 { GNM_FUNC_HELP_ARG
, F_("spot_max:maximum spot price of the underlying asset so far observed")},
1876 DEF_ARG_TIME_MATURITY_Y
,
1877 DEF_ARG_RATE_RISKFREE_ANN
,
1879 DEF_ARG_VOLATILITY_SHORT
,
1880 { GNM_FUNC_HELP_DESCRIPTION
, F_("OPT_FIXED_STRK_LKBK determines the theoretical price of a "
1881 "fixed-strike lookback option where the holder "
1882 "of the option may exercise on expiry at the most favourable price "
1883 "observed during the options life of the underlying asset.")},
1884 { GNM_FUNC_HELP_SEEALSO
, "OPT_BS,OPT_BS_DELTA,OPT_BS_RHO,OPT_BS_THETA,OPT_BS_GAMMA"},
1885 { GNM_FUNC_HELP_END
}
1890 /* Binomial Tree valuation */
1892 opt_binomial(GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1894 OptionType amer_euro_flag
= option_type(value_peek_string(argv
[0]));
1895 OptionSide call_put_flag
= option_side (value_peek_string(argv
[1]));
1896 gnm_float n
= gnm_floor (value_get_as_float (argv
[2]));
1897 gnm_float s
= value_get_as_float (argv
[3]);
1898 gnm_float x
= value_get_as_float (argv
[4]);
1899 gnm_float t
= value_get_as_float (argv
[5]);
1900 gnm_float r
= value_get_as_float (argv
[6]);
1901 gnm_float v
= value_get_as_float (argv
[7]);
1902 gnm_float b
= argv
[8] ? value_get_as_float (argv
[8]) : 0;
1904 gnm_float
*value_array
;
1905 gnm_float u
, d
, p
, dt
, Df
, temp1
, temp2
, gf_result
;
1908 if (n
< 0 || n
> 100000)
1909 return value_new_error_NUM (ei
->pos
);
1911 if (OS_Call
== call_put_flag
)
1913 else if (OS_Put
== call_put_flag
)
1916 return value_new_error_NUM (ei
->pos
);
1918 if (OT_Error
== amer_euro_flag
)
1919 return value_new_error_NUM (ei
->pos
);
1921 value_array
= (gnm_float
*) g_try_malloc ((n
+ 2)* sizeof(gnm_float
));
1922 if (value_array
== NULL
)
1923 return value_new_error_NUM (ei
->pos
);
1926 u
= gnm_exp (v
* gnm_sqrt (dt
));
1928 p
= (gnm_exp (b
* dt
) - d
) / (u
- d
);
1929 Df
= gnm_exp (-r
* dt
);
1931 for (i
= 0; i
<= n
; ++i
) {
1932 temp1
= z
* (s
* gnm_pow (u
, i
) * gnm_pow (d
, (n
- i
)) - x
);
1933 value_array
[i
] = MAX (temp1
, 0.0);
1936 for (j
= n
- 1; j
> -1; --j
) {
1937 for (i
= 0; i
<= j
; ++i
) {
1938 /*if (0==i)g_printerr("secondloop %d\n",j);*/
1939 if (OT_Euro
== amer_euro_flag
)
1940 value_array
[i
] = (p
* value_array
[i
+ 1] + (1.0 - p
) * value_array
[i
]) * Df
;
1941 else if (OT_Amer
== amer_euro_flag
) {
1942 temp1
= (z
* (s
* gnm_pow (u
, i
) * gnm_pow (d
, (gnm_abs (i
- j
))) - x
));
1943 temp2
= (p
* value_array
[i
+ 1] + (1.0 - p
) * value_array
[i
]) * Df
;
1944 value_array
[i
] = MAX (temp1
, temp2
);
1948 gf_result
= value_array
[0];
1949 g_free (value_array
);
1950 return value_new_float (gf_result
);
1953 static GnmFuncHelp
const help_opt_binomial
[] = {
1954 { GNM_FUNC_HELP_NAME
, F_("OPT_BINOMIAL:theoretical price of either an American or European style option using a binomial tree")},
1955 { GNM_FUNC_HELP_ARG
, F_("amer_euro_flag:'a' for an American style option or 'e' for a European style option")},
1956 DEF_ARG_CALL_PUT_FLAG
,
1957 { GNM_FUNC_HELP_ARG
, F_("num_time_steps:number of time steps used in the valuation")},
1960 DEF_ARG_TIME_MATURITY_Y
,
1961 DEF_ARG_RATE_RISKFREE_ANN
,
1962 DEF_ARG_VOLATILITY_SHORT
,
1964 { GNM_FUNC_HELP_NOTE
, F_("A larger @{num_time_steps} yields greater accuracy but OPT_BINOMIAL is slower to calculate.")},
1965 { GNM_FUNC_HELP_SEEALSO
, "OPT_BS,OPT_BS_DELTA,OPT_BS_RHO,OPT_BS_THETA,OPT_BS_GAMMA"},
1966 { GNM_FUNC_HELP_END
}
1971 GnmFuncDescriptor
const derivatives_functions
[] = {
1974 help_opt_bs
, opt_bs
, NULL
,
1975 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_BASIC
},
1979 help_opt_bs_delta
, opt_bs_delta
, NULL
,
1980 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_BASIC
},
1984 help_opt_bs_rho
, opt_bs_rho
, NULL
,
1985 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_BASIC
},
1989 help_opt_bs_theta
, opt_bs_theta
, NULL
,
1990 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_BASIC
},
1994 help_opt_bs_gamma
, opt_bs_gamma
, NULL
,
1995 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_BASIC
},
1999 help_opt_bs_vega
, opt_bs_vega
, NULL
,
2000 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_BASIC
},
2002 { "opt_bs_carrycost",
2004 help_opt_bs_carrycost
, opt_bs_carrycost
, NULL
,
2005 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_BASIC
},
2007 { "cum_biv_norm_dist",
2009 help_cum_biv_norm_dist
, cum_biv_norm_dist
, NULL
,
2010 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_NO_TESTSUITE
},
2012 { "opt_garman_kohlhagen",
2014 help_opt_garman_kohlhagen
, opt_garman_kohlhagen
, NULL
,
2015 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_BASIC
},
2019 help_opt_french
, opt_french
, NULL
,
2020 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_BASIC
},
2024 help_opt_jump_diff
, opt_jump_diff
, NULL
,
2025 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_BASIC
},
2029 help_opt_exec
, opt_exec
, NULL
,
2030 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_BASIC
},
2034 help_opt_bjer_stens
, opt_bjer_stens
, NULL
,
2035 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_BASIC
},
2037 { "opt_miltersen_schwartz",
2039 help_opt_miltersen_schwartz
, opt_miltersen_schwartz
, NULL
,
2040 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_BASIC
},
2044 help_opt_baw_amer
, opt_baw_amer
, NULL
,
2045 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_BASIC
},
2049 help_opt_rgw
, opt_rgw
, NULL
,
2050 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_BASIC
},
2052 { "opt_forward_start",
2054 help_opt_forward_start
, opt_forward_start
, NULL
,
2055 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_BASIC
},
2057 { "opt_time_switch",
2059 help_opt_time_switch
, opt_time_switch
, NULL
,
2060 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_BASIC
},
2062 { "opt_simple_chooser",
2064 help_opt_simple_chooser
, opt_simple_chooser
, NULL
,
2065 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_BASIC
},
2067 { "opt_complex_chooser",
2069 help_opt_complex_chooser
, opt_complex_chooser
, NULL
,
2070 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_BASIC
},
2074 help_opt_on_options
, opt_on_options
, NULL
,
2075 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_BASIC
},
2077 { "opt_extendible_writer",
2079 help_opt_extendible_writer
, opt_extendible_writer
, NULL
,
2080 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_BASIC
},
2082 { "opt_2_asset_correlation",
2084 help_opt_2_asset_correlation
, opt_2_asset_correlation
, NULL
,
2085 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_BASIC
},
2087 { "opt_euro_exchange",
2089 help_opt_euro_exchange
, opt_euro_exchange
, NULL
,
2090 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_BASIC
},
2092 { "opt_amer_exchange",
2094 help_opt_amer_exchange
, opt_amer_exchange
, NULL
,
2095 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_BASIC
},
2097 { "opt_spread_approx",
2099 help_opt_spread_approx
, opt_spread_approx
, NULL
,
2100 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_BASIC
},
2102 { "opt_float_strk_lkbk",
2104 help_opt_float_strk_lkbk
, opt_float_strk_lkbk
, NULL
,
2105 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_BASIC
},
2107 { "opt_fixed_strk_lkbk",
2109 help_opt_fixed_strk_lkbk
, opt_fixed_strk_lkbk
, NULL
,
2110 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_BASIC
},
2115 help_opt_binomial
, opt_binomial
, NULL
,
2116 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_BASIC
},