0
$\begingroup$

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()
       sess.run(init_op)

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

       sess.run(constraints_op)

       #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

$\endgroup$

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.