function lkly = findlk3(tpars,x,xc,logrf,logspret,minage,c,d,h,lvgrid,maxT,which,bankhand,stockind,dok); % proc to evaluate likelyhood function */ % returns - log likelyhood so that optmum can minimize */ global RECORD TEST; numdel = 0; huge = inf; % huge value to send back for zero probabilites, other states to be avoided if TEST == 2; lkv = zeros(rows(x),4); % keep track to see most influential observations and their character % 1: likelyhood of this obs. 2: category number end; % check for wild parameters that will bomb likelyhood % if so, reset to boundary and add a graduated continuous penalty to % keep L out of here. xlow = trans3( -1,-10 ,0.1 ,0.01 ,0.1 ,0.1 ,0.000001,which); xhi = trans3( 1, 10 ,5 ,1.5 ,10 , 10,0.999999,which); penalty = sum( (tparsxhi).*(tpars-xhi)); if (penalty>0)&(TEST == 1); disp('findlk3 parameter values outside bounds. resetting parameters and adding penalty. original transformed parameters'); disp([tpars']) end; penalty = 1E6*penalty^2; tpars = (tparsxhi).*xhi+((tpars>=xlow)&(tpars<=xhi)).*tpars; % reset offending parameters to limit % recover parameters from transformed [gam,delt,sig,k,a,b,pim] = back3(tpars,which); if which(7) == 0; % if not searching over measurement error, set it to zero pim = 0; end; if which(1) == 0; % this is used as code to impose alpha = 0; if stockind == 0; % ER = 400*(exp(gam+1/2*sig^2)-1); gam = log(1+(15/400))-1/2*sig^2 ; % this will force ER = 15% annually elseif (stockind == 1); mlogrf = mean(logrf); mum = mean(logspret); sigm = std(logspret); gam = -log( exp(delt*(mum-mlogrf)+1/2*delt^2*sigm^2+1/2*sig^2)*... (1+(exp(delt*sigm^2)-1)*(exp(-(mum-mlogrf)-1/2*sigm^2)-1)/(exp(sigm^2)-1))); % this reverse engineers the formula use to calculate alpha so it will be 0 else; disp('findlk3 error: trying to impose alpha = 0 for model other than SP500 or no stock. Needs more programming to do this.'); end; end; if (TEST == 1); disp('findlk3 trying transformed, actual gam delt sig k a b'); disp([tpars']) disp([gam delt sig k a b pim]); end; % check for k off the bottom of the grid. We really have to keep this % from happening. (Above may keep this from happening, but code kept % just to be sure if (log(k) <= min(lvgrid))|(log(k) > max(lvgrid)); disp('findlk3 being asked for k < min of grid or > max of grid -- sending back huge likly. SHOULD NOT SEE THIS. '); disp('better to raise penalty in findlk3 so that the likelyhood function is continuous'); lkly = huge; RECORD = [RECORD ; tpars' lkly]; return; end; begdatinx = 0; % initialize date in quarters since 87 */ if stockind == 0; % with no stock index you only have to do sim once as beginning date is irrelevant [pnoseet,pseeipt,pnosipt,pseebkt,pnosbkt] = sim3(gam,delt,sig,k,a,b,pim,c,d,0,logrf,logspret,lvgrid,stockind,dok,0); % beg date 0 since not used end; % now loop through data, find probability of each data point, add up */ lkly = 0; for il=1:rows(x); if (TEST == 1)&(il<5); disp('il'); disp(il); end; newbeg = ddate(x(il,4)); % find beginning date of this observation */ outdat = x(il,7); newbeginx = floor((newbeg-1987)*4)+1; % should be the quarter in which this project starts */ if newbeginx ~= begdatinx; % If this observation has a new begin date, do sim again */ if stockind > 0; % version with stock index [pnoseet,pseeipt,pnosipt,pseebkt,pnosbkt] = sim3(gam,delt,sig,k,a,b,pim,c,d,newbeginx,logrf,logspret,lvgrid,stockind,dok,0); end; begdatinx = newbeginx; end; % all logic maintained for version with no stock so that ages are calculated right, using begdat below. % categories of observation: % 1. Ipo/acquired/another round, have good dates and return % 2. Ipo/acquired/another round, good dates but return bad % 3. Ipo/acq/another round, bad return and bad dates % 4. Still private, age to end of data set % 5. Out of business, date known % 6. Out of business, date unknown % % 1. ipo/acq with good date and return data */ if xc(il) == 1; ageindx = floor((ddate(outdat)-1987)*4)+1 - begdatinx; % quarter of exit with 1987:1 = 1 - start*/ logV = log(x(il,10)); % xcase tested to make sure no zeros. doit3 changed zero returns to out of business. [trash, logVindx] = min(abs(logV-lvgrid)); % find nearest value gridpoint clear trash; if ageindx <= minage*4; % treat dates less than minage as "on or before" newprob = sum(pseeipt(1:min([minage*4;size(pseeipt,1)]),logVindx)); % at end of sample can't do minage*4 else; newprob = pseeipt(ageindx,logVindx); end; if newprob > 0; lkly = lkly + log(newprob); else; lkly = huge; % now taking zero probabilities as serious. Send back a huge likelyhood function. RECORD = [RECORD ; tpars' lkly]; return; end; if TEST == 2; lkv(il,:) = [log(newprob) 1 ageindx logV]; end; % used in the past to debug zero probabilities that were % results of bugs, especially in sim3. % disp('findlk3 ERROR: pseeipt says this event is impossible. Adding 1k to ln L. i ='); disp(il); % disp('ageindx '); disp([ageindx ]); % disp('Vindx and lnV'); disp([logVindx logV]); % disp( [ (x(il,:))]); % disp('par gam delt sig k a b');disp([gam delt sig k a b]); % disp('workspace saved in sim3'); % lkly = lkly + 1000 ; % This should really discourage minimizer from going here. % save sim3; % end; %disp(x(il,1:10)); %disp([il ddate(outdat)-newbeg ageindx logV logVindx lvgrid(logVindx) log(newprob)]); % 2. ipo/acq/another round with bad return but good dates */ elseif xc(il) == 2; ageindx = floor((ddate(outdat)-1987)*4)+1 -begdatinx; if ageindx < minage*4; newprob = sum(pnosipt(1:min([minage*4;size(pnosipt,1)]))); else; newprob = pnosipt(ageindx); end; if newprob > 0; lkly = lkly + log(newprob); else; lkly = huge; % now taking zero probabilities as serious. Send back a huge likelyhood function. RECORD = [RECORD ; tpars' lkly]; return; % disp('findlk3 ERROR pnosipt(ageindx) = 0. i, x'); disp(il); disp(1:10); disp(x(il,:)); % disp('par gam delt sig k a b'); disp([gam delt sig k a b]); end; if TEST == 2; lkv(il,:) = [log(newprob) 2 ageindx -99]; end; % 3. ipo/acq with bad return and bad end date */ elseif xc(il) == 3; ageindx = 54 -begdatinx; % qtr exit - start -- on or before end of sample */ if sum(pnosipt(1:ageindx)) > 0; newprob = sum(pnosipt(1:ageindx)); lkly = lkly + log(newprob); else; lkly = huge; % now taking zero probabilities as serious. Send back a huge likelyhood function. RECORD = [RECORD ; tpars' lkly]; return; % disp('findlk3 ERROR sum(pnosipt(1:ageindx)) = 0. i.x '); disp(il); disp(1:10); disp(x(il,:)); % disp('par gam delt sig k a b'); disp([ gam delt sig k a b ]); end; if TEST == 2; lkv(il,:) = [log(newprob) 3 ageindx -99]; end; % 4. still private, good dates */ elseif xc(il) == 4; ageindx = 54 - begdatinx; % qtr exit - start */ if pnoseet(ageindx) > 0; newprob = (pnoseet(ageindx)); lkly = lkly + log(newprob); else; lkly = huge; % now taking zero probabilities as serious. Send back a huge likelyhood function. RECORD = [RECORD ; tpars' lkly]; return; % disp('findlk3 par gam delt sig k a b'); disp([gam delt sig k a b]); % disp('findlk3 ERROR: pnoseet(agindx) = 0 i x'); disp(il); disp(1:10); disp(x(il,:)); end; if TEST == 2; lkv(il,:) = [log(newprob) 4 ageindx -99]; end; % 5. Bankrupt, dates ok */ % A: if bankhand says use the dates */ % elseif xc(il) == 5.1; % disp('findlk3 error. this should no longer be used'); % ageindx = floor((ddate(outdat)-1987)*4)+1; % quarter of exit */ % ageindx = ageindx - begdatinx; % qtr exit - start */ % if ageindx > 0; % if pseebkt(ageindx) > 0; % lkly = lkly + log(pseebkt(ageindx)); % else; % disp('findlk3 ERROR A: pseebkt(ageindx) <= 0 i,x'); disp(il); disp(x(il,:)); % disp('par'); disp([ gam delt sig k a b]); % end; % else; % numdel = numdel + 1; % end; % % % B: treat dates as bad */ % elseif xc(il) == 5.2; % disp('findlk3 error. this should no longer be used'); % ageindx = 54; % ageindx = ageindx - begdatinx; % qtr exit - start */ % % if sum(pnosbkt(1:ageindx)) > 0; % lkly = lkly + log(sum(pnosbkt(1:ageindx))); % else; % disp('findlk3 ERROR B : sum(pnosbkt(1:ageindx)) <= 0)'); disp(il); disp(x(il,:)); % disp([gam delt sig k a b]); % end; % C: use dates to infer bankrupt 'on or before' given date */ elseif xc(il) == 5.3; ageindx = floor((ddate(outdat)-1987)*4)+1 - begdatinx; if ageindx > minage*4; if sum(pseebkt(1:ageindx)) > 0; newprob = (sum(pseebkt(1:ageindx))); lkly = lkly + log(newprob); else; lkly = huge; % now taking zero probabilities as serious. Send back a huge likelyhood function. RECORD = [RECORD ; tpars' lkly]; return; % disp('findlk3 ERROR C sum pseebkt(ageindx) <= 0 '); disp(il); disp(x(il,:)); % disp([gam delt sig k a b]); end; end; if ageindx <= minage*4; if sum(pseebkt(1:min([minage*4;size(pseebkt,1)]))) > 0; newprob = (sum(pseebkt(1:min([minage*4;size(pseebkt,1)])))); lkly = lkly +log(newprob); else; lkly = huge; % now taking zero probabilities as serious. Send back a huge likelyhood function. RECORD = [RECORD ; tpars' lkly]; return; % disp('findlk3 ERROR D sum pseebkt(minage) <= 0 '); disp(il); disp(x(il,:)); % disp([gam delt sig k a b]); end; end; if TEST == 2; lkv(il,:) = [log(newprob) 5 ageindx -99]; end; % 6. Bankrupt, dates not ok */ elseif xc(il) == 6; ageindx = 54 - begdatinx; % qtr exit - start */ if sum(pnosbkt(1:ageindx)) > 0; newprob = (sum(pnosbkt(1:ageindx))); lkly = lkly + log(newprob); else; lkly = huge; % now taking zero probabilities as serious. Send back a huge likelyhood function. RECORD = [RECORD ; tpars' lkly]; return; % disp('findlk3 ERROR D: sum(pnosbkt(1:ageindx)) <= 0/'); disp(il); disp(x(il,:)); % disp([gam delt sig k a b]); end; if TEST == 2; lkv(il,:) = [log(newprob) 6 ageindx -99]; end; % make sure we have every one */ else; disp('findlk3 Observation Does not fit in a category. Observation:'); disp(il); disp(x(il,:)); end; if (TEST == 1)&(il<5); disp(' ageindx lkyly so far'); disp([ageindx lkly]); end; end; lkly = -lkly+penalty; if TEST == 2; lkv(:,1) = -lkv(:,1); [lkvsort indx] = sort(lkv(:,1)); disp('10 most influential observations and their contrib to lkly'); sp = x(indx,:); disp(' co. no. round date post value exit date exit typ post value '); sp = [sp(:,[1 4 6 7 8 9 10]) 12*(ddate(sp(:,7))-ddate(sp(:,4))) lkv(indx,:)]; disp(sp(end-10:end,1:6)); disp(' co no gross ret age(mo) lkly contrib category agindx logV'); disp([sp(end-10:end,1) sp(end-10:end,7:end)]); disp('categories: 1: ipo etc good data. 2: ipo bad r good dates 3: ipo etc., bad r and bad date 4: private good dates 5: out, good dates 6: out, bad dates'); TEST = sp; % use test to return sp to main program. as global. end; if (TEST == 1); disp('findlk3 likelyhood 1/E04 '); disp([lkly/1E4]); end; RECORD = [RECORD ; tpars' lkly]; return;