// File: ArashPartow[P]exprtk/exprtk_simple_example_21.cpp
// Function: void binomial_option_pricing_model<double>()
void binomial_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 european_option_binomial_model_program =
      " var dt     := t / n;                                              "
      " var z      := exp(r * dt);                                        "
      " var z_inv  := 1 / z;                                              "
      " var u      := exp(v * sqrt(dt));                                  "
      " var p_up   := (z * u - 1) / (u^2 - 1);                            "
      " var p_down := 1 - p_up;                                           "
      "                                                                   "
      " var option_price[n + 1] := [0];                                   "
      "                                                                   "
      " for (var i := 0; i <= n; i += 1)                                  "
      " {                                                                 "
      "    var base_price := s * u^(n - 2i);                              "
      "                                                                   "
      "    option_price[i] :=                                             "
      "       switch                                                      "
      "       {                                                           "
      "          case callput_flag == 'call' : max(base_price - k, 0);    "
      "          case callput_flag == 'put'  : max(k - base_price, 0);    "
      "       };                                                          "
      " };                                                                "
      "                                                                   "
      " for (var j := n - 1; j >= 0; j -= 1)                              "
      " {                                                                 "
      "    for (var i := 0; i <= j; i += 1)                               "
      "    {                                                              "
      "       option_price[i] := z_inv *                                  "
      "          (p_up * option_price[i] + p_down * option_price[i + 1]); "
      "    }                                                              "
      " };                                                                "
      "                                                                   "
      " option_price[0];                                                  ";

   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(1000.00); // Number of time steps

   std::string callput_flag;

   symbol_table_t symbol_table;
   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);

   expression_t expression;
   expression.register_symbol_table(symbol_table);

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

   callput_flag = "call";

   const T binomial_call_option_price = expression.value();

   callput_flag = "put";

   const T binomial_put_option_price = expression.value();

   printf("BinomialPrice(call, %5.3f, %5.3f, %5.3f, %5.3f, %5.3f) = %22.18f\n",
          s, k, t, r, v,
          binomial_call_option_price);

   printf("BinomialPrice(put , %5.3f, %5.3f, %5.3f, %5.3f, %5.3f) = %22.18f\n",
          s, k, t, r, v,
          binomial_put_option_price);

   const T put_call_parity_diff =
      (binomial_call_option_price - binomial_put_option_price) -
      (s - k * std::exp(-r * t));

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

