0

I am currently using Python and am getting strange results when using Scipy.optimize - specifically the minimize function. Everything up to def optimize_portfolio(initial,returns,rf) seems to run fine. The first few iterations of minimizing run fine, but after that it appears that the arguments "weights" and "returns" get switched around in def portfolio_stats(returns,weights,rf) and I am not sure why. If anyone can figure out what is going on, that would be much appreciated!

from math import exp 
import numpy as np
import pandas_datareader.data as web
import matplotlib.pyplot as plt
import scipy.optimize as optimization

#Get data from Yahoo
def stock_data(stocks,start_date,end_date):
    start_date= start_date
    end_date= end_date
    data=web.DataReader(stocks,data_source='yahoo',start=start_date,end=end_date)['Adj Close']
    return data

#Calulate daily log returns (as opposed to arithmetic returns)
def stock_returns(data):
    daily_returns=(data/data.shift(1))
    daily_returns=np.log(daily_returns)
    return daily_returns


#Get statistics for stocks (yearly approximate based on log returns)
def stock_stats(returns):
    expected=returns.mean()*252
    variance=returns.var()*252
    covariance=returns.cov()*252
    return [expected,variance,covariance]

#Get statistics for porfolio (yearly approximate based on log returns)
def portfolio_stats(returns,weights,rf):
    expected=np.sum(returns.mean()*weights)*252
    variance =np.dot(weights.T,np.dot(returns.cov()*252,weights))
    sd=np.sqrt(variance)
    sharpe=(expected-rf)/sd
    return [expected,sd,sharpe]

#Run simulation of portfolios
def monte_carlo_porfolios(stocks,returns,simulations,rf):
    mc_expected=[]
    mc_sd=[]
    optimum=[]
    sharpe=0
    for i in range(simulations):
        weights=np.random.random(len(stocks))
        weights /= np.sum(weights)
        stats =portfolio_stats(returns,weights,rf)
        expected =stats[0]
        sd =stats[1]
        mc_expected.append(expected)
        mc_sd.append(sd)
        if (expected-rf)/sd>sharpe:
            optimum=weights
            sharpe=(expected-rf)/sd
    
    mc_expected=np.array(mc_expected)
    mc_sd=np.array(mc_sd)
    
    return [mc_expected,mc_sd,np.array(optimum)]


#Define function to minmise
def min_func_sharpe(weights,*args):
    return -portfolio_stats(weights,args[0],args[1])[2]

#Find best combination via optimization algorithm
def optimize_portfolio(initial,returns,rf):
    constraints = ({'type':'eq','fun':lambda x:np.sum(x)-1})
    bounds = tuple((0,1) for x in range(len(stocks)))
    optimum = optimization.minimize(fun=min_func_sharpe,x0=initial,args=(returns,rf),method='SLSQP',bounds=bounds,constraints=constraints)
    return optimum


stocks = ['AAPL','WMT','TSLA','GE','AMZN','DB']
start_date ='01/01/2010'
end_date ='01/01/2020'
rf=0.02
data = stock_data(stocks,start_date,end_date)
log_returns = stock_returns(data)
monte_carlo = monte_carlo_porfolios(stocks,log_returns,1000,rf)

print(optimize_portfolio(monte_carlo[2],log_returns,rf))
Timus
  • 10,974
  • 5
  • 14
  • 28
Charmalade
  • 645
  • 1
  • 6
  • 14
  • Can you specify a minimal working example – Marc Nov 28 '20 at 19:58
  • I removed a fair few functioned before putting it on here haha. Um, in terms of simplifying it, the function that is causing issues is optimize_portfolio(). Optimize portfolio tries to minimise the function min_func_sharpe. min_func_sharpe is based on the function portfolio_stats. All other functions can be ignored, however they are required for the program to run. – Charmalade Nov 28 '20 at 20:08
  • A more fleshed-out MWE (i.e. something that someone can run) would be helpful. Why are you specifying additional arguments in `min_fun_sharpe` as `*args` instead of specifying them explicitly? I'd be surprised if that was the issue but it does seem to introduce some unnecessary mystery. Replacing that with actual arguments is where I would start. – webelo Nov 28 '20 at 20:17
  • I wil write up a MWE when i have access to an IDE. I originally soecified them explicitly, but I changed it to *args in hope that it might fix my error. – Charmalade Nov 28 '20 at 20:23

1 Answers1

0

you have weights, and the other arguments mixed up in their positional order in the

function call within min_func_sharpe

-portfolio_stats(weights,args[0],args[1])[2]

this does not match the signature in portfolio stats

def portfolio_stats(returns,weights,rf):
MaxYarmolinsky
  • 1,117
  • 1
  • 10
  • 16