def efficient_return(self, target): num_stocks = len(self._data.columns) cvm = cov_matrix(self._data) args = (cvm, self._freq) def _pf_return(weights): ret = pf_mean_returns(weights, self._mr) return ret constraints = ( { "type": "eq", "fun": lambda x: _pf_return(x) - target }, { "type": "eq", "fun": lambda x: np.sum(x) - 1 }, ) bounds = tuple((0, 1) for asset in range(num_stocks)) result = sco.minimize( pf_volatility, num_stocks * [ 1.0 / num_stocks, ], args=args, method="SLSQP", bounds=bounds, constraints=constraints, ) return result
def min_volatility(self): num_stocks = len(self._data.columns) cvm = cov_matrix(self._data) args = (cvm, self._freq) constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1}) bound = (0.0, 1.0) bounds = tuple(bound for asset in range(num_stocks)) result = sco.minimize(pf_volatility, num_stocks * [1. / num_stocks, ], args=args, method='SLSQP', bounds=bounds, constraints=constraints) return result
def pf_valuation(weights, data: pd.DataFrame, risk_free_rate=0.001, freq=252): weights_ndarray = None if isinstance(weights, pd.DataFrame): if len(weights.columns) > 1: raise ValueError( 'Incorrect dataframe with weights provided. Expected 1 column with weights' ) weights_list = [] for column in data.columns: stock_weight = weights.at[column, weights.columns[0]] weights_list.append(stock_weight) weights_ndarray = np.array(weights_list) elif isinstance(weights, np.ndarray): weights_ndarray = weights else: raise ValueError('Weights should be numpy ndarray or pd.DataFrame') if len(weights_ndarray) < len(data.columns) or len(weights_ndarray) > len( data.columns): raise ValueError('Incorrect data or weights were provided') cvm = cov_matrix(data) stocks_yearly_returns = mean_returns(data, freq=freq, type='log') stocks_yearly_downside_vol = downside_volatility(data, freq=freq) returns = pf_mean_returns(weights_ndarray, stocks_yearly_returns) volatility = pf_volatility( weights_ndarray, cvm, freq=freq) # Annual standard deviation = volatility sh_ratio = (returns - risk_free_rate) / volatility pf_stocks_yearly_downside_vol = pf_negative_volatility( weights=weights_ndarray, stocks_yearly_downside_vol=stocks_yearly_downside_vol) sor_ratio = (returns - risk_free_rate) / pf_stocks_yearly_downside_vol return { 'Returns': returns, 'Volatility': volatility, 'Sharp': sh_ratio, 'Downside volatility': pf_stocks_yearly_downside_vol, 'Sortino': sor_ratio }
def efficient_return(self, target): num_stocks = len(self._data.columns) cvm = cov_matrix(self._data) args = (cvm, self._freq) def _pf_return(weights): ret = pf_valuation(weights=weights, data=self._data, risk_free_rate=self._risk_free_rate, freq=self._freq).get('Returns') return ret constraints = ({'type': 'eq', 'fun': lambda x: _pf_return(x) - target}, {'type': 'eq', 'fun': lambda x: np.sum(x) - 1}) bounds = tuple((0, 1) for asset in range(num_stocks)) result = sco.minimize(pf_volatility, num_stocks * [1. / num_stocks, ], args=args, method='SLSQP', bounds=bounds, constraints=constraints) return result
def min_volatility(self): num_stocks = len(self._data.columns) cvm = cov_matrix(self._data) args = (cvm, self._freq) constraints = {"type": "eq", "fun": lambda x: np.sum(x) - 1} bound = (0.0, 1.0) bounds = tuple(bound for asset in range(num_stocks)) result = sco.minimize( pf_volatility, num_stocks * [ 1.0 / num_stocks, ], args=args, method="SLSQP", bounds=bounds, constraints=constraints, ) return result
def __init__(self, data: pd.DataFrame, weights = None, risk_free_rate=0.0425, freq=252): if not isinstance(freq, int): raise ValueError('Frequency must be an integer') elif freq <= 0: raise ValueError('Freq must be > 0') else: self._freq = freq if not isinstance(risk_free_rate, (float, int)): raise ValueError('Risk free rate must be a float or an integer') else: self._risk_free_rate = risk_free_rate if not isinstance(data, pd.DataFrame): raise ValueError('data should be a pandas.DataFrame') if isinstance(data.columns, pd.MultiIndex): self._data = clean_data(data) else: self._data = data self._portfolios = None self._min_vol_port = None self._min_downside_vol_port = None self._max_sharpe_port = None self._max_sortino_port = None self._df_results = None ##################### if weights is None: self._weights = np.array([1./len(self._data.columns) for i in range(len(self._data.columns))]) else: self._weights = np.array(weights) self._cvm = cov_matrix(self._data) self._mr = mean_returns(self._data, freq=self._freq)
def mc_random_portfolios(data: pd.DataFrame, risk_free_rate=0.01, num_portfolios=10000, freq=252): pbar = tqdm(total=num_portfolios) pf_ret = [] # Define an empty array for pf returns pf_vol = [] # Define an empty array for pf volatility pf_down_vol = [] # Define an empty array for pf downside volatility pf_weights = [] # Define an empty array for asset weights pf_sharp_ratio = [] # Define an empty array for Sharp ratio pf_sortino_ratio = [] # Define an empty array for Sortino ratio cvm = cov_matrix(data) stocks_returns = mean_returns(data, freq=freq, type="log") stocks_negative_volatility = negative_volatility(data) num_assets = len(data.columns) for idx, portfolio in enumerate(range(num_portfolios)): # weights = np.random.random(num_assets) # weights = weights / np.sum(weights) # weights = random_weights_norm(num_assets) weights = random_weights_exp(num_assets) pf_weights.append(weights) # Returns are the product of individual expected returns of asset and its weights returns = pf_mean_returns(weights, stocks_returns) pf_ret.append(returns) volatility = pf_volatility( weights, cvm, freq=freq) # Annual standard deviation = volatility pf_vol.append(volatility) sh_ratio = (returns - risk_free_rate) / volatility pf_sharp_ratio.append(sh_ratio) pf_stocks_yearly_downside_vol = pf_negative_volatility( weights=weights, stocks_yearly_downside_vol=stocks_negative_volatility) pf_down_vol.append(pf_stocks_yearly_downside_vol) sor_ratio = (returns - risk_free_rate) / pf_stocks_yearly_downside_vol pf_sortino_ratio.append(sor_ratio) if idx % 1000 == 0: pbar.update(1000) pbar.close() df_rv = { "Returns": pf_ret, "Volatility": pf_vol, "Down. Volatility": pf_down_vol, "Sharp Ratio": pf_sharp_ratio, "Sortino Ratio": pf_sortino_ratio, } for counter, symbol in enumerate(data.columns, start=0): df_rv[symbol] = [w[counter] for w in pf_weights] portfolios = pd.DataFrame(df_rv) return portfolios
def __init__(self, data: pd.DataFrame, weights=None, risk_free_rate=0.0425, freq=252): if not isinstance(freq, int): raise ValueError("Frequency must be an integer") elif freq <= 0: raise ValueError("Freq must be > 0") else: self._freq = freq if not isinstance(risk_free_rate, (float, int)): raise ValueError("Risk free rate must be a float or an integer") else: self._risk_free_rate = risk_free_rate if not isinstance(data, pd.DataFrame): raise ValueError("data should be a pandas.DataFrame") if isinstance(data.columns, pd.MultiIndex): self._data = clean_data(data) else: self._data = data self._mc_portfolios = None self._mc_min_vol_port = None self._mc_min_downside_vol_port = None self._mc_max_sharpe_port = None self._mc_max_sortino_port = None self._mc_simulations_results = None self._weights = None ##################### if weights is None: self._weights = np.array([ 1.0 / len(self._data.columns) for i in range(len(self._data.columns)) ]) else: if isinstance(weights, pd.DataFrame): if len(weights.columns) > 1: raise ValueError( "Incorrect dataframe with weights provided. Expected 1 column with weights" ) weights_list = [] for column in data.columns: stock_weight = weights.at[column, weights.columns[0]] weights_list.append(stock_weight) self._weights = np.array(weights_list) elif isinstance(weights, np.ndarray): self._weights = weights else: raise ValueError( "Weights should be numpy ndarray or pd.DataFrame") if len(self._weights) < len(self._data.columns) or len( self._weights) > len(self._data.columns): raise ValueError("Incorrect data or weights were provided") self._cvm = cov_matrix(self._data) self._mr = mean_returns(self._data, freq=self._freq) self._negative_vol = negative_volatility(data=self._data, freq=self._freq) self._df_perfomamce = {} self._df_perfomamce["Returns"] = self.returns self._df_perfomamce["Volatility"] = self.volatility self._df_perfomamce["Down. Volatility"] = self.negative_volatility self._df_perfomamce["Sharp Ratio"] = self.sharp self._df_perfomamce["Sortino Ratio"] = self.sortino