Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question: How to use PyPortfolioOpt for algo trading strategies rather than stocks/assets #580

Open
ts-project opened this issue Jan 25, 2024 · 1 comment
Labels
question Further information is requested

Comments

@ts-project
Copy link

Rather than use PyPortfolioOpt to weight or balance a set of stocks or assets, I am trying to use it to weight or balance a set of algo futures trading strategies. Trying to achieve what the README describes as "an algorithmic trader who has a basket of strategies".

I have dataframes of the trades taken by each strategy for a single futures contract with each trade date, the profit/loss in dollars, and a trade-by-trade cumulative balance per strategy, among other data points like drawdown etc. If needed, I also certainly have entry and exit prices for each futures trade (but obviously this would require each contract's point values to calculate the actual PnL).

What I don't quite understand is how to use PyPortfolioOpt when using this sort of trade by trade data for a set of strategies, rather than what the examples describe, which appears to be more of a weighted buy and hold approach and using the adjusted close prices for a set of assets over a period of time.

Thanks for any input and feedback on how to optimize a basket of algo strategies.

While I don't believe what I describe below is probably close to the right approach, let me also share what I have tried.

I have tried building a dataframe with the various strategies as columns and with each of their daily cumulative balances as rows.

If a strategy didn't take a trade on a given day, then the "adjusted close" value or balance of that strategy would remain the previous day's balance.

When I chop the dataframe to only include rows that have no initial balance (or zero values) for a strategy's initial balance and each strategy has already experienced a first trade, I don't get any errors, but all of my returned raw weights are 'nan'. This is also true if I don't chop the dataframes and include 'nan' as an initial balance rather than 0.

Again, don't believe this approach is right, but just wanted to share what I've tried.

When I include zeros as the initial balance before a first trade, I get an error that says:

...python3.8/site-packages/pypfopt/expected_returns.py:36: UserWarning:
Some returns are infinite. Please check your price data."

Followed by:

ValueError Traceback (most recent call last)
in
200
201
--> 202 run_strategies(0.5,0.75,9)
203
204

in run_strategies(ratio, ratio_2, min_pnldd)
140 # Optimize for maximal Sharpe ratio
141 ef = EfficientFrontier(mu, S)
--> 142 raw_weights = ef.max_sharpe()
143 cleaned_weights = ef.clean_weights()
144 # ef.save_weights_to_file("weights.csv") # saves to file

~/opt/anaconda3/lib/python3.8/site-packages/pypfopt/efficient_frontier/efficient_frontier.py in max_sharpe(self, risk_free_rate)
251 # max_sharpe requires us to make a variable transformation.
252 # Here we treat w as the transformed variable.
--> 253 self._objective = cp.quad_form(self._w, self.cov_matrix)
254 k = cp.Variable()
255

~/opt/anaconda3/lib/python3.8/site-packages/cvxpy/atoms/quad_form.py in quad_form(x, P, assume_PSD)
250 if assume_PSD:
251 P = psd_wrap(P)
--> 252 return QuadForm(x, P)
253 else:
254 raise Exception(

~/opt/anaconda3/lib/python3.8/site-packages/cvxpy/atoms/quad_form.py in init(self, x, P)
40 def init(self, x, P) -> None:
41 """Atom representing :math:x^T P x."""
---> 42 super(QuadForm, self).init(x, P)
43
44 def numeric(self, values):

~/opt/anaconda3/lib/python3.8/site-packages/cvxpy/atoms/atom.py in init(self, *args)
48 # Convert raw values to Constants.
49 self.args = [Atom.cast_to_const(arg) for arg in args]
---> 50 self.validate_arguments()
51 self._shape = self.shape_from_args()
52 if len(self._shape) > 2:

~/opt/anaconda3/lib/python3.8/site-packages/cvxpy/atoms/quad_form.py in validate_arguments(self)
56 raise ValueError("Invalid dimensions for arguments.")
57 if not self.args[1].is_hermitian():
---> 58 raise ValueError("Quadratic form matrices must be symmetric/Hermitian.")
59
60 def sign_from_args(self) -> Tuple[bool, bool]:

ValueError: Quadratic form matrices must be symmetric/Hermitian.

@ts-project ts-project added the question Further information is requested label Jan 25, 2024
@88d52bdba0366127fffca9dfa93895
Copy link
Collaborator

interesting topic, here is my quick reply:

Again, don't believe this approach is right, but just wanted to share what I've tried.

=> yes you are doing right

When I include zeros as the initial balance before a first trade, I get an error that says

=> yes pls drop NaN in the returns

ValueError Traceback (most recent call last)
in
200
201
--> 202 run_strategies(0.5,0.75,9)
203
204

in run_strategies(ratio, ratio_2, min_pnldd)
140 # Optimize for maximal Sharpe ratio
141 ef = EfficientFrontier(mu, S)
--> 142 raw_weights = ef.max_sharpe()
143 cleaned_weights = ef.clean_weights()
144 # ef.save_weights_to_file("weights.csv") # saves to file

=> I guess your covariance matrix S is not valid, could you share how you compute the mu and S

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants