Finding the Efficient Frontier in Tensorflow

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

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