diff --git a/README.md b/README.md index 8a02ac6..08f2fb2 100644 --- a/README.md +++ b/README.md @@ -36,5 +36,7 @@ unzip -n zips/19fall_optimize_something.zip -d ./ # Reports - [Report 1](./martingale/martingale.md) -- [Report 2](#) +- [Report 2](./optimize_something/readme.md) +- [Report 3](#) + diff --git a/optimize_something/optimization.py b/optimize_something/optimization.py index 461df53..309fab6 100644 --- a/optimize_something/optimization.py +++ b/optimize_something/optimization.py @@ -30,8 +30,42 @@ import pandas as pd import matplotlib.pyplot as plt import numpy as np import datetime as dt +import math +import scipy.optimize as opt from util import get_data, plot_data + +def get_sharpe_ratio(daily_returns): + SR = daily_returns.mean() / daily_returns.std() + k = math.sqrt(252) # daily sampling + SR = k * SR + return SR + + +def get_daily_returns(df): + daily_returns = df.copy() + daily_returns[1:] = (df[1:] / df[:-1].values) - 1 + daily_returns = daily_returns.iloc[1:] + return daily_returns + + +def get_daily_portfolio_value(prices, allocs): + normed = prices / prices.iloc[0, :] + alloced = normed * allocs + port_values = alloced.sum(axis=1) + return port_values + + +def calculate_stats(prices, allocs): + port_value = get_daily_portfolio_value(prices, allocs) + cum_ret = (port_value.iloc[-1] / port_value.iloc[0]) - 1 + daily_returns = get_daily_returns(port_value) + avg_daily_ret = daily_returns.mean() + std_daily_ret = daily_returns.std() + sharpe_ratio = get_sharpe_ratio(daily_returns) + return [cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio] + + # This is the function that will be tested by the autograder # The student must update this code to properly implement the functionality def optimize_portfolio(sd=dt.datetime(2008,1,1), ed=dt.datetime(2009,1,1), \ @@ -43,41 +77,52 @@ def optimize_portfolio(sd=dt.datetime(2008,1,1), ed=dt.datetime(2009,1,1), \ prices = prices_all[syms] # only portfolio symbols prices_SPY = prices_all['SPY'] # only SPY, for comparison later - plot_data(prices_all) + def calc_sr(allocs): + port_value = get_daily_portfolio_value(prices, allocs) + cum_ret = (port_value.iloc[-1] / port_value.iloc[0]) - 1 + daily_returns = get_daily_returns(port_value) + sharpe_ratio = get_sharpe_ratio(daily_returns) + return sharpe_ratio * -1 # find the allocations for the optimal portfolio - # note that the values here ARE NOT meant to be correct for a test case - allocs = np.asarray([0.2, 0.2, 0.3, 0.3]) # add code here to find the allocations - cr, adr, sddr, sr = [0.25, 0.001, 0.0005, 2.1] # add code here to compute stats - - # Get daily portfolio value - port_val = prices_SPY # add code here to compute daily portfolio values + len_syms = len(syms) + allocs = np.asarray([1 / len_syms for _ in range(len_syms)]) + bounds = [(0, 1) for _ in range(len_syms)] + consts = ({'type': 'eq', 'fun': lambda inputs: 1.0 - np.sum(inputs)}) + result = opt.minimize(calc_sr, x0=allocs, bounds=bounds, constraints=consts) + print(result) + allocs = result.x + cr, adr, sddr, sr = calculate_stats(prices, allocs) # Compare daily portfolio value with SPY using a normalized plot if gen_plot: - # add code to plot here - df_temp = pd.concat([port_val, prices_SPY], keys=['Portfolio', 'SPY'], axis=1) - pass + port_val = get_daily_portfolio_value(prices, allocs) + prices_SPY_normed = prices_SPY / prices_SPY.iloc[0] + df_temp = pd.concat([port_val, prices_SPY_normed], keys=['Portfolio', 'SPY'], axis=1) + ax = df_temp.plot(title="SPY and Portfolio Normed", fontsize=12) + plt.savefig('plot.png') + plt.show() return allocs, cr, adr, sddr, sr -def test_code(): - # This function WILL NOT be called by the auto grader - # Do not assume that any variables defined here are available to your function/code - # It is only here to help you set up and test your code +def report(): + start_date = dt.datetime(2008,6,1) + end_date = dt.datetime(2009,6,1) + symbols = ['IBM', 'X', 'GLD', 'JPM'] + allocations, cr, adr, sddr, sr = optimize_portfolio(sd = start_date, ed = end_date,\ + syms = symbols, gen_plot = True) + + +def test_code(): # Define input parameters # Note that ALL of these values will be set to different values by # the autograder! - start_date = dt.datetime(2009,1,1) end_date = dt.datetime(2010,1,1) symbols = ['GOOG', 'AAPL', 'GLD', 'XOM', 'IBM'] - - # Assess the portfolio allocations, cr, adr, sddr, sr = optimize_portfolio(sd = start_date, ed = end_date,\ - syms = symbols, \ - gen_plot = False) + syms = symbols, gen_plot = True) # Print statistics print(f"Start Date: {start_date}") @@ -90,6 +135,5 @@ def test_code(): print(f"Cumulative Return: {cr}") if __name__ == "__main__": - # This code WILL NOT be called by the auto grader - # Do not assume that it will be called - test_code() + # test_code() + report() diff --git a/optimize_something/plot.png b/optimize_something/plot.png new file mode 100644 index 0000000..b9c9e1e Binary files /dev/null and b/optimize_something/plot.png differ diff --git a/optimize_something/readme.md b/optimize_something/readme.md new file mode 100644 index 0000000..d622c6e --- /dev/null +++ b/optimize_something/readme.md @@ -0,0 +1,7 @@ +# Report + +IBM, X, GLD, JPM portfolio optimization for the timeframe from 08-06-01 till +09-06-01. + +![](plot.png) +