%
% function V = down_and_out_call(r,sigma,T,S,K,B,opt)
%
% Black-Scholes European down and out call
% option solution as defined on page 209 of 
% The Mathematics of Financial Derivatives
% by Wilmott, Howison and Dewynne
%
% r     - interest rate
% sigma - volatility
% T     - time interval
% S     - asset value(s) / strike price
% K     - strike price(s)
% B     - barrier price
% opt   - 'value', 'delta' or 'gamma'
% V     - option value(s)
%

function V = down_and_out_call(r,sigma,T,S,K,B,opt)

if nargin ~= 7
  error('wrong number of arguments');
end

S  = max(1e-100,S);     % avoids problems with S=0

ex  = (1-2*r/sigma^2);
ex2 =    4*r/sigma^3;

switch opt
  case 'value'
    V =                      european_call(r,sigma,T,S     ,K,'value')     ...
          -   (S/B).^ex    .*european_call(r,sigma,T,B^2./S,K,'value');

  case 'delta'
    V =                      european_call(r,sigma,T,S     ,K,'delta')     ...
      -    ex*(S/B).^(ex-1).*european_call(r,sigma,T,B^2./S,K,'value')/B   ...
      +       (S/B).^(ex-2).*european_call(r,sigma,T,B^2./S,K,'delta');

  case 'gamma'
    V =                      european_call(r,sigma,T,S     ,K,'gamma')     ...
  - ex*(ex-1)*(S/B).^(ex-2).*european_call(r,sigma,T,B^2./S,K,'value')/B^2 ...
  +  2*(ex-1)*(S/B).^(ex-3).*european_call(r,sigma,T,B^2./S,K,'delta')/B   ...
  -           (S/B).^(ex-4).*european_call(r,sigma,T,B^2./S,K,'gamma');

  case 'vega'
    V =                      european_call(r,sigma,T,S     ,K,'vega')     ...
                - (S/B).^ex.*european_call(r,sigma,T,B^2./S,K,'vega')     ...
  - ex2*log(S/B).*(S/B).^ex.*european_call(r,sigma,T,B^2./S,K,'value');

  otherwise
    error('invalid value for opt -- must be ''value'', ''delta'' or ''gamma''')
end
