예제 #1
0
    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
예제 #2
0
    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
예제 #3
0
파일: valuations.py 프로젝트: ajmal017/pfo
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
    }
예제 #4
0
    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
예제 #5
0
    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
예제 #6
0
파일: portfolio.py 프로젝트: ajmal017/pfo
    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)
예제 #7
0
파일: mc.py 프로젝트: neverbreaks/pfo
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
예제 #8
0
    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