Closed amos-peter closed 3 years ago
Hi @amos-peter, does this snippet help?
import cvxpy
import matplotlib.pyplot as plt
import numpy as np
from tests.utilities_for_tests import setup_efficient_frontier
turnovers = []
sigmas = []
turnover_constraints = np.arange(0, 2.01, 0.1)
weight_matrix = []
for turnover_constraint in turnover_constraints:
ef = setup_efficient_frontier()
equal_weights = np.ones(ef.n_assets) / ef.n_assets
ef.add_constraint(lambda w: cvxpy.sum(cvxpy.abs(w - equal_weights)) <= turnover_constraint)
ef.min_volatility()
weights = np.array(list(ef.clean_weights().values()))
turnover = np.sum(np.abs(weights - equal_weights))
_, sigma, _ = ef.portfolio_performance()
turnovers.append(turnover)
sigmas.append(sigma)
weight_matrix.append(weights)
plt.plot(sigmas, turnovers)
plt.xlabel("Sigma")
plt.ylabel("Turnover")
plt.show()
plt.plot(turnover_constraints, turnovers)
plt.xlabel("Turnover Budget")
plt.ylabel("Turnover")
plt.show()
plt.stackplot(turnovers, np.vstack(weight_matrix).T)
plt.xlabel("Turnover")
plt.ylabel("Weight")
plt.show()
Hi @phschiele. Thank you for your help! I will try to implement the code. I am still quite poor in convex optimization code. Do you have any example for convex optimization with different constraints such maximize a set of the score, min-max sector allocation and etc.
Hi All
I manage to set the turnover constraints via cvxpy. I think I got an idea to set the sum of within weight size to be reference as sector and set it min, max.
from pypfopt import EfficientFrontier
from pypfopt import risk_models
from pypfopt import plotting
from pypfopt import expected_returns
from pypfopt.discrete_allocation import DiscreteAllocation, get_latest_prices
import cvxpy
#get previous port weight for 2001-01-30
current_w = latest_w.values
current_w = current_w.reshape(20,)
current_w
data = df[(df.index >= '2001-01-31') & (df.index <= '2001-02-28')]
mu = expected_returns.capm_return(data)
S = risk_models.CovarianceShrinkage(data).ledoit_wolf()
ef = EfficientFrontier(mu, S,(0,1)) # weight_bounds automatically set to (0, 1)
ef.add_constraint(lambda w: cvxpy.sum(cvxpy.abs(w - current_w)) <= 0.50)
ef.add_constraint(lambda w: cvxpy.sum((w[0:5])) <= 0.50) #to be explored (sector allocation)
ef.add_constraint(lambda w: cvxpy.sum((w[0:5])) >= 0.40) #to be explored (sector allocation)
ef.min_volatility()
weights = ef.clean_weights()
turnover = np.sum(np.abs(weights - latest_w))
latest_prices = get_latest_prices(data[0:1])
latest_prices = latest_prices.fillna(0)
da = DiscreteAllocation(weights, latest_prices, total_portfolio_value=final_value)
allocation, leftover = da.lp_portfolio()
w = dict.fromkeys(weights, 0)
w.update(allocation)
print(w)
initial_value = final_value
temp = data*w
cash = initial_value - temp.iloc[0].sum()
print(cash)
final_value = cash + temp.iloc[-2].sum()
print(final_value)
temp['Cash'] = cash
port = port.append(temp[:-1])
port
@amos-peter The sector constraints look good. There is an even simple way to implement those, though:
sector_mapper = {
"GOOG": "tech",
"FB": "tech",,
"XOM": "Oil/Gas",
"RRC": "Oil/Gas",
"MA": "Financials",
"JPM": "Financials",
}
sector_lower = {"tech": 0.1} # at least 10% to tech
sector_upper = {
"tech": 0.4, # less than 40% tech
"Oil/Gas": 0.1 # less than 10% oil and gas
}
ef.add_sector_constraints(sector_mapper, sector_lower, sector_upper)
Yes, I agree. I have done some workaround to combine the sector allocation with turnover constraint. loop through monthly data to get optimal weight. My next step would be to try to go deeper in convex optimization within pyportfolioopt to maximize the set of composite scores for my universe. Thank you!
if first_round == 1:
prev_port = port[port.index<=prev_m].iloc[[-2]]
current_value = prev_port.iloc[0].sum() - prev_port.Cash.iloc[0]
latest_w = prev_port.drop('Cash',
axis='columns')
latest_w = latest_w[-1:]/current_value
latest_w = latest_w.fillna(0)
current_w = latest_w.values
current_w = current_w.reshape(20,)
#print(current_w)
if current_w.sum() > 0:
ef.add_constraint(lambda w: cvxpy.sum(cvxpy.abs(w - current_w)) <= 0.60)
ef.add_sector_constraints(group_mapper, group_lower, group_upper)
ef.add_sector_constraints(group_mapper2, group_lower2, group_upper2)
ef.min_volatility()
weights = ef.clean_weights()
weights
cash_adj = initial_value - (initial_value * 0.025)
latest_prices = get_latest_prices(data[0:1])
latest_prices = latest_prices.fillna(0)
da = DiscreteAllocation(weights, latest_prices, total_portfolio_value=cash_adj)
allocation, leftover = da.lp_portfolio()
w = dict.fromkeys(weights, 0)
w.update(allocation)
#print(w)
I'm glad you've got it working!
@phschiele Nice work with the transition map (stackplot) – will include that in plotting
at some point!
Hi Robert, may I know if there are any example of portfolio turnover constraints within this module?