def test_marketsim(description, group, inputs, outputs, grader): """Test compute_portvals() returns correct daily portfolio values. Requires test description, test case group, inputs, expected outputs, and a grader fixture. """ points_earned = 0.0 # initialize points for this test case try: # Try to import student code (only once) if not main_code in globals(): import importlib # * Import module mod = importlib.import_module(main_code) globals()[main_code] = mod # * Import methods to test for m in ['compute_portvals']: globals()[m] = getattr(mod, m) incorrect = False msgs = [] if group == 'author': try: auth_string = run_with_timeout(marketsim.author, seconds_per_test_case, (), {}) if auth_string == 'tb34': incorrect = True msgs.append(" Incorrect author name (tb34)") points_earned = -10 elif auth_string == '': incorrect = True msgs.append(" Empty author name") points_earned = -10 except Exception as e: incorrect = True msgs.append( " Exception occured when calling author() method: {}". format(e)) points_earned = -10 else: # Unpack test case orders_file = inputs['orders_file'] start_val = inputs['start_val'] impct = inputs['impact'] commish = inputs['commission'] portvals = None fullpath_orders_file = get_orders_data_file(orders_file) portvals = run_with_timeout( compute_portvals, seconds_per_test_case, (), { 'orders_file': fullpath_orders_file, 'start_val': start_val, 'commission': commish, 'impact': impct }) # * Check return type is correct, coax into Series assert (type(portvals) == pd.Series) or ( type(portvals) == pd.DataFrame and len(portvals.columns) == 1), "You must return a Series or single-column DataFrame!" if type(portvals) == pd.DataFrame: portvals = portvals[portvals.columns[ 0]] # convert single-column DataFrame to Series if group == 'basic': if len(portvals) != outputs['num_days']: incorrect = True msgs.append( " Incorrect number of days: {}, expected {}".format( len(portvals), outputs['num_days'])) else: points_earned += 2.0 if abs(portvals[-1] - outputs['last_day_portval']) > ( 0.001 * outputs['last_day_portval']): incorrect = True msgs.append( " Incorrect final value: {}, expected {}".format( portvals[-1], outputs['last_day_portval'])) else: points_earned += 5.0 adr, sr = get_stats(portvals) if abs(sr - outputs['sharpe_ratio']) > abs( 0.001 * outputs['sharpe_ratio']): incorrect = True msgs.append( " Incorrect sharpe ratio: {}, expected {}".format( sr, outputs['sharpe_ratio'])) else: points_earned += 1.0 if abs(adr - outputs['avg_daily_ret']) > abs( 0.001 * outputs['avg_daily_ret']): incorrect = True msgs.append( " Incorrect avg daily return: {}, expected {}". format(adr, outputs['avg_daily_ret'])) else: points_earned += 1.0 elif group == 'commission' or group == 'impact' or group == 'both': if abs(portvals[-1] - outputs['last_day_portval']) > 0.001: incorrect = True msgs.append( " Incorrect final value: {}, expected {}".format( portvals[-1], outputs['last_day_portval'])) else: points_earned += 2.0 if incorrect: raise IncorrectOutput, "Test failed on one or more output criteria.\n Inputs:\n{}\n Failures:\n{}".format( inputs, "\n".join(msgs)) except Exception as e: # Test result: failed msg = "Test case description: {}\n".format(description) # Generate a filtered stacktrace, only showing erroneous lines in student file(s) tb_list = tb.extract_tb(sys.exc_info()[2]) if 'grading_traceback' in dir(e): tb_list = e.grading_traceback for i in xrange(len(tb_list)): row = tb_list[i] tb_list[i] = (os.path.basename(row[0]), row[1], row[2], row[3] ) # show only filename instead of long absolute path tb_list = [row for row in tb_list if row[0] == 'marketsim_old.py'] if tb_list: msg += "Traceback:\n" msg += ''.join(tb.format_list(tb_list)) # contains newlines msg += "{}: {}".format(e.__class__.__name__, e.message) # Report failure result to grader, with stacktrace grader.add_result( GradeResult(outcome='failed', points=max(points_earned, 0), msg=msg)) raise else: # Test result: passed (no exceptions) grader.add_result( GradeResult(outcome='passed', points=points_earned, msg=None))
def compute_portvals(orders_file="./orders/orders.csv", start_val=1000000): orders = get_orders_data_file(orders_file) orders_data = pd.read_csv(orders) orders_data.sort_values(by='Date', inplace=True, ascending=True) start_date = orders_data.iloc[0, 0] end_date = orders_data.iloc[len(orders_data) - 1, 0] adj_close_prices = get_data(['SPY'], pd.date_range(start_date, end_date)) orders_data_new = orders_data.set_index('Date', inplace=False) orders_join = orders_data_new.join(adj_close_prices) adj_close_prices = adj_close_prices.join(orders_data_new) adj_close_prices = adj_close_prices[['SPY']] adj_close_prices.rename(columns={'SPY': 'Portval'}, inplace=True) portvals = pd.DataFrame().reindex_like(adj_close_prices) cash = start_val equity = 0 portval = cash + equity shares_allocation = {} daily_cash = pd.DataFrame().reindex_like(adj_close_prices) daily_shares_allocation = {} df = adj_close_prices.index df1 = orders_join.index i = 0 orders_data_index = 0 value = df[0] while value in df: value1 = pd.to_datetime(value).strftime('%Y-%m-%d') if (value in df1): sd = orders_data.iloc[orders_data_index, 0] sym = orders_data.iloc[orders_data_index, 1] order = orders_data.iloc[orders_data_index, 2] shares = orders_data.iloc[orders_data_index, 3] adj_close_price = get_data([sym], pd.date_range(sd, sd)) adj_close_price = adj_close_price[[sym]] commission = 9.95 if (not np.isnan(adj_close_price.iloc[0, 0])): if (order == 'SELL'): if (i != 0): cash = daily_cash.iloc[i - 1, 0] cash += adj_close_price.iloc[0, 0] * 0.995 * shares cash -= commission if (i != 0): previous_date = pd.to_datetime( df[i - 1]).strftime('%Y-%m-%d') shares_allocation = daily_shares_allocation[ previous_date] shares_allocation_n = shares_allocation.copy() if (shares_allocation_n.has_key(sym)): shares_allocation_n[sym] -= shares else: shares_allocation_n[sym] = 0 - shares if (order == 'BUY'): if (i != 0): cash = daily_cash.iloc[i - 1, 0] cash -= adj_close_price.iloc[0, 0] * 1.005 * shares cash -= commission if (i != 0): previous_date = pd.to_datetime( df[i - 1]).strftime('%Y-%m-%d') shares_allocation = daily_shares_allocation[ previous_date] shares_allocation_n = shares_allocation.copy() if (not shares_allocation.has_key(sym)): shares_allocation_n[sym] = shares else: shares_allocation_n[sym] += shares orders_data_index += 1 leverage = sum_of_abs_of_stock_positions( shares_allocation_n, value1) / (compute_equity(shares_allocation_n, value1) + cash) if (leverage <= 2.0): daily_shares_allocation[value1] = shares_allocation_n daily_cash.set_value(value1, 'Portval', cash) equity = compute_equity(shares_allocation_n, value1) portval = cash + equity portvals.set_value(sd, 'Portval', portval) else: last_date = pd.to_datetime(df[i - 1]).strftime('%Y-%m-%d') sa = daily_shares_allocation[last_date] daily_shares_allocation[value1] = sa c = daily_cash.iloc[i - 1, 0] daily_cash.set_value(value1, 'Portval', c) e = compute_equity(sa, value1) p = c + e portvals.set_value(sd, 'Portval', p) i += 1 if (i == len(df)): break value = df[i] else: current_date = value1 previous_date = pd.to_datetime(df[i - 1]).strftime('%Y-%m-%d') next_order_date = pd.to_datetime( df1[orders_data_index]).strftime('%Y-%m-%d') new_data = get_data(['SPY'], pd.date_range(current_date, next_order_date)) l = i + len(new_data) - 2 b = i date_before_next_order_date = pd.to_datetime( df[l]).strftime('%Y-%m-%d') cash_new = daily_cash.iloc[i - 1, 0] shares_allocation_new = daily_shares_allocation[previous_date] equity = compute_equity_range(shares_allocation_new, current_date, date_before_next_order_date) portvals_intermed = equity + cash_new portvals['Portval'][ current_date:date_before_next_order_date] = portvals_intermed daily_cash['Portval'][ current_date:date_before_next_order_date] = cash_new for a in range(b, l + 1): date_assigned = pd.to_datetime(df[a]).strftime('%Y-%m-%d') daily_shares_allocation[date_assigned] = shares_allocation_new i = l + 1 value = df[i] portvals = portvals.groupby(portvals.index).last() return portvals