** mvport package v2
  * mvport command 
  * Author: Alberto Dorantes, July, 2016
  * cdorante@itesm.mx
  
capture program drop mvport
program mvport, rclass
    version 11.0
    syntax varlist(min=2 numeric ts) [if] [in], ret(real) [NOShort] [MINweight(real -1)] [MAXweight(real -1)] [CASEwise] [RMINweights(numlist)] [RMAXweights(numlist)] [COVMatrix(string)] [MRets(string)] 
	marksample touse
	tempname peso i vecweights meanrets covmat srmin srmax rmin rmax vecmaxweights sumw rpesos
	local nvar : word count `varlist'
	if "`casewise'"=="" {
	  marksample touse, novarlist
	}	
	 if "`mrets'"!="" { 
	  capture matrix `meanrets' = `mrets'
	  if (_rc!=0) {
	    display as error "The matrix for Expected Returns does not exist; define a Stata Matrix (Vertical Vector of N rows and 1 column)"
	    exit
	  }
	  else if (rowsof(`meanrets')!=`nvar') {
	    display as error "The length of the vertical mean vector specified in the mrets option is not equal to the number of variables "
		exit
	  }
	  else { 
        mata: MR=st_matrix("`mrets'")
		mata: st_numscalar("srmin",min(MR))
        mata: st_numscalar("srmax",max(MR))
		local rmax=srmax
		local rmin=srmin
	  }
	}
	else {
	  quietly meanrets `varlist' `if' `in', `casewise'	
	  scalar srmax=r(maxret)
	  scalar srmin=r(minret)
	  local rmax=srmax
	  local rmin=srmin
	  matrix `meanrets'=r(meanrets)

	}  
	if "`covmatrix'"!="" { 
	  capture matrix `covmat' = `covmatrix'
	  if (_rc!=0) {
	    display as error "The Variance-Covariance Matrix does not exist; define a Stata Matrix with that name or change to the right matrix name"
	    exit
	  }	  
	  else if (rowsof(`covmat')!=`nvar' | colsof(`covmat')!=`nvar') {
	    display as error "The number of columns or rows of the variance-covariance matrix specified in the covm option is not equal to the number of variables "
		exit
	  }
	}
	else {
	  matrix `covmat' = J(1,1,0)
	}
	local i=0
	local sumw=0
	matrix `vecmaxweights'=J(`nvar',1,100)
	if "`noshort'"!="noshort" {
    	matrix `vecweights'=J(`nvar',1,-100)
	}
	else {
	    matrix `vecweights'=J(`nvar',1,0)
	}
    if "`rmaxweights'"!="" {
     foreach peso in `rmaxweights' {
     if `i'<`nvar' {
	   local i=`i'+1
	   matrix `vecmaxweights'[`i',1] = `peso'
	   local sumw=`sumw'+`peso'
	 }
   }
   if `sumw'<=1 {
	  display as error "The sum of each weight specified for the returns is too small; it is not possible to assign 100% in the weights."
      exit
	    }
   }
	else {
	if `maxweight'!=-1 {
    	if `maxweight'*`nvar'<=1 {
	      display as error "The maximum weight specified for all returns is too small; it is not possible to assign 100% in the weights."
	      exit
	    }
	  matrix `vecmaxweights'=J(`nvar',1,`maxweight')
	}
	
	}
	if ("`rmaxweights'"!="" | `maxweight'!=-1) { 
	  mata: maxr=m_getmaxr(st_matrix("`meanrets'"),st_matrix("`vecmaxweights'"))
      mata: st_numscalar("srmax",maxr)	
	  local rmax=srmax
	}
 local i=0
 local sumw=0
   if "`rminweights'"!="" {
	   local noshort "noshort"
	   matrix `vecweights'=J(`nvar',1,0)
       foreach peso in `rminweights' {
	    if `i'<`nvar' {
    	 local i=`i'+1
	     matrix `vecweights'[`i',1] = `peso'  
		 local sumw=`sumw'+`peso'
		} 
	   }
	   if `sumw'>=1 {
	      display as error "The minimum weights specified for each returns exceed 1 (100%); you have to change them so that the sum of all minimum weights is less than 1"
	    exit
	    }
    }
*	
	else {
	if `minweight'!=-1 {
    	if `minweight'*`nvar'>=1 {
	      display as error "The minimum weight specified for all returns is not valid; they exceed 1 (100%) considering all returns"
	    exit
	    }
	  matrix `vecweights'=J(`nvar',1,`minweight')
	  local noshort "noshort"
	}
	else if "`noshort'"!="" {
	  local minweight 0
	  matrix `vecweights'=J(`nvar',1,0)
	  local noshort "noshort"
	}

	}
		
	   qui gmvport `varlist' `if' `in', `casewise' `noshort' minweight(`minweight') maxweight(`maxweight') rminweights(`rminweights') rmaxweights(`rmaxweights') covmatrix(`covmatrix') mrets(`mrets')
	   scalar srmin=r(retport)
	   local rmin=srmin
    if ( (`ret'>`rmax'  & "`noshort'"!="") | (`ret'<`rmin') )  {
       display as error "Return `ret' is out of range; according to the return variables specified, the return must be between `rmin' and `rmax'"
	   matrix `rpesos'=J(`nvar',1,0)
	   return matrix weights=`rpesos'
	   return scalar retport=0
	   return scalar sdport=0
	   return scalar N=0
    }
   else {
	tempname  rcov retp sdp rexprets nnoshort mcr cr pcr betas
	local nnoshort=("`noshort'"!="")
    mata: `rpesos'= m_mvport2("`varlist'",`ret',st_matrix("`vecweights'"),"`touse'", "`casewise'", st_matrix("`covmat'"), st_matrix("`meanrets'"),st_matrix("`vecmaxweights'"), `nnoshort')
	matrix `rpesos'=r(weights)
	matrix `rcov'=r(cov)
	matrix `rexprets' = r(exprets)
	matrix `mcr'=r(mcr)
	matrix `cr'=r(cr)
	matrix `pcr'=r(pcr)
	matrix `betas'=r(betas)
	if `r(retp)'<`ret' {
	  display "It was not possible to match the specified return due to the specified constraints"
	  display "A maximum return of `r(retp)' was calculated given the weight constraints"
	} 
	foreach v of varlist `varlist' {
	   local nomvar "`nomvar' `v'"
	} 
	matrix rownames `rpesos' = `nomvar'
	matrix colnames `rpesos' = "Weights"
    matrix rownames `rcov' = `nomvar'
	matrix colnames `rcov' = `nomvar'
	matrix rownames `mcr' = `nomvar'
	matrix colnames `mcr' = "Marginal Contribution to Risk"
	matrix rownames `cr' = `nomvar'
	matrix colnames `cr' = "Contribution to Risk"
	matrix rownames `pcr' = `nomvar'
	matrix colnames `pcr' = "Percent Contribution to Risk"
	matrix rownames `betas' = `nomvar'
	matrix colnames `betas' ="Asset betas"
	
	display "Portfolio weights of the portfolio: "
	matlist `rpesos'
	display "Number of observations used to calculate expected returns and var-covariance matrix : " r(N)
    display "Required return of the Portfolio:  " `r(retp)'
    if "`noshort'"=="" {
	  display "Minimum standard deviation of the portfolio (Allowing for short sales): " `r(sdp)'
	}
	else { 
      display "Minimum standard deviation of the portfolio (DO NOT Allow Short Sales): " `r(sdp)'
	}

	return matrix weights=`rpesos'
	return matrix cov=`rcov'
	return matrix exprets=`rexprets'
	return matrix mcr=`mcr'
	return matrix cr=`cr'
	return matrix pcr=`pcr'
	return matrix betas=`betas'
	return scalar retport=r(retp)
	return scalar sdport=r(sdp)
	return scalar varport=r(varp)
	return scalar N=r(N)
	}
end