// File: /workspace/github_cpp_makefile_star2_O2/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:
pushq %rbx
subq $0x1ee0, %rsp           # imm = 0x1EE0
leaq 0x12bdc3(%rip), %rsi    # 0x23c115
leaq 0x98(%rsp), %rdi
leaq 0xb30(%rsp), %rdx
callq 0x110308
movabsq $0x4059000000000000, %rax # imm = 0x4059000000000000
movq %rax, 0x38(%rsp)
movabsq $0x405b800000000000, %rax # imm = 0x405B800000000000
movq %rax, 0x30(%rsp)
movabsq $0x3fd3333333333333, %rax # imm = 0x3FD3333333333333
movq %rax, 0x40(%rsp)
movabsq $0x4001c28f5c28f5c3, %rax # imm = 0x4001C28F5C28F5C3
movq %rax, 0x28(%rsp)
movabsq $0x3fa999999999999a, %rax # imm = 0x3FA999999999999A
movq %rax, 0x20(%rsp)
movabsq $0x417312d000000000, %rax # imm = 0x417312D000000000
movq %rax, 0x50(%rsp)
leaq 0x88(%rsp), %rax
movq %rax, -0x10(%rax)
andq $0x0, -0x8(%rax)
movb $0x0, (%rax)
leaq 0xb30(%rsp), %rdi
callq 0x1108fc
leaq 0x8(%rsp), %rdi
pushq $0x2
popq %rsi
callq 0x1109c8
leaq 0x12bbcf(%rip), %rsi    # 0x23bfc5
leaq 0x208(%rsp), %rdi
leaq 0xb8(%rsp), %rdx
callq 0x110308
leaq 0x8(%rsp), %rdi
leaq 0x208(%rsp), %rsi
leaq 0x38(%rsp), %rdx
xorl %ecx, %ecx
callq 0x1109ec
leaq 0x208(%rsp), %rdi
callq 0x10e608
leaq 0x12bb20(%rip), %rsi    # 0x23bf58
leaq 0x208(%rsp), %rdi
leaq 0xb8(%rsp), %rdx
callq 0x110308
leaq 0x8(%rsp), %rdi
leaq 0x208(%rsp), %rsi
leaq 0x30(%rsp), %rdx
xorl %ecx, %ecx
callq 0x1109ec
leaq 0x208(%rsp), %rdi
callq 0x10e608
leaq 0x12c818(%rip), %rsi    # 0x23cc92
leaq 0x208(%rsp), %rdi
leaq 0xb8(%rsp), %rdx
callq 0x110308
leaq 0x8(%rsp), %rdi
leaq 0x208(%rsp), %rsi
leaq 0x28(%rsp), %rdx
xorl %ecx, %ecx
callq 0x1109ec
leaq 0x208(%rsp), %rdi
callq 0x10e608
leaq 0x12baf4(%rip), %rsi    # 0x23bfb0
leaq 0x208(%rsp), %rdi
leaq 0xb8(%rsp), %rdx
callq 0x110308
leaq 0x8(%rsp), %rdi
leaq 0x208(%rsp), %rsi
leaq 0x20(%rsp), %rdx
xorl %ecx, %ecx
callq 0x1109ec
leaq 0x208(%rsp), %rdi
callq 0x10e608
leaq 0x12c032(%rip), %rsi    # 0x23c530
leaq 0x208(%rsp), %rdi
leaq 0xb8(%rsp), %rdx
callq 0x110308
leaq 0x8(%rsp), %rdi
leaq 0x208(%rsp), %rsi
leaq 0x40(%rsp), %rdx
xorl %ecx, %ecx
callq 0x1109ec
leaq 0x208(%rsp), %rdi
callq 0x10e608
leaq 0x12baa0(%rip), %rsi    # 0x23bfe0
leaq 0x208(%rsp), %rdi
leaq 0xb8(%rsp), %rdx
callq 0x110308
leaq 0x8(%rsp), %rdi
leaq 0x208(%rsp), %rsi
leaq 0x50(%rsp), %rdx
callq 0x110a58
leaq 0x208(%rsp), %rdi
callq 0x10e608
leaq 0x12bfb2(%rip), %rsi    # 0x23c532
leaq 0x208(%rsp), %rdi
leaq 0xb8(%rsp), %rdx
callq 0x110308
leaq 0x8(%rsp), %rdi
leaq 0x208(%rsp), %rsi
leaq 0x78(%rsp), %rdx
xorl %ecx, %ecx
callq 0x110ad4
leaq 0x208(%rsp), %rdi
callq 0x10e608
leaq 0x12bf7d(%rip), %rsi    # 0x23c53f
leaq 0x208(%rsp), %rdi
leaq 0xb8(%rsp), %rdx
callq 0x110308
leaq 0x8(%rsp), %rdi
leaq 0x208(%rsp), %rsi
leaq 0xb30(%rsp), %rdx
callq 0x110b46
leaq 0x208(%rsp), %rdi
callq 0x10e608
leaq 0x58(%rsp), %rdi
callq 0x110ba6
leaq 0x58(%rsp), %rdi
leaq 0x8(%rsp), %rsi
callq 0x110c06
leaq 0xb8(%rsp), %rdi
pushq $0x7f
popq %rsi
callq 0x110c62
leaq 0x208(%rsp), %rdi
leaq 0xb8(%rsp), %rsi
callq 0x110d72
leaq 0xb8(%rsp), %rdi
callq 0x11138a
leaq 0x208(%rsp), %rdi
leaq 0x98(%rsp), %rsi
leaq 0x58(%rsp), %rdx
callq 0x1113d2
leaq 0x12f88b(%rip), %rsi    # 0x23fef5
leaq 0x78(%rsp), %rdi
callq 0x10e5c0
movq 0x58(%rsp), %rax
movq 0x8(%rax), %rdi
movq (%rdi), %rax
callq *0x18(%rax)
movsd %xmm0, 0x18(%rsp)
leaq 0x12beb6(%rip), %rsi    # 0x23c546
leaq 0x78(%rsp), %rdi
callq 0x10e5c0
movq 0x58(%rsp), %rax
movq 0x8(%rax), %rdi
movq (%rdi), %rax
callq *0x18(%rax)
movsd %xmm0, 0x10(%rsp)
movsd 0x38(%rsp), %xmm0
movsd 0x30(%rsp), %xmm1
movsd 0x28(%rsp), %xmm2
movsd 0x20(%rsp), %xmm3
movsd 0x40(%rsp), %xmm4
leaq 0x12be76(%rip), %rdi    # 0x23c54a
movsd 0x18(%rsp), %xmm5
movb $0x6, %al
callq 0x10e060
movsd 0x38(%rsp), %xmm0
movsd 0x30(%rsp), %xmm1
movsd 0x28(%rsp), %xmm2
movsd 0x20(%rsp), %xmm3
movsd 0x40(%rsp), %xmm4
leaq 0x12be85(%rip), %rdi    # 0x23c58b
movsd 0x10(%rsp), %xmm5
movb $0x6, %al
callq 0x10e060
movsd 0x18(%rsp), %xmm0
subsd 0x10(%rsp), %xmm0
movsd %xmm0, 0x18(%rsp)
movsd 0x38(%rsp), %xmm0
movsd %xmm0, 0x10(%rsp)
movsd 0x30(%rsp), %xmm0
movsd %xmm0, 0x48(%rsp)
movsd 0x20(%rsp), %xmm0
xorpd 0x1268c5(%rip), %xmm0   # 0x237010
mulsd 0x28(%rsp), %xmm0
callq 0x10e0e0
mulsd 0x48(%rsp), %xmm0
movsd 0x10(%rsp), %xmm1
subsd %xmm0, %xmm1
movsd 0x18(%rsp), %xmm0
subsd %xmm1, %xmm0
leaq 0x12be55(%rip), %rdi    # 0x23c5cc
movb $0x1, %al
callq 0x10e060
leaq 0x208(%rsp), %rdi
callq 0x111854
leaq 0x58(%rsp), %rdi
callq 0x11198e
leaq 0x8(%rsp), %rdi
callq 0x1119a4
leaq 0x78(%rsp), %rdi
callq 0x10e608
leaq 0x98(%rsp), %rdi
callq 0x10e608
addq $0x1ee0, %rsp           # imm = 0x1EE0
popq %rbx
retq
jmp 0x110818
movq %rax, %rbx
leaq 0xb8(%rsp), %rdi
callq 0x11138a
jmp 0x110828
jmp 0x1107d5
movq %rax, %rbx
jmp 0x110828
jmp 0x11080a
jmp 0x1107f8
jmp 0x11080a
jmp 0x1107f8
jmp 0x11080a
jmp 0x1107f8
jmp 0x11080a
jmp 0x1107f8
jmp 0x11080a
jmp 0x1107f8
jmp 0x11080a
jmp 0x1107f8
jmp 0x11080a
jmp 0x1107f8
jmp 0x11080a
movq %rax, %rbx
leaq 0x208(%rsp), %rdi
callq 0x10e608
jmp 0x110832
movq %rax, %rbx
jmp 0x110832
jmp 0x110811
movq %rax, %rbx
jmp 0x11083c
jmp 0x110818
movq %rax, %rbx
leaq 0x208(%rsp), %rdi
callq 0x111854
leaq 0x58(%rsp), %rdi
callq 0x11198e
leaq 0x8(%rsp), %rdi
callq 0x1119a4
leaq 0x78(%rsp), %rdi
callq 0x10e608
leaq 0x98(%rsp), %rdi
callq 0x10e608
movq %rbx, %rdi
callq 0x10e340