tarf_monte_carlo 3.26 → 3.31
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ext/tarf_monte_carlo/tarf_monte_carlo.c +66 -33
- data/lib/tarf_monte_carlo/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1ffba748a882648f94602365c6fe89ba13ad4012e4daa54ce87e836c757c2df7
|
4
|
+
data.tar.gz: 56cf966863ed9d42802d78634b411aef7039eab87a74420d33a3dc429e5c1fa5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e15a1be8f1f8fcc330201ccbfd814866da27b0010428de8e8f4b449ca74b4879d62947309aedabecb86432657f5a1729f52b737518b2de147e967932beedbd96
|
7
|
+
data.tar.gz: 6d3a80d0819af9cacb1f4a15beb51a3e6edf3a65f38fdb50a0b6c03d0992d73f7046b126c7cf9e6a7febb1e1430fc4fbafba04590b629c02d21e51debcd0d7d7
|
@@ -56,6 +56,9 @@ VALUE cTarfMonteCarlo = Qnil;
|
|
56
56
|
|
57
57
|
// Prototype for the initialization method - Ruby calls this, not you
|
58
58
|
void Init_tarf_monte_carlo();
|
59
|
+
double european_payoff(double, double, int, int, double);
|
60
|
+
double get_equivalent_notional(int, double, float);
|
61
|
+
double get_equivalent_rebate(int, double, float);
|
59
62
|
|
60
63
|
// Prototype for our methods - methods are prefixed by 'method_' here
|
61
64
|
VALUE method_box_muller( VALUE );
|
@@ -80,6 +83,20 @@ VALUE method_box_muller( VALUE self ) {
|
|
80
83
|
return DBL2NUM(eps);
|
81
84
|
}
|
82
85
|
|
86
|
+
double european_payoff(double strike, double spot, int cp_sign, int dir_sign, double notional){
|
87
|
+
double diff = (spot - strike) * cp_sign;
|
88
|
+
diff = diff > 0 ? diff : 0;
|
89
|
+
return (diff * notional * dir_sign);
|
90
|
+
}
|
91
|
+
|
92
|
+
double get_equivalent_notional(int conversion_sign, double notional, float rate){
|
93
|
+
return (conversion_sign == 1) ? (notional / rate) : notional;
|
94
|
+
}
|
95
|
+
|
96
|
+
double get_equivalent_rebate(int conversion_sign, double rebate, float rate){
|
97
|
+
return (conversion_sign == 1) ? (rebate * rate) : rebate;
|
98
|
+
}
|
99
|
+
|
83
100
|
// main method for running monte carlo simulation from sidekiq worker/outside method
|
84
101
|
VALUE method_run_monte_carlo( VALUE self, VALUE args ) {
|
85
102
|
VALUE MCInputs = rb_ary_shift(args);
|
@@ -105,6 +122,8 @@ VALUE method_run_monte_carlo( VALUE self, VALUE args ) {
|
|
105
122
|
int dir_sign = NUM2INT( rb_hash_aref(MCInputs, rb_str_new2("direction_sign")) );
|
106
123
|
int dir2_sign = NUM2INT( rb_hash_aref(MCInputs, rb_str_new2("direction2_sign")) );
|
107
124
|
int cp_sign = NUM2INT( rb_hash_aref(MCInputs, rb_str_new2("callput_sign")) );
|
125
|
+
int conversion_sign = NUM2INT( rb_hash_aref(MCInputs, rb_str_new2("conversion_sign")) );
|
126
|
+
int rebate_conversion_sign = NUM2INT( rb_hash_aref(MCInputs, rb_str_new2("rebate_conversion_sign")) );
|
108
127
|
|
109
128
|
// assign leg specific attributes
|
110
129
|
double *pvs_pos = ( double* ) malloc( SCount * sizeof(double) );
|
@@ -122,6 +141,7 @@ VALUE method_run_monte_carlo( VALUE self, VALUE args ) {
|
|
122
141
|
double *USts_array = ( double* ) malloc( NL * sizeof(double) );
|
123
142
|
double *TempNs_array = ( double* ) malloc( NL * sizeof(double) );
|
124
143
|
double *Barrier_array = ( double* ) malloc( NL * sizeof(double) );
|
144
|
+
double *Rebate_array = ( double* ) malloc( NL * sizeof(double) );
|
125
145
|
|
126
146
|
VALUE Ls = rb_hash_aref(MCInputs, rb_str_new2("leverage_ratios") );
|
127
147
|
VALUE Ts = rb_hash_aref(MCInputs, rb_str_new2("expiration_times") );
|
@@ -135,6 +155,7 @@ VALUE method_run_monte_carlo( VALUE self, VALUE args ) {
|
|
135
155
|
VALUE LSts = rb_hash_aref(MCInputs, rb_str_new2("lower_strikes") );
|
136
156
|
VALUE USts = rb_hash_aref(MCInputs, rb_str_new2("upper_strikes") );
|
137
157
|
VALUE Brs = rb_hash_aref(MCInputs, rb_str_new2("barriers") );
|
158
|
+
VALUE Rbts = rb_hash_aref(MCInputs, rb_str_new2("rebates") );
|
138
159
|
|
139
160
|
for (leg = 0; leg < NL; ++leg) {
|
140
161
|
Ls_array[leg] = NUM2DBL( rb_ary_entry(Ls, leg) );
|
@@ -163,7 +184,8 @@ VALUE method_run_monte_carlo( VALUE self, VALUE args ) {
|
|
163
184
|
}
|
164
185
|
} else if (KType == FX_AMERICAN_BARRIER_KNOCKIN_DISCRETE || KType == FX_AMERICAN_BARRIER_KNOCKOUT_DISCRETE) {
|
165
186
|
for (leg = 0; leg < NL; ++leg) {
|
166
|
-
Barrier_array[leg]
|
187
|
+
Barrier_array[leg] = NUM2DBL( rb_ary_entry(Brs, leg) );
|
188
|
+
Rebate_array[leg] = NUM2DBL( rb_ary_entry(Rbts, leg) );
|
167
189
|
}
|
168
190
|
}
|
169
191
|
|
@@ -171,6 +193,7 @@ VALUE method_run_monte_carlo( VALUE self, VALUE args ) {
|
|
171
193
|
// first create a 1-D array of pointers, and then, for each array entry, create another 1-D array.
|
172
194
|
//
|
173
195
|
double **metrics;
|
196
|
+
double data[4][NL];
|
174
197
|
metrics = ( double** ) malloc( DATAPOINTS * sizeof(double*) );
|
175
198
|
for( metric = 0; metric < DATAPOINTS; metric++ ) {
|
176
199
|
metrics[metric] = ( double* ) malloc( NL * sizeof(double) );
|
@@ -194,6 +217,10 @@ VALUE method_run_monte_carlo( VALUE self, VALUE args ) {
|
|
194
217
|
sim_dash[leg] = 0.0;
|
195
218
|
sim_dash_pos[leg] = 0.0;
|
196
219
|
sim_dash_neg[leg] = 0.0;
|
220
|
+
data[0][leg] = 0.0;
|
221
|
+
data[1][leg] = 0.0;
|
222
|
+
data[2][leg] = 0.0;
|
223
|
+
data[3][leg] = 0.0;
|
197
224
|
}
|
198
225
|
|
199
226
|
int knockedLeg = -1;
|
@@ -215,26 +242,18 @@ VALUE method_run_monte_carlo( VALUE self, VALUE args ) {
|
|
215
242
|
Spot_dash = Spot_dash * exp( drift + vSqrdt * eps_dash );
|
216
243
|
|
217
244
|
if(KType == FX_AMERICAN_BARRIER_KNOCKIN_DISCRETE || KType == FX_AMERICAN_BARRIER_KNOCKOUT_DISCRETE){
|
218
|
-
profit_loss =
|
219
|
-
profit_loss_dash =
|
245
|
+
profit_loss = Spot;
|
246
|
+
profit_loss_dash = Spot_dash;
|
220
247
|
|
221
|
-
double knockin = (Spot - *(Barrier_array + leg)) *
|
222
|
-
double knockin_dash = (Spot_dash - *(Barrier_array + leg)) *
|
248
|
+
double knockin = (Spot - *(Barrier_array + leg)) * dir2_sign;
|
249
|
+
double knockin_dash = (Spot_dash - *(Barrier_array + leg)) * dir2_sign;
|
223
250
|
|
224
|
-
if(knockedLeg == -1 && knockin
|
251
|
+
if(knockedLeg == -1 && knockin >= 0){
|
225
252
|
knockedLeg = leg;
|
226
253
|
}
|
227
|
-
if(
|
228
|
-
profit_loss = dir_sign * dir2_sign * cp_sign * ( Spot - ( *( Xs_array + leg ) ) );
|
229
|
-
}
|
230
|
-
|
231
|
-
if(knockedLeg_dash == -1 && knockin_dash > 0){
|
254
|
+
if(knockedLeg_dash == -1 && knockin_dash >= 0){
|
232
255
|
knockedLeg_dash = leg;
|
233
256
|
}
|
234
|
-
if(knockedLeg_dash == -1 && knockin_dash < 0 && KType == FX_AMERICAN_BARRIER_KNOCKOUT_DISCRETE){
|
235
|
-
profit_loss = dir_sign * dir2_sign * cp_sign * ( Spot_dash - ( *( Xs_array + leg ) ) );
|
236
|
-
}
|
237
|
-
|
238
257
|
} else if ( KType == DOUBLE_STRIKE_POINTS || KType == DOUBLE_STRIKE_ABSOLUTE || KType == DOUBLE_STRIKE_LEGS ) {
|
239
258
|
if ( Spot < *( LSts_array + leg ) ) {
|
240
259
|
profit_loss = Spot - (*( LSts_array + leg ));
|
@@ -355,6 +374,8 @@ VALUE method_run_monte_carlo( VALUE self, VALUE args ) {
|
|
355
374
|
sim[leg] = profit_loss;
|
356
375
|
sim_dash[leg] = profit_loss_dash;
|
357
376
|
|
377
|
+
data[0][leg] = sim[leg];
|
378
|
+
data[1][leg] = sim_dash[leg];
|
358
379
|
//
|
359
380
|
// Store spot and spot dash
|
360
381
|
//
|
@@ -371,30 +392,42 @@ VALUE method_run_monte_carlo( VALUE self, VALUE args ) {
|
|
371
392
|
Spot_dash = S;
|
372
393
|
}
|
373
394
|
}
|
395
|
+
|
374
396
|
// legs loop end
|
375
397
|
// start from the Knock value
|
376
398
|
double ko_so_far = K, ko_so_far_dash = K;
|
377
399
|
if(KType == FX_AMERICAN_BARRIER_KNOCKIN_DISCRETE){
|
378
400
|
if(knockedLeg >= 0){
|
379
|
-
|
401
|
+
double equivalent_notional = get_equivalent_notional(conversion_sign, ( *( Ns_array + knockedLeg ) ), sim[NL-1]);
|
402
|
+
sim_pos[NL-1] = european_payoff(( *( Xs_array + (knockedLeg) ) ), sim[NL-1], cp_sign, dir_sign, equivalent_notional);
|
403
|
+
}
|
404
|
+
else{
|
405
|
+
sim_pos[NL-1] = get_equivalent_rebate(rebate_conversion_sign, ( *( Rebate_array + 0 ) ), sim[NL-1]);
|
380
406
|
}
|
381
407
|
if(knockedLeg_dash >= 0 ){
|
382
|
-
|
408
|
+
double equivalent_notional = get_equivalent_notional(conversion_sign, ( *( Ns_array + knockedLeg_dash ) ), sim_dash[NL-1]);
|
409
|
+
sim_dash_pos[NL-1] = european_payoff(( *( Xs_array + (knockedLeg_dash) ) ), sim_dash[NL-1], cp_sign, dir_sign, equivalent_notional);
|
383
410
|
}
|
411
|
+
else{
|
412
|
+
sim_dash_pos[NL-1] = get_equivalent_rebate(rebate_conversion_sign, ( *( Rebate_array + 0 ) ), sim_dash[NL-1]);
|
413
|
+
}
|
414
|
+
|
415
|
+
data[2][NL-1] = sim_pos[NL-1];
|
416
|
+
data[3][NL-1] = sim_dash_pos[NL-1];
|
384
417
|
} else if(KType == FX_AMERICAN_BARRIER_KNOCKOUT_DISCRETE){
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
418
|
+
if(knockedLeg >= 0){
|
419
|
+
sim_pos[knockedLeg] = get_equivalent_rebate(rebate_conversion_sign, ( *( Rebate_array + knockedLeg ) ), sim[knockedLeg]);
|
420
|
+
}
|
421
|
+
else{
|
422
|
+
double equivalent_notional = get_equivalent_notional(conversion_sign, ( *( Ns_array + 0 ) ), sim[NL-1]);
|
423
|
+
sim_pos[NL-1] = european_payoff(( *( Xs_array + 0 ) ), sim[NL-1], cp_sign, dir_sign, equivalent_notional);
|
424
|
+
}
|
425
|
+
if(knockedLeg_dash >= 0 ){
|
426
|
+
sim_dash_pos[knockedLeg_dash] = get_equivalent_rebate(rebate_conversion_sign, ( *( Rebate_array + knockedLeg_dash ) ), sim[knockedLeg_dash]);
|
427
|
+
}
|
428
|
+
else{
|
429
|
+
double equivalent_notional = get_equivalent_notional(conversion_sign, ( *( Ns_array + 0 ) ), sim_dash[NL-1]);
|
430
|
+
sim_dash_pos[NL-1] = european_payoff(( *( Xs_array + 0 ) ), sim_dash[NL-1], cp_sign, dir_sign, equivalent_notional);
|
398
431
|
}
|
399
432
|
} else if( KType == ABSOLUTE || KType == PIVOT_ABSOLUTE || KType == COLLAR_ABSOLUTE || KType == DOUBLE_STRIKE_ABSOLUTE ) {
|
400
433
|
for( leg = 0; leg < NL; ++leg ) {
|
@@ -562,11 +595,11 @@ VALUE method_run_monte_carlo( VALUE self, VALUE args ) {
|
|
562
595
|
//
|
563
596
|
// rb_p(rb_str_new2("Converting metrics"));
|
564
597
|
VALUE final_metrics = rb_ary_new();
|
565
|
-
for(metric = 0; metric <
|
598
|
+
for(metric = 0; metric < 5; metric++) {
|
566
599
|
VALUE leg_metrics = rb_ary_new();
|
567
600
|
|
568
601
|
for(leg = 0; leg < NL; leg++) {
|
569
|
-
rb_ary_push( leg_metrics, DBL2NUM(
|
602
|
+
rb_ary_push( leg_metrics, DBL2NUM( data[metric][leg] ) );
|
570
603
|
}
|
571
604
|
|
572
605
|
rb_ary_push(final_metrics, leg_metrics);
|
@@ -603,4 +636,4 @@ void Init_tarf_monte_carlo() {
|
|
603
636
|
// void rb_define_singleton_method(VALUE klass, const char *name, VALUE (*func)(), int argc)
|
604
637
|
rb_define_singleton_method(cTarfMonteCarlo, "box_muller", method_box_muller, 0);
|
605
638
|
rb_define_singleton_method(cTarfMonteCarlo, "run_monte_carlo", method_run_monte_carlo, -2);
|
606
|
-
}
|
639
|
+
}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tarf_monte_carlo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '3.
|
4
|
+
version: '3.31'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vivek Routh
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-10-
|
11
|
+
date: 2020-10-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|