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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1b551fb41bf0f6bada89b8b9b56a1cc16d1b6bdba6c4bece434a5ca8bbb103bc
4
- data.tar.gz: 6c76e80342cc906a4ad39665a8cc6ffe460b473e3fd2985bf3df571a6252f1d4
3
+ metadata.gz: 1ffba748a882648f94602365c6fe89ba13ad4012e4daa54ce87e836c757c2df7
4
+ data.tar.gz: 56cf966863ed9d42802d78634b411aef7039eab87a74420d33a3dc429e5c1fa5
5
5
  SHA512:
6
- metadata.gz: 5fe7a19bb8dd61ca522a23e5a216c726f7af22b385c9d16b111c9c903f5b7414ef64569168ee301e3a5fe62cb5b2f534e3445c65290f355c0d38c10af30ac5b0
7
- data.tar.gz: 6115a3972cb63edc48c8ee6c93d6206931608ef780a6322d9c6ff1add58cb3f43562288a0399abac710b4b27c5de5ede3a10d1166834da1044134d444a247c3b
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] = NUM2DBL( rb_ary_entry(Brs, 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 = 0;
219
- profit_loss_dash = 0;
245
+ profit_loss = Spot;
246
+ profit_loss_dash = Spot_dash;
220
247
 
221
- double knockin = (Spot - *(Barrier_array + leg)) * dir_sign * cp_sign * dir2_sign;
222
- double knockin_dash = (Spot_dash - *(Barrier_array + leg)) * dir_sign * cp_sign * dir2_sign;
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 > 0){
251
+ if(knockedLeg == -1 && knockin >= 0){
225
252
  knockedLeg = leg;
226
253
  }
227
- if(knockedLeg == -1 && knockin < 0 && KType == FX_AMERICAN_BARRIER_KNOCKOUT_DISCRETE){
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
- sim_pos[knockedLeg] = dir_sign * dir2_sign * cp_sign * ( Spot - ( *( Xs_array + (knockedLeg) ) ) ) * ( *( Ns_array + knockedLeg ) );
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
- sim_dash_pos[knockedLeg_dash] = dir_sign * dir2_sign * cp_sign * ( Spot_dash - ( *( Xs_array + (knockedLeg_dash) ) ) ) * ( *( Ns_array + knockedLeg_dash ) );
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
- int brk_flg = 1;
386
- int brk_flg_dash = 1;
387
- for( leg = 0; leg < NL; ++leg ) {
388
- if((leg != knockedLeg) && brk_flg){
389
- sim_pos[leg] = sim[leg] * ( *( Ns_array + leg ) );
390
- }else{
391
- brk_flg = 0;
392
- }
393
- if((leg != knockedLeg_dash) && brk_flg_dash){
394
- sim_dash_pos[leg] = sim[leg] * ( *( Ns_array + leg ) );
395
- }else{
396
- brk_flg_dash = 0;
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 < DATAPOINTS; 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( metrics[metric][leg] ) );
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
+ }
@@ -3,5 +3,5 @@
3
3
  # gem yank tarf_monte_carlo -v 2.3
4
4
 
5
5
  module TarfMonteCarlo
6
- VERSION = "3.26"
6
+ VERSION = "3.31"
7
7
  end
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.26'
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-02 00:00:00.000000000 Z
11
+ date: 2020-10-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler