// File: ArashPartow[P]exprtk-extras/exprtk_montecarlo_option_pricing_model.cpp
// Function: void exprtk_montecarlo_option_pricing_model<double>()
void exprtk_montecarlo_option_pricing_model()
{
   typedef exprtk::symbol_table<T> symbol_table_t;
   typedef exprtk::expression<T>   expression_t;
   typedef exprtk::parser<T>       parser_t;

   const std::string exprtk_montecarlo_option_pricing_model_program =
      " var payoff_sum := 0;                                                 "
      " var sqrt_t     := sqrt(t);                                           "
      "                                                                      "
      " for (var i := 0; i < n; i += 1)                                      "
      " {                                                                    "
      "    var s_t := s * exp((r - v^2 / 2) * t + v * sqrt_t * normal(0,1)); "
      "    payoff_sum +=                                                     "
      "       switch                                                         "
      "       {                                                              "
      "          case callput_flag == 'call' : max(s_t - k, 0);              "
      "          case callput_flag == 'put'  : max(k - s_t, 0);              "
      "       };                                                             "
      " };                                                                   "
      "                                                                      "
      " exp(-r * t) * payoff_sum / n;                                        ";

   T s = T(100.00); // Spot / Stock / Underlying / Base price
   T k = T(110.00); // Strike price
   T v = T(  0.30); // Volatility
   T t = T(  2.22); // Years to maturity
   T r = T(  0.05); // Risk free rate
   T n = T( 2.0e7); // Number of simulations

   std::string callput_flag;

   normal_distribution<T> normal;

   symbol_table_t symbol_table(symbol_table_t::e_immutable);
   symbol_table.add_variable("s",s);
   symbol_table.add_variable("k",k);
   symbol_table.add_variable("t",t);
   symbol_table.add_variable("r",r);
   symbol_table.add_variable("v",v);
   symbol_table.add_constant("n",n);
   symbol_table.add_stringvar("callput_flag", callput_flag);
   symbol_table.add_function ("normal"      , normal      );

   expression_t expression;
   expression.register_symbol_table(symbol_table);

   parser_t parser;
   parser.compile(exprtk_montecarlo_option_pricing_model_program, expression);

   callput_flag = "call";

   const T montecarlo_call_option_price = expression.value();

   callput_flag = "put";

   const T montecarlo_put_option_price = expression.value();

   printf("MCOptionPrice(call, %5.3f, %5.3f, %5.3f, %5.3f, %5.3f) = %10.6f\n",
          s, k, t, r, v,
          montecarlo_call_option_price);

   printf("MCOptionPrice(put , %5.3f, %5.3f, %5.3f, %5.3f, %5.3f) = %10.6f\n",
          s, k, t, r, v,
          montecarlo_put_option_price);

   const double put_call_parity_diff =
      (montecarlo_call_option_price - montecarlo_put_option_price) -
      (s - k * std::exp(-r * t));

   printf("Put-Call parity difference: %20.17f\n", put_call_parity_diff);
}

