hudson-and-thames / mlfinlab

MlFinLab helps portfolio managers and traders who want to leverage the power of machine learning by providing reproducible, interpretable, and easy to use tools.
Other
3.92k stars 1.14k forks source link

Add Mean and covariance matrix. #469

Open andrewcztrack opened 3 years ago

andrewcztrack commented 3 years ago

Hi @Jackal08 @PanPip !

I hope your well.

I was wondering if it was possible to add the mean and covariance calculation based on the below reference -

https://github.com/twistedcubic/coin-press

I am trying to use it with Robust Bayesian allocation but i am getting errors.

andrewcztrack commented 3 years ago

import utils
import torch
import numpy as np
from algos import *
import pandas as pd

args = utils.parse_args()
args.d = 6
dist_mean = torch.zeros(args.d)
dist_cov = torch.eye(args.d)
args.u = 10*np.sqrt(args.d)
args.total_budget = .5
args.t = 3
args.rho = [(1.0/8.0)*args.total_budget, (1.0/8.0)*args.total_budget, (3.0/4.0)*args.total_budget]
args.n = 5000

rr=torch.from_numpy(data.to_numpy()).float()

Sigma_numpy = cov_est(rr, args)
#print(Sigma_numpy)
px = pd.DataFrame(Sigma_numpy).astype("float")
cov=np.array(px)
cov

import numpy as np
from mlfinlab.portfolio_optimization.bayesian import RobustBayesianAllocation

# Number of time series observations to use for the model.
returns = data.to_numpy()
num_assets=6
# Sample estimate
sample_mean = np.mean(returns, axis=0).reshape((num_assets, 1))
sample_covariance = np.cov(returns, rowvar=False)
sample_covariance = px

# Bayesian prior
prior_covariance = np.diag(np.diag(sample_covariance))
prior_mean = 0.5 * sample_covariance.dot(np.ones((num_assets, 1))) / num_assets

# Do robust bayesian allocation
bayes_allocator = RobustBayesianAllocation(discretisations=10)
bayes_allocator.allocate(
    sample_mean=sample_mean,
    sample_covariance=sample_covariance,
    prior_mean=prior_mean,
    prior_covariance=prior_covariance,
    relative_confidence_in_prior_mean=1e-5,
    relative_confidence_in_prior_covariance=1e-5,
    max_volatility=0.8 * max(sample_mean),
    sample_size=500
)

# Get the weights
portfolio_weights = bayes_allocator.weights
portfolio_weights

---------------------------------------------------------------------------
DCPError                                  Traceback (most recent call last)
<ipython-input-32-60b6de718f08> in <module>
     24     relative_confidence_in_prior_covariance=1e-5,
     25     max_volatility=0.8 * max(sample_mean),
---> 26     sample_size=500
     27 )
     28 

~/miniconda3/envs/mlfinll/lib/python3.7/site-packages/mlfinlab/portfolio_optimization/bayesian/robust_bayesian_allocation.py in allocate(self, prior_mean, prior_covariance, sample_mean, sample_covariance, sample_size, relative_confidence_in_prior_mean, relative_confidence_in_prior_covariance, posterior_mean_estimation_risk_level, posterior_covariance_estimation_risk_level, max_volatility, asset_names)
     90 
     91         # Get portfolios along Bayesian Efficient Frontier
---> 92         bayesian_portfolios, bayesian_portfolio_volatilities, bayesian_portfolio_returns = self._calculate_bayesian_frontier(asset_names)
     93 
     94         # Calculate gamma values

~/miniconda3/envs/mlfinll/lib/python3.7/site-packages/mlfinlab/portfolio_optimization/bayesian/robust_bayesian_allocation.py in _calculate_bayesian_frontier(self, asset_names)
    230                      covariance_matrix=self.posterior_covariance,
    231                      asset_names=asset_names,
--> 232                      solution='min_volatility')
    233         min_volatility_weights = mvo.weights.values
    234         min_volatility_return = mvo.portfolio_return

~/miniconda3/envs/mlfinll/lib/python3.7/site-packages/mlfinlab/portfolio_optimization/modern_portfolio_theory/mean_variance.py in allocate(self, asset_names, asset_prices, expected_asset_returns, covariance_matrix, solution, target_return, target_risk, risk_aversion, weight_bounds)
     89         elif solution == 'min_volatility':
     90             self._min_volatility(covariance=covariance,
---> 91                                  expected_returns=expected_asset_returns)
     92         elif solution == 'max_return_min_volatility':
     93             self._max_return_min_volatility(covariance=covariance,

~/miniconda3/envs/mlfinll/lib/python3.7/site-packages/mlfinlab/portfolio_optimization/modern_portfolio_theory/mean_variance.py in _min_volatility(self, covariance, expected_returns)
    385             constraints=allocation_constraints
    386         )
