Search code examples
pythoncsviteratorfinance

For each item, calculate with 2 other items in an array


For a school project, I am trying to calculate the highest performing portfolio (sharpe ratio) that is made up of three stocks at a given historical date.

I already know how to gather the information and calculate the average returns and variances with python. However, I have no idea how to iterate over the data and compare results for all possible portfolios.

For example:

result 1 = stockA + stock B + stock C
result 2 = stockB + Stock C + Stock D
result 3 = stockC + Stock D + Stock E

etc, etc.

Adding to the complication, the stocks will be weighted. I understand that do do all possible weights for 3 stocks in every combination will require several days to compute, so I was going to do something a little leaner:

# checks to see which stock will perform better with higher weight:

trialstockA = (stockA * .75) + (stockB * .125) + (stockC * .125)
trialstockB = (stockA * .125) + (stockB * .75) + (stockC * .125)
trialstockC = (stockA * .125) + (stockB * .125) + (stockC * .75)
 
# if trialstockA should be weighed higher:

if trialstockA > trialstockB and trialstockC:

trialstockA2 = (stockA * .95) + (stockB * .025) + (stockC * .025)
trialstockA3 = (stockA * .85) + (stockB * .075) + (stockC * .075)
trialstockA4 = (stockA * .80) + (stockB * .10) + (stockC * .10)
trialstockA5 = (stockA * .70) + (stockB * .15) + (stockC * .15)
trialstockA6 = (stockA * .65) + (stockB * .175) + (stockC * .175)
trialstockA7 = (stockA * .60) + (stockB * .20) + (stockC * .20)
trialstockA8 = (stockA * .55) + (stockB * .225) + (stockC * .225)
trialstockA9 = (stockA * .50) + (stockB * .25) + (stockC * .25)

This part is less important however. I'm just not sure how to iterate through each possible portfolio. I can either export the data to a CSV file in which it will be displayed as [NAME (string) ,MEAN RETURN (INT) ,VARIANCE (INT), RISK (INT)] such as [AAPL, .427, .1957, .442], or I can leave them as variables in a scrapy project. I have a feeling that the CSV method may be easier though.

I was also wondering if splitting the stocks into three groups would help?

Hopefully this makes sense. Not sure what else to mention...

Thanks for your help in advance!

Update

For every combination of stocks and every combination of weights, the goal is the following calculation given that the combination of stocks are named stockA, stockB, and StockC. In order to save time, I'm going to export the each stocks data to a csv, in which the stocks mean, variance, standard deviation(risk), and list of returns(about 100 numbers) are stored in different columns for each row of stocks.

First the correlations would need to be found between each combination of two stocks:

stockAB_corr = numpy.corrcoef(stockA_returns, stockB_returns)[0, 1]
stockAC_corr = numpy.corrcoef(stockA_returns, stockC_returns)[0, 1]
stockBC_corr = numpy.corrcoef(stockB_returns, stockC_returns)[0, 1]

Then, we can run the following function:

portfolio_return =  (stockA[avgret] * stockA[weight]) + (stockB)
portfolio_variance = ((stockA[weight]^2) * stockA[variance]) + ((stockB[weight]^2) * stockB[variance]) + ((stockC[weight]^2) * stockC[variance]) + (2*stockA[weight]*stockB[weight]*stockAB_corr*stockA[risk]*stockB[risk]) + (2*stockA[weight]*stockC[weight]*stockAC_corr*stockA[risk]*stockC[risk]) + (2*stockB[weight]*stockC[weight]*stockBC_corr*stockB[risk]*stockC[risk]) 
portfolio_risk = portfolio_variance ** 0.5

Sharpe = (porfolio_return - 0.03)/portfolio_variance

The Sharpe ratio is the end result. For every stock, their respective variance, and average are already calculated.


Solution

  • As per @Aaron's comment, you can use the itertools module, specifically combinations and permutations.

    You would create a collection of stocks from a list of all possible stocks using combinations, a unique ordering of weights using permutations and set, combine them using zip, and yield them from a generator function.

    import itertools
    
    stocks = ['stock{}'.format(x) for x in xrange(10)]
    weights_list = [(0.95, 0.025, 0.025),
                   (0.90, 0.05, 0.05),
                   (0.85, 0.075, 0.075),
                   (0.80, 0.1, 0.1),
                   (0.75, 0.125, 0.125),
                   (0.70, 0.15, 0.15),
                   (0.65, 0.175, 0.175),
                   (0.60, 0.20, 0.20),
                   (0.55, 0.225, 0.225),
                   (0.50, 0.25, 0.25)]
    
    
    def portfolios(stocks, weights_list):
        for stock_triplet in itertools.combinations(stocks, 3):
            for weights in weights_list:
                unique_weight_orders = set(itertools.permutations(weights))
                for weight_order in unique_weight_orders:
                    yield zip(stock_triplet, weight_order)
    
    
    for port in portfolios(stocks, weights_list):
        print port
    

    Output would look like this:

    >>> ...
    [('stock0', 0.95), ('stock1', 0.025), ('stock2', 0.025)]
    [('stock0', 0.025), ('stock1', 0.025), ('stock2', 0.95)]
    [('stock0', 0.025), ('stock1', 0.95), ('stock2', 0.025)]
    [('stock0', 0.075), ('stock1', 0.075), ('stock2', 0.85)]
    [('stock0', 0.075), ('stock1', 0.85), ('stock2', 0.075)]
    [('stock0', 0.85), ('stock1', 0.075), ('stock2', 0.075)]
    [('stock0', 0.1), ('stock1', 0.1), ('stock2', 0.8)]
    ...