diff --git a/marketsim.py b/marketsim.py deleted file mode 100644 index 91c0b38..0000000 --- a/marketsim.py +++ /dev/null @@ -1,163 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Wed Feb 5 21:56:42 2020 - -@author: cpan -""" - -"""MC2-P1: Market simulator.""" - -import pandas as pd -import numpy as np -# import datetime as dt -# import os -from util import get_data, plot_data - -def normalize_data(df): - return df/df.iloc[0,:] - -def fill_missing_values(df_data): - '''First fill forward and then fill backward''' - df_data.fillna(method="ffill", inplace=True) - df_data.fillna(method="bfill", inplace=True) - -def get_orders(orders_file): - if isinstance(orders_file, pd.DataFrame): - # orders_df = orders_file.set_index('Date') - orders_df = orders_file - else: - orders_df = pd.read_csv(orders_file, index_col = 'Date', parse_dates = True, - na_values = ['nan']) - orders_df = orders_df.dropna() - orders_df = orders_df.sort_index() - return orders_df - -def compute_daily_returns(df): - daily_returns = df.copy() - daily_returns[1:] = (df[1:] / df[:-1].values) - 1 - daily_returns.iloc[0, :] = 0 - return daily_returns - -def compute_portfolio_stats(price, allocs=[0.1,0.2,0,3,0.4], rfr=0.0, sf=252.0): - norm_price = normalize_data(price) - norm_positions_val = norm_price * allocs - if len(norm_positions_val.columns) == 1: - norm_portfolio_val = norm_positions_val - else: - norm_portfolio_val = norm_positions_val.sum(axis=1).to_frame('PORTFOLIO') - cr = norm_portfolio_val.iloc[-1] / norm_portfolio_val.iloc[0] -1 - daily_returns = compute_daily_returns(norm_portfolio_val) - daily_returns = daily_returns[1:] # remove first row (all zeros) - adr = daily_returns.mean() - sddr = daily_returns.std() - sr = np.sqrt(sf) * (adr - rfr)/sddr - return cr, adr, sddr, sr - -def plot_against_SPY(df): - df_temp = df.copy() - if 'SPY' not in df_temp.columns: - df_SPY = get_data(['SPY'], pd.to_datetime(df_temp.index.values)) - df_temp['SPY'] = df_SPY.values - else: - df_SPY = df_temp['SPY'] - df_temp = normalize_data(df_temp) - plot_data(df_temp) - return df_SPY - -def compute_portvals(orders_file = "./orders/orders.csv", start_val = 1000000, - commission=9.95, impact=0.005): - #read in order data - orders_df = get_orders(orders_file) - #scan symbols - symbols = list(set(orders_df['Symbol'].values)) - #get date range - dates = pd.date_range(orders_df.index.values[0], orders_df.index.values[-1]) - #read in prices - prices = get_data(symbols, dates) - # fill_missing_values(prices) # included in get_data() function - prices = prices[symbols] - #add an extra column 'Cash' and initialize it to all ones - prices['Cash'] = np.ones(prices.shape[0]) - - #duplicate price df into a units df, intialize it to all zeros - positions=prices*0.0 - #initialize cash position with starting value - positions.loc[positions.index.values[0],['Cash']]=start_val - - #adjust positions to show how stock units and cash are changing over time with orders - for index, row in orders_df.iterrows(): - stock_sym = row['Symbol'] - order_price = prices.loc[index, stock_sym] - order_shrs = row['Shares'] - - if row['Order'].upper() == 'BUY': - if positions.loc[index, 'Cash'] < order_shrs*order_price +\ - commission + order_shrs*order_price*impact: - # print('Not enough cash to excute the order:\n', row) - pass - else: - #update positions on transaction days - positions.loc[index, stock_sym] += order_shrs - positions.loc[index, "Cash"] -= order_shrs*order_price - #deduct commission - positions.loc[index,"Cash"] -= commission - #impact = no. of orders in transaction * price of each share * impact. - positions.loc[index,"Cash"] -= order_shrs*order_price*impact - elif row['Order'].upper() == 'SELL': - if positions.loc[index, stock_sym] < order_shrs: - # print('Not enough shares to sell to fill the order:\n', row) - pass - else: - positions.loc[index, stock_sym] -= order_shrs - positions.loc[index, "Cash"] += order_shrs*order_price - #deduct commission - positions.loc[index,"Cash"] -= commission - #impact = no. of orders in transaction * price of each share * impact. - positions.loc[index,"Cash"] -= order_shrs*order_price*impact - - # propagate positions beyond transaction days - start_row = positions.index.get_loc(index) + 1 - positions.iloc[start_row:, :] = positions.iloc[start_row-1].values - - #calculate port_vals - port_vals=prices*positions - port_vals.insert(0, 'Portfolio', port_vals.sum(axis=1)) - - return port_vals - -def test_code(): - of = "./orders/orders-05.csv" - sv = 1000000 - - # Process orders - portvals = compute_portvals(orders_file = of, start_val = sv) - if isinstance(portvals, pd.DataFrame): - portvals = portvals[portvals.columns[0]].to_frame() # just get the first column - else: - print("warning, code did not return a DataFrame") - - # Get portfolio stats - start_date = pd.to_datetime(portvals.index.values[0]) - end_date = pd.to_datetime(portvals.index.values[-1]) - price_SPY = plot_against_SPY(portvals) - #portfolio stats calculated similar to assess_portfolio - rfr=0 - sf=252 - - cr, adr, sddr, sr = compute_portfolio_stats(portvals, [1.0], rfr, sf) - crSP,adrSP,sddrSP,srSP = compute_portfolio_stats(price_SPY, [1.0], rfr, sf) - # Compare portfolio against $SPX - print("\nDate Range: {} to {}".format(start_date.date(), end_date.date())) - print() - print("Sharpe Ratio: {}, {}".format(sr, srSP)) - print() - print("Cumulative Return: {}, {}".format(cr, crSP)) - print() - print("Standard Deviation: {}, {}".format(sddr, sddrSP)) - print() - print("Average Daily Return: {}, {}".format(adr, adrSP)) - print() - print("Final Portfolio Value: {:.2f}".format(portvals['Portfolio'].iloc[-1])) - -if __name__ == "__main__": - test_code() \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 0767ca9..b8fc103 100644 Binary files a/requirements.txt and b/requirements.txt differ