I have two assets A and B. Asset A has an expected return of 0.92% with a standard deviation of 2.10. Asset B has an expected return of 1.39% and a standard deviation of 2.20. I want to find the set of efficient portfolios from these two assets by solving the equation:

Min(x) Variance(x) - q * Expected Return(x)

where x is the vector of asset weights and q is a risk aversion parameter. By adjusting q and solving that equation, I should get the set of efficient portfolios (https://en.wikipedia.org/wiki/Modern_portfolio_theory)

I have set up a simple experiment in Tensorflow. When q=0, the optimizer indeed puts 100% of the portfolio in asset A as it has the lowest variance. However, when I move q out to large numbers, the optimizer fails to put 100% of the portfolio in asset B even though Asset B clearly has the highest Expected Return. It always gives me a mixture of asset A and B, no matter my learning rate and gradient steps, which leads me to believe that I am performing the optimization incorrectly. Please see my code below:

def get_portfolio_volatility(port_weights,Sigma):

   product_1 = tf.transpose(port_weights)
   product_2 = tf.matmul(product_1,Sigma)
   portfolio_variance = tf.matmul(product_2,port_weights)

return portfolio_variance

def get_portfolio_return(u,port_weights):

   portfolio_return = tf.matmul(u,port_weights)

return portfolio_return

def ensure_constraints_op(port_weights):

   #all values positive, with sum = 1
   weights_sum = tf.reduce_sum(port_weights)
   wgts = port_weights.assign(tf.divide(tf.abs(port_weights), tf.abs(weights_sum) ))

return wgts

def generate_efficient_frontier(Sigma, u, risk_tol, learning_rate = 0.0005, steps = 3000):
   port_weights = tf.Variable(tf.random_normal((len(u.columns), 1), dtype=tf.float64,seed=42)) #weights

   risk_tol = tf.constant(risk_tol,dtype='float64')
   portfolio_volatility = get_portfolio_volatility(port_weights,Sigma)
   portfolio_return = get_portfolio_return(u,port_weights)

   obj = portfolio_volatility - tf.multiply(risk_tol,portfolio_return)

   constraints_op = ensure_constraints_op(port_weights)

   # Training using Gradient Descent to minimize cost
   optimize_op = tf.train.GradientDescentOptimizer(learning_rate, use_locking=True).minimize(obj)

   init_op = tf.global_variables_initializer()

   with tf.Session() as sess:
       vol = np.zeros(steps)
       returns = np.zeros(steps)
       w = pd.DataFrame()

      for i in range(steps):
           vol[i] = math.sqrt(sess.run(portfolio_volatility))
           returns[i] = sess.run(portfolio_return) 
           w = w.append(pd.DataFrame(sess.run(port_weights).transpose()))


       #return optimal portfolio
       return sess.run(port_weights), sess.run(portfolio_return), sess.run(portfolio_volatility)

In the last function,

optimize_op = tf.train.GradientDescentOptimizer(learning_rate, use_locking=True).minimize(obj)

is the optimizer I am using. I then find the minimum in the following for loop. Am I setting the optimizer up in the right way? Why cant I get 100% of the portfolio in asset B when q=1000?

EDIT: ensure_constraints_op is a constraint which forces the asset allocation to sum to 1 and for all asset weights to be positive


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.