black_scholes.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. //---------------------------------------------------------------------------//
  2. // Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com>
  3. //
  4. // Distributed under the Boost Software License, Version 1.0
  5. // See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt
  7. //
  8. // See http://boostorg.github.com/compute for more information.
  9. //---------------------------------------------------------------------------//
  10. #include <cstdlib>
  11. #include <iostream>
  12. #include <boost/compute/command_queue.hpp>
  13. #include <boost/compute/system.hpp>
  14. #include <boost/compute/algorithm/copy_n.hpp>
  15. #include <boost/compute/container/vector.hpp>
  16. #include <boost/compute/utility/source.hpp>
  17. namespace compute = boost::compute;
  18. // return a random float between lo and hi
  19. float rand_float(float lo, float hi)
  20. {
  21. float x = (float) std::rand() / (float) RAND_MAX;
  22. return (1.0f - x) * lo + x * hi;
  23. }
  24. // this example demostrates a black-scholes option pricing kernel.
  25. int main()
  26. {
  27. // number of options
  28. const int N = 4000000;
  29. // black-scholes parameters
  30. const float risk_free_rate = 0.02f;
  31. const float volatility = 0.30f;
  32. // get default device and setup context
  33. compute::device gpu = compute::system::default_device();
  34. compute::context context(gpu);
  35. compute::command_queue queue(context, gpu);
  36. std::cout << "device: " << gpu.name() << std::endl;
  37. // initialize option data on host
  38. std::vector<float> stock_price_data(N);
  39. std::vector<float> option_strike_data(N);
  40. std::vector<float> option_years_data(N);
  41. std::srand(5347);
  42. for(int i = 0; i < N; i++){
  43. stock_price_data[i] = rand_float(5.0f, 30.0f);
  44. option_strike_data[i] = rand_float(1.0f, 100.0f);
  45. option_years_data[i] = rand_float(0.25f, 10.0f);
  46. }
  47. // create memory buffers on the device
  48. compute::vector<float> call_result(N, context);
  49. compute::vector<float> put_result(N, context);
  50. compute::vector<float> stock_price(N, context);
  51. compute::vector<float> option_strike(N, context);
  52. compute::vector<float> option_years(N, context);
  53. // copy initial values to the device
  54. compute::copy_n(stock_price_data.begin(), N, stock_price.begin(), queue);
  55. compute::copy_n(option_strike_data.begin(), N, option_strike.begin(), queue);
  56. compute::copy_n(option_years_data.begin(), N, option_years.begin(), queue);
  57. // source code for black-scholes program
  58. const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE(
  59. // approximation of the cumulative normal distribution function
  60. static float cnd(float d)
  61. {
  62. const float A1 = 0.319381530f;
  63. const float A2 = -0.356563782f;
  64. const float A3 = 1.781477937f;
  65. const float A4 = -1.821255978f;
  66. const float A5 = 1.330274429f;
  67. const float RSQRT2PI = 0.39894228040143267793994605993438f;
  68. float K = 1.0f / (1.0f + 0.2316419f * fabs(d));
  69. float cnd =
  70. RSQRT2PI * exp(-0.5f * d * d) *
  71. (K * (A1 + K * (A2 + K * (A3 + K * (A4 + K * A5)))));
  72. if(d > 0){
  73. cnd = 1.0f - cnd;
  74. }
  75. return cnd;
  76. }
  77. // black-scholes option pricing kernel
  78. __kernel void black_scholes(__global float *call_result,
  79. __global float *put_result,
  80. __global const float *stock_price,
  81. __global const float *option_strike,
  82. __global const float *option_years,
  83. float risk_free_rate,
  84. float volatility)
  85. {
  86. const uint opt = get_global_id(0);
  87. float S = stock_price[opt];
  88. float X = option_strike[opt];
  89. float T = option_years[opt];
  90. float R = risk_free_rate;
  91. float V = volatility;
  92. float sqrtT = sqrt(T);
  93. float d1 = (log(S / X) + (R + 0.5f * V * V) * T) / (V * sqrtT);
  94. float d2 = d1 - V * sqrtT;
  95. float CNDD1 = cnd(d1);
  96. float CNDD2 = cnd(d2);
  97. float expRT = exp(-R * T);
  98. call_result[opt] = S * CNDD1 - X * expRT * CNDD2;
  99. put_result[opt] = X * expRT * (1.0f - CNDD2) - S * (1.0f - CNDD1);
  100. }
  101. );
  102. // build black-scholes program
  103. compute::program program = compute::program::create_with_source(source, context);
  104. program.build();
  105. // setup black-scholes kernel
  106. compute::kernel kernel(program, "black_scholes");
  107. kernel.set_arg(0, call_result);
  108. kernel.set_arg(1, put_result);
  109. kernel.set_arg(2, stock_price);
  110. kernel.set_arg(3, option_strike);
  111. kernel.set_arg(4, option_years);
  112. kernel.set_arg(5, risk_free_rate);
  113. kernel.set_arg(6, volatility);
  114. // execute black-scholes kernel
  115. queue.enqueue_1d_range_kernel(kernel, 0, N, 0);
  116. // print out the first option's put and call prices
  117. float call0, put0;
  118. compute::copy_n(put_result.begin(), 1, &put0, queue);
  119. compute::copy_n(call_result.begin(), 1, &call0, queue);
  120. std::cout << "option 0 call price: " << call0 << std::endl;
  121. std::cout << "option 0 put price: " << put0 << std::endl;
  122. // due to the differences in the random-number generators between Operating Systems
  123. // and/or compilers, we will get different "expected" results for this example
  124. #ifdef __APPLE__
  125. double expected_call0 = 0.000249461;
  126. double expected_put0 = 26.2798;
  127. #elif _MSC_VER
  128. double expected_call0 = 8.21412;
  129. double expected_put0 = 2.25904;
  130. #else
  131. double expected_call0 = 0.0999f;
  132. double expected_put0 = 43.0524f;
  133. #endif
  134. // check option prices
  135. if(std::abs(call0 - expected_call0) > 1e-4 || std::abs(put0 - expected_put0) > 1e-4){
  136. std::cerr << "error: option prices are wrong" << std::endl;
  137. return -1;
  138. }
  139. return 0;
  140. }