def market_simulator(df_orders, df_orders_benchmark, start_val=1000000, commission=9.95, impact=0.005, daily_rf=0.0, samples_per_year=252.0, save_fig=False, fig_name="plot.png"): """ This function takes in and executes trades from orders dataframes Parameters: df_orders: A dataframe that contains portfolio orders df_orders_benchmark: A dataframe that contains benchmark orders start_val: The starting cash in dollars commission: The fixed amount in dollars charged for each transaction (both entry and exit) impact: The amount the price moves against the trader compared to the historical data at each transaction daily_rf: Daily risk-free rate, assuming it does not change samples_per_year: Sampling frequency per year save_fig: Whether to save the plot or not fig_name: The name of the saved figure Returns: Print out final portfolio value of the portfolio, as well as Sharpe ratio, cumulative return, average daily return and standard deviation of the portfolio and Benchmark. Plot a chart of the portfolio and benchmark performances """ # Process portfolio orders portvals = compute_portvals(df_orders=df_orders, start_val=start_val, commission=commission, impact=impact) # Get portfolio stats cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats(portvals, daily_rf=daily_rf, samples_per_year=samples_per_year) # Process benchmark orders portvals_bm = compute_portvals(df_orders=df_orders_benchmark, start_val=start_val, commission=commission, impact=impact) # Get benchmark stats cum_ret_bm, avg_daily_ret_bm, std_daily_ret_bm, sharpe_ratio_bm = get_portfolio_stats(portvals_bm, daily_rf=daily_rf, samples_per_year=samples_per_year) # Compare portfolio against Benchmark print ("Sharpe Ratio of Portfolio: {}".format(sharpe_ratio)) print ("Sharpe Ratio of Benchmark : {}".format(sharpe_ratio_bm)) print () print ("Cumulative Return of Portfolio: {}".format(cum_ret)) print ("Cumulative Return of Benchmark : {}".format(cum_ret_bm)) print () print ("Standard Deviation of Portfolio: {}".format(std_daily_ret)) print ("Standard Deviation of Benchmark : {}".format(std_daily_ret_bm)) print () print ("Average Daily Return of Portfolio: {}".format(avg_daily_ret)) print ("Average Daily Return of Benchmark : {}".format(avg_daily_ret_bm)) print () print ("Final Portfolio Value: {}".format(portvals.iloc[-1, -1])) print ("Final Benchmark Value: {}".format(portvals_bm.iloc[-1, -1])) # Rename columns and normalize data to the first date of the date range portvals.rename(columns={"port_val": "Portfolio"}, inplace=True) portvals_bm.rename(columns={"port_val": "Benchmark"}, inplace=True) plot_norm_data_vertical_lines(df_orders, portvals, portvals_bm, save_fig=False, fig_name="plot.png")
def simulateOrders(start_date, end_date, orders_file, start_val, title="Portfolio Value"): # Process orders portvals = compute_portvals(start_date, end_date, orders_file, start_val) if isinstance(portvals, pd.DataFrame): portvals = portvals[portvals.columns[0]] # if a DataFrame is returned select the first column to get a Series # Get portfolio stats cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats(portvals) # Simulate a $SPX-only reference portfolio to get stats prices_SPX = get_data(['$SPX'], pd.date_range(start_date, end_date)) prices_SPX = prices_SPX[['$SPX']] # remove SPY portvals_SPX = get_portfolio_value(prices_SPX, [1.0]) cum_ret_SPX, avg_daily_ret_SPX, std_daily_ret_SPX, sharpe_ratio_SPX = get_portfolio_stats(portvals_SPX) # Compare portfolio against $SPX print "Data Range: {} to {}".format(start_date, end_date) print print "Sharpe Ratio of Fund: {}".format(sharpe_ratio) print "Sharpe Ratio of $SPX: {}".format(sharpe_ratio_SPX) print print "Cumulative Return of Fund: {}".format(cum_ret) print "Cumulative Return of $SPX: {}".format(cum_ret_SPX) print print "Standard Deviation of Fund: {}".format(std_daily_ret) print "Standard Deviation of $SPX: {}".format(std_daily_ret_SPX) print print "Average Daily Return of Fund: {}".format(avg_daily_ret) print "Average Daily Return of $SPX: {}".format(avg_daily_ret_SPX) print print "Final Portfolio Value: {}".format(portvals[-1]) # Plot computed daily portfolio value df_temp = pd.concat([portvals, prices_SPX['$SPX']], keys=['Portfolio', 'SPY'], axis=1) plot_normalized_data(df_temp, title)
def test_run(): """Driver function.""" # Define input parameters # Test 1 # start_date = '2011-01-05' # end_date = '2011-01-20' # orders_file = os.path.join(".\orders", "orders-short.csv") # start_val = 1000000 # Test 2 # start_date = '2011-01-10' # end_date = '2011-12-20' # orders_file = os.path.join(".\orders", "orders.csv") # start_val = 1000000 # Test 3 start_date = '2011-01-14' end_date = '2011-12-14' orders_file = os.path.join(".\orders", "orders2.csv") start_val = 1000000 # Process orders portvals = compute_portvals(start_date, end_date, orders_file, start_val) if isinstance(portvals, pd.DataFrame): portvals = portvals[portvals.columns[0]] # if a DataFrame is returned select the first column to get a Series # Get portfolio stats cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats(portvals) # Simulate a $SPX-only reference portfolio to get stats prices_SPX = get_data(['$SPX'], pd.date_range(start_date, end_date)) prices_SPX = prices_SPX[['$SPX']] # remove SPY portvals_SPX = get_portfolio_value(prices_SPX, [1.0]) cum_ret_SPX, avg_daily_ret_SPX, std_daily_ret_SPX, sharpe_ratio_SPX = get_portfolio_stats(portvals_SPX) # Compare portfolio against $SPX print "Data Range: {} to {}".format(start_date, end_date) print print "Sharpe Ratio of Fund: {}".format(sharpe_ratio) print "Sharpe Ratio of $SPX: {}".format(sharpe_ratio_SPX) print print "Cumulative Return of Fund: {}".format(cum_ret) print "Cumulative Return of $SPX: {}".format(cum_ret_SPX) print print "Standard Deviation of Fund: {}".format(std_daily_ret) print "Standard Deviation of $SPX: {}".format(std_daily_ret_SPX) print print "Average Daily Return of Fund: {}".format(avg_daily_ret) print "Average Daily Return of $SPX: {}".format(avg_daily_ret_SPX) print print "Final Portfolio Value: {}".format(portvals[-1]) # Plot computed daily portfolio value df_temp = pd.concat([portvals, prices_SPX['$SPX']], keys=['Portfolio', '$SPX'], axis=1) plot_normalized_data(df_temp, title="Daily portfolio value and $SPX")
def testcode_marketsim(symbol = 'ML_based', base_dir = './orders/', \ sv = 100000, leverLimit = True, verbose = True): ### Use one of the order folders below ### # of = "./orders/benchmark.csv" # of = "./orders/bestPossibleStrategy.csv" # of = "./orders/rule_based.csv" # of = "./orders/ML_based.csv" of = symbol_to_path(symbol, base_dir) # sv = 100000 # starting value of portfolio, i.e. initial cash available # Process orders portVals = compute_portvals(of, sv, leverLimit) if isinstance(portVals, pd.DataFrame): portVals = portVals[ portVals.columns[0]] # just get the first column as a Series else: "warning, code did not return a DataFrame" start_date = portVals.index[0] end_date = portVals.index[-1] pricesSPX = get_data(['$SPX'], pd.date_range(start_date, end_date)) pricesSPX = pricesSPX['$SPX'] cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats(portVals, \ daily_rf = 0, samples_per_year = 252) cum_ret_SPY, avg_daily_ret_SPY, std_daily_ret_SPY, sharpe_ratio_SPY = \ get_portfolio_stats(pricesSPX, daily_rf = 0, samples_per_year = 252) # Compare portfolio against $SPX if verbose == True: dfTemp = pd.concat([portVals, pricesSPX], axis=1, keys=['portfolio', '$SPX']) plot_normalized_data(dfTemp, '', '', '') print "\nDate Range: {} to {}".format(start_date.date(), end_date.date()) print print "Sharpe Ratio of Fund: {}".format(sharpe_ratio) print "Sharpe Ratio of SPY : {}".format(sharpe_ratio_SPY) print print "Cumulative Return of Fund: {}".format(cum_ret) print "Cumulative Return of SPY : {}".format(cum_ret_SPY) print print "Standard Deviation of Fund: {}".format(std_daily_ret) print "Standard Deviation of SPY : {}".format(std_daily_ret_SPY) print print "Average Daily Return of Fund: {}".format(avg_daily_ret) print "Average Daily Return of SPY : {}".format(avg_daily_ret_SPY) print print "Final Portfolio Value: {}".format(portVals[-1]) return cum_ret, portVals
def error_alloc_vol(allocs, portfolio, start_val=1): """Function that takes allocations and portfolio and returns the portfolio's sharpe ratio*(-1). Used with find_optimsed_alloc.""" port_final = get_portfolio_value(portfolio, allocs, start_val) cum_ret, ave_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats( port_final) return cum_ret
def optimize_portfolio(start_date, end_date, symbols): """Simulate and optimize portfolio allocations.""" # Read in adjusted closing prices for given symbols, date range dates = pd.date_range(start_date, end_date) prices_all = get_data(symbols, dates) # automatically adds SPY prices = prices_all[symbols] # only portfolio symbols prices_SPY = prices_all['SPY'] # only SPY, for comparison later # Get optimal allocations allocs = find_optimal_allocations(prices) allocs = allocs / np.sum(allocs) # normalize allocations, if they don't sum to 1.0 # Get daily portfolio value (already normalized since we use default start_val=1.0) port_val = get_portfolio_value(prices, allocs) # Get portfolio statistics (note: std_daily_ret = volatility) cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats(port_val) # Print statistics print "Start Date:", start_date print "End Date:", end_date print "Symbols:", symbols print "Optimal allocations:", allocs print "Sharpe Ratio:", sharpe_ratio print "Volatility (stdev of daily returns):", std_daily_ret print "Average Daily Return:", avg_daily_ret print "Cumulative Return:", cum_ret # Compare daily portfolio value with normalized SPY normed_SPY = prices_SPY / prices_SPY.ix[0, :] df_temp = pd.concat([port_val, normed_SPY], keys=['Portfolio', 'SPY'], axis=1) plot_data(df_temp, title="Daily Portfolio Value and SPY")
def sharpe_func(allocs, prices): "compute sharpe ratio given allocs and price data" port_val = get_portfolio_value(prices, allocs, 1) port_stats = get_portfolio_stats(port_val) sharpe_ratio = port_stats[3] return (-1 * sharpe_ratio)
def f(X): Y = get_portfolio_stats(get_portfolio_value( prices, [X[0], X[1], X[2], X[3]], start_val=1), daily_rf=0, samples_per_year=252)[3] * -1 return Y
def find_sharpe_ratio(allocs, prices): start_val = 1 port_val = get_portfolio_value(prices, allocs, start_val) daily_rf = 0 samples_per_year = 252 cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats(port_val, daily_rf, samples_per_year) return -sharpe_ratio
def get_negative_sharp_ratio(prices, allocs): # Get daily portfolio value port_val = get_portfolio_value(prices=prices, allocs=allocs) #plot_data(port_val, title="Daily Portfolio Value") # Get portfolio statistics (note: std_daily_ret = volatility) _, _, _, sharpe_ratio = get_portfolio_stats(port_val) return sharpe_ratio * -1
def statistics(weights): global gprices weights = np.array(weights) port_val = get_portfolio_value(gprices, weights) gret = port_val.sum() cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats(port_val) return np.array([gret, std_daily_ret, sharpe_ratio])
def test_code(): ### Use one of the order folders below ### ### of = "./orders/orders-leverage-3.csv" # verify from wiki of = "./orders_mc2p1_spr2016/orders-12-modified.csv" #verify from saved pdf sv = 1000000 # starting value of portfolio, i.e. initial cash available # Process orders portVals = compute_portvals(orders_file=of, start_val=sv) if isinstance(portVals, pd.DataFrame): portVals = portVals[ portVals.columns[0]] # just get the first column as a Series else: "warning, code did not return a DataFrame" start_date = portVals.index[0] end_date = portVals.index[-1] pricesSPX = get_data(['$SPX'], pd.date_range(start_date, end_date)) pricesSPX = pricesSPX['$SPX'] dfTemp = pd.concat([portVals, pricesSPX], axis=1, keys=['portfolio', '$SPX']) plot_normalized_data(dfTemp, '', '', '') cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats(portVals, \ daily_rf = 0, samples_per_year = 252) cum_ret_SPY, avg_daily_ret_SPY, std_daily_ret_SPY, sharpe_ratio_SPY = \ get_portfolio_stats(pricesSPX, daily_rf = 0, samples_per_year = 252) # Compare portfolio against $SPX print "\nDate Range: {} to {}".format(start_date.date(), end_date.date()) print print "Sharpe Ratio of Fund: {}".format(sharpe_ratio) print "Sharpe Ratio of SPY : {}".format(sharpe_ratio_SPY) print print "Cumulative Return of Fund: {}".format(cum_ret) print "Cumulative Return of SPY : {}".format(cum_ret_SPY) print print "Standard Deviation of Fund: {}".format(std_daily_ret) print "Standard Deviation of SPY : {}".format(std_daily_ret_SPY) print print "Average Daily Return of Fund: {}".format(avg_daily_ret) print "Average Daily Return of SPY : {}".format(avg_daily_ret_SPY) print print "Final Portfolio Value: {}".format(portVals[-1])
def negSharpeRatio(allocs, prices): # Get daily portfolio value (already normalized since we use default start_val=1.0) port_val = get_portfolio_value(prices, allocs) # Get portfolio statistics (note: std_daily_ret = volatility) cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats( port_val) return (sharpe_ratio * -1)
def test_run(start_date, end_date, orders, start_val,plot=True): # Process orders portvals = compute_portvals(start_date, end_date, orders, start_val) if isinstance(portvals, pd.DataFrame): portvals = portvals[portvals.columns[0]] # if a DataFrame is returned select the first column to get a Series # Get portfolio stats cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats(portvals) # Simulate a SPY-only reference portfolio to get stats prices_SPX = get_data(['SPY'], pd.date_range(start_date, end_date)) prices_SPX = prices_SPX[['SPY']] # remove SPY portvals_SPX = get_portfolio_value(prices_SPX, [1.0]) cum_ret_SPX, avg_daily_ret_SPX, std_daily_ret_SPX, sharpe_ratio_SPX = get_portfolio_stats(portvals_SPX) # Compare portfolio against $SPX print "Data Range: {} to {}".format(start_date, end_date) print print "Sharpe Ratio of Fund: {}".format(sharpe_ratio) print "Sharpe Ratio of $SPX: {}".format(sharpe_ratio_SPX) print print "Cumulative Return of Fund: {}".format(cum_ret) print "Cumulative Return of $SPX: {}".format(cum_ret_SPX) print print "Standard Deviation of Fund: {}".format(std_daily_ret) print "Standard Deviation of $SPX: {}".format(std_daily_ret_SPX) print print "Average Daily Return of Fund: {}".format(avg_daily_ret) print "Average Daily Return of $SPX: {}".format(avg_daily_ret_SPX) print print "Final Portfolio Value: {}".format(portvals[-1]) print "Final SPY Value: {}".format(portvals_SPX[-1]*start_val) # Plot computed daily portfolio value if plot == True: df_temp = pd.concat([portvals, prices_SPX['SPY']], keys=['Portfolio', 'SPY'], axis=1) plot_normalized_data(df_temp, title="Daily portfolio value", ylabel="Normalized Price")
def optimise_portfolio(sd, ed, syms, rfr=0.0, sf=252, gen_plot=True): """Find the optimal allocation for a given set of stocks, optimised for volatility (standard deviation of daily return). Parameters: ----------- sd: A datetime object that represents the start date ed: A datetime object that represents the end date syms: A list of symbols that make up the portfolio rfr: float - risk free rate, default to 0.0 per day. sf: int - sampling frequency per year, default to 252 days gen_plot: If True, create a plot named plot.png Returns: ------- allocs: A 1-d Numpy ndarray of allocations to the stocks. All the allocations must be between 0.0 and 1.0 and they must sum to 1.0. cr: Cumulative return adr: Average daily return sddr: Standard deviation of daily return sr: Sharpe ratio """ #---------Build the portfolio--------------------------------- joint_df = get_port_SPY(sd, ed, syms) #syms + SPY df port = joint_df[0] #portfolio df w/o SPY SPY = joint_df[1] #SPY df - used to add to plot later normed_SPY = normalise_data(SPY) #Normalise SPY #Find the optimal allocations optimised_alloc = find_optimised_alloc(port, error_alloc_vol) #portfolio based on optimised allocations optimised_port = get_portfolio_value(port, optimised_alloc) #Get optimised portfolio's performance statistics cum_ret, ave_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats( optimised_port) #----------Plot the normalised portfolio and SPY prices-------- if gen_plot == True: df_temp = pd.concat([optimised_port, normed_SPY], keys=['Portfolio', 'SPY'], axis=1) plot_data(df_temp, title='Daily portfolio value and SPY', fontsize=2, xlabel='Date', ylabel='Normalised price') return optimised_alloc, cum_ret, ave_daily_ret, std_daily_ret, sharpe_ratio
def sharpe_maximizer(allocs, prices): """Optimization function to be passed to the optimizer. Parameters ---------- prices: daily prices for each stock in portfolio allocs: Allocation for each portfolio component Returns ------- sharpe_ratio: Negative sharpe ratio so the minimizer finds the maximum """ #Get portfolio value port_val = get_portfolio_value(prices, allocs) #Get portfolio statistics cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats(port_val) return -sharpe_ratio
def sharpe_maximizer(allocs, prices): """Optimization function to be passed to the optimizer. Parameters ---------- prices: daily prices for each stock in portfolio allocs: Allocation for each portfolio component Returns ------- sharpe_ratio: Negative sharpe ratio so the minimizer finds the maximum """ #Get portfolio value port_val = get_portfolio_value(prices, allocs) #Get portfolio statistics cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats( port_val) return -sharpe_ratio
def try_get_portfolio_stats(self, portvals): statsMethodExists = True # First try from previous assignment file try: cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats(portvals) except AttributeError: statsMethodExists = False if statsMethodExists: return statsMethodExists, cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio # Otherwise try this function try: cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = marketsim.assess_my_portfolio(portvals) except AttributeError: statsMethodExists = False if statsMethodExists: return statsMethodExists, cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio return False, 0.0, 0.0, 0.0, 0.0
def test_orders(self): portvals = marketsim.compute_portvals(orders_file = "./orders/orders.csv", start_val=1000000) final_portfolio_value = portvals.ix[-1,:][0] final_portfolio_dataframe_length = len(portvals) self.assertAlmostEqual(1133860.0, final_portfolio_value, 4, "Final portfolio value {} is incorrect".format(final_portfolio_value), delta=None) self.assertEqual(240, final_portfolio_dataframe_length, "Final portfolio dataframe length {} is incorrect".format(final_portfolio_dataframe_length)) cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats(portvals) expected_value = 1.21540888742 self.assertAlmostEqual(expected_value, sharpe_ratio[0], 4, "Sharpe ratio {} is incorrect. Expected {}".format(sharpe_ratio[0], expected_value), delta=None) expected_value = 0.13386 self.assertAlmostEqual(expected_value, cum_ret[0], 4, "Cumulative return {} is incorrect. Expected {}".format(cum_ret[0], expected_value), delta=None) expected_value = 0.00720514136323 self.assertAlmostEqual(expected_value, std_daily_ret[0], 4, "Standard deviation {} is incorrect. Expected {}".format(std_daily_ret[0], expected_value), delta=None) expected_value = 0.000551651296638 self.assertAlmostEqual(expected_value, avg_daily_ret[0], 4, "Avg daily return {} is incorrect. Expected {}".format(avg_daily_ret[0], expected_value), delta=None) '''
def test_orders_leverage_2(self): portvals = marketsim.compute_portvals(orders_file = "./orders/orders-leverage-2.csv", start_val=1000000) final_portfolio_value = portvals.ix[-1,:][0] final_portfolio_dataframe_length = len(portvals) self.assertAlmostEqual(1074650.0, final_portfolio_value, 4, "Final portfolio value is {} incorrect".format(final_portfolio_value), delta=None) self.assertEqual(37, final_portfolio_dataframe_length, "Final portfolio dataframe length {} is incorrect".format(final_portfolio_dataframe_length)) cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats(portvals) expected_value = 4.92529481246 self.assertAlmostEqual(expected_value, sharpe_ratio[0], 4, "Sharpe ratio {} is incorrect. Expected {}".format(sharpe_ratio[0], expected_value), delta=None) expected_value = 0.07465 self.assertAlmostEqual(expected_value, cum_ret[0], 4, "Cumulative return {} is incorrect. Expected {}".format(cum_ret[0], expected_value), delta=None) expected_value = 0.00651837064888 self.assertAlmostEqual(expected_value, std_daily_ret[0], 4, "Standard deviation {} is incorrect. Expected {}".format(std_daily_ret[0], expected_value), delta=None) expected_value = 0.00202241842159 self.assertAlmostEqual(expected_value, avg_daily_ret[0], 4, "Avg dailt return {} is incorrect. Expected".format(avg_daily_ret[0], expected_value), delta=None) '''
def test_orders_leverage_1(self): portvals = marketsim.compute_portvals(orders_file = "./orders/orders-leverage-1.csv", start_val=1000000) final_portfolio_value = portvals.ix[-1,:][0] final_portfolio_dataframe_length = len(portvals) self.assertAlmostEqual(1050160.0, final_portfolio_value, 4, "Final portfolio value is {} incorrect".format(final_portfolio_value), delta=None) self.assertEqual(106, final_portfolio_dataframe_length, "Final portfolio dataframe length {} is incorrect".format(final_portfolio_dataframe_length)) cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats(portvals) expected_value = 1.19402406143 self.assertAlmostEqual(expected_value, sharpe_ratio[0], 4, "Sharpe ratio {} is incorrect. Expected {}".format(sharpe_ratio[0], expected_value), delta=None) expected_value = 0.05016 self.assertAlmostEqual(expected_value, cum_ret[0], 4, "Cumulative return {} is incorrect. Expected {}".format(cum_ret[0], expected_value), delta=None) expected_value = 0.00647534272091 self.assertAlmostEqual(expected_value, std_daily_ret[0], 4, "Standard deviation {} is incorrect. Expected {}".format(std_daily_ret[0], expected_value), delta=None) expected_value = 0.000487052265169 self.assertAlmostEqual(expected_value, avg_daily_ret[0], 4, "Avg daily return {} is incorrect. Expected {}".format(avg_daily_ret[0], expected_value), delta=None) '''
def test_orders_leverage_3(self): portvals = marketsim.compute_portvals(orders_file = "./orders/orders-leverage-3.csv", start_val=1000000) final_portfolio_value = portvals.ix[-1,:][0] final_portfolio_dataframe_length = len(portvals) self.assertAlmostEqual(1050160.0, final_portfolio_value, 4, "Final portfolio value is {} incorrect".format(final_portfolio_value), delta=None) self.assertEqual(141, final_portfolio_dataframe_length, "Final portfolio dataframe length {} is incorrect".format(final_portfolio_dataframe_length)) cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats(portvals) expected_value = 1.03455887842 self.assertAlmostEqual(expected_value, sharpe_ratio[0], 4, "Sharpe ratio {} is incorrect. Expected {}".format(sharpe_ratio[0], expected_value), delta=None) expected_value = 0.05016 self.assertAlmostEqual(expected_value, cum_ret[0], 4, "Cumulative return {} is incorrect. Expected {}".format(cum_ret[0], expected_value), delta=None) expected_value = 0.00560508094997 self.assertAlmostEqual(expected_value, std_daily_ret[0], 4, "Standard deviation {} is incorrect. Expected {}".format(std_daily_ret[0], expected_value), delta=None) expected_value = 0.000365289198877 self.assertAlmostEqual(expected_value, avg_daily_ret[0], 4, "Avg dailt return {} is incorrect. Expected".format(avg_daily_ret[0], expected_value), delta=None) '''
def test_orders2(self): portvals = marketsim.compute_portvals(orders_file = "./orders/orders2.csv", start_val=1000000) final_portfolio_value = portvals.ix[-1,:][0] final_portfolio_dataframe_length = len(portvals) self.assertAlmostEqual(1078752.6, final_portfolio_value, 4, "Final portfolio value {} is incorrect".format(final_portfolio_value), delta=None) self.assertEqual(232, final_portfolio_dataframe_length, "Final portfolio dataframe length {} is incorrect".format(final_portfolio_dataframe_length)) cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats(portvals) expected_value = 0.788982285751 self.assertAlmostEqual(expected_value, sharpe_ratio[0], 4, "Sharpe ratio {} is incorrect. Expected {}".format(sharpe_ratio[0], expected_value), delta=None) expected_value = 0.0787526 self.assertAlmostEqual(expected_value, cum_ret[0], 4, "Cumulative return {} is incorrect. Expected {}".format(cum_ret[0], expected_value), delta=None) expected_value = 0.00711102080156 self.assertAlmostEqual(expected_value, std_daily_ret[0], 4, "Standard deviation {} is incorrect. Expected {}".format(std_daily_ret[0], expected_value), delta=None) expected_value = 0.000353426354584 self.assertAlmostEqual(expected_value, avg_daily_ret[0], 4, "Avg daily return {} is incorrect. Expected {}".format(avg_daily_ret[0], expected_value), delta=None) '''
def test_orders_short(self): portvals = marketsim.compute_portvals(orders_file = "./orders/orders-short.csv", start_val=1000000) final_portfolio_value = portvals.ix[-1,:][0] final_portfolio_dataframe_length = len(portvals) self.assertAlmostEqual(998035.0, final_portfolio_value, 4, "Final portfolio value {} is incorrect".format(final_portfolio_value), delta=None) self.assertEqual(11, final_portfolio_dataframe_length, "Final portfolio dataframe length {} is incorrect".format(final_portfolio_dataframe_length)) cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats(portvals) expected_value = -0.446948390642 self.assertAlmostEqual(expected_value, sharpe_ratio[0], 4, "Sharpe ratio {} is incorrect. Expected {}".format(sharpe_ratio[0], expected_value), delta=None) expected_value = -0.001965 self.assertAlmostEqual(expected_value, cum_ret[0], 4, "Cumulative return {} is incorrect. Expected {}".format(cum_ret[0], expected_value), delta=None) expected_value = 0.00634128215394 self.assertAlmostEqual(expected_value, std_daily_ret[0], 4, "Standard deviation {} is incorrect. Expected {}".format(std_daily_ret[0], expected_value), delta=None) expected_value = -0.000178539446839 self.assertAlmostEqual(expected_value, avg_daily_ret[0], 4, "Avg daily return {} is incorrect. Expected {}".format(avg_daily_ret[0], expected_value), delta=None) '''
def test_compute_portvals(self): orders_file = "./orders/orders.csv" portvals = compute_portvals(orders_file) # Check if portvals is a dataframe self.assertTrue(isinstance(portvals, pd.DataFrame)) # Test portfolio stats cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats( portvals, daily_rf=0.0, samples_per_year=252.0) self.assertTrue(math.isclose(cum_ret, 0.108872698544, rel_tol=0.02), "Cumulative return is incorrect") self.assertTrue( math.isclose(avg_daily_ret, 0.000459098655493, rel_tol=0.02), "Average daily return is incorrect") self.assertTrue( math.isclose(std_daily_ret, 0.00730509916835, rel_tol=0.02), "Standard deviation is incorrect") self.assertTrue( math.isclose(sharpe_ratio, 0.997654521878, rel_tol=0.02), "Sharpe ratio is incorrect") self.assertTrue( math.isclose(portvals.iloc[-1, -1], 1106025.8065, rel_tol=0.02), "Portfolio value is incorrect")
def optimize_portfolio(sd=dt.datetime(2008,1,1), ed=dt.datetime(2009,1,1), \ syms=['GOOG','AAPL','GLD','XOM'], gen_plot=False): start_val = 1000000 daily_rf = 0 samples_per_year = 252 # Read in adjusted closing prices for given symbols, date range dates = pd.date_range(sd, ed) prices_all = get_data(syms, dates) # automatically adds SPY prices = prices_all[syms] # only portfolio symbols prices_SPY = prices_all['SPY'] # only SPY, for comparison later # find the allocations for the optimal portfolio allocGuess = np.ones(len(syms), dtype='float32') / len(syms) setBnds = tuple([(0, 1) for x, y in enumerate(allocGuess) ]) #create tuple of (0,1) tuples # 'constraints' below constrains allocations to sum to 1 # and 'setBnds' forces each allocation to lie in (0,1) srMax = spo.minimize(cost, allocGuess, bounds = setBnds, \ constraints = ({ 'type': 'eq', 'fun': lambda inputs: 1.0 - np.sum(inputs) }), \ args = (prices,start_val,daily_rf,samples_per_year,), \ method = 'SLSQP', options = {'disp': True}) allocs = srMax.x portVal = get_portfolio_value(prices, allocs, start_val) cr, adr, sddr, sr = get_portfolio_stats(portVal, daily_rf, samples_per_year) # Compare daily portfolio value with SPY using a normalized plot if gen_plot: df_temp = pd.concat([portVal, prices_SPY], keys=['Portfolio', 'SPY'], axis=1) plot_normalized_data(df_temp, 'Optimized portfolio values', 'date', \ 'normalized price') return allocs, cr, adr, sddr, sr
def try_get_portfolio_stats(self, portvals): statsMethodExists = True # First try from previous assignment file try: cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats( portvals) except AttributeError: statsMethodExists = False if statsMethodExists: return statsMethodExists, cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio # Otherwise try this function try: cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = marketsim.assess_my_portfolio( portvals) except AttributeError: statsMethodExists = False if statsMethodExists: return statsMethodExists, cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio return False, 0., 0., 0., 0.
def test_compute_portvals(self): orders_file = "./orders/orders2.csv" portvals = compute_portvals(orders_file) # Check if portvals is a dataframe self.assertTrue(isinstance(portvals, pd.DataFrame)) # Test portfolio stats cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats( portvals, daily_rf=0.0, samples_per_year=252.0) self.assertTrue(math.isclose(cum_ret, 0.0538411196951, rel_tol=0.02), "Cumulative return is incorrect") self.assertTrue( math.isclose(avg_daily_ret, 0.000253483085898, rel_tol=0.02), "Average daily return is incorrect") self.assertTrue( math.isclose(std_daily_ret, 0.00728172910323, rel_tol=0.02), "Standard deviation is incorrect") self.assertTrue( math.isclose(sharpe_ratio, 0.552604907987, rel_tol=0.02), "Sharpe ratio is incorrect") self.assertTrue( math.isclose(portvals.iloc[-1, -1], 1051088.0915, rel_tol=0.02), "Portfolio value is incorrect")
def cost(allocs, prices, start_val, daily_rf, samples_per_year): portVal = get_portfolio_value(prices, allocs, start_val) cr, adr, sddr, sr = get_portfolio_stats(portVal, daily_rf, samples_per_year) return -sr
def min_fun(x): x = np.array(x) port_val = get_portfolio_value(prices, x) cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats(port_val) return -sharpe_ratio
def min_sharpe_ratio(allocs): '''Returns the sharpe ratio of the portfolio with weights.''' port_val = get_portfolio_value(prices, allocs, start_val=1) sharpe = get_portfolio_stats(port_val)[3] return -sharpe
def function_to_minimize(allocs, prices): port_val = get_portfolio_value(prices, allocs, start_val=1000000) stats = get_portfolio_stats(port_val) sharpe_ratio = stats[3] return -sharpe_ratio
def min_func_sharpe(weights, prices): port_val = get_portfolio_value(prices, weights) return -get_portfolio_stats(port_val)[3]
def sharpe_ratio(allocs,prices): port_val = get_portfolio_value(prices, allocs) cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats(port_val) return -1*sharpe_ratio
def statistics(weights): weights = np.array(weights) port_val = get_portfolio_value(df, weights, 1) cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats( port_val) return sharpe_ratio
def min_func_sharpe(allocs, prices): cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats( get_portfolio_value(prices, allocs, 1)) return (-1 * sharpe_ratio)
def test_run(): """Driver function.""" # Define input parameters start_date = '2007-12-31' end_date = '2009-12-31' orders_file = os.path.join("orders", "current_order.csv") dates = pd.date_range(start_date, end_date) symbols = ['IBM'] df = get_data(symbols, dates, True) window_size = 20 sma_band, upper_band, lower_band = get_bands(df['IBM'],window=window_size) #+1 going out, -1 coming in transition_array_upper = np.pad(np.diff(np.array(df['IBM'] > upper_band).astype(int)), (1,0), 'constant', constant_values = (0,)) #+2 stock price going up,-2 stock price going down transition_array_sma = np.pad(np.diff(np.array(df['IBM'] > sma_band).astype(int)*2), (1,0), 'constant', constant_values = (0,)) #+3 stock price going up from lower_band,-3 stock price going down from lower_band transition_array_lower = np.pad(np.diff(np.array(df['IBM'] > lower_band).astype(int)*3), (1,0), 'constant', constant_values = (0,)) write_orders(df,transition_array_upper,transition_array_sma,transition_array_lower, orders_file) ax = df['IBM'].plot(title="Bollinger Bands", label='IBM') sma_band.plot(label='SMA', ax=ax, color = 'Goldenrod') upper_band.plot(label='Upper Bollinger Band', ax=ax, color = 'Turquoise') lower_band.plot(label='Lower Bollinger Band', ax=ax, color = 'Turquoise') ax.set_xlabel("Date") ax.set_ylabel("Price") ax.legend(loc='upper left') plt.show() portvals = compute_portvals(start_date, end_date, orders_file, 10000) # Get portfolio stats cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats(portvals) # Simulate a $SPX-only reference portfolio to get stats prices_SPX = get_data(['$SPX'], pd.date_range(start_date, end_date)) prices_SPX = prices_SPX[['$SPX']] # remove SPY portvals_SPX = get_portfolio_value(prices_SPX, [1.0]) cum_ret_SPX, avg_daily_ret_SPX, std_daily_ret_SPX, sharpe_ratio_SPX = get_portfolio_stats(portvals_SPX) # Compare portfolio against $SPX print "Data Range: {} to {}".format(start_date, end_date) print print "Sharpe Ratio of Fund: {}".format(sharpe_ratio) print "Sharpe Ratio of $SPX: {}".format(sharpe_ratio_SPX) print print "Cumulative Return of Fund: {}".format(cum_ret) print "Cumulative Return of $SPX: {}".format(cum_ret_SPX) print print "Standard Deviation of Fund: {}".format(std_daily_ret) print "Standard Deviation of $SPX: {}".format(std_daily_ret_SPX) print print "Average Daily Return of Fund: {}".format(avg_daily_ret) print "Average Daily Return of $SPX: {}".format(avg_daily_ret_SPX) print print "Final Portfolio Value: {}".format(portvals[-1]) # Plot computed daily portfolio value df_temp = pd.concat([portvals, prices_SPX['$SPX']], keys=['Portfolio', 'SPY'], axis=1) plot_normalized_data(df_temp, title="Daily portfolio value")
def min_func_sharpe(allocs, prices): cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats(get_portfolio_value(prices, allocs, 1)) return (-1*sharpe_ratio)
def sharp_func(allocs, prices): port_val = get_portfolio_value(prices, allocs, start_val=1) sharpe_ratio = get_portfolio_stats(port_val)[3] return sharpe_ratio * -1
def add_evidence(self, df_prices, symbol="IBM", start_val=100000): """Create a QLearner, and train it for trading. Parameters: df_prices: Data price dataframe symbol: The stock symbol to act on start_val: Start value of the portfolio which contains only the symbol """ # Get features and thresholds df_features = self.get_features(df_prices['Adj Close']) thresholds = self.get_thresholds(df_features, self.num_steps) cum_returns = [] epochs = [] for epoch in range(1, self.epochs + 1): # Initial position is holding nothing position = self.CASH # Create a series that captures order signals based on actions taken orders = pd.Series(index=df_features.index) # Iterate over the data by date for day, date in enumerate(df_features.index): # Get a state; add 1 to position so that states >= 0 state = self.discretize(df_features.loc[date], position + 1, thresholds) # On the first day, get an action without updating the Q-table if date == df_features.index[0]: action = self.q_learner.query_set_state(state) # On other days, calculate the reward and update the Q-table else: prev_price = df_prices['Adj Close'].iloc[day - 1] curr_price = df_prices['Adj Close'].loc[date] reward = self.get_daily_reward(prev_price, curr_price, position) action = self.q_learner.query(state, reward) # On the last day, close any open positions if date == df_features.index[-1]: new_pos = -position else: new_pos = self.get_position(position, action - 1) # Add new_pos to orders orders.loc[date] = new_pos # Update current position position += new_pos df_trades = create_df_trades(orders, symbol, self.num_shares) portvals = compute_portvals_single_symbol( df_orders=df_trades, symbol=symbol, start_val=start_val, commission=self.commission, impact=self.impact) cum_return = get_portfolio_stats(portvals)[0] cum_returns.append(cum_return) epochs.append(epoch) if self.verbose: print(epoch, cum_return) # Check for convergence after running for at least 20 epochs if epoch > 10: # Stop if the cum_return doesn't improve for 10 epochs if self.has_converged(cum_returns): break if self.verbose: return plot_cum_return(epochs, cum_returns)
def find_negative_sharpe(allocs, prices): port_val = get_portfolio_value(prices, allocs) cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats( port_val) return sharpe_ratio * (-1.0)
def market_simulator(orders_file, start_val=1000000, daily_rf=0.0, samples_per_year=252.0, save_fig=False, fig_name="plot.png"): """ This function takes in an orders file and execute trades based on the file Parameters: orders_file: The file whose orders will be execute start_val: The starting cash in dollars daily_rf: Daily risk-free rate, assuming it does not change samples_per_year: Sampling frequency per year Returns: Print out final portfolio value of the portfolio, as well as Sharpe ratio, cumulative return, average daily return and standard deviation of the portfolio and $SPX. Plot a chart of the portfolio and $SPX performances """ # Process orders portvals = compute_portvals(orders_file=orders_file, start_val=start_val) if not isinstance(portvals, pd.DataFrame): print("warning, code did not return a DataFrame") # Get portfolio stats cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats( portvals, daily_rf=daily_rf, samples_per_year=samples_per_year) # Get the stats for $SPX for the same date range for comparison start_date = portvals.index.min() end_date = portvals.index.max() SPX_prices = get_data(["$SPX"], pd.date_range(start_date, end_date), addSPY=False).dropna() cum_ret_SPX, avg_daily_ret_SPX, std_daily_ret_SPX, sharpe_ratio_SPX = \ get_portfolio_stats(SPX_prices, daily_rf=daily_rf, samples_per_year=samples_per_year) # Compare portfolio against $SPX print("Date Range: {} to {}".format(start_date, end_date)) print() print("Sharpe Ratio of Fund: {}".format(sharpe_ratio)) print("Sharpe Ratio of $SPX : {}".format(sharpe_ratio_SPX)) print() print("Cumulative Return of Fund: {}".format(cum_ret)) print("Cumulative Return of $SPX : {}".format(cum_ret_SPX)) print() print("Standard Deviation of Fund: {}".format(std_daily_ret)) print("Standard Deviation of $SPX : {}".format(std_daily_ret_SPX)) print() print("Average Daily Return of Fund: {}".format(avg_daily_ret)) print("Average Daily Return of $SPX : {}".format(avg_daily_ret_SPX)) print() print("Final Portfolio Value: {}".format(portvals.iloc[-1, -1])) # Plot the data plot_normalized_data(SPX_prices.join(portvals), "Portfolio vs. SPX", "Date", "Normalized prices", save_fig=save_fig, fig_name=fig_name)
def error_optimal_allocations(allocs, prices): port_val = get_portfolio_value(prices, allocs, 1) cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats(port_val) error = sharpe_ratio * -1 return error
def test_run(): """Driver function.""" # Define input parameters start_date = '2007-12-31' end_date = '2009-12-31' symbol = 'IBM' dates = pd.date_range(start_date, end_date) prices_all = get_data([symbol], dates) prices = prices_all[symbol] # Compute Bollinger Bands rm = get_rolling_mean(prices, window=20) rstd = get_rolling_std(prices, window=20) upper_band, lower_band = get_bollinger_bands(rm, rstd) # Find Bollinger strategy orders df_orders = get_orders_bollinger(symbol, prices, rm, upper_band, lower_band, window=20) # Plot raw values, rolling mean and Bollinger Bands plot_data_bollinger(symbol, prices, rm, upper_band, lower_band, df_orders) #orders_file = os.path.join(".\orders", "orders-short.csv") with open('orders3.csv', 'wb') as outfile: writer = csv.writer(outfile, delimiter=',') writer.writerow(['Date', 'Symbol', 'Order', 'Shares']) for i in range(len(df_orders)): writer.writerow([df_orders.ix[i,0].strftime('%Y-%m-%d'), df_orders.ix[i,1], df_orders.ix[i,2], df_orders.ix[i,3]]) ########################################################################### orders_file = os.path.join("orders3.csv") start_val = 10000 # Process orders portvals = compute_portvals(start_date, end_date, orders_file, start_val) if isinstance(portvals, pd.DataFrame): portvals = portvals[portvals.columns[0]] # Get portfolio stats cum_ret, avg_daily_ret, std_daily_ret, sharpe_ratio = get_portfolio_stats(portvals) # Simulate a $SPX-only reference portfolio to get stats prices_SPX = get_data(['$SPX'], pd.date_range(start_date, end_date)) prices_SPX = prices_SPX[['$SPX']] # remove SPY portvals_SPX = get_portfolio_value(prices_SPX, [1.0]) cum_ret_SPX, avg_daily_ret_SPX, std_daily_ret_SPX, sharpe_ratio_SPX = get_portfolio_stats(portvals_SPX) # Compare portfolio against $SPX print "Data Range: {} to {}".format(start_date, end_date) print print "Sharpe Ratio of Fund: {}".format(sharpe_ratio) print "Sharpe Ratio of $SPX: {}".format(sharpe_ratio_SPX) print print "Cumulative Return of Fund: {}".format(cum_ret) print "Cumulative Return of $SPX: {}".format(cum_ret_SPX) print print "Standard Deviation of Fund: {}".format(std_daily_ret) print "Standard Deviation of $SPX: {}".format(std_daily_ret_SPX) print print "Average Daily Return of Fund: {}".format(avg_daily_ret) print "Average Daily Return of $SPX: {}".format(avg_daily_ret_SPX) print print "Final Portfolio Value: {}".format(portvals[-1])
def add_evidence(self, symbol="IBM", start_date=dt.datetime(2008,1,1), end_date=dt.datetime(2009,12,31), start_val = 10000): """Create a QLearner, and train it for trading. Parameters: symbol: The stock symbol to act on start_date: A datetime object that represents the start date end_date: A datetime object that represents the end date start_val: Start value of the portfolio which contains only the symbol """ dates = pd.date_range(start_date, end_date) # Get adjusted close prices for symbol df_prices = get_data([symbol], dates) # Get features and thresholds df_features = self.get_features(df_prices[symbol]) thresholds = self.get_thresholds(df_features, self.num_steps) cum_returns = [] for epoch in range(1, self.epochs + 1): # Initial position is holding nothing position = self.CASH # Create a series that captures order signals based on actions taken orders = pd.Series(index=df_features.index) # Iterate over the data by date for day, date in enumerate(df_features.index): # Get a state; add 1 to position so that states >= 0 state = self.discretize(df_features.loc[date], position + 1, thresholds) # On the first day, get an action without updating the Q-table if date == df_features.index[0]: # Get the first action based on nothing # action = self.q_learner.act(state) action = self.q_learner.act(state, 0.0, update=False) # On other days, calculate the reward and update the Q-table else: prev_price = df_prices[symbol].iloc[day-1] curr_price = df_prices[symbol].loc[date] reward = self.get_daily_reward(prev_price, curr_price, position) action = self.q_learner.act(state, reward, update=True, done=date==df_features.index[-1]) # On the last day, close any open positions if date == df_features.index[-1]: new_pos = -position else: new_pos = self.get_position(position, action - 1) # Add new_pos to orders orders.loc[date] = new_pos # Update current position position += new_pos self.q_learner.replay(batch_size=32) df_trades = create_df_trades(orders, symbol, self.num_shares) portvals = compute_portvals_single_symbol(df_orders=df_trades, symbol=symbol, start_val=start_val, commission=self.commission, impact=self.impact) cum_return = get_portfolio_stats(portvals)[0] cum_returns.append(cum_return) if self.verbose: print (epoch, cum_return) # Check for convergence after running for at least 20 epochs if epoch > 20: # Stop if the cum_return doesn't improve for 10 epochs if self.has_converged(cum_returns): break if self.verbose: sns.heatmap(self.q_learner.Q, cmap='Blues') plt.plot(cum_returns) plt.xlabel("Epoch") plt.ylabel("Cumulative return (%)") plt.show()
def get_sharpe_ratio(allocs,prices): port_val = get_portfolio_value(prices,allocs) sharpe_ratio = get_portfolio_stats(port_val)[-1] sharpe_ratio = -1.0 * sharpe_ratio return sharpe_ratio