// Assembly:
subq $0xcc8, %rsp            # imm = 0xCC8
leaq 0xca7(%rsp), %rdi
movq %rdi, 0x68(%rsp)
callq 0x111640
movq 0x68(%rsp), %rdx
leaq 0x330d2c(%rip), %rsi    # 0x449551
leaq 0xca8(%rsp), %rdi
callq 0x118740
jmp 0x118834
leaq 0xca7(%rsp), %rdi
callq 0x111760
movabsq $0x4059000000000000, %rax # imm = 0x4059000000000000
movq %rax, 0xc88(%rsp)
movabsq $0x405b800000000000, %rax # imm = 0x405B800000000000
movq %rax, 0xc80(%rsp)
movabsq $0x3fd3333333333333, %rax # imm = 0x3FD3333333333333
movq %rax, 0xc78(%rsp)
movabsq $0x4001c28f5c28f5c3, %rax # imm = 0x4001C28F5C28F5C3
movq %rax, 0xc70(%rsp)
movabsq $0x3fa999999999999a, %rax # imm = 0x3FA999999999999A
movq %rax, 0xc68(%rsp)
movabsq $0x408f400000000000, %rax # imm = 0x408F400000000000
movq %rax, 0xc60(%rsp)
leaq 0xc40(%rsp), %rdi
callq 0x111260
leaq 0xc38(%rsp), %rdi
movl $0x1, %esi
callq 0x119390
jmp 0x1188ce
leaq 0xc17(%rsp), %rdi
movq %rdi, 0x60(%rsp)
callq 0x111640
movq 0x60(%rsp), %rdx
leaq 0x330b15(%rip), %rsi    # 0x449401
leaq 0xc18(%rsp), %rdi
callq 0x118740
jmp 0x1188fb
leaq 0xc38(%rsp), %rdi
leaq 0xc18(%rsp), %rsi
leaq 0xc88(%rsp), %rdx
xorl %ecx, %ecx
callq 0x1193d0
jmp 0x11891c
leaq 0xc18(%rsp), %rdi
callq 0x111778
leaq 0xc17(%rsp), %rdi
callq 0x111760
leaq 0xbef(%rsp), %rdi
movq %rdi, 0x58(%rsp)
callq 0x111640
movq 0x58(%rsp), %rdx
leaq 0x330a40(%rip), %rsi    # 0x449394
leaq 0xbf0(%rsp), %rdi
callq 0x118740
jmp 0x118963
leaq 0xc38(%rsp), %rdi
leaq 0xbf0(%rsp), %rsi
leaq 0xc80(%rsp), %rdx
xorl %ecx, %ecx
callq 0x1193d0
jmp 0x118984
leaq 0xbf0(%rsp), %rdi
callq 0x111778
leaq 0xbef(%rsp), %rdi
callq 0x111760
leaq 0xbc7(%rsp), %rdi
movq %rdi, 0x50(%rsp)
callq 0x111640
movq 0x50(%rsp), %rdx
leaq 0x331afe(%rip), %rsi    # 0x44a4ba
leaq 0xbc8(%rsp), %rdi
callq 0x118740
jmp 0x1189cb
leaq 0xc38(%rsp), %rdi
leaq 0xbc8(%rsp), %rsi
leaq 0xc70(%rsp), %rdx
xorl %ecx, %ecx
callq 0x1193d0
jmp 0x1189ec
leaq 0xbc8(%rsp), %rdi
callq 0x111778
leaq 0xbc7(%rsp), %rdi
callq 0x111760
leaq 0xb9f(%rsp), %rdi
movq %rdi, 0x48(%rsp)
callq 0x111640
movq 0x48(%rsp), %rdx
leaq 0x3309c8(%rip), %rsi    # 0x4493ec
leaq 0xba0(%rsp), %rdi
callq 0x118740
jmp 0x118a33
leaq 0xc38(%rsp), %rdi
leaq 0xba0(%rsp), %rsi
leaq 0xc68(%rsp), %rdx
xorl %ecx, %ecx
callq 0x1193d0
jmp 0x118a54
leaq 0xba0(%rsp), %rdi
callq 0x111778
leaq 0xb9f(%rsp), %rdi
callq 0x111760
leaq 0xb77(%rsp), %rdi
movq %rdi, 0x40(%rsp)
callq 0x111640
movq 0x40(%rsp), %rdx
leaq 0x3312e3(%rip), %rsi    # 0x449d6f
leaq 0xb78(%rsp), %rdi
callq 0x118740
jmp 0x118a9b
leaq 0xc38(%rsp), %rdi
leaq 0xb78(%rsp), %rsi
leaq 0xc78(%rsp), %rdx
xorl %ecx, %ecx
callq 0x1193d0
jmp 0x118abc
leaq 0xb78(%rsp), %rdi
callq 0x111778
leaq 0xb77(%rsp), %rdi
callq 0x111760
leaq 0xb4f(%rsp), %rdi
movq %rdi, 0x38(%rsp)
callq 0x111640
movq 0x38(%rsp), %rdx
leaq 0x330928(%rip), %rsi    # 0x44941c
leaq 0xb50(%rsp), %rdi
callq 0x118740
jmp 0x118b03
leaq 0xc38(%rsp), %rdi
leaq 0xb50(%rsp), %rsi
leaq 0xc60(%rsp), %rdx
callq 0x119480
jmp 0x118b22
leaq 0xb50(%rsp), %rdi
callq 0x111778
leaq 0xb4f(%rsp), %rdi
callq 0x111760
leaq 0xb27(%rsp), %rdi
movq %rdi, 0x30(%rsp)
callq 0x111640
movq 0x30(%rsp), %rdx
leaq 0x331217(%rip), %rsi    # 0x449d71
leaq 0xb28(%rsp), %rdi
callq 0x118740
jmp 0x118b69
leaq 0xc38(%rsp), %rdi
leaq 0xb28(%rsp), %rsi
leaq 0xc40(%rsp), %rdx
xorl %ecx, %ecx
callq 0x119560
jmp 0x118b8a
leaq 0xb28(%rsp), %rdi
callq 0x111778
leaq 0xb27(%rsp), %rdi
callq 0x111760
leaq 0xb00(%rsp), %rdi
callq 0x119620
jmp 0x118bb3
leaq 0xb00(%rsp), %rdi
leaq 0xc38(%rsp), %rsi
callq 0x1196d0
jmp 0x118bca
leaq 0x88(%rsp), %rdi
movl $0x7f, %esi
callq 0x119780
jmp 0x118bde
leaq 0x1d8(%rsp), %rdi
leaq 0x88(%rsp), %rsi
callq 0x1198b0
jmp 0x118bf5
leaq 0x88(%rsp), %rdi
callq 0x11a0e0
leaq 0x1d8(%rsp), %rdi
leaq 0xca8(%rsp), %rsi
leaq 0xb00(%rsp), %rdx
callq 0x11a150
jmp 0x118c21
leaq 0x334b1c(%rip), %rsi    # 0x44d744
leaq 0xc40(%rsp), %rdi
callq 0x1112e0
jmp 0x118c37
leaq 0xb00(%rsp), %rdi
callq 0x11a9e0
movsd %xmm0, 0x28(%rsp)
jmp 0x118c4c
movsd 0x28(%rsp), %xmm0
movsd %xmm0, 0x80(%rsp)
leaq 0x33111c(%rip), %rsi    # 0x449d7e
leaq 0xc40(%rsp), %rdi
callq 0x1112e0
jmp 0x118c71
leaq 0xb00(%rsp), %rdi
callq 0x11a9e0
movsd %xmm0, 0x20(%rsp)
jmp 0x118c86
movsd 0x20(%rsp), %xmm0
movsd %xmm0, 0x78(%rsp)
movsd 0xc88(%rsp), %xmm0
movsd 0xc80(%rsp), %xmm1
movsd 0xc70(%rsp), %xmm2
movsd 0xc68(%rsp), %xmm3
movsd 0xc78(%rsp), %xmm4
movsd 0x80(%rsp), %xmm5
leaq 0x3310b3(%rip), %rdi    # 0x449d82
movb $0x6, %al
callq 0x111080
jmp 0x118cd8
movsd 0xc88(%rsp), %xmm0
movsd 0xc80(%rsp), %xmm1
movsd 0xc70(%rsp), %xmm2
movsd 0xc68(%rsp), %xmm3
movsd 0xc78(%rsp), %xmm4
movsd 0x78(%rsp), %xmm5
leaq 0x3310b2(%rip), %rdi    # 0x449dc4
movb $0x6, %al
callq 0x111080
jmp 0x118d1b
movsd 0x80(%rsp), %xmm0
movsd 0x78(%rsp), %xmm1
subsd %xmm1, %xmm0
movsd %xmm0, 0x18(%rsp)
movsd 0xc88(%rsp), %xmm0
movsd %xmm0, 0x10(%rsp)
movsd 0xc80(%rsp), %xmm0
movsd %xmm0, 0x8(%rsp)
movaps 0x32b2b7(%rip), %xmm1   # 0x444010
movsd 0xc68(%rsp), %xmm0
pxor %xmm1, %xmm0
movsd 0xc70(%rsp), %xmm1
mulsd %xmm1, %xmm0
callq 0x111130
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, 0x70(%rsp)
movsd 0x70(%rsp), %xmm0
leaq 0x33105a(%rip), %rdi    # 0x449e06
movb $0x1, %al
callq 0x111080
jmp 0x118db5
leaq 0x1d8(%rsp), %rdi
callq 0x11aa00
leaq 0xb00(%rsp), %rdi
callq 0x11ac00
leaq 0xc38(%rsp), %rdi
callq 0x11ac40
leaq 0xc40(%rsp), %rdi
callq 0x111778
leaq 0xca8(%rsp), %rdi
callq 0x111778
addq $0xcc8, %rsp            # imm = 0xCC8
retq
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc98(%rsp)
movl %eax, 0xc94(%rsp)
leaq 0xca7(%rsp), %rdi
callq 0x111760
jmp 0x1190dd
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc98(%rsp)
movl %eax, 0xc94(%rsp)
jmp 0x1190c3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc98(%rsp)
movl %eax, 0xc94(%rsp)
jmp 0x118e74
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc98(%rsp)
movl %eax, 0xc94(%rsp)
leaq 0xc18(%rsp), %rdi
callq 0x111778
leaq 0xc17(%rsp), %rdi
callq 0x111760
jmp 0x1190b6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc98(%rsp)
movl %eax, 0xc94(%rsp)
jmp 0x118ebd
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc98(%rsp)
movl %eax, 0xc94(%rsp)
leaq 0xbf0(%rsp), %rdi
callq 0x111778
leaq 0xbef(%rsp), %rdi
callq 0x111760
jmp 0x1190b6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc98(%rsp)
movl %eax, 0xc94(%rsp)
jmp 0x118f06
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc98(%rsp)
movl %eax, 0xc94(%rsp)
leaq 0xbc8(%rsp), %rdi
callq 0x111778
leaq 0xbc7(%rsp), %rdi
callq 0x111760
jmp 0x1190b6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc98(%rsp)
movl %eax, 0xc94(%rsp)
jmp 0x118f4f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc98(%rsp)
movl %eax, 0xc94(%rsp)
leaq 0xba0(%rsp), %rdi
callq 0x111778
leaq 0xb9f(%rsp), %rdi
callq 0x111760
jmp 0x1190b6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc98(%rsp)
movl %eax, 0xc94(%rsp)
jmp 0x118f98
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc98(%rsp)
movl %eax, 0xc94(%rsp)
leaq 0xb78(%rsp), %rdi
callq 0x111778
leaq 0xb77(%rsp), %rdi
callq 0x111760
jmp 0x1190b6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc98(%rsp)
movl %eax, 0xc94(%rsp)
jmp 0x118fe1
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc98(%rsp)
movl %eax, 0xc94(%rsp)
leaq 0xb50(%rsp), %rdi
callq 0x111778
leaq 0xb4f(%rsp), %rdi
callq 0x111760
jmp 0x1190b6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc98(%rsp)
movl %eax, 0xc94(%rsp)
jmp 0x11902a
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc98(%rsp)
movl %eax, 0xc94(%rsp)
leaq 0xb28(%rsp), %rdi
callq 0x111778
leaq 0xb27(%rsp), %rdi
callq 0x111760
jmp 0x1190b6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc98(%rsp)
movl %eax, 0xc94(%rsp)
jmp 0x1190b6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc98(%rsp)
movl %eax, 0xc94(%rsp)
jmp 0x1190a9
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc98(%rsp)
movl %eax, 0xc94(%rsp)
leaq 0x88(%rsp), %rdi
callq 0x11a0e0
jmp 0x1190a9
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc98(%rsp)
movl %eax, 0xc94(%rsp)
leaq 0x1d8(%rsp), %rdi
callq 0x11aa00
leaq 0xb00(%rsp), %rdi
callq 0x11ac00
leaq 0xc38(%rsp), %rdi
callq 0x11ac40
leaq 0xc40(%rsp), %rdi
callq 0x111778
leaq 0xca8(%rsp), %rdi
callq 0x111778
movq 0xc98(%rsp), %rdi
callq 0x111440
nopw (%rax,%rax)