--> 387         problem.solve(warm_start=True)
    388         if weights.value is None:
    389             raise ValueError('No optimal set of weights found.')

~/miniconda3/envs/mlfinll/lib/python3.7/site-packages/cvxpy/problems/problem.py in solve(self, *args, **kwargs)
    393         else:
    394             solve_func = Problem._solve
--> 395         return solve_func(self, *args, **kwargs)
    396 
    397     @classmethod

~/miniconda3/envs/mlfinll/lib/python3.7/site-packages/cvxpy/problems/problem.py in _solve(self, solver, warm_start, verbose, gp, qcp, requires_grad, enforce_dpp, **kwargs)
    742 
    743         data, solving_chain, inverse_data = self.get_problem_data(
--> 744             solver, gp, enforce_dpp)
    745         solution = solving_chain.solve_via_data(
    746             self, data, warm_start, verbose, kwargs)

~/miniconda3/envs/mlfinll/lib/python3.7/site-packages/cvxpy/problems/problem.py in get_problem_data(self, solver, gp, enforce_dpp)
    497             self._cache.invalidate()
    498             solving_chain = self._construct_chain(
--> 499                 solver=solver, gp=gp, enforce_dpp=enforce_dpp)
    500             self._cache.key = key
    501             self._cache.solving_chain = solving_chain

~/miniconda3/envs/mlfinll/lib/python3.7/site-packages/cvxpy/problems/problem.py in _construct_chain(self, solver, gp, enforce_dpp)
    650         candidate_solvers = self._find_candidate_solvers(solver=solver, gp=gp)
    651         return construct_solving_chain(self, candidate_solvers, gp=gp,
--> 652                                        enforce_dpp=enforce_dpp)
    653 
    654     def _invalidate_cache(self):

~/miniconda3/envs/mlfinll/lib/python3.7/site-packages/cvxpy/reductions/solvers/solving_chain.py in construct_solving_chain(problem, candidates, gp, enforce_dpp)
    149     if len(problem.variables()) == 0:
    150         return SolvingChain(reductions=[ConstantSolver()])
--> 151     reductions = _reductions_for_problem_class(problem, candidates, gp)
    152 
    153     dpp_context = 'dcp' if not gp else 'dgp'

~/miniconda3/envs/mlfinll/lib/python3.7/site-packages/cvxpy/reductions/solvers/solving_chain.py in _reductions_for_problem_class(problem, candidates, gp)
     88                        "Consider calling solve() with `qcp=True`.")
     89         raise DCPError(
---> 90             "Problem does not follow DCP rules. Specifically:\n" + append)
     91     elif gp and not problem.is_dgp():
     92         append = build_non_disciplined_error_msg(problem, 'DGP')

DCPError: Problem does not follow DCP rules. Specifically:
The objective is not DCP. Its following subexpressions are not:
QuadForm(var1732, [[ 8.34021141e-04  3.08789520e-04  2.31343587e-04  5.05312825e-04
  -9.42613832e-05 -3.41530294e-04]
 [ 2.94395753e-04  1.25483692e-03  5.66166581e-04 -3.44443558e-04
   1.65212615e-05 -1.46168376e-04]
 [ 2.31597647e-04  5.84590227e-04  1.42932241e-03 -4.90658025e-04
   1.56349033e-04 -4.02760446e-04]
 [ 5.14689928e-04 -3.50829457e-04 -5.00810387e-04  1.82570622e-03
   4.31106599e-04 -8.51376009e-05]
 [-9.16821548e-05  3.87639180e-05  1.77022819e-04  4.07299234e-04
   4.15572259e-04  2.58098892e-04]
 [-2.98206154e-04 -1.34785050e-04 -3.61017472e-04 -7.23656363e-05
   2.55446861e-04  1.57409953e-03]])
aditya1702 commented 3 years ago

@andrewcztrack Thanks for raising the issue. Seems like cvxpy encountered matrices which make the problem non-convex. I will look into this and update as soon as possible

andrewcztrack commented 3 years ago

@aditya1702 !!! hi! thank you :)!

I was just wondering if you could have a look at the matrix calculation. i calculated the correlation matrix from the covariance matrix and got some strange results.

https://github.com/twistedcubic/coin-press https://github.com/twistedcubic/coin-press/issues/3

could you possibly have a look and if this covariance matrix and mean calculation adds value could you possibly add them to the library.

Kind regards and thanks, Andrew

aditya1702 commented 3 years ago

@andrewcztrack Sure. Will give it a look soon

andrewcztrack commented 3 years ago

Hi @aditya1702 !! thank you :). much appreciated :)