tarf_monte_carlo 3.26 → 3.31
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.
- 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
|