def test_value_error_for_non_dataframe_input(self): """ Test ValueError on passing non-dataframe input. """ with self.assertRaises(ValueError): cla = CriticalLineAlgorithm() cla.allocate(asset_prices=self.data.values, solution='cla_turning_points', asset_names=self.data.columns)
def test_value_error_for_unknown_solution(self): """ Test ValueError on passing unknown solution string. """ with self.assertRaises(ValueError): cla = CriticalLineAlgorithm() cla.allocate(asset_prices=self.data, solution='unknown_string', asset_names=self.data.columns)
def test_all_inputs_none(self): """ Test allocation when all inputs are None. """ with self.assertRaises(ValueError): cla = CriticalLineAlgorithm() cla.allocate(asset_names=self.data.columns)
def test_value_error_for_unknown_returns(self): """ Test ValueError on passing unknown returns string. """ with self.assertRaises(ValueError): cla = CriticalLineAlgorithm(calculate_expected_returns="unknown_returns") cla.allocate(asset_prices=self.data, solution='cla_turning_points', asset_names=self.data.columns)
def test_value_error_for_non_date_index(self): """ Test ValueError on passing dataframe not indexed by date. """ with self.assertRaises(ValueError): cla = CriticalLineAlgorithm() data = self.data.reset_index() cla.allocate(asset_prices=data, solution='cla_turning_points', asset_names=self.data.columns)
def test_cla_efficient_frontier(self): """ Test the calculation of the efficient frontier solution. """ cla = CriticalLineAlgorithm(weight_bounds=(0, 1), calculate_expected_returns="mean") cla.allocate(asset_prices=self.data, solution='efficient_frontier', asset_names=self.data.columns) assert len(cla.efficient_frontier_means) == len(cla.efficient_frontier_sigma) and \ len(cla.efficient_frontier_sigma) == len(cla.weights.values) assert cla.efficient_frontier_sigma[-1] <= cla.efficient_frontier_sigma[0] and \ cla.efficient_frontier_means[-1] <= cla.efficient_frontier_means[0] # higher risk = higher return
def test_cla_min_volatility(self): """ Test the calculation for minimum volatility weights. """ cla = CriticalLineAlgorithm(weight_bounds=(0, 1), calculate_expected_returns="mean") cla.allocate(asset_prices=self.data, solution='min_volatility', asset_names=self.data.columns) weights = cla.weights.values[0] assert (weights >= 0).all() assert len(weights) == self.data.shape[1] np.testing.assert_almost_equal(np.sum(weights), 1)
def test_free_bound_weights(self): # pylint: disable=protected-access,invalid-name """ Test the method of freeing bounded weights when free-weights is None. """ cla = CriticalLineAlgorithm(weight_bounds=(0, 1), calculate_expected_returns="mean") cla.allocate(asset_prices=self.data, solution='min_volatility', asset_names=self.data.columns) x, y = cla._free_bound_weight(free_weights=[1]*(cla.expected_returns.shape[0]+1)) assert not x assert not y
def test_no_asset_names(self): """ Test CLA when not supplying a list of asset names. """ cla = CriticalLineAlgorithm() cla.allocate(asset_prices=self.data) weights = cla.weights.values[0] assert (weights >= 0).all() assert len(weights) == self.data.shape[1] np.testing.assert_almost_equal(np.sum(weights), 1)
def test_valuerror_with_no_asset_names(self): """ Test ValueError when not supplying a list of asset names and no other input. """ with self.assertRaises(ValueError): cla = CriticalLineAlgorithm() expected_returns = ReturnsEstimators().calculate_mean_historical_returns(asset_prices=self.data, resample_by='W') covariance = ReturnsEstimators().calculate_returns(asset_prices=self.data, resample_by='W').cov() cla.allocate(expected_asset_returns=expected_returns, covariance_matrix=covariance)
def test_resampling_asset_prices(self): """ Test resampling of asset prices. """ cla = CriticalLineAlgorithm() cla.allocate(asset_prices=self.data, resample_by='B', solution='min_volatility', asset_names=self.data.columns) weights = cla.weights.values[0] assert (weights >= 0).all() assert len(weights) == self.data.shape[1] np.testing.assert_almost_equal(np.sum(weights), 1)
def test_cla_with_exponential_returns(self): """ Test the calculation of CLA turning points using exponential returns """ cla = CriticalLineAlgorithm(weight_bounds=(0, 1), calculate_expected_returns="exponential") cla.allocate(asset_prices=self.data, asset_names=self.data.columns) weights = cla.weights.values weights[weights <= 1e-15] = 0 # Convert very very small numbers to 0 for turning_point in weights: assert (turning_point >= 0).all() assert len(turning_point) == self.data.shape[1] np.testing.assert_almost_equal(np.sum(turning_point), 1)
def test_cla_with_weight_bounds_as_lists(self): """ Test the calculation of CLA turning points when we pass the weight bounds as a list instead of just lower and upper bound value. """ cla = CriticalLineAlgorithm(weight_bounds=([0]*self.data.shape[1], [1]*self.data.shape[1]), calculate_expected_returns="mean") cla.allocate(asset_prices=self.data, asset_names=self.data.columns) weights = cla.weights.values weights[weights <= 1e-15] = 0 # Convert very very small numbers to 0 for turning_point in weights: assert (turning_point >= 0).all() assert len(turning_point) == self.data.shape[1] np.testing.assert_almost_equal(np.sum(turning_point), 1)
def test_w_for_no_bounded_weights(self): # pylint: disable=protected-access,invalid-name """ Test the computation of weights (w) when there are no bounded weights. """ cla = CriticalLineAlgorithm(weight_bounds=(0, 1), calculate_expected_returns="mean") cla.allocate(asset_prices=self.data, solution='min_volatility', asset_names=self.data.columns) data = self.data.cov() data = data.values x, y = cla._compute_w(covar_f_inv=data, covar_fb=data, mean_f=cla.expected_returns, w_b=None) assert isinstance(x, np.ndarray) assert isinstance(y, float)
def test_flag_true_for_purge_num_err(self): # pylint: disable=protected-access, no-self-use """ Test whether the flag becomes True in the purge num error function. """ cla = CriticalLineAlgorithm() cla.weights = [[1]] cla.lower_bounds = [100] cla.upper_bounds = [1] cla.lambdas = [[1]] cla.gammas = [[1]] cla.free_weights = [[1]] cla._purge_num_err(tol=1) assert not cla.weights assert not cla.lambdas assert not cla.gammas
def test_cla_with_input_as_returns_and_covariance(self): # pylint: disable=invalid-name """ Test CLA when we pass expected returns and covariance matrix as input. """ cla = CriticalLineAlgorithm() expected_returns = ReturnsEstimators().calculate_mean_historical_returns(asset_prices=self.data) covariance = ReturnsEstimators().calculate_returns(asset_prices=self.data).cov() cla.allocate(covariance_matrix=covariance, expected_asset_returns=expected_returns, asset_names=self.data.columns) weights = cla.weights.values weights[weights <= 1e-15] = 0 # Convert very very small numbers to 0 for turning_point in weights: assert (turning_point >= 0).all() assert len(turning_point) == self.data.shape[1] np.testing.assert_almost_equal(np.sum(turning_point), 1)
def test_purge_excess(self): # pylint: disable=protected-access,invalid-name """ Test purge number excess for very very small tolerance. """ with self.assertRaises(IndexError): cla = CriticalLineAlgorithm(weight_bounds=(0, 1), calculate_expected_returns="mean") cla.allocate(asset_prices=self.data, solution='cla_turning_points', asset_names=self.data.columns) cla.weights = list(cla.weights.values) cla.weights = cla.weights*100 cla._purge_num_err(tol=1e-18)
def test_lambda_for_zero_matrices(self): # pylint: disable=protected-access,invalid-name """ Test the computation of lambda when there are no bounded weights. The method should return None, None. """ cla = CriticalLineAlgorithm(weight_bounds=(0, 1), calculate_expected_returns="mean") cla.allocate(asset_prices=self.data, solution='min_volatility', asset_names=self.data.columns) data = self.data.cov() data = data.values data[:, :] = 0 x, y = cla._compute_lambda(covar_f_inv=data, covar_fb=data, mean_f=cla.expected_returns, w_b=None, asset_index=1, b_i=[[0], [1]]) assert not x assert not y
def test_expected_returns_equals_means(self): # pylint: disable=protected-access,invalid-name """ Test for condition when expected returns equal the mean value. """ cla = CriticalLineAlgorithm(weight_bounds=(0, 1), calculate_expected_returns="mean") cla.allocate(asset_prices=self.data, solution='min_volatility', asset_names=self.data.columns) data = self.data.copy() data.iloc[:, :] = 0.02320653 cla._initialise(asset_prices=data, resample_by='B', expected_asset_returns=None, covariance_matrix=None) assert cla.expected_returns[-1, 0] == 1e-5