"""
Jay Chen's Python for Finance
Ch18 Exercise 2c
Create the Efficient Frontier with 4 assets
Brute force search with matrix algebra
This includes the creation of the variance-covariance matrix
"""
import random
import matplotlib.pyplot as plt
import numpy as np


def xlist(n):
    x = []
    for i in range(n):
        x.append(random.random())
    return [i/sum(x) for i in x] #Use a for loop to generate a list

"""
Parameters must be stacked in the exactly same way as following for the 
def covmat() function to work. Pay special attention to the correlation
coefficient. It is nested list.
"""
sigma =[.042,.089,.071,.06]
rho = [[-.09,.332,.4],[-.141,.104],[.219]]
r = [.003, .036,.013,.015]

def covmat(sigma, rho):
    n = len(sigma)
    sigma = np.matrix(sigma)
    sigmatrix = np.dot(np.transpose(sigma),sigma)
    temp = np.ones([n,n])
    for i in range(n):
        j=i+1
        while j < n:
            temp[i,j] = rho[i][j-i-1]
            j += 1
    rhomatrix = np.multiply(temp,np.transpose(temp))
    varcov = np.multiply(rhomatrix,sigmatrix)
    return varcov
    
def port(x,r,sigma,rho):
    port_ret = np.dot(x,np.transpose(r))
    x = np.matrix(x)
    xSig = np.dot(x,covmat(sigma,rho))
    temp = np.dot(xSig,np.transpose(x))
    port_sig = np.asscalar(temp)**.5
    return [port_ret,port_sig]

x = []
y = []
portlist = []


"""
You have changed the function port(). Make sure you also change the way
you call the function.

"""
for i in range(100000):
    allocation = xlist(len(sigma))
    portlist.append(allocation)
    portfolio = port(allocation,r,sigma,rho)
    x.append(portfolio[1])
    y.append(portfolio[0])

plt.plot(x,y,"b.")
plt.xlabel("Sigma")
plt.ylabel("Return")

import pandas as pd
data = pd.DataFrame({"Return" : y, "Sigma" :x, "Portfolio": portlist})
data = data.sort_values(by="Return")

data = data.reset_index()
del data["index"]

xx = [ ]
yy = [ ]
ef = [ ]
for i in range(100):
    subset = data.ix[i*1000:i*1000+999,:]
    subset = subset.reset_index()
    del subset["index"]
    for j in range(len(subset)):
        if subset.ix[j,2] == min(subset["Sigma"]):
            xx.append(subset.ix[j,2])
            yy.append(subset.ix[j,1])
            ef.append(subset.ix[j,0])

plt.figure()            
plt.plot(xx, yy, "k.")
plt.xlabel("Sigma")
plt.ylabel("Return")