// Assembly:
subq $0x20a8, %rsp           # imm = 0x20A8
leaq 0x2087(%rsp), %rdi
movq %rdi, 0x70(%rsp)
callq 0x111690
movq 0x70(%rsp), %rdx
leaq 0x334cf4(%rip), %rsi    # 0x44d569
leaq 0x2088(%rsp), %rdi
callq 0x118790
jmp 0x118884
leaq 0x2087(%rsp), %rdi
callq 0x1117b0
movabsq $0x4059000000000000, %rax # imm = 0x4059000000000000
movq %rax, 0x2068(%rsp)
movabsq $0x405b800000000000, %rax # imm = 0x405B800000000000
movq %rax, 0x2060(%rsp)
movabsq $0x3fd3333333333333, %rax # imm = 0x3FD3333333333333
movq %rax, 0x2058(%rsp)
movabsq $0x4001c28f5c28f5c3, %rax # imm = 0x4001C28F5C28F5C3
movq %rax, 0x2050(%rsp)
movabsq $0x3fa999999999999a, %rax # imm = 0x3FA999999999999A
movq %rax, 0x2048(%rsp)
movabsq $0x417312d000000000, %rax # imm = 0x417312D000000000
movq %rax, 0x2040(%rsp)
leaq 0x2020(%rsp), %rdi
callq 0x111290
leaq 0xc70(%rsp), %rdi
callq 0x1194e0
jmp 0x118919
leaq 0xc68(%rsp), %rdi
movl $0x2, %esi
callq 0x119670
jmp 0x11892d
leaq 0xc47(%rsp), %rdi
movq %rdi, 0x68(%rsp)
callq 0x111690
movq 0x68(%rsp), %rdx
leaq 0x334ace(%rip), %rsi    # 0x44d419
leaq 0xc48(%rsp), %rdi
callq 0x118790
jmp 0x11895a
leaq 0xc68(%rsp), %rdi
leaq 0xc48(%rsp), %rsi
leaq 0x2068(%rsp), %rdx
xorl %ecx, %ecx
callq 0x1196b0
jmp 0x11897b
leaq 0xc48(%rsp), %rdi
callq 0x1117c8
leaq 0xc47(%rsp), %rdi
callq 0x1117b0
leaq 0xc1f(%rsp), %rdi
movq %rdi, 0x60(%rsp)
callq 0x111690
movq 0x60(%rsp), %rdx
leaq 0x3349f9(%rip), %rsi    # 0x44d3ac
leaq 0xc20(%rsp), %rdi
callq 0x118790
jmp 0x1189c2
leaq 0xc68(%rsp), %rdi
leaq 0xc20(%rsp), %rsi
leaq 0x2060(%rsp), %rdx
xorl %ecx, %ecx
callq 0x1196b0
jmp 0x1189e3
leaq 0xc20(%rsp), %rdi
callq 0x1117c8
leaq 0xc1f(%rsp), %rdi
callq 0x1117b0
leaq 0xbf7(%rsp), %rdi
movq %rdi, 0x58(%rsp)
callq 0x111690
movq 0x58(%rsp), %rdx
leaq 0x3356b9(%rip), %rsi    # 0x44e0d4
leaq 0xbf8(%rsp), %rdi
callq 0x118790
jmp 0x118a2a
leaq 0xc68(%rsp), %rdi
leaq 0xbf8(%rsp), %rsi
leaq 0x2050(%rsp), %rdx
xorl %ecx, %ecx
callq 0x1196b0
jmp 0x118a4b
leaq 0xbf8(%rsp), %rdi
callq 0x1117c8
leaq 0xbf7(%rsp), %rdi
callq 0x1117b0
leaq 0xbcf(%rsp), %rdi
movq %rdi, 0x50(%rsp)
callq 0x111690
movq 0x50(%rsp), %rdx
leaq 0x334981(%rip), %rsi    # 0x44d404
leaq 0xbd0(%rsp), %rdi
callq 0x118790
jmp 0x118a92
leaq 0xc68(%rsp), %rdi
leaq 0xbd0(%rsp), %rsi
leaq 0x2048(%rsp), %rdx
xorl %ecx, %ecx
callq 0x1196b0
jmp 0x118ab3
leaq 0xbd0(%rsp), %rdi
callq 0x1117c8
leaq 0xbcf(%rsp), %rdi
callq 0x1117b0
leaq 0xba7(%rsp), %rdi
movq %rdi, 0x48(%rsp)
callq 0x111690
movq 0x48(%rsp), %rdx
leaq 0x334e99(%rip), %rsi    # 0x44d984
leaq 0xba8(%rsp), %rdi
callq 0x118790
jmp 0x118afa
leaq 0xc68(%rsp), %rdi
leaq 0xba8(%rsp), %rsi
leaq 0x2058(%rsp), %rdx
xorl %ecx, %ecx
callq 0x1196b0
jmp 0x118b1b
leaq 0xba8(%rsp), %rdi
callq 0x1117c8
leaq 0xba7(%rsp), %rdi
callq 0x1117b0
leaq 0xb7f(%rsp), %rdi
movq %rdi, 0x40(%rsp)
callq 0x111690
movq 0x40(%rsp), %rdx
leaq 0x3348e1(%rip), %rsi    # 0x44d434
leaq 0xb80(%rsp), %rdi
callq 0x118790
jmp 0x118b62
leaq 0xc68(%rsp), %rdi
leaq 0xb80(%rsp), %rsi
leaq 0x2040(%rsp), %rdx
callq 0x119760
jmp 0x118b81
leaq 0xb80(%rsp), %rdi
callq 0x1117c8
leaq 0xb7f(%rsp), %rdi
callq 0x1117b0
leaq 0xb57(%rsp), %rdi
movq %rdi, 0x38(%rsp)
callq 0x111690
movq 0x38(%rsp), %rdx
leaq 0x334dcd(%rip), %rsi    # 0x44d986
leaq 0xb58(%rsp), %rdi
callq 0x118790
jmp 0x118bc8
leaq 0xc68(%rsp), %rdi
leaq 0xb58(%rsp), %rsi
leaq 0x2020(%rsp), %rdx
xorl %ecx, %ecx
callq 0x119840
jmp 0x118be9
leaq 0xb58(%rsp), %rdi
callq 0x1117c8
leaq 0xb57(%rsp), %rdi
callq 0x1117b0
leaq 0xb2f(%rsp), %rdi
movq %rdi, 0x30(%rsp)
callq 0x111690
movq 0x30(%rsp), %rdx
leaq 0x334d72(%rip), %rsi    # 0x44d993
leaq 0xb30(%rsp), %rdi
callq 0x118790
jmp 0x118c30
leaq 0xc68(%rsp), %rdi
leaq 0xb30(%rsp), %rsi
leaq 0xc70(%rsp), %rdx
callq 0x119900
jmp 0x118c4f
leaq 0xb30(%rsp), %rdi
callq 0x1117c8
leaq 0xb2f(%rsp), %rdi
callq 0x1117b0
leaq 0xb08(%rsp), %rdi
callq 0x1199a0
jmp 0x118c78
leaq 0xb08(%rsp), %rdi
leaq 0xc68(%rsp), %rsi
callq 0x119a50
jmp 0x118c8f
leaq 0x90(%rsp), %rdi
movl $0x7f, %esi
callq 0x119b00
jmp 0x118ca3
leaq 0x1e0(%rsp), %rdi
leaq 0x90(%rsp), %rsi
callq 0x119c30
jmp 0x118cba
leaq 0x90(%rsp), %rdi
callq 0x11a460
leaq 0x1e0(%rsp), %rdi
leaq 0x2088(%rsp), %rsi
leaq 0xb08(%rsp), %rdx
callq 0x11a4d0
jmp 0x118ce6
leaq 0x338671(%rip), %rsi    # 0x45135e
leaq 0x2020(%rsp), %rdi
callq 0x111310
jmp 0x118cfc
leaq 0xb08(%rsp), %rdi
callq 0x11ad60
movsd %xmm0, 0x28(%rsp)
jmp 0x118d11
movsd 0x28(%rsp), %xmm0
movsd %xmm0, 0x88(%rsp)
leaq 0x334c73(%rip), %rsi    # 0x44d99a
leaq 0x2020(%rsp), %rdi
callq 0x111310
jmp 0x118d36
leaq 0xb08(%rsp), %rdi
callq 0x11ad60
movsd %xmm0, 0x20(%rsp)
jmp 0x118d4b
movsd 0x20(%rsp), %xmm0
movsd %xmm0, 0x80(%rsp)
movsd 0x2068(%rsp), %xmm0
movsd 0x2060(%rsp), %xmm1
movsd 0x2050(%rsp), %xmm2
movsd 0x2048(%rsp), %xmm3
movsd 0x2058(%rsp), %xmm4
movsd 0x88(%rsp), %xmm5
leaq 0x334c07(%rip), %rdi    # 0x44d99e
movb $0x6, %al
callq 0x111080
jmp 0x118da0
movsd 0x2068(%rsp), %xmm0
movsd 0x2060(%rsp), %xmm1
movsd 0x2050(%rsp), %xmm2
movsd 0x2048(%rsp), %xmm3
movsd 0x2058(%rsp), %xmm4
movsd 0x80(%rsp), %xmm5
leaq 0x334c02(%rip), %rdi    # 0x44d9df
movb $0x6, %al
callq 0x111080
jmp 0x118de6
movsd 0x88(%rsp), %xmm0
movsd 0x80(%rsp), %xmm1
subsd %xmm1, %xmm0
movsd %xmm0, 0x18(%rsp)
movsd 0x2068(%rsp), %xmm0
movsd %xmm0, 0x10(%rsp)
movsd 0x2060(%rsp), %xmm0
movsd %xmm0, 0x8(%rsp)
movaps 0x32f1e9(%rip), %xmm1   # 0x448010
movsd 0x2048(%rsp), %xmm0
pxor %xmm1, %xmm0
movsd 0x2050(%rsp), %xmm1
mulsd %xmm1, %xmm0
callq 0x111140
movsd 0x8(%rsp), %xmm2
movsd 0x10(%rsp), %xmm1
movaps %xmm0, %xmm3
movsd 0x18(%rsp), %xmm0
mulsd %xmm3, %xmm2
subsd %xmm2, %xmm1
subsd %xmm1, %xmm0
movsd %xmm0, 0x78(%rsp)
movsd 0x78(%rsp), %xmm0
leaq 0x334ba6(%rip), %rdi    # 0x44da20
movb $0x1, %al
callq 0x111080
jmp 0x118e83
leaq 0x1e0(%rsp), %rdi
callq 0x11ad80
leaq 0xb08(%rsp), %rdi
callq 0x11af80
leaq 0xc68(%rsp), %rdi
callq 0x11afc0
leaq 0xc70(%rsp), %rdi
callq 0x11b040
leaq 0x2020(%rsp), %rdi
callq 0x1117c8
leaq 0x2088(%rsp), %rdi
callq 0x1117c8
addq $0x20a8, %rsp           # imm = 0x20A8
retq
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2078(%rsp)
movl %eax, 0x2074(%rsp)
leaq 0x2087(%rsp), %rdi
callq 0x1117b0
jmp 0x119227
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2078(%rsp)
movl %eax, 0x2074(%rsp)
jmp 0x11920d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2078(%rsp)
movl %eax, 0x2074(%rsp)
jmp 0x119200
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2078(%rsp)
movl %eax, 0x2074(%rsp)
jmp 0x118f68
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2078(%rsp)
movl %eax, 0x2074(%rsp)
leaq 0xc48(%rsp), %rdi
callq 0x1117c8
leaq 0xc47(%rsp), %rdi
callq 0x1117b0
jmp 0x1191f3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2078(%rsp)
movl %eax, 0x2074(%rsp)
jmp 0x118fb1
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2078(%rsp)
movl %eax, 0x2074(%rsp)
leaq 0xc20(%rsp), %rdi
callq 0x1117c8
leaq 0xc1f(%rsp), %rdi
callq 0x1117b0
jmp 0x1191f3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2078(%rsp)
movl %eax, 0x2074(%rsp)
jmp 0x118ffa
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2078(%rsp)
movl %eax, 0x2074(%rsp)
leaq 0xbf8(%rsp), %rdi
callq 0x1117c8
leaq 0xbf7(%rsp), %rdi
callq 0x1117b0
jmp 0x1191f3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2078(%rsp)
movl %eax, 0x2074(%rsp)
jmp 0x119043
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2078(%rsp)
movl %eax, 0x2074(%rsp)
leaq 0xbd0(%rsp), %rdi
callq 0x1117c8
leaq 0xbcf(%rsp), %rdi
callq 0x1117b0
jmp 0x1191f3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2078(%rsp)
movl %eax, 0x2074(%rsp)
jmp 0x11908c
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2078(%rsp)
movl %eax, 0x2074(%rsp)
leaq 0xba8(%rsp), %rdi
callq 0x1117c8
leaq 0xba7(%rsp), %rdi
callq 0x1117b0
jmp 0x1191f3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2078(%rsp)
movl %eax, 0x2074(%rsp)
jmp 0x1190d5
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2078(%rsp)
movl %eax, 0x2074(%rsp)
leaq 0xb80(%rsp), %rdi
callq 0x1117c8
leaq 0xb7f(%rsp), %rdi
callq 0x1117b0
jmp 0x1191f3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2078(%rsp)
movl %eax, 0x2074(%rsp)
jmp 0x11911e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2078(%rsp)
movl %eax, 0x2074(%rsp)
leaq 0xb58(%rsp), %rdi
callq 0x1117c8
leaq 0xb57(%rsp), %rdi
callq 0x1117b0
jmp 0x1191f3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2078(%rsp)
movl %eax, 0x2074(%rsp)
jmp 0x119167
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2078(%rsp)
movl %eax, 0x2074(%rsp)
leaq 0xb30(%rsp), %rdi
callq 0x1117c8
leaq 0xb2f(%rsp), %rdi
callq 0x1117b0
jmp 0x1191f3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2078(%rsp)
movl %eax, 0x2074(%rsp)
jmp 0x1191f3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2078(%rsp)
movl %eax, 0x2074(%rsp)
jmp 0x1191e6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2078(%rsp)
movl %eax, 0x2074(%rsp)
leaq 0x90(%rsp), %rdi
callq 0x11a460
jmp 0x1191e6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2078(%rsp)
movl %eax, 0x2074(%rsp)
leaq 0x1e0(%rsp), %rdi
callq 0x11ad80
leaq 0xb08(%rsp), %rdi
callq 0x11af80
leaq 0xc68(%rsp), %rdi
callq 0x11afc0
leaq 0xc70(%rsp), %rdi
callq 0x11b040
leaq 0x2020(%rsp), %rdi
callq 0x1117c8
leaq 0x2088(%rsp), %rdi
callq 0x1117c8
movq 0x2078(%rsp), %rdi
callq 0x111470
nopw %cs:(%rax,%rax)
nop