Black scholes mgl

From Jacket Wiki

Jump to: navigation, search

This is a copy of jacket/examples/black_scholes_example/black_scholes_mgl.m released in Jacket v2.0

% This is a multi-GPU version of black_scholes_example.m
function black_scholes_mgl(varargin)
  disp '** Black-Scholes Multi-GPU Example **'
 
  %%-- setup --%%
  % pricing parameters
  risk = 0.02; % risk-free interest
  volatility = 0.30;
  ngpu = getfield(ginfo, 'gpu_count');
  % determine precision
  use_double = determine_precision(varargin);
  if use_double   [cpu_cls gpu_cls] = deal('double', @gdouble);
  else            [cpu_cls gpu_cls] = deal('single', @gsingle); end
 
  %%-- iterate over progressively larger option pools --%%
  fprintf(' %8s     %9s', 'options', 'cpu rate')
  for i = 1:ngpu, fprintf('            %d gpu', i), end
  fprintf('\n')
  fprintf(' --------     ---------')
  for i = 1:ngpu, fprintf('    ---------------'), end
  fprintf('\n')
 
  current_device = gselect;
  flops = getfield(ginfo('all'), 'flops');
 
  for options = 100e3*(1:20)
    % generate random input at this size
    stock_price   = randu(5,    30, [options 1], cpu_cls); % ~ U[5,30]
    strike_price  = randu(1,   100, [options 1], cpu_cls); % ~ U[1,100]
    maturity_time = randu(0.25, 10, [options 1], cpu_cls); % ~ U[0.25,10]
 
    % evaluate on CPU
    time = timeit(@blackscholes, stock_price, strike_price, risk, volatility, maturity_time);
    rate_cpu = options / time;
    fprintf(' %8d     %-9.3e', options, rate_cpu);
 
    % try spreading across more and more GPUs
    for n = 1:ngpu
      % transfer same input out to each GPU
      ratio = flops(1:n);
      splits = [0, ceil(cumsum(options * (ratio / sum(ratio))))];
      for i = 1:n
        range = [(splits(i)+1):splits(i+1)];
        stock{i}    = gpu_cls(stock_price(range, :));
        strike{i}   = gpu_cls(strike_price(range, :));
        maturity{i} = gpu_cls(maturity_time(range, :));
      end
 
      % execute
      time = timeit(@blackscholes_multi, n, stock, strike, risk, volatility, maturity,'all');
      rate_gpu = options / time;
      speedup = rate_gpu / rate_cpu;
 
      fprintf('    %-9.3e (%2.0fx)', rate_gpu, speedup);
    end
    fprintf('\n')
  end
 
  gselect(current_device);
end
 
 
function use_double = determine_precision(args)
  is_double = getfield(ginfo, 'compute') >= 1.3;
  if numel(args)
    switch args{1}
     case 'double',  use_double = true;
     case 'single',  use_double = false;
     otherwise       error('Input arguments are incorrect.')
    end
  else
    use_double = is_double;
  end
  if use_double
    disp '(using double-precision)'
  else
    disp '(using single-precision)'
  end
end
 
 
% uniform random distribution ~ U[min,max]
function X = randu(min,max, varargin)
  X = min + (max-min) * rand(varargin{:});
end
 
 
function blackscholes_multi(ngpu, stock, strike, risk, volatility, maturity)
  for i = 1:ngpu
    gselect(i)
    [c p] = blackscholes(stock{i}, strike{i}, risk, volatility, maturity{i});
    geval(c,p)
  end
end
 
 
% calculate call/put option prices based on Black-Scholes European model
% from Black, Scholes, "Pricing of Options and Corporate Liabilities" (1973)
function [Vcall, Vput] = blackscholes(S,X,R,V,T)
  % S = Underlying stock price
  % X = Strike Price
  % R = Risk free rate of interest
  % V = Volatility
  % T = Time to maturity
 
  d1 = (log(S ./ X) + (R + (V.*V)*0.5) .* T) ./ (V.*sqrt(T));
  d2 = d1 - (V.*sqrt(T));
 
  % cumulative normal distribution (probability that a variable will be less than x std)
  eps = 1e-16;
  cnd_d1 = 0.5 + sign(d1+eps) .* erf(sign(d1).*d1/sqrt(2))/2;
  cnd_d2 = 0.5 + sign(d2+eps) .* erf(sign(d2).*d2/sqrt(2))/2;
 
  Vcall = S .* cnd_d1  - X .* exp(-R.*T) .* cnd_d2;
  Vput  = X .* exp(-R.*T) .* (1-cnd_d2) - (S .* (1-cnd_d1));
end
Views
Personal tools