rupee 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/ext/rupee/option.c +542 -46
- data/ext/rupee/rupee.h +18 -2
- data/ext/rupee/statistics.c +133 -0
- data/lib/rupee.rb +1 -0
- data/lib/rupee/calendar.rb +238 -0
- data/lib/rupee/calendar/japan.rb +54 -0
- data/lib/rupee/calendar/us.rb +59 -0
- data/lib/rupee/option.rb +8 -0
- data/lib/rupee/quote.rb +37 -8
- data/lib/rupee/version.rb +1 -1
- data/spec/native/option_spec.rb +118 -31
- data/spec/ruby/calendar_spec.rb +85 -0
- data/test_rubies +0 -0
- metadata +49 -49
data/ext/rupee/option.c
CHANGED
@@ -9,7 +9,7 @@ is_call(call_put_flag)
|
|
9
9
|
return (call_put_flag[0] != 'p');
|
10
10
|
}
|
11
11
|
|
12
|
-
|
12
|
+
double
|
13
13
|
bs(call_put_flag, S, X, T, r, q, v)
|
14
14
|
const char *call_put_flag;
|
15
15
|
double S, X, T, r, q, v;
|
@@ -25,9 +25,477 @@ bs(call_put_flag, S, X, T, r, q, v)
|
|
25
25
|
return X * exp(-r * T) * cnd(-d2) - S * exp(-q * T) * cnd(-d1);
|
26
26
|
}
|
27
27
|
|
28
|
-
|
29
|
-
|
30
|
-
|
28
|
+
// GREEKS
|
29
|
+
|
30
|
+
double
|
31
|
+
delta(call_put_flag, S, K, T, r, q, v)
|
32
|
+
const char *call_put_flag;
|
33
|
+
double S, K, T, r, q, v;
|
34
|
+
{
|
35
|
+
double d1;
|
36
|
+
|
37
|
+
d1 = (log(S / K) + (r - q + v * v / 2) * T) / (v * sqrt(T));
|
38
|
+
|
39
|
+
if (is_call(call_put_flag))
|
40
|
+
return exp(-q * T) * cnd(d1);
|
41
|
+
else
|
42
|
+
return -exp(-q * T) * cnd(-d1);
|
43
|
+
}
|
44
|
+
|
45
|
+
double
|
46
|
+
vega(call_put_flag, S, K, T, r, q, v)
|
47
|
+
const char *call_put_flag;
|
48
|
+
double S, K, T, r, q, v;
|
49
|
+
{
|
50
|
+
double d1;
|
51
|
+
|
52
|
+
d1 = (log(S / K) + (r - q + v * v / 2) * T) / (v * sqrt(T));
|
53
|
+
|
54
|
+
return S * exp(-q * T) * pdf(d1) * sqrt(T);
|
55
|
+
}
|
56
|
+
|
57
|
+
double
|
58
|
+
theta(call_put_flag, S, K, T, r, q, v)
|
59
|
+
const char *call_put_flag;
|
60
|
+
double S, K, T, r, q, v;
|
61
|
+
{
|
62
|
+
double d1, d2;
|
63
|
+
|
64
|
+
d1 = (log(S / K) + (r - q + v * v / 2) * T) / (v * sqrt(T));
|
65
|
+
d2 = d1 - v * sqrt(T);
|
66
|
+
|
67
|
+
if (is_call(call_put_flag))
|
68
|
+
return -exp(-q * T) * (S * pdf(d1) * v) / (2 * sqrt(T)) -
|
69
|
+
r * K * exp(-r * T) * cnd(d2) + q * S * exp(-q * T) * cnd(d1);
|
70
|
+
else
|
71
|
+
return -exp(-q * T) * (S * pdf(d1) * v) / (2 * sqrt(T)) +
|
72
|
+
r * K * exp(-r * T) * cnd(-d2) - q * S * exp(-q * T) * cnd(-d1);
|
73
|
+
}
|
74
|
+
|
75
|
+
double
|
76
|
+
rho(call_put_flag, S, K, T, r, q, v)
|
77
|
+
const char *call_put_flag;
|
78
|
+
double S, K, T, r, q, v;
|
79
|
+
{
|
80
|
+
double d1, d2;
|
81
|
+
|
82
|
+
d1 = (log(S / K) + (r - q + v * v / 2) * T) / (v * sqrt(T));
|
83
|
+
d2 = d1 - v * sqrt(T);
|
84
|
+
|
85
|
+
if (is_call(call_put_flag))
|
86
|
+
return K * T * exp(-r * T) * cnd(d2);
|
87
|
+
else
|
88
|
+
return -K * T * exp(-r * T) * cnd(-d2);
|
89
|
+
}
|
90
|
+
|
91
|
+
double
|
92
|
+
bs_gamma(call_put_flag, S, K, T, r, q, v)
|
93
|
+
const char *call_put_flag;
|
94
|
+
double S, K, T, r, q, v;
|
95
|
+
{
|
96
|
+
double d1;
|
97
|
+
|
98
|
+
d1 = (log(S / K) + (r - q + v * v / 2) * T) / (v * sqrt(T));
|
99
|
+
|
100
|
+
return exp(-q * T) * pdf(d1) / (S * v * sqrt(T));
|
101
|
+
}
|
102
|
+
|
103
|
+
/* call-seq: delta(call_put_flag, underlying, strike, time, rate, div_yield,
|
104
|
+
* volatility)
|
105
|
+
*
|
106
|
+
* Returns the delta options Greek (sensitivity to changes in the underlying's
|
107
|
+
* price
|
108
|
+
*/
|
109
|
+
static VALUE
|
110
|
+
rupee_delta(self, _call_put_flag, _S, _K, _T, _r, _q, _v)
|
111
|
+
VALUE self, _call_put_flag, _S, _K, _T, _r, _q, _v;
|
112
|
+
{
|
113
|
+
const char *call_put_flag;
|
114
|
+
double S, K, T, r, q, v;
|
115
|
+
|
116
|
+
call_put_flag = StringValuePtr(_call_put_flag);
|
117
|
+
S = NUM2DBL(_S);
|
118
|
+
K = NUM2DBL(_K);
|
119
|
+
T = NUM2DBL(_T);
|
120
|
+
r = NUM2DBL(_r);
|
121
|
+
q = NUM2DBL(_q);
|
122
|
+
v = NUM2DBL(_v);
|
123
|
+
|
124
|
+
return rb_float_new(delta(call_put_flag, S, K, T, r, q, v));
|
125
|
+
}
|
126
|
+
|
127
|
+
/* call-seq: vega(call_put_flag, underlying, strike, time, rate, div_yield,
|
128
|
+
* volatility)
|
129
|
+
*
|
130
|
+
* Returns the vega options Greek (sensitivity to changes in volatility)
|
131
|
+
*/
|
132
|
+
static VALUE
|
133
|
+
rupee_vega(self, _call_put_flag, _S, _K, _T, _r, _q, _v)
|
134
|
+
VALUE self, _call_put_flag, _S, _K, _T, _r, _q, _v;
|
135
|
+
{
|
136
|
+
const char *call_put_flag;
|
137
|
+
double S, K, T, r, q, v;
|
138
|
+
|
139
|
+
call_put_flag = StringValuePtr(_call_put_flag);
|
140
|
+
S = NUM2DBL(_S);
|
141
|
+
K = NUM2DBL(_K);
|
142
|
+
T = NUM2DBL(_T);
|
143
|
+
r = NUM2DBL(_r);
|
144
|
+
q = NUM2DBL(_q);
|
145
|
+
v = NUM2DBL(_v);
|
146
|
+
|
147
|
+
return rb_float_new(vega(call_put_flag, S, K, T, r, q, v));
|
148
|
+
}
|
149
|
+
|
150
|
+
/* call-seq: theta(call_put_flag, underlying, strike, time, rate, div_yield,
|
151
|
+
* volatility)
|
152
|
+
*
|
153
|
+
* returns the theta options greek (sensitivity to the passage of time; time
|
154
|
+
* decay)
|
155
|
+
*/
|
156
|
+
static VALUE
|
157
|
+
rupee_theta(self, _call_put_flag, _S, _K, _T, _r, _q, _v)
|
158
|
+
VALUE self, _call_put_flag, _S, _K, _T, _r, _q, _v;
|
159
|
+
{
|
160
|
+
const char *call_put_flag;
|
161
|
+
double S, K, T, r, q, v;
|
162
|
+
|
163
|
+
call_put_flag = StringValuePtr(_call_put_flag);
|
164
|
+
S = NUM2DBL(_S);
|
165
|
+
K = NUM2DBL(_K);
|
166
|
+
T = NUM2DBL(_T);
|
167
|
+
r = NUM2DBL(_r);
|
168
|
+
q = NUM2DBL(_q);
|
169
|
+
v = NUM2DBL(_v);
|
170
|
+
|
171
|
+
return rb_float_new(theta(call_put_flag, S, K, T, r, q, v));
|
172
|
+
}
|
173
|
+
|
174
|
+
/* call-seq: rho(call_put_flag, underlying, strike, time, rate, div_yield,
|
175
|
+
* volatility)
|
176
|
+
*
|
177
|
+
* Returns the rho options Greek (sensitivity to the risk-free rate)
|
178
|
+
*/
|
179
|
+
static VALUE
|
180
|
+
rupee_rho(self, _call_put_flag, _S, _K, _T, _r, _q, _v)
|
181
|
+
VALUE self, _call_put_flag, _S, _K, _T, _r, _q, _v;
|
182
|
+
{
|
183
|
+
const char *call_put_flag;
|
184
|
+
double S, K, T, r, q, v;
|
185
|
+
|
186
|
+
call_put_flag = StringValuePtr(_call_put_flag);
|
187
|
+
S = NUM2DBL(_S);
|
188
|
+
K = NUM2DBL(_K);
|
189
|
+
T = NUM2DBL(_T);
|
190
|
+
r = NUM2DBL(_r);
|
191
|
+
q = NUM2DBL(_q);
|
192
|
+
v = NUM2DBL(_v);
|
193
|
+
|
194
|
+
return rb_float_new(rho(call_put_flag, S, K, T, r, q, v));
|
195
|
+
}
|
196
|
+
|
197
|
+
/* call-seq: gamma(call_put_flag, underlying, strike, time, rate, div_yield,
|
198
|
+
* volatility)
|
199
|
+
*
|
200
|
+
* Returns the gamma options Greek (sensitivity to changes in delta; convexity)
|
201
|
+
*/
|
202
|
+
static VALUE
|
203
|
+
rupee_gamma(self, _call_put_flag, _S, _K, _T, _r, _q, _v)
|
204
|
+
VALUE self, _call_put_flag, _S, _K, _T, _r, _q, _v;
|
205
|
+
{
|
206
|
+
const char *call_put_flag;
|
207
|
+
double S, K, T, r, q, v;
|
208
|
+
|
209
|
+
call_put_flag = StringValuePtr(_call_put_flag);
|
210
|
+
S = NUM2DBL(_S);
|
211
|
+
K = NUM2DBL(_K);
|
212
|
+
T = NUM2DBL(_T);
|
213
|
+
r = NUM2DBL(_r);
|
214
|
+
q = NUM2DBL(_q);
|
215
|
+
v = NUM2DBL(_v);
|
216
|
+
|
217
|
+
return rb_float_new(bs_gamma(call_put_flag, S, K, T, r, q, v));
|
218
|
+
}
|
219
|
+
|
220
|
+
/* call-seq: vanna(call_put_flag, S, K, T, r, q, v)
|
221
|
+
*
|
222
|
+
* Returns the vanna options Greek (sensitivity of delta to changes in
|
223
|
+
* volatility)
|
224
|
+
*/
|
225
|
+
static VALUE
|
226
|
+
rupee_vanna(self, _call_put_flag, _S, _K, _T, _r, _q, _v)
|
227
|
+
VALUE self, _call_put_flag, _S, _K, _T, _r, _q, _v;
|
228
|
+
{
|
229
|
+
const char *call_put_flag;
|
230
|
+
double d1, d2, S, K, T, r, q, v;
|
231
|
+
|
232
|
+
call_put_flag = StringValuePtr(_call_put_flag);
|
233
|
+
S = NUM2DBL(_S);
|
234
|
+
K = NUM2DBL(_K);
|
235
|
+
T = NUM2DBL(_T);
|
236
|
+
r = NUM2DBL(_r);
|
237
|
+
q = NUM2DBL(_q);
|
238
|
+
v = NUM2DBL(_v);
|
239
|
+
d1 = (log(S / K) + (r - q + v * v / 2) * T) / (v * sqrt(T));
|
240
|
+
d2 = d1 - v * sqrt(T);
|
241
|
+
|
242
|
+
return rb_float_new(-exp(-q * T) * pdf(d1) * d2 / v);
|
243
|
+
}
|
244
|
+
|
245
|
+
/* call-seq: charm(call_put_flag, S, K, T, r, q, v)
|
246
|
+
*
|
247
|
+
* Returns the charm options Greek (sensitivity of delta to the passage of
|
248
|
+
* time)
|
249
|
+
*/
|
250
|
+
static VALUE
|
251
|
+
rupee_charm(self, _call_put_flag, _S, _K, _T, _r, _q, _v)
|
252
|
+
VALUE self, _call_put_flag, _S, _K, _T, _r, _q, _v;
|
253
|
+
{
|
254
|
+
const char *call_put_flag;
|
255
|
+
double d1, d2, S, K, T, r, q, v;
|
256
|
+
|
257
|
+
call_put_flag = StringValuePtr(_call_put_flag);
|
258
|
+
S = NUM2DBL(_S);
|
259
|
+
K = NUM2DBL(_K);
|
260
|
+
T = NUM2DBL(_T);
|
261
|
+
r = NUM2DBL(_r);
|
262
|
+
q = NUM2DBL(_q);
|
263
|
+
v = NUM2DBL(_v);
|
264
|
+
|
265
|
+
d1 = (log(S / K) + (r - q + v * v / 2) * T) / (v * sqrt(T));
|
266
|
+
d2 = d1 - v * sqrt(T);
|
267
|
+
|
268
|
+
if (is_call(call_put_flag))
|
269
|
+
return rb_float_new(-q * exp(-q * T) * cnd(d1) + exp(-q * T) * pdf(d1) *
|
270
|
+
(2 * (r - q) * T - d2 * v * sqrt(T)) / (2 * T * v * sqrt(T)));
|
271
|
+
else
|
272
|
+
return rb_float_new(q * exp(-q * T) * cnd(-d1) + exp(-q * T) * pdf(d1) *
|
273
|
+
(2 * (r - q) * T - d2 * v * sqrt(T)) / (2 * T * v * sqrt(T)));
|
274
|
+
}
|
275
|
+
|
276
|
+
/* call-seq: rupee_speed(call_put_flag, S, K, T, r, q, v)
|
277
|
+
*
|
278
|
+
* Returns the speed options Greek (sensitivity of gamma to changes in the
|
279
|
+
* underlying's price).
|
280
|
+
*/
|
281
|
+
static VALUE
|
282
|
+
rupee_speed(self, _call_put_flag, _S, _K, _T, _r, _q, _v)
|
283
|
+
VALUE self, _call_put_flag, _S, _K, _T, _r, _q, _v;
|
284
|
+
{
|
285
|
+
const char *call_put_flag;
|
286
|
+
double d1, S, K, T, r, q, v;
|
287
|
+
|
288
|
+
call_put_flag = StringValuePtr(_call_put_flag);
|
289
|
+
S = NUM2DBL(_S);
|
290
|
+
K = NUM2DBL(_K);
|
291
|
+
T = NUM2DBL(_T);
|
292
|
+
r = NUM2DBL(_r);
|
293
|
+
q = NUM2DBL(_q);
|
294
|
+
v = NUM2DBL(_v);
|
295
|
+
d1 = (log(S / K) + (r - q + v * v / 2) * T) / (v * sqrt(T));
|
296
|
+
|
297
|
+
return rb_float_new(-exp(-q * T) * pdf(d1) / (S * S * v * sqrt(T)) *
|
298
|
+
(d1 / (v * sqrt(T)) + 1));
|
299
|
+
}
|
300
|
+
|
301
|
+
/* call-seq: zomma(call_put_flag, S, K, T, r, q, v)
|
302
|
+
*
|
303
|
+
* Returns the zomma options Greek (sensitivity of gamma to changes in
|
304
|
+
* volatility)
|
305
|
+
*/
|
306
|
+
static VALUE
|
307
|
+
rupee_zomma(self, _call_put_flag, _S, _K, _T, _r, _q, _v)
|
308
|
+
VALUE self, _call_put_flag, _S, _K, _T, _r, _q, _v;
|
309
|
+
{
|
310
|
+
const char *call_put_flag;
|
311
|
+
double d1, d2, S, K, T, r, q, v;
|
312
|
+
|
313
|
+
call_put_flag = StringValuePtr(_call_put_flag);
|
314
|
+
S = NUM2DBL(_S);
|
315
|
+
K = NUM2DBL(_K);
|
316
|
+
T = NUM2DBL(_T);
|
317
|
+
r = NUM2DBL(_r);
|
318
|
+
q = NUM2DBL(_q);
|
319
|
+
v = NUM2DBL(_v);
|
320
|
+
d1 = (log(S / K) + (r - q + v * v / 2) * T) / (v * sqrt(T));
|
321
|
+
d2 = d1 - v * sqrt(T);
|
322
|
+
|
323
|
+
return rb_float_new(-exp(-q * T) * pdf(d1) * (d1 * d2 - 1) /
|
324
|
+
(S * v * v * sqrt(T)));
|
325
|
+
}
|
326
|
+
|
327
|
+
/* call-seq: color(call_put_flag, S, K, T, r, q, v)
|
328
|
+
*
|
329
|
+
* Returns the color options Greek (sensitivity of gamma to the passage of
|
330
|
+
* time)
|
331
|
+
*/
|
332
|
+
static VALUE
|
333
|
+
rupee_color(self, _call_put_flag, _S, _K, _T, _r, _q, _v)
|
334
|
+
VALUE self, _call_put_flag, _S, _K, _T, _r, _q, _v;
|
335
|
+
{
|
336
|
+
const char *call_put_flag;
|
337
|
+
double d1, d2, S, K, T, r, q, v;
|
338
|
+
|
339
|
+
call_put_flag = StringValuePtr(_call_put_flag);
|
340
|
+
S = NUM2DBL(_S);
|
341
|
+
K = NUM2DBL(_K);
|
342
|
+
T = NUM2DBL(_T);
|
343
|
+
r = NUM2DBL(_r);
|
344
|
+
q = NUM2DBL(_q);
|
345
|
+
v = NUM2DBL(_v);
|
346
|
+
d1 = (log(S / K) + (r - q + v * v / 2) * T) / (v * sqrt(T));
|
347
|
+
d2 = d1 - v * sqrt(T);
|
348
|
+
|
349
|
+
return rb_float_new(-exp(-q * T) * pdf(d1) / (2.0 * S * T * v * sqrt(T)) *
|
350
|
+
(2.0 * q * T + 1.0 + (2.0 * (r - q) * T - d2 * v * sqrt(T)) /
|
351
|
+
(2.0 * T * v * sqrt(T)) * d1));
|
352
|
+
}
|
353
|
+
|
354
|
+
/* call-seq: dvega_dtime(call_put_flag, S, K, T, r, q, v)
|
355
|
+
*
|
356
|
+
* Returns the dvega dtime options Greek (sensitivity of vega to the passage of
|
357
|
+
* time)
|
358
|
+
*/
|
359
|
+
static VALUE
|
360
|
+
rupee_dvega_dtime(self, _call_put_flag, _S, _K, _T, _r, _q, _v)
|
361
|
+
VALUE self, _call_put_flag, _S, _K, _T, _r, _q, _v;
|
362
|
+
{
|
363
|
+
const char *call_put_flag;
|
364
|
+
double d1, d2, S, K, T, r, q, v;
|
365
|
+
|
366
|
+
call_put_flag = StringValuePtr(_call_put_flag);
|
367
|
+
S = NUM2DBL(_S);
|
368
|
+
K = NUM2DBL(_K);
|
369
|
+
T = NUM2DBL(_T);
|
370
|
+
r = NUM2DBL(_r);
|
371
|
+
q = NUM2DBL(_q);
|
372
|
+
v = NUM2DBL(_v);
|
373
|
+
d1 = (log(S / K) + (r - q + v * v / 2) * T) / (v * sqrt(T));
|
374
|
+
d2 = d1 - v * sqrt(T);
|
375
|
+
|
376
|
+
return rb_float_new(S * exp(-q * T) * pdf(d1) * sqrt(T) *
|
377
|
+
(q + ((r - q) * d1) / (v * sqrt(T)) - (1 + d1 * d2) / (2 * T)));
|
378
|
+
}
|
379
|
+
|
380
|
+
/* call-seq: vomma(call_put_flag, S, K, T, r, q, v)
|
381
|
+
*
|
382
|
+
* Returns the vomma options Greek (sensitivity of vega to changes in
|
383
|
+
* volatility)
|
384
|
+
*/
|
385
|
+
static VALUE
|
386
|
+
rupee_vomma(self, _call_put_flag, _S, _K, _T, _r, _q, _v)
|
387
|
+
VALUE self, _call_put_flag, _S, _K, _T, _r, _q, _v;
|
388
|
+
{
|
389
|
+
const char *call_put_flag;
|
390
|
+
double d1, d2, S, K, T, r, q, v;
|
391
|
+
|
392
|
+
call_put_flag = StringValuePtr(_call_put_flag);
|
393
|
+
S = NUM2DBL(_S);
|
394
|
+
K = NUM2DBL(_K);
|
395
|
+
T = NUM2DBL(_T);
|
396
|
+
r = NUM2DBL(_r);
|
397
|
+
q = NUM2DBL(_q);
|
398
|
+
v = NUM2DBL(_v);
|
399
|
+
d1 = (log(S / K) + (r - q + v * v / 2) * T) / (v * sqrt(T));
|
400
|
+
d2 = d1 - v * sqrt(T);
|
401
|
+
|
402
|
+
return rb_float_new(S * exp(-q * T) * pdf(d1) * sqrt(T) * d1 * d2 / v);
|
403
|
+
}
|
404
|
+
|
405
|
+
/* call-seq: dual_delta(call_put_flag, S, K, T, r, q, v)
|
406
|
+
*
|
407
|
+
* Returns the dual delta options Greek (probability of finishing in-the-money)
|
408
|
+
*/
|
409
|
+
static VALUE
|
410
|
+
rupee_dual_delta(self, _call_put_flag, _S, _K, _T, _r, _q, _v)
|
411
|
+
VALUE self, _call_put_flag, _S, _K, _T, _r, _q, _v;
|
412
|
+
{
|
413
|
+
const char *call_put_flag;
|
414
|
+
double d1, d2, S, K, T, r, q, v;
|
415
|
+
|
416
|
+
call_put_flag = StringValuePtr(_call_put_flag);
|
417
|
+
S = NUM2DBL(_S);
|
418
|
+
K = NUM2DBL(_K);
|
419
|
+
T = NUM2DBL(_T);
|
420
|
+
r = NUM2DBL(_r);
|
421
|
+
q = NUM2DBL(_q);
|
422
|
+
v = NUM2DBL(_v);
|
423
|
+
d1 = (log(S / K) + (r - q + v * v / 2) * T) / (v * sqrt(T));
|
424
|
+
d2 = d1 - v * sqrt(T);
|
425
|
+
|
426
|
+
if (is_call(call_put_flag))
|
427
|
+
return rb_float_new(-exp(-q * T) * cnd(d2));
|
428
|
+
else
|
429
|
+
return rb_float_new(exp(-q * T) * cnd(-d2));
|
430
|
+
}
|
431
|
+
|
432
|
+
/* call-seq: dual_gamma(call_put_flag, S, K, T, r, q, v)
|
433
|
+
*
|
434
|
+
* Returns the dual gamma options Greek.
|
435
|
+
*/
|
436
|
+
static VALUE
|
437
|
+
rupee_dual_gamma(self, _call_put_flag, _S, _K, _T, _r, _q, _v)
|
438
|
+
VALUE self, _call_put_flag, _S, _K, _T, _r, _q, _v;
|
439
|
+
{
|
440
|
+
const char *call_put_flag;
|
441
|
+
double d1, d2, S, K, T, r, q, v;
|
442
|
+
|
443
|
+
call_put_flag = StringValuePtr(_call_put_flag);
|
444
|
+
S = NUM2DBL(_S);
|
445
|
+
K = NUM2DBL(_K);
|
446
|
+
T = NUM2DBL(_T);
|
447
|
+
r = NUM2DBL(_r);
|
448
|
+
q = NUM2DBL(_q);
|
449
|
+
v = NUM2DBL(_v);
|
450
|
+
d1 = (log(S / K) + (r - q + v * v / 2) * T) / (v * sqrt(T));
|
451
|
+
d2 = d1 - v * sqrt(T);
|
452
|
+
|
453
|
+
return rb_float_new(exp(-r * T) * pdf(d2) / (K * v * sqrt(T)));
|
454
|
+
}
|
455
|
+
|
456
|
+
|
457
|
+
/* call-seq: implied_volatility(call_put_flag, underlying, strike, time, rate,
|
458
|
+
* div_yield, price)
|
459
|
+
*
|
460
|
+
* Returns the Black-Scholes implied volatility using the Newton-Raphson method
|
461
|
+
*/
|
462
|
+
static VALUE
|
463
|
+
rupee_impl_vol(self, _call_put_flag, _S, _K, _T, _r, _q, _cm)
|
464
|
+
VALUE self, _call_put_flag, _S, _K, _T, _r, _q, _cm;
|
465
|
+
{
|
466
|
+
static const double epsilon = 0.00000001;
|
467
|
+
double vi, ci, vegai, min_diff, S, K, T, r, q, cm;
|
468
|
+
const char *call_put_flag;
|
469
|
+
|
470
|
+
call_put_flag = StringValuePtr(_call_put_flag);
|
471
|
+
S = NUM2DBL(_S);
|
472
|
+
K = NUM2DBL(_K);
|
473
|
+
T = NUM2DBL(_T);
|
474
|
+
r = NUM2DBL(_r);
|
475
|
+
q = NUM2DBL(_q);
|
476
|
+
cm = NUM2DBL(_cm);
|
477
|
+
|
478
|
+
// Manaster and Koehler seed value
|
479
|
+
vi = sqrt(abs(log(S / K) + r * T) * 2 / T);
|
480
|
+
ci = bs(call_put_flag, S, K, T, r, q, vi);
|
481
|
+
vegai = vega(call_put_flag, S, K, T, r, q, vi);
|
482
|
+
min_diff = abs(cm - ci);
|
483
|
+
|
484
|
+
while (min_diff >= epsilon) {
|
485
|
+
vi -= (ci - cm) / vegai;
|
486
|
+
ci = bs(call_put_flag, S, K, T, r, q, vi);
|
487
|
+
vegai = vega(call_put_flag, S, K, T, r, q, vi);
|
488
|
+
min_diff = abs(cm - ci);
|
489
|
+
}
|
490
|
+
|
491
|
+
if (min_diff < epsilon)
|
492
|
+
return vi;
|
493
|
+
else
|
494
|
+
return 0;
|
495
|
+
}
|
496
|
+
|
497
|
+
/* call-seq: black_scholes(call_put_flag, underlying, strike, time, rate,
|
498
|
+
* volatility)
|
31
499
|
*
|
32
500
|
* The Black-Scholes European call/put valuation
|
33
501
|
*
|
@@ -42,37 +510,37 @@ bs(call_put_flag, S, X, T, r, q, v)
|
|
42
510
|
* * +volatility+ - The implied volatility at expiry
|
43
511
|
*/
|
44
512
|
static VALUE
|
45
|
-
rupee_black_scholes(self,
|
46
|
-
VALUE self,
|
513
|
+
rupee_black_scholes(self, _call_put_flag, _S, _K, _T, _r, _q, _v)
|
514
|
+
VALUE self, _call_put_flag, _S, _K, _T, _r, _q, _v;
|
47
515
|
{
|
48
516
|
const char *call_put_flag;
|
49
|
-
double
|
517
|
+
double S, K, T, r, q, v;
|
50
518
|
|
51
|
-
call_put_flag = StringValuePtr(
|
52
|
-
|
53
|
-
|
54
|
-
T = NUM2DBL(
|
55
|
-
r = NUM2DBL(
|
56
|
-
q = NUM2DBL(
|
57
|
-
v = NUM2DBL(
|
519
|
+
call_put_flag = StringValuePtr(_call_put_flag);
|
520
|
+
S = NUM2DBL(_S);
|
521
|
+
K = NUM2DBL(_K);
|
522
|
+
T = NUM2DBL(_T);
|
523
|
+
r = NUM2DBL(_r);
|
524
|
+
q = NUM2DBL(_q);
|
525
|
+
v = NUM2DBL(_v);
|
58
526
|
|
59
|
-
return rb_float_new(bs(call_put_flag,
|
527
|
+
return rb_float_new(bs(call_put_flag, S, K, T, r, q, v));
|
60
528
|
}
|
61
529
|
|
62
530
|
double
|
63
|
-
gbs(call_put_flag, S,
|
531
|
+
gbs(call_put_flag, S, K, T, r, b, v)
|
64
532
|
const char *call_put_flag;
|
65
|
-
double S,
|
533
|
+
double S, K, T, r, b, v;
|
66
534
|
{
|
67
535
|
double d1, d2;
|
68
536
|
|
69
|
-
d1 = (log(S /
|
537
|
+
d1 = (log(S / K) + (b + v * v / 2) * T) / (v * sqrt(T));
|
70
538
|
d2 = d1 - v * sqrt(T);
|
71
539
|
|
72
540
|
if (is_call(call_put_flag))
|
73
|
-
return S * exp((b - r) * T) * cnd(d1) -
|
541
|
+
return S * exp((b - r) * T) * cnd(d1) - K * exp(-r * T) * cnd(d2);
|
74
542
|
else
|
75
|
-
return
|
543
|
+
return K * exp(-r * T) * cnd(-d2) - S * exp((b - r) * T) * cnd(-d1);
|
76
544
|
}
|
77
545
|
|
78
546
|
/* call-seq:
|
@@ -92,37 +560,37 @@ gbs(call_put_flag, S, X, T, r, b, v)
|
|
92
560
|
* * +volatility+ - The implied volatility at expiry
|
93
561
|
*/
|
94
562
|
static VALUE
|
95
|
-
rupee_generalized_black_scholes(self,
|
96
|
-
VALUE self,
|
563
|
+
rupee_generalized_black_scholes(self, _call_put_flag, _S, _K, _T, _r, _b, _v)
|
564
|
+
VALUE self, _call_put_flag, _S, _K, _T, _r, _b, _v;
|
97
565
|
{
|
98
566
|
const char *call_put_flag;
|
99
|
-
double
|
567
|
+
double S, K, T, r, b, v;
|
100
568
|
|
101
|
-
call_put_flag = StringValuePtr(
|
102
|
-
|
103
|
-
|
104
|
-
T = NUM2DBL(
|
105
|
-
r = NUM2DBL(
|
106
|
-
b = NUM2DBL(
|
107
|
-
v = NUM2DBL(
|
569
|
+
call_put_flag = StringValuePtr(_call_put_flag);
|
570
|
+
S = NUM2DBL(_S);
|
571
|
+
K = NUM2DBL(_K);
|
572
|
+
T = NUM2DBL(_T);
|
573
|
+
r = NUM2DBL(_r);
|
574
|
+
b = NUM2DBL(_b);
|
575
|
+
v = NUM2DBL(_v);
|
108
576
|
|
109
|
-
return rb_float_new(gbs(call_put_flag,
|
577
|
+
return rb_float_new(gbs(call_put_flag, S, K, T, r, b, v));
|
110
578
|
}
|
111
579
|
|
112
580
|
static double
|
113
|
-
black76(call_put_flag,
|
581
|
+
black76(call_put_flag, S, K, T, r, v)
|
114
582
|
const char *call_put_flag;
|
115
|
-
double
|
583
|
+
double S, K, T, r, v;
|
116
584
|
{
|
117
585
|
double d1, d2;
|
118
586
|
|
119
|
-
d1 = (log(
|
587
|
+
d1 = (log(S / K) + (v * v / 2.0) * T) / (v * sqrt(T));
|
120
588
|
d2 = d1 - v * sqrt(T);
|
121
589
|
|
122
590
|
if (is_call(call_put_flag))
|
123
|
-
return exp(-r * T) * (
|
591
|
+
return exp(-r * T) * (S * cnd(d1) - K * cnd(d2));
|
124
592
|
else
|
125
|
-
return exp(-r * T) * (
|
593
|
+
return exp(-r * T) * (K * cnd(-d2) - S * cnd(-d1));
|
126
594
|
}
|
127
595
|
|
128
596
|
/* call-seq:
|
@@ -141,20 +609,20 @@ black76(call_put_flag, F, X, T, r, v)
|
|
141
609
|
* * +volatility+ - The implied volatility at expiry
|
142
610
|
*/
|
143
611
|
static VALUE
|
144
|
-
rupee_black76(self,
|
145
|
-
VALUE self,
|
612
|
+
rupee_black76(self, _call_put_flag, _S, _K, _T, _r, _v)
|
613
|
+
VALUE self, _call_put_flag, _S, _K, _T, _r, _v;
|
146
614
|
{
|
147
615
|
const char *call_put_flag;
|
148
|
-
double
|
616
|
+
double S, K, T, r, v;
|
149
617
|
|
150
|
-
call_put_flag = StringValuePtr(
|
151
|
-
|
152
|
-
|
153
|
-
T = NUM2DBL(
|
154
|
-
r = NUM2DBL(
|
155
|
-
v = NUM2DBL(
|
618
|
+
call_put_flag = StringValuePtr(_call_put_flag);
|
619
|
+
S = NUM2DBL(_S);
|
620
|
+
K = NUM2DBL(_K);
|
621
|
+
T = NUM2DBL(_T);
|
622
|
+
r = NUM2DBL(_r);
|
623
|
+
v = NUM2DBL(_v);
|
156
624
|
|
157
|
-
return rb_float_new(black76(call_put_flag,
|
625
|
+
return rb_float_new(black76(call_put_flag, S, K, T, r, v));
|
158
626
|
}
|
159
627
|
|
160
628
|
void
|
@@ -173,7 +641,35 @@ init_option()
|
|
173
641
|
rb_define_singleton_method(klass, "black76", rupee_black76, 6);
|
174
642
|
rb_define_singleton_method(klass, "black_scholes", rupee_black_scholes, 7);
|
175
643
|
rb_define_alias(singleton, "bs", "black_scholes");
|
644
|
+
rb_define_singleton_method(klass, "charm", rupee_charm, 7);
|
645
|
+
rb_define_singleton_method(klass, "color", rupee_color, 7);
|
646
|
+
rb_define_singleton_method(klass, "delta", rupee_delta, 7);
|
647
|
+
rb_define_singleton_method(klass, "dual_delta", rupee_dual_delta, 7);
|
648
|
+
rb_define_singleton_method(klass, "dual_gamma", rupee_dual_gamma, 7);
|
649
|
+
rb_define_singleton_method(klass, "dvega_dtime", rupee_dvega_dtime, 7);
|
650
|
+
rb_define_singleton_method(klass, "gamma", rupee_gamma, 7);
|
176
651
|
rb_define_singleton_method(klass, "generalized_black_scholes",
|
177
652
|
rupee_generalized_black_scholes, 7);
|
178
653
|
rb_define_alias(singleton, "gbs", "generalized_black_scholes");
|
654
|
+
rb_define_singleton_method(klass, "implied_volatility", rupee_impl_vol, 7);
|
655
|
+
rb_define_singleton_method(klass, "rho", rupee_rho, 7);
|
656
|
+
rb_define_singleton_method(klass, "speed", rupee_speed, 7);
|
657
|
+
rb_define_singleton_method(klass, "theta", rupee_theta, 7);
|
658
|
+
rb_define_singleton_method(klass, "vanna", rupee_vanna, 7);
|
659
|
+
rb_define_singleton_method(klass, "vega", rupee_vega, 7);
|
660
|
+
rb_define_singleton_method(klass, "vomma", rupee_vomma, 7);
|
661
|
+
rb_define_singleton_method(klass, "zomma", rupee_zomma, 7);
|
179
662
|
}
|
663
|
+
|
664
|
+
|
665
|
+
|
666
|
+
|
667
|
+
|
668
|
+
|
669
|
+
|
670
|
+
|
671
|
+
|
672
|
+
|
673
|
+
|
674
|
+
|
675
|
+
|