function butterfly
% BUTTERFLY Visualize payoff schedule of option strategy
% PURPOSE : The function aims to assist students and instructors of 
%           finance in visualizing payoffs of simple option strate-
%           gies. Portfolios of n < 9 securities including a stock,
%           a zero-coupon bond,  a forward contract, and a European 
%           call or  put option, are allowed. Terminal  payoff  and
%           terminal payoff adjusted for accrued time-0 expense are
%           plotted. Discounting and valuation follow Black-Scholes.
% EXAMPLE : buttefly (Oh, the FEX code metrics..)  
% AUTHOR  : Dimitri Shvorob, dimitri.shvorob@vanderbilt.edu, 11/5/07

fw = 560;     fh = 350;
bx = .62*fw;  by = .07*fh;
ew = .08*fw;  eh = .5*ew;
tx = .1*ew;   ty = .25*eh;
bw = 2*ew+tx; bh = .25*bw;
wy = 1.5*bh;  
x2 = bx+bw+tx;
x3 = x2+ew+tx; 

n = 8;  % max number of securities 
st = {' Stock', ...
      ' Bond', ...
      ' Forward', ...
      ' Call option', ...
      ' Put option'};
pT = {'S', ...
      'K', ...
      '(S-K)', ...
      'max(S-K,0)', ...
      'max(K-S,0)'};   
p0 = {'(-S0)', ...
      '(-exp(-R*T)*K)', ...
      '(exp(-R*T)*K-S0)', ...
      '(-blscall(S0,K,R,T,sigma))', ...
      '(-blsput(S0,K,R,T,sigma))'};

ax = setupAxisAndButtons;
hp = setupParameterSelection;
[hs,hk,hn] = setupSecuritySelection;
clearSecuritySelection

function[ax] = setupAxisAndButtons
ax = .05; ay = (by + bh + wy)/fh;
ah = .7;  aw = (bx - ew)/fw;   
figure('Name','Butterfly: visualize payoffs of an option strategy', ...
       'NumberTitle','off', 'Position',[232 246 fw fh], ...
       'Color','white','Resize','off','MenuBar','none');
ax = axes('Position' ,[ax ay aw ah],'FontSize',8);
guiinput('pushbutton',[bx by bw bh],'Plot' ,@evalSecuritySelection);   
guiinput('pushbutton',[x2 by bw bh],'Reset',@clearSecuritySelection);
end

function[h] = setupParameterSelection
tw = .75*bw;
iw = .75*ew;
tt = .10*ew;
v = {'90' ,'100','0.05';
     '110','0.1','1'};
l = {'xmin','Stock price','Interest rate';
     'xmax','Volatility','Time to expiry'};
h = nan(2,3);
for i = 1:2
   y = .4*by + (i-1)*(eh + ty);
   for j = 1:3
       x = (j-1)*(tw + tx + iw + tt);
       guilabel([x y-4 tw eh],l{i,j});
       h(i,j) = guiinput('edit',[x+tw+tx y iw eh],v{i,j},@checkIfPositive);
   end          
end
end

function[hs,hk,hn] = setupSecuritySelection
bx = .62*fw; 
by = .07*fh;
[hs,hk,hn] = deal(nan(n,1));
for i = 1:n
    y = by + bh + wy + (i-1)*(eh + ty);
    hs(i) = guiinput('popupmenu',[bx y-3 bw eh+2],st,''); 
    hk(i) = guiinput('edit',[x2 y ew eh],'',@checkIfPositive); 
    hn(i) = guiinput('edit',[x3 y ew eh],'',@checkIfNumber);          
end    
y = y + ty + 1.2*eh;
guilabel([bx y bw eh],'Security type')
guilabel([x2 y-10 ew 2*eh],{'Strike /','Face value'})
guilabel([x3 y ew eh],'Units') 
end

function[h] = guiinput(style,position,string,callback)
h = uicontrol('Style',style,'Position',position,'BackgroundColor','white',...
              'FontSize',8,'String',string,'Callback',callback); 
end

function guilabel(position,string)
guiinput('text',position,string,'');
end

function checkIfPositive(hObject,eventdata)      %#ok
i = str2double(get(hObject,'String'));
if isnan(i) || i < 0, beep, end
end

function checkIfNumber(hObject,eventdata)        %#ok
i = str2double(get(hObject,'String'));
if isnan(i), beep, end
end

function evalSecuritySelection(hObject,eventdata)%#ok
cla(ax)
[p,e] = evalSchedule;
plotSchedule(p,e)
end

    function[p,e] = evalSchedule
    p = ''; e = '';
    for i = 1:n
        m = get(hn(i),'String');
        if ~isempty(m) 
           if strcmp(m(1),'-')
              m = ['(' m ')'];
           end   
           s = get(hs(i),'Value');
           k = get(hk(i),'String');
           p = [p '+(' m '*'           strrep(pT{s},'K',k)  ')'];
           e = [e '+(exp(R*T)*(' m '*' strrep(p0{s},'K',k) '))'];
        end
    end
    v = {'S0','R'; 'sigma','T'};
    for i = 1:2
        for j = 1:2
            m = get(hp(i,j+1),'String');
            p = strrep(p,v{i,j},m);
            e = strrep(e,v{i,j},m);
        end    
    end
    end
         
    function plotSchedule(p,e)
    try
       a = str2double(get(hp(1,1),'String'));
       b = str2double(get(hp(2,1),'String'));
       x = linspace(a,b,100);
       p = feval(eval(['@(S) ' p]),x);
       e = feval(eval(['@(S) ' e]),x);
       plot(ax,x,p  ,'Color',[.1 .1 .1],'LineWidth',1.5); hold on
       plot(ax,x,p+e,'Color',[.8 .8 .8],'LineWidth',1.5); hold on
       legend(ax,'\pi_{\itT}','\pi_{\itT} + \ite^{rT}\rm\pi_{0}','Location','Best')
       legend('boxoff') 
       plot(ax,[a b],[0 0],'k:')
    catch
       beep 
    end   
    
end

function clearSecuritySelection(hObject,eventdata) %#ok
% Clear/initialize security selections
m = fliplr([1:5 4 4 5]);
for i = 1:n
    set(hn(i),'String','')
    set(hk(i),'String','')
    set(hs(i),'Value',m(i))
end    
cla(ax)
end

function[c] = blscall(S,K,r,T,sigma)
% Black-Scholes call price
d = (log(S/K) + (r + [1 -1]*sigma^2/2)*T)/(sigma*sqrt(T));
c = S*normcdf(d(1)) - K*exp(-r*T)*normcdf(d(2));
end

function[p] = blsput(S,K,r,T,sigma)
% Black-Scholes put price
d = -(log(S/K) + (r + [1 -1]*sigma^2/2)*T)/(sigma*sqrt(T));
p = K*exp(-r*T)*normcdf(d(2)) - S*normcdf(d(1));
end